Skip to content

Commit 78b91a8

Browse files
damgoujcamrrx
andauthored
[backend/frontend] fix: documents for atomic testings (#3956)
Co-authored-by: Camille Roux <[email protected]>
1 parent 5cf27f1 commit 78b91a8

File tree

7 files changed

+159
-43
lines changed

7 files changed

+159
-43
lines changed

openaev-api/src/main/java/io/openaev/rest/inject/service/InjectService.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ public InjectResultOverviewOutput relaunch(String id) {
405405
Inject duplicatedInject = findAndDuplicateInject(id);
406406
this.throwIfInjectNotLaunchable(duplicatedInject);
407407
Inject savedInject = saveInjectAndStatusAsQueuing(duplicatedInject);
408-
deleteForRelaunch(id);
408+
deleteForRelaunch(id, savedInject.getId());
409409
return injectMapper.toInjectResultOverviewOutput(savedInject);
410410
}
411411

@@ -416,9 +416,9 @@ public void delete(String id) {
416416
}
417417

418418
@Transactional
419-
public void deleteForRelaunch(String id) {
420-
injectDocumentRepository.deleteDocumentsFromInject(id);
421-
injectRepository.deleteByIdNative(id);
419+
public void deleteForRelaunch(String oldId, String newId) {
420+
injectDocumentRepository.updateInjectId(newId, oldId);
421+
injectRepository.deleteByIdNative(oldId);
422422
}
423423

424424
/**

openaev-api/src/main/java/io/openaev/service/AtomicTestingService.java

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public class AtomicTestingService {
6060
private final InjectSearchService injectSearchService;
6161
private final InjectService injectService;
6262
private final GrantService grantService;
63+
private final InjectDocumentRepository injectDocumentRepository;
6364

6465
// -- CRUD --
6566

@@ -119,35 +120,38 @@ public InjectResultOverviewOutput createOrUpdate(AtomicTestingInput input, Strin
119120
injectToSave.setAssetGroups(
120121
fromIterable(this.assetGroupRepository.findAllById(input.getAssetGroups())));
121122

122-
List<String> previousDocumentIds =
123-
injectToSave.getDocuments().stream()
124-
.map(InjectDocument::getDocument)
125-
.map(Document::getId)
126-
.toList();
123+
injectToSave.getDocuments().clear();
127124

128125
Inject finalInjectToSave = injectToSave;
129-
List<InjectDocument> injectDocuments =
130-
input.getDocuments().stream()
131-
.map(
132-
i -> {
133-
if (!previousDocumentIds.contains(i.getDocumentId())) {
134-
InjectDocument injectDocument = new InjectDocument();
135-
injectDocument.setInject(finalInjectToSave);
136-
injectDocument.setDocument(
137-
documentRepository.findById(i.getDocumentId()).orElseThrow());
138-
injectDocument.setAttached(i.isAttached());
139-
return injectDocument;
140-
}
141-
return null;
142-
})
143-
.filter(Objects::nonNull)
144-
.toList();
145-
injectToSave.getDocuments().addAll(injectDocuments);
126+
input
127+
.getDocuments()
128+
.forEach(
129+
i -> {
130+
InjectDocumentId injectDocumentId = new InjectDocumentId();
131+
injectDocumentId.setInjectId(finalInjectToSave.getId());
132+
injectDocumentId.setDocumentId(i.getDocumentId());
133+
InjectDocument injectDocument =
134+
injectDocumentRepository.findById(injectDocumentId).orElse(new InjectDocument());
135+
if (injectDocument.getInject() == null) {
136+
injectDocument.setCompositeId(injectDocumentId);
137+
injectDocument.setInject(finalInjectToSave);
138+
injectDocument.setDocument(
139+
documentRepository.findById(i.getDocumentId()).orElseThrow());
140+
}
141+
injectDocument.setAttached(i.isAttached());
142+
finalInjectToSave
143+
.getDocuments()
144+
.add(
145+
injectId == null
146+
? injectDocument
147+
: injectDocumentRepository.save(injectDocument));
148+
});
149+
146150
if (injectId == null) {
147151
actionMetricCollector.addAtomicTestingCreatedCount();
148152
}
149-
Inject inject = injectRepository.save(injectToSave);
150-
return injectMapper.toInjectResultOverviewOutput(inject);
153+
injectToSave = injectRepository.save(injectToSave);
154+
return injectMapper.toInjectResultOverviewOutput(injectToSave);
151155
}
152156

153157
private ObjectNode setExpectations(

openaev-api/src/test/java/io/openaev/rest/AtomicTestingApiTest.java

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package io.openaev.rest;
22

33
import static io.openaev.injectors.email.EmailContract.EMAIL_DEFAULT;
4+
import static io.openaev.utils.JsonUtils.asJsonString;
45
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
5-
import static org.junit.jupiter.api.Assertions.assertEquals;
6-
import static org.junit.jupiter.api.Assertions.assertNotNull;
6+
import static org.junit.jupiter.api.Assertions.*;
77
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
88
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
99
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@@ -13,6 +13,7 @@
1313
import com.jayway.jsonpath.JsonPath;
1414
import io.openaev.IntegrationTest;
1515
import io.openaev.database.model.*;
16+
import io.openaev.database.repository.DocumentRepository;
1617
import io.openaev.database.repository.InjectRepository;
1718
import io.openaev.database.repository.InjectStatusRepository;
1819
import io.openaev.database.repository.InjectorContractRepository;
@@ -39,6 +40,7 @@ public class AtomicTestingApiTest extends IntegrationTest {
3940
static Inject INJECT_WITHOUT_STATUS;
4041
static InjectStatus INJECT_STATUS;
4142
static InjectorContract INJECTOR_CONTRACT;
43+
static Document DOCUMENT;
4244

4345
@Autowired private AgentComposer agentComposer;
4446
@Autowired private EndpointComposer endpointComposer;
@@ -51,6 +53,7 @@ public class AtomicTestingApiTest extends IntegrationTest {
5153
@Autowired private InjectRepository injectRepository;
5254
@Autowired private InjectorContractRepository injectorContractRepository;
5355
@Autowired private InjectStatusRepository injectStatusRepository;
56+
@Autowired private DocumentRepository documentRepository;
5457
@Autowired private EntityManager entityManager;
5558
@Autowired private ObjectMapper mapper;
5659

@@ -65,6 +68,8 @@ void before() {
6568
InjectStatus injectStatus = InjectStatusFixture.createPendingInjectStatus();
6669
injectStatus.setInject(injectWithPayload);
6770
INJECT_STATUS = injectStatusRepository.save(injectStatus);
71+
72+
DOCUMENT = documentRepository.save(DocumentFixture.getDocumentJpeg());
6873
}
6974

7075
private InjectComposer.Composer getAtomicTestingWrapper(
@@ -137,6 +142,57 @@ void findAnAtomicTestingWithStatusAndCommandLines() throws Exception {
137142
mapper.readTree(expectedExpectationsJson), mapper.readTree(actualExpectationsJson));
138143
}
139144

145+
@Test
146+
@DisplayName("Create and upadte an atomic testing")
147+
@WithMockUser(isAdmin = true)
148+
void createAndUpdateAnAtomicTesting() throws Exception {
149+
String response =
150+
mvc.perform(
151+
post(ATOMIC_TESTINGS_URI)
152+
.contentType(MediaType.APPLICATION_JSON)
153+
.accept(MediaType.APPLICATION_JSON)
154+
.content(
155+
asJsonString(InjectFixture.createAtomicTesting("test", DOCUMENT.getId()))))
156+
.andExpect(status().is2xxSuccessful())
157+
.andReturn()
158+
.getResponse()
159+
.getContentAsString();
160+
assertNotNull(response);
161+
String newInjectId = JsonPath.read(response, "$.inject_id");
162+
response =
163+
mvc.perform(get(ATOMIC_TESTINGS_URI + "/" + newInjectId).accept(MediaType.APPLICATION_JSON))
164+
.andExpect(status().is2xxSuccessful())
165+
.andReturn()
166+
.getResponse()
167+
.getContentAsString();
168+
assertEquals(newInjectId, JsonPath.read(response, "$.inject_id"));
169+
assertEquals("test", JsonPath.read(response, "$.inject_title"));
170+
List<String> documentIds = JsonPath.read(response, "$.injects_documents");
171+
assertEquals(1, documentIds.size());
172+
173+
response =
174+
mvc.perform(
175+
put(ATOMIC_TESTINGS_URI + "/" + newInjectId)
176+
.contentType(MediaType.APPLICATION_JSON)
177+
.accept(MediaType.APPLICATION_JSON)
178+
.content(asJsonString(InjectFixture.createAtomicTesting("test2", null))))
179+
.andExpect(status().is2xxSuccessful())
180+
.andReturn()
181+
.getResponse()
182+
.getContentAsString();
183+
assertNotNull(response);
184+
response =
185+
mvc.perform(get(ATOMIC_TESTINGS_URI + "/" + newInjectId).accept(MediaType.APPLICATION_JSON))
186+
.andExpect(status().is2xxSuccessful())
187+
.andReturn()
188+
.getResponse()
189+
.getContentAsString();
190+
assertEquals(newInjectId, JsonPath.read(response, "$.inject_id"));
191+
assertEquals("test2", JsonPath.read(response, "$.inject_title"));
192+
documentIds = JsonPath.read(response, "$.injects_documents");
193+
assertEquals(0, documentIds.size());
194+
}
195+
140196
@Test
141197
@DisplayName("Duplicate and delete an atomic testing")
142198
@WithMockUser(isAdmin = true)

openaev-api/src/test/java/io/openaev/utils/fixtures/InjectFixture.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package io.openaev.utils.fixtures;
22

33
import static io.openaev.database.model.InjectorContract.CONTRACT_ELEMENT_CONTENT_KEY_EXPECTATIONS;
4+
import static io.openaev.injectors.email.EmailContract.EMAIL_DEFAULT;
45

56
import com.fasterxml.jackson.databind.JsonNode;
67
import com.fasterxml.jackson.databind.ObjectMapper;
78
import com.fasterxml.jackson.databind.node.ArrayNode;
89
import com.fasterxml.jackson.databind.node.ObjectNode;
910
import io.openaev.database.model.*;
1011
import io.openaev.injectors.challenge.model.ChallengeContent;
12+
import io.openaev.rest.atomic_testing.form.AtomicTestingInput;
13+
import io.openaev.rest.inject.form.InjectDocumentInput;
1114
import java.util.List;
1215
import java.util.Map;
1316
import java.util.UUID;
@@ -17,12 +20,31 @@ public class InjectFixture {
1720
public static final String INJECT_EMAIL_NAME = "Test email inject";
1821
public static final String INJECT_CHALLENGE_NAME = "Test challenge inject";
1922

23+
public static AtomicTestingInput createAtomicTesting(String title, String documentId) {
24+
AtomicTestingInput input = new AtomicTestingInput();
25+
input.setInjectorContract(EMAIL_DEFAULT);
26+
input.setContent(injectContent());
27+
input.setTitle(title);
28+
input.setAllTeams(false);
29+
if (documentId != null) {
30+
InjectDocumentInput documentInput = new InjectDocumentInput();
31+
documentInput.setDocumentId(documentId);
32+
documentInput.setAttached(true);
33+
input.setDocuments(List.of(documentInput));
34+
}
35+
return input;
36+
}
37+
2038
public static Inject createInject(InjectorContract injectorContract, String title) {
2139
Inject inject = createInjectWithTitle(title);
2240
inject.setInjectorContract(injectorContract);
2341
inject.setEnabled(true);
2442
inject.setDependsDuration(0L);
43+
inject.setContent(injectContent());
44+
return inject;
45+
}
2546

47+
private static ObjectNode injectContent() {
2648
ObjectMapper objectMapper = new ObjectMapper();
2749
ObjectNode injectContent = objectMapper.createObjectNode();
2850
injectContent.set(
@@ -31,9 +53,7 @@ public static Inject createInject(InjectorContract injectorContract, String titl
3153
List.of(
3254
ExpectationFixture.createExpectation(InjectExpectation.EXPECTATION_TYPE.MANUAL)),
3355
ArrayNode.class));
34-
inject.setContent(injectContent);
35-
36-
return inject;
56+
return injectContent;
3757
}
3858

3959
public static Inject createTechnicalInject(

openaev-front/src/admin/components/common/injects/form/documents/InjectDocumentsList.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const InjectDocumentsList = ({ readOnly, hasAttachments }: Props) => {
6161
useEffect(() => {
6262
const test = (injectDocuments || [])
6363
.map(d => ({
64+
...d,
6465
...documentsMap[d.document_id],
6566
document_attached: d.document_attached,
6667
}))
@@ -92,8 +93,29 @@ const InjectDocumentsList = ({ readOnly, hasAttachments }: Props) => {
9293
document_attached: boolean;
9394
}[]) => {
9495
const docIds = injectDocuments.map(d => d.document_id);
95-
const newDocs = documents.filter(d => !docIds.includes(d.document_id));
96-
appendInjectDocuments(newDocs);
96+
const selectedIds = documents.map(d => d.document_id);
97+
98+
// Add only documents that are not already present
99+
const newDocs = documents
100+
.filter(d => !docIds.includes(d.document_id))
101+
.map(d => ({
102+
document_id: d.document_id,
103+
document_attached: hasAttachments,
104+
}));
105+
106+
if (newDocs.length > 0) {
107+
appendInjectDocuments(newDocs);
108+
}
109+
110+
// Remove documents that are currently stored but no longer selected
111+
const idsToRemove = docIds.filter(id => !selectedIds.includes(id));
112+
113+
idsToRemove.forEach((id) => {
114+
const index = injectDocuments.findIndex(d => d.document_id === id);
115+
if (index !== -1) {
116+
removeInjectDocuments(index);
117+
}
118+
});
97119
};
98120

99121
return (

openaev-front/src/components/fields/FileTransferDialog.tsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,18 @@ const FileTransferDialog: FunctionComponent<Props> = ({
6969
const { documents }: { documents: [RawDocument] } = useHelper((helper: DocumentHelper & UserHelper) => ({ documents: helper.getDocuments() }));
7070

7171
useEffect(() => {
72-
if (initialDocumentIds.length > 0) {
73-
setSelectedDocuments(documents.filter((document) => {
74-
const docId = document.document_id;
75-
return docId && initialDocumentIds.includes(docId);
76-
}));
77-
}
72+
// If initial data hasn't arrived yet, do nothing
73+
if (initialDocumentIds.length === 0) return;
74+
75+
// If we already have selected documents, don't override user changes
76+
if (selectedDocuments.length > 0) return;
77+
78+
// Initialize selectedDocuments from initialDocumentIds (only once)
79+
setSelectedDocuments(
80+
documents.filter(
81+
doc => doc.document_id && initialDocumentIds.includes(doc.document_id),
82+
),
83+
);
7884
}, [initialDocumentIds]);
7985

8086
const handleSearchDocuments = (value?: string) => {
@@ -137,9 +143,11 @@ const FileTransferDialog: FunctionComponent<Props> = ({
137143
return tags.length === 0 || tags.every(tag => document.document_tags?.includes(tag.id));
138144
};
139145

146+
const selectedIds = selectedDocuments.map(d => d.document_id);
147+
140148
const filteredDocuments = documents.filter((document) => {
141-
const isInitialValue = document.document_id && initialDocumentIds?.includes(document.document_id);
142-
return !isInitialValue
149+
const isSelected = document.document_id && selectedIds.includes(document.document_id);
150+
return !isSelected
143151
&& filterByExtensions(document)
144152
&& filterByKeyword(document)
145153
&& filterByTag(document);

openaev-model/src/main/java/io/openaev/database/repository/InjectDocumentRepository.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,10 @@ void addInjectDoc(
3535
@Param("injectId") String injectId,
3636
@Param("documentId") String docId,
3737
@Param("documentAttached") boolean docAttached);
38+
39+
@Modifying
40+
@Query(
41+
value = "UPDATE injects_documents SET inject_id = :injectId where inject_id = :oldInjectId",
42+
nativeQuery = true)
43+
void updateInjectId(@Param("injectId") String injectId, @Param("oldInjectId") String oldInjectId);
3844
}

0 commit comments

Comments
 (0)