Skip to content

Commit 49ace24

Browse files
committed
#747 | /api/subjectMigration/bulk tests and code review comments
1 parent 37efb57 commit 49ace24

File tree

5 files changed

+149
-27
lines changed

5 files changed

+149
-27
lines changed

avni-server-api/src/main/java/org/avni/server/service/SubjectMigrationService.java

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import org.joda.time.DateTime;
1313
import org.slf4j.LoggerFactory;
1414
import org.springframework.beans.factory.annotation.Autowired;
15+
import org.springframework.data.domain.Page;
16+
import org.springframework.data.domain.PageRequest;
1517
import org.springframework.stereotype.Service;
1618

1719
import javax.transaction.Transactional;
@@ -36,6 +38,7 @@ public class SubjectMigrationService implements ScopeAwareService<SubjectMigrati
3638
private final LocationRepository locationRepository;
3739
private final ConceptRepository conceptRepository;
3840
private final IndividualService individualService;
41+
private final AvniJobRepository avniJobRepository;
3942

4043
public enum BulkSubjectMigrationModes {
4144
byAddress,
@@ -54,7 +57,7 @@ public SubjectMigrationService(EntityApprovalStatusRepository entityApprovalStat
5457
GroupSubjectRepository groupSubjectRepository, AddressLevelService addressLevelService,
5558
ChecklistRepository checklistRepository,
5659
ChecklistItemRepository checklistItemRepository,
57-
IndividualRelationshipRepository individualRelationshipRepository, AccessControlService accessControlService, LocationRepository locationRepository, ConceptRepository conceptRepository, IndividualService individualService) {
60+
IndividualRelationshipRepository individualRelationshipRepository, AccessControlService accessControlService, LocationRepository locationRepository, ConceptRepository conceptRepository, IndividualService individualService, AvniJobRepository avniJobRepository) {
5861
this.entityApprovalStatusRepository = entityApprovalStatusRepository;
5962
this.subjectMigrationRepository = subjectMigrationRepository;
6063
this.subjectTypeRepository = subjectTypeRepository;
@@ -71,6 +74,7 @@ public SubjectMigrationService(EntityApprovalStatusRepository entityApprovalStat
7174
this.locationRepository = locationRepository;
7275
this.conceptRepository = conceptRepository;
7376
this.individualService = individualService;
77+
this.avniJobRepository = avniJobRepository;
7478
}
7579

7680
@Override
@@ -155,6 +159,7 @@ public void changeSubjectSyncConceptValues(Individual subject, String destinatio
155159
individualService.save(subject);
156160
}
157161

162+
@Transactional
158163
public Map<String, String> bulkMigrate(BulkSubjectMigrationModes mode, BulkSubjectMigrationRequest bulkSubjectMigrationRequest) {
159164
if (mode == BulkSubjectMigrationModes.byAddress) {
160165
return bulkMigrateByAddress(bulkSubjectMigrationRequest.getSubjectIds(), bulkSubjectMigrationRequest.getDestinationAddresses());
@@ -163,6 +168,7 @@ public Map<String, String> bulkMigrate(BulkSubjectMigrationModes mode, BulkSubje
163168
}
164169
}
165170

171+
@Transactional
166172
public Map<String, String> bulkMigrateByAddress(List<Long> subjectIds, Map<String, String> destinationAddresses) {
167173
Map<String, String> migrationFailures = new HashMap<>();
168174
Map<AddressLevel, AddressLevel> addressLevelMap = new HashMap<>();
@@ -197,6 +203,7 @@ public Map<String, String> bulkMigrateByAddress(List<Long> subjectIds, Map<Strin
197203
return migrationFailures;
198204
}
199205

206+
@Transactional
200207
public Map<String, String> bulkMigrateBySyncConcept(List<Long> subjectIds, Map<String, String> destinationSyncConcepts) {
201208
Map<String, String> migrationFailures = new HashMap<>();
202209
subjectIds.forEach(subjectId -> {
@@ -219,16 +226,18 @@ public Map<String, String> bulkMigrateBySyncConcept(List<Long> subjectIds, Map<S
219226
}
220227

221228
private String validateSyncConcept(String subjectTypeSyncConceptUuid, String currentValue, Map<String, String> destinationSyncConcepts) {
222-
String destinationSyncConceptValue = destinationSyncConcepts.get(subjectTypeSyncConceptUuid);
223-
if (subjectTypeSyncConceptUuid != null && destinationSyncConceptValue == null) {
224-
return null; // No migration required for this sync concept.
229+
if (subjectTypeSyncConceptUuid == null || //sync concept not configured for subject type
230+
!destinationSyncConcepts.containsKey(subjectTypeSyncConceptUuid) //sync concept not included in migration
231+
) {
232+
return null;
225233
}
226-
if (subjectTypeSyncConceptUuid == null) {
227-
throw new RuntimeException("No sync concept configured for subject type");
234+
String destinationSyncConceptValue = destinationSyncConcepts.get(subjectTypeSyncConceptUuid);
235+
if (destinationSyncConceptValue == null) {
236+
return null;
228237
}
229238
Concept syncConcept = conceptRepository.findByUuid(subjectTypeSyncConceptUuid);
230239

231-
if (Objects.equals(currentValue, destinationSyncConceptValue)) {
240+
if (currentValue != null && Objects.equals(currentValue.trim(), destinationSyncConceptValue.trim())) {
232241
throw new RuntimeException("Source value and Destination value are the same");
233242
}
234243

@@ -243,12 +252,19 @@ private String validateSyncConcept(String subjectTypeSyncConceptUuid, String cur
243252

244253
private static ObservationCollection buildSyncConceptValueObservations(Individual subject, String destinationSyncConcept1Value, String destinationSyncConcept2Value) {
245254
ObservationCollection newObservations = new ObservationCollection();
246-
if (destinationSyncConcept1Value != null) {
247-
newObservations.put(subject.getSubjectType().getSyncRegistrationConcept1(), destinationSyncConcept1Value.trim());
255+
//set observation for unchanged values if sync concept exists so unchanged sync concept values are not overwritten
256+
if (subject.getSubjectType().getSyncRegistrationConcept1() != null) {
257+
newObservations.put(subject.getSubjectType().getSyncRegistrationConcept1(), destinationSyncConcept1Value != null ? destinationSyncConcept1Value.trim() : subject.getSyncConcept1Value());
248258
}
249-
if (destinationSyncConcept2Value != null) {
250-
newObservations.put(subject.getSubjectType().getSyncRegistrationConcept2(), destinationSyncConcept2Value.trim());
259+
if (subject.getSubjectType().getSyncRegistrationConcept2() != null) {
260+
newObservations.put(subject.getSubjectType().getSyncRegistrationConcept2(), destinationSyncConcept2Value != null ? destinationSyncConcept2Value.trim() : subject.getSyncConcept2Value());
251261
}
252262
return newObservations;
253263
}
264+
265+
public JobStatus getBulkSubjectMigrationJobStatus(String jobUuid) {
266+
String jobFilterCondition = " and uuid = '" + jobUuid + "'";
267+
Page<JobStatus> jobStatuses = avniJobRepository.getJobStatuses(UserContextHolder.getUser(), jobFilterCondition, PageRequest.of(0, 1));
268+
return (jobStatuses != null && !jobStatuses.getContent().isEmpty()) ? jobStatuses.getContent().get(0) : null;
269+
}
254270
}

avni-server-api/src/main/java/org/avni/server/web/SubjectMigrationController.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,9 @@ public class SubjectMigrationController extends AbstractController<SubjectMigrat
5454
private final AccessControlService accessControlService;
5555
private final Job bulkSubjectMigrationJob;
5656
private final JobLauncher bulkSubjectMigrationJobLauncher;
57-
private final AvniJobRepository avniJobRepository;
5857

5958
@Autowired
60-
public SubjectMigrationController(SubjectMigrationRepository subjectMigrationRepository, SubjectTypeRepository subjectTypeRepository, UserService userService, ScopeBasedSyncService<SubjectMigration> scopeBasedSyncService, SubjectMigrationService subjectMigrationService, IndividualRepository individualRepository, LocationRepository locationRepository, AccessControlService accessControlService, Job bulkSubjectMigrationJob, JobLauncher bulkSubjectMigrationJobLauncher, AvniJobRepository avniJobRepository) {
59+
public SubjectMigrationController(SubjectMigrationRepository subjectMigrationRepository, SubjectTypeRepository subjectTypeRepository, UserService userService, ScopeBasedSyncService<SubjectMigration> scopeBasedSyncService, SubjectMigrationService subjectMigrationService, IndividualRepository individualRepository, LocationRepository locationRepository, AccessControlService accessControlService, Job bulkSubjectMigrationJob, JobLauncher bulkSubjectMigrationJobLauncher) {
6160
this.scopeBasedSyncService = scopeBasedSyncService;
6261
this.subjectMigrationService = subjectMigrationService;
6362
this.individualRepository = individualRepository;
@@ -69,7 +68,6 @@ public SubjectMigrationController(SubjectMigrationRepository subjectMigrationRep
6968
this.subjectMigrationRepository = subjectMigrationRepository;
7069
this.subjectTypeRepository = subjectTypeRepository;
7170
this.userService = userService;
72-
this.avniJobRepository = avniJobRepository;
7371
}
7472

7573
@RequestMapping(value = "/subjectMigrations/v2", method = RequestMethod.GET)
@@ -122,10 +120,12 @@ public ResponseEntity migrate(@RequestParam(value = "mode", defaultValue = "byAd
122120
if (bulkSubjectMigrationRequest.getSubjectIds() == null) {
123121
throw new BadRequestError("subjectIds is required");
124122
}
125-
if (mode == SubjectMigrationService.BulkSubjectMigrationModes.byAddress && bulkSubjectMigrationRequest.getDestinationAddresses() == null) {
123+
if (mode == SubjectMigrationService.BulkSubjectMigrationModes.byAddress
124+
&& (bulkSubjectMigrationRequest.getDestinationAddresses() == null || bulkSubjectMigrationRequest.getDestinationAddresses().isEmpty())) {
126125
throw new BadRequestError("destinationAddresses is required for mode: byAddress");
127126
}
128-
if (mode == SubjectMigrationService.BulkSubjectMigrationModes.bySyncConcept && bulkSubjectMigrationRequest.getDestinationSyncConcepts() == null) {
127+
if (mode == SubjectMigrationService.BulkSubjectMigrationModes.bySyncConcept
128+
&& (bulkSubjectMigrationRequest.getDestinationSyncConcepts() == null || bulkSubjectMigrationRequest.getDestinationSyncConcepts().isEmpty())) {
129129
throw new BadRequestError("destinationSyncConcepts is required for mode: bySyncConcepts");
130130
}
131131

@@ -151,15 +151,14 @@ public ResponseEntity migrate(@RequestParam(value = "mode", defaultValue = "byAd
151151
throw new RuntimeException(String.format("Error while starting the bulk subject migration job, %s", e.getMessage()), e);
152152
}
153153

154-
return ResponseEntity.status(HttpStatus.ACCEPTED).body(migrationStatus(jobUUID));
154+
return ResponseEntity.status(HttpStatus.ACCEPTED).body(subjectMigrationService.getBulkSubjectMigrationJobStatus(jobUUID));
155155
}
156156

157157
@RequestMapping(value = "/api/subjectMigration/bulk/status/{jobUuid}", method = RequestMethod.GET)
158158
@PreAuthorize(value = "hasAnyAuthority('user')")
159-
public JobStatus migrationStatus(@PathVariable("jobUuid") String jobUuid) {
159+
public ResponseEntity migrationStatus(@PathVariable("jobUuid") String jobUuid) {
160160
accessControlService.checkPrivilege(PrivilegeType.MultiTxEntityTypeUpdate);
161-
String jobFilterCondition = " and uuid = '" + jobUuid + "'";
162-
Page<JobStatus> jobStatuses = avniJobRepository.getJobStatuses(UserContextHolder.getUser(), jobFilterCondition, PageRequest.of(0, 1));
163-
return (jobStatuses != null && !jobStatuses.getContent().isEmpty()) ? jobStatuses.getContent().get(0) : null;
161+
JobStatus jobStatus = subjectMigrationService.getBulkSubjectMigrationJobStatus(jobUuid);
162+
return jobStatus != null ? ResponseEntity.ok(jobStatus) : ResponseEntity.notFound().build();
164163
}
165164
}

avni-server-api/src/main/resources/api/external-api.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,8 +1247,8 @@ paths:
12471247
"5ecbc89b-3d06-4911-95c3-8227e9f78790": "Karnataka"
12481248
},
12491249
"subjectIds": [
1250-
"c47cc708-5707-42ee-8f27-098a567c3229",
1251-
"329760fe-aa7e-448a-9b48-2a3aaba7ffa5"
1250+
1234,
1251+
1235
12521252
]
12531253
}
12541254
required: true
@@ -1300,8 +1300,8 @@ paths:
13001300
application/json:
13011301
schema:
13021302
$ref: '#/components/schemas/JobStatusBody'
1303-
"400":
1304-
description: bad input parameter
1303+
"404":
1304+
description: Job not found
13051305
/api/subjectTree:
13061306
delete:
13071307
tags:

0 commit comments

Comments
 (0)