Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete attachments when deleting report #4447

Merged
merged 3 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions src/main/java/mil/dds/anet/database/AttachmentDao.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package mil.dds.anet.database;

import static org.jdbi.v3.core.statement.EmptyHandling.NULL_KEYWORD;

import io.leangen.graphql.annotations.GraphQLRootContext;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -8,6 +10,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import mil.dds.anet.AnetObjectEngine;
Expand All @@ -21,6 +24,7 @@
import mil.dds.anet.views.ForeignKeyFetcher;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.io.EofException;
import org.jdbi.v3.core.result.ResultIterable;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.customizer.BindBean;
import org.jdbi.v3.sqlobject.statement.SqlBatch;
Expand Down Expand Up @@ -197,9 +201,43 @@ private void insertAttachmentRelatedObjects(String uuid,
ab.insertAttachmentRelatedObjects(uuid, attachmentRelatedObjects);
}

private void deleteAttachmentRelatedObjects(String uuid) {
getDbHandle().execute(
"/* deleteAttachmentRelatedObjects */ DELETE FROM \"attachmentRelatedObjects\" WHERE \"attachmentUuid\" = ?",
uuid);
private void deleteAttachmentRelatedObjects(String attachmentUuid) {
getDbHandle()
.createUpdate(
"/* deleteAttachmentRelatedObjects */ DELETE FROM \"attachmentRelatedObjects\""
+ " WHERE \"attachmentUuid\" = :attachmentUuid")
.bind("attachmentUuid", attachmentUuid).execute();
}

public void deleteAttachments(String relatedObjectType, String relatedObjectUuid) {
final String relatedObjectTypeParam = "relatedObjectType";
final String relatedObjectUuidParam = "relatedObjectUuid";
final String fromClause = "FROM \"attachmentRelatedObjects\" WHERE \"" + relatedObjectTypeParam
+ "\" = :relatedObjectType AND \"" + relatedObjectUuidParam + "\" = :relatedObjectUuid";
final String selectAttachmentUuids = "SELECT \"attachmentUuid\" " + fromClause;

// get uuid's of attachments linked to related object
final Set<String> attachmentUuids = getDbHandle()
.createQuery("/* selectAttachmentUuidsForRelatedObject */ " + selectAttachmentUuids)
.bind(relatedObjectTypeParam, relatedObjectType)
.bind(relatedObjectUuidParam, relatedObjectUuid).mapTo(String.class)
.collect(Collectors.toSet());
if (attachmentUuids.isEmpty()) {
// nothing to delete
return;
}

// delete attachmentRelatedObjects for the related object
getDbHandle().createUpdate("/* deleteAttachmentRelatedObjects */ DELETE " + fromClause)
.bind(relatedObjectTypeParam, relatedObjectType)
.bind(relatedObjectUuidParam, relatedObjectUuid).execute();

// delete attachments for the related object if they no longer have any links
getDbHandle()
.createUpdate("/* deleteAttachments */ DELETE FROM attachments"
+ " WHERE uuid in (<attachmentUuids>) AND uuid NOT IN (" + selectAttachmentUuids + ")")
.bindList(NULL_KEYWORD, "attachmentUuids", attachmentUuids)
.bind(relatedObjectTypeParam, relatedObjectType)
.bind(relatedObjectUuidParam, relatedObjectUuid).execute();
}
}
4 changes: 4 additions & 0 deletions src/main/java/mil/dds/anet/database/ReportDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,10 @@ public int deleteInternal(String reportUuid) {
// Delete orphan notes
noteDao.deleteOrphanNotes();

final AttachmentDao attachmentDao = instance.getAttachmentDao();
// Delete attachments
attachmentDao.deleteAttachments(TABLE_NAME, reportUuid);

// Delete report
// GraphQL mutations *have* to return something, so we return the number of deleted report rows
return getDbHandle()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public void testCreateAttachment()
final Report updatedReport = adminQueryExecutor.report(REPORT_FIELDS, testReport.getUuid());
assertThat(updatedReport.getAttachments()).hasSize(1);
final Attachment reportAttachment = updatedReport.getAttachments().get(0);
assertThat(reportAttachment.getUuid()).isEqualTo(createdAttachmentUuid);
assertThat(reportAttachment.getAttachmentRelatedObjects()).hasSize(1);
assertThat(reportAttachment.getDescription()).isEqualTo(testAttachmentInput.getDescription());
assertThat(reportAttachment.getClassification())
Expand Down Expand Up @@ -122,13 +123,14 @@ public void testDeleteAttachment()
final Report updatedReport = adminQueryExecutor.report(REPORT_FIELDS, testReport.getUuid());
assertThat(updatedReport.getAttachments()).hasSize(1);
final Attachment reportAttachment = updatedReport.getAttachments().get(0);
assertThat(reportAttachment.getUuid()).isEqualTo(createdAttachmentUuid);
assertThat(reportAttachment.getAttachmentRelatedObjects()).hasSize(1);
assertThat(reportAttachment.getDescription()).isEqualTo(testAttachmentInput.getDescription());
assertThat(reportAttachment.getClassification())
.isEqualTo(testAttachmentInput.getClassification());
assertThat(reportAttachment.getFileName()).isEqualTo(testAttachmentInput.getFileName());

// F - delete attachment classification as someone else
// F - delete attachment as someone else
final MutationExecutor erinMutationExecutor =
getMutationExecutor(getRegularUser().getDomainUsername());
failAttachmentDelete(erinMutationExecutor, reportAttachment.getUuid());
Expand Down Expand Up @@ -221,16 +223,15 @@ private AttachmentRelatedObjectInput createAttachmentRelatedObject(final String
private String succeedAttachmentCreate(final MutationExecutor mutationExecutor,
final AttachmentInput attachmentInput)
throws GraphQLRequestPreparationException, GraphQLRequestExecutionException {
final String createdAttachmentUuid =
mutationExecutor.createAttachment(attachmentInput.getUuid(), attachmentInput);
final String createdAttachmentUuid = mutationExecutor.createAttachment("", attachmentInput);
assertThat(createdAttachmentUuid).isNotNull();
return createdAttachmentUuid;
}

private void failAttachmentCreate(final MutationExecutor mutationExecutor,
final AttachmentInput attachmentInput) {
try {
mutationExecutor.createAttachment(attachmentInput.getUuid(), attachmentInput);
mutationExecutor.createAttachment("", attachmentInput);
fail("Expected exception creating attachment");
} catch (Exception expected) {
// OK
Expand Down
42 changes: 39 additions & 3 deletions src/test/java/mil/dds/anet/test/resources/ReportResourceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand All @@ -23,6 +24,8 @@
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.NotFoundException;
import mil.dds.anet.AnetObjectEngine;
import mil.dds.anet.database.ReportDao;
import mil.dds.anet.resources.AttachmentResource;
import mil.dds.anet.test.TestData;
import mil.dds.anet.test.client.AdvisorReportsEntry;
import mil.dds.anet.test.client.AnetBeanList_Location;
Expand All @@ -34,6 +37,9 @@
import mil.dds.anet.test.client.ApprovalStepInput;
import mil.dds.anet.test.client.ApprovalStepType;
import mil.dds.anet.test.client.Atmosphere;
import mil.dds.anet.test.client.Attachment;
import mil.dds.anet.test.client.AttachmentInput;
import mil.dds.anet.test.client.AttachmentRelatedObjectInput;
import mil.dds.anet.test.client.Comment;
import mil.dds.anet.test.client.Location;
import mil.dds.anet.test.client.LocationSearchQueryInput;
Expand Down Expand Up @@ -108,9 +114,10 @@ public class ReportResourceTest extends AbstractResourceTest {
+ " reportPeople %3$s tasks %4$s approvalStep { uuid relatedObjectUuid } location %5$s"
+ " comments %6$s notes %7$s authorizationGroups { uuid name }"
+ " workflow { step { uuid relatedObjectUuid approvers { uuid person { uuid } } }"
+ " person { uuid } type createdAt } reportSensitiveInformation { uuid text } }",
+ " person { uuid } type createdAt } reportSensitiveInformation { uuid text } "
+ " attachments %8$s }",
REPORT_FIELDS, ORGANIZATION_FIELDS, REPORT_PEOPLE_FIELDS, TASK_FIELDS, LOCATION_FIELDS,
COMMENT_FIELDS, NoteResourceTest.NOTE_FIELDS);
COMMENT_FIELDS, NoteResourceTest.NOTE_FIELDS, AttachmentResourceTest.ATTACHMENT_FIELDS);

@Test
public void createReport()
Expand Down Expand Up @@ -1412,8 +1419,9 @@ public void searchAttendeePosition()
}

@Test
public void reportDeleteTest()
void reportDeleteTest()
throws GraphQLRequestExecutionException, GraphQLRequestPreparationException {
final Map<String, Object> attachmentSettings = AttachmentResource.getAttachmentSettings();
final Person elizabeth = getElizabethElizawell();
final MutationExecutor elizabethMutationExecutor =
getMutationExecutor(elizabeth.getDomainUsername());
Expand All @@ -1434,6 +1442,26 @@ public void reportDeleteTest()
assertThat(r).isNotNull();
assertThat(r.getUuid()).isNotNull();

// Attach attachment to test report
final var allowedMimeTypes = (List<String>) attachmentSettings.get("mimeTypes");
final String mimeType = allowedMimeTypes.get(0);

final AttachmentRelatedObjectInput testAroInput = AttachmentRelatedObjectInput.builder()
.withRelatedObjectType(ReportDao.TABLE_NAME).withRelatedObjectUuid(r.getUuid()).build();
final AttachmentInput testAttachmentInput =
AttachmentInput.builder().withFileName("testDeleteAttachment.jpg").withMimeType(mimeType)
.withDescription("a test attachment created by testDeleteAttachment")
.withAttachmentRelatedObjects(Collections.singletonList(testAroInput)).build();
final String createdAttachmentUuid =
adminMutationExecutor.createAttachment("", testAttachmentInput);
assertThat(createdAttachmentUuid).isNotNull();

final Report updatedReport = adminQueryExecutor.report(FIELDS, r.getUuid());
assertThat(updatedReport.getAttachments()).hasSize(1);
final Attachment reportAttachment = updatedReport.getAttachments().get(0);
assertThat(reportAttachment.getUuid()).isEqualTo(createdAttachmentUuid);
assertThat(reportAttachment.getAttachmentRelatedObjects()).hasSize(1);

// Try to delete by jack, this should fail.
try {
jackMutationExecutor.deleteReport("", r.getUuid());
Expand All @@ -1451,6 +1479,14 @@ public void reportDeleteTest()
fail("Expected NotFoundException");
} catch (NotFoundException expectedException) {
}

// Assert that the attachment is gone
try {
adminQueryExecutor.attachment(AttachmentResourceTest.ATTACHMENT_FIELDS,
reportAttachment.getUuid());
fail("Expected NotFoundException");
} catch (NotFoundException expectedException) {
}
}

@Test
Expand Down