From bd87b24b9efdf134d2c3e278a7e01e0b2e17a5bd Mon Sep 17 00:00:00 2001 From: Jan-Niklas Brandes Date: Mon, 11 May 2020 19:54:20 +0200 Subject: [PATCH 01/50] Add `BulkOperationService` and bulk insert implementation for exposure contacts --- .../imis/api/ExposureContactController.java | 43 +++++++++++++ .../ExposureContactRepository.java | 2 + .../services/util/BulkOperationService.java | 63 +++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 server/src/main/java/de/coronavirus/imis/services/util/BulkOperationService.java diff --git a/server/src/main/java/de/coronavirus/imis/api/ExposureContactController.java b/server/src/main/java/de/coronavirus/imis/api/ExposureContactController.java index 9930e6ac..9efb0ed7 100644 --- a/server/src/main/java/de/coronavirus/imis/api/ExposureContactController.java +++ b/server/src/main/java/de/coronavirus/imis/api/ExposureContactController.java @@ -4,6 +4,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import lombok.Data; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -21,6 +22,8 @@ import de.coronavirus.imis.domain.ExposureContact; import de.coronavirus.imis.mapper.ExposureContactMapper; import de.coronavirus.imis.repositories.ExposureContactRepository; +import de.coronavirus.imis.services.util.BulkOperationService; +import static de.coronavirus.imis.services.util.BulkOperationService.*; @RestController @RequestMapping("/api/exposure-contacts") @@ -29,6 +32,8 @@ public class ExposureContactController { private final ExposureContactRepository exposureContactRepository; private final ExposureContactMapper exposureContactMapper; + private final BulkOperationService bulkOps; + @PostMapping public ExposureContactDTO.FromServer createExposureContact(@RequestBody ExposureContactDTO.ToServer dto) { return exposureContactMapper.toExposureContactDTO( @@ -69,4 +74,42 @@ public List getExposureSourceContactsForPatient(@ public void removeExposureContact(@PathVariable("id") long id) { this.exposureContactRepository.deleteById(id); } + + @PostMapping("/bulk") + public List> bulkInsert(@RequestBody BulkRequest req) { + return bulkOps.performBulkOperation(req, (var item, var options) -> { + OpResult op = OpResult.CREATE; + try { + var exposureContact = this.exposureContactMapper.toExposureContact(item); + var inDb = exposureContactRepository.findBySourceIdAndContactId( + exposureContact.getSource().getId(), exposureContact.getContact().getId()); + + if (inDb.isPresent()) { + // Override entry + op = OpResult.OVERRIDE; + if (!options.isAllowOverride()) throw new RuntimeException("Overriding not allowed by option"); + exposureContact.setId(inDb.get().getId()); + } + + var result = exposureContactMapper.toExposureContactDTO( + exposureContactRepository.saveAndFlush(exposureContact)); + + return new ItemStatus() + .setResult(result, op); + + } catch (Exception e) { + return new ItemStatus() + .setError(e.getMessage(), op); + } + }); + } + + @Data + public static class BulkInsertOptions { + private boolean allowOverride; + } + public enum OpResult { + CREATE, + OVERRIDE, + } } diff --git a/server/src/main/java/de/coronavirus/imis/repositories/ExposureContactRepository.java b/server/src/main/java/de/coronavirus/imis/repositories/ExposureContactRepository.java index 479463b8..274f26f8 100644 --- a/server/src/main/java/de/coronavirus/imis/repositories/ExposureContactRepository.java +++ b/server/src/main/java/de/coronavirus/imis/repositories/ExposureContactRepository.java @@ -13,4 +13,6 @@ public interface ExposureContactRepository extends JpaRepository findBySourceId(String patientId); List findByContactId(String patientId); + + Optional findBySourceIdAndContactId(String sourceId, String contactId); } diff --git a/server/src/main/java/de/coronavirus/imis/services/util/BulkOperationService.java b/server/src/main/java/de/coronavirus/imis/services/util/BulkOperationService.java new file mode 100644 index 00000000..77f06f76 --- /dev/null +++ b/server/src/main/java/de/coronavirus/imis/services/util/BulkOperationService.java @@ -0,0 +1,63 @@ +package de.coronavirus.imis.services.util; + +import java.util.List; +import java.util.stream.Collectors; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.springframework.stereotype.Service; + +@Service +public class BulkOperationService { + public interface Operation { + ItemStatus process(Item item, Options options); + } + + public + List> performBulkOperation( + BulkRequest request, + Operation itemHandler) { + + return request.getItems().stream() + .map((var item) -> itemHandler.process(item, request.getOptions())) + .collect(Collectors.toList()); + } + + + @Data + public static class BulkRequest { + private Options options; + private List items; + } + + @Accessors(chain = true) + @Data + public static class ItemStatus { + private boolean success; + private Error error; + private Item result; + private Details details; + + public ItemStatus setError(Error e, Details d) { + this.error = e; + this.details = d; + this.success = false; + return this; + } + + public ItemStatus setError(Error e) { + return this.setError(e, null); + } + + public ItemStatus setResult(Item r, Details d) { + this.result = r; + this.details = d; + this.success = true; + return this; + } + + public ItemStatus setResult(Item r) { + return this.setResult(r, null); + } + } +} From e0596c9b4d0a40ac168c79b6489782d2acc6ea9d Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 18 May 2020 18:41:55 +0200 Subject: [PATCH 02/50] test es-lint checks in PR again --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12fada13..02d4baea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,10 @@ jobs: with: java-version: 1.11 - uses: actions/checkout@v2 + - uses: MichaelSp/eslint-action@master + with: + repo-token: "${{secrets.GITHUB_TOKEN}}" + source-root: "client" - run: | git fetch --unshallow - gradle build lint test \ No newline at end of file + gradle build lint test From 71a0e740d3014e3e4cf342d43bb5391bedb1e50d Mon Sep 17 00:00:00 2001 From: Henning Wobken Date: Mon, 18 May 2020 21:45:51 +0200 Subject: [PATCH 03/50] #302 quarantine contact persons --- client/src/components/PatientInput.vue | 45 +- client/src/views/PatientDetails.vue | 890 ++++++++++++++----------- client/src/views/RequestQuarantine.vue | 241 +++++-- 3 files changed, 719 insertions(+), 457 deletions(-) diff --git a/client/src/components/PatientInput.vue b/client/src/components/PatientInput.vue index 310ac0c5..79d9b376 100644 --- a/client/src/components/PatientInput.vue +++ b/client/src/components/PatientInput.vue @@ -1,14 +1,17 @@ diff --git a/client/src/components/ChangeInstitutionForm.vue b/client/src/components/ChangeInstitutionForm.vue index ce985be2..3a94c56a 100644 --- a/client/src/components/ChangeInstitutionForm.vue +++ b/client/src/components/ChangeInstitutionForm.vue @@ -4,60 +4,109 @@ title="Institution ändern" okText="Speichern" cancelText="Abbrechen" - @cancel="() => { $emit('cancel') }" + @cancel=" + () => { + $emit('cancel') + } + " @ok="save" > - + - +
- +
- +
@@ -107,24 +156,25 @@ export default Vue.extend({ ...values, institutionType: this.institution.institutionType, id: this.institution.id, - }).then(() => { - this.$notification.success({ - message: 'Institution erfolgreich geändert', - description: '', + }) + .then(() => { + this.$notification.success({ + message: 'Institution erfolgreich geändert', + description: '', + }) + this.form.resetFields() + this.$emit('create') }) - this.form.resetFields() - this.$emit('create') - }).catch((error: Error) => { - this.$notification.error({ - message: 'Institution konnte nicht geändert werden.', - description: error.message, + .catch((error: Error) => { + this.$notification.error({ + message: 'Institution konnte nicht geändert werden.', + description: error.message, + }) }) - }) }) }, }, }) - + diff --git a/client/src/components/ChangePasswordForm.vue b/client/src/components/ChangePasswordForm.vue index 12f091e7..be841480 100644 --- a/client/src/components/ChangePasswordForm.vue +++ b/client/src/components/ChangePasswordForm.vue @@ -1,15 +1,16 @@ @@ -50,25 +55,26 @@ export default Vue.extend({ values.dateOfDeath = values.dateOfDeath.format('YYYY-MM-DD') } values = { ...this.patient, ...values } - Api.updatePatientUsingPut(values).then((updatedPatient) => { - this.setPatient(updatedPatient) - this.$notification.success({ - message: 'Patient erfolgreich aktualisiert', - description: '', + Api.updatePatientUsingPut(values) + .then((updatedPatient) => { + this.setPatient(updatedPatient) + this.$notification.success({ + message: 'Patient erfolgreich aktualisiert', + description: '', + }) + this.form.resetFields() + this.$emit('create') }) - this.form.resetFields() - this.$emit('create') - }).catch((error: Error) => { - this.$notification.error({ - message: 'Patient konnte nicht aktualisiert werden.', - description: error.message, + .catch((error: Error) => { + this.$notification.error({ + message: 'Patient konnte nicht aktualisiert werden.', + description: error.message, + }) }) - }) }) }, }, }) - + diff --git a/client/src/components/DateInput.vue b/client/src/components/DateInput.vue index 59adf393..a9e8d394 100644 --- a/client/src/components/DateInput.vue +++ b/client/src/components/DateInput.vue @@ -26,8 +26,8 @@ import moment from 'moment' */ export interface State { - dateOfBirthPickerOpen: boolean; - wasJustFocused: boolean; + dateOfBirthPickerOpen: boolean + wasJustFocused: boolean } export default mixins(FormControlMixin).extend({ @@ -67,6 +67,4 @@ export default mixins(FormControlMixin).extend({ }) - + diff --git a/client/src/components/EditExposureContact.vue b/client/src/components/EditExposureContact.vue index 5e3ad119..8e62e64f 100644 --- a/client/src/components/EditExposureContact.vue +++ b/client/src/components/EditExposureContact.vue @@ -1,75 +1,86 @@