From fece63c1167cd4c4ef218c5d30feee3f51dec408 Mon Sep 17 00:00:00 2001 From: Mikhail Podolskiy Date: Mon, 31 Jan 2022 10:50:07 +0100 Subject: [PATCH 01/10] IPT Resource networks produce json --- .../gbif/registry/ws/resources/legacy/IptNetworkResource.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/IptNetworkResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/IptNetworkResource.java index e98b2c4183..aa88a59ac1 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/IptNetworkResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/IptNetworkResource.java @@ -70,7 +70,9 @@ public ResponseEntity> getNetworks( .body(networks); } - @GetMapping("resource/{key}/networks") + @GetMapping( + value = "resource/{key}/networks", + produces = MediaType.APPLICATION_JSON_VALUE) public List listResourceNetworks(@PathVariable("key") UUID datasetKey) { return networkMapper.listByDataset(datasetKey); } From 4db2f6adcc3449b94b6bde6915671f6c1e5f077d Mon Sep 17 00:00:00 2001 From: Matthew Blissett Date: Tue, 22 Feb 2022 15:40:50 +0100 Subject: [PATCH 02/10] Use correct database method for download statistics. --- .../gbif/registry/ws/resources/OccurrenceDownloadResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/OccurrenceDownloadResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/OccurrenceDownloadResource.java index a8b52fb973..ac24ec8250 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/OccurrenceDownloadResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/OccurrenceDownloadResource.java @@ -383,7 +383,7 @@ public Map> getDownloadedRecordsByDataset( @RequestParam(value = "datasetKey", required = false) UUID datasetKey, @RequestParam(value = "publishingOrgKey", required = false) UUID publishingOrgKey) { return groupByYear( - occurrenceDownloadMapper.getDownloadsByDataset( + occurrenceDownloadMapper.getDownloadedRecordsByDataset( fromDate, toDate, Optional.ofNullable(publishingCountry).map(Country::getIso2LetterCode).orElse(null), From 6623fb2971e721ea1c4ec198c9b4f69f0527508e Mon Sep 17 00:00:00 2001 From: Marcos Lopez Gonzalez Date: Thu, 24 Feb 2022 11:51:56 +0100 Subject: [PATCH 03/10] updated gbif-api version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ae24a9ba2f..a3fbf0200d 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ 2.2.8.RELEASE - 0.163 + 0.165-SNAPSHOT 0.52 1.1 1.19 From ab8ba6b1b5db0fbfabb285f82135220f068d08f2 Mon Sep 17 00:00:00 2001 From: Mikhail Podolskiy Date: Mon, 28 Feb 2022 10:06:06 +0100 Subject: [PATCH 04/10] gbif-api v0.165 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a3fbf0200d..a6655d801d 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ 2.2.8.RELEASE - 0.165-SNAPSHOT + 0.165 0.52 1.1 1.19 From 1ca2c5714111865a4f97594ea848e0c0f38b3450 Mon Sep 17 00:00:00 2001 From: Mikhail Podolskiy Date: Mon, 28 Feb 2022 10:06:31 +0100 Subject: [PATCH 05/10] #409 gbif-doi v2.17 --- pom.xml | 2 +- .../cli/doiupdater/DoiUpdateListener.java | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index a6655d801d..c6060c8241 100644 --- a/pom.xml +++ b/pom.xml @@ -91,7 +91,7 @@ 1.1 1.19 1.12 - 2.16 + 2.17 1.45 0.10 1.2 diff --git a/registry-cli/src/main/java/org/gbif/registry/cli/doiupdater/DoiUpdateListener.java b/registry-cli/src/main/java/org/gbif/registry/cli/doiupdater/DoiUpdateListener.java index 5d3c53e584..c5d791afa7 100644 --- a/registry-cli/src/main/java/org/gbif/registry/cli/doiupdater/DoiUpdateListener.java +++ b/registry-cli/src/main/java/org/gbif/registry/cli/doiupdater/DoiUpdateListener.java @@ -104,7 +104,7 @@ public void handleMessage(ChangeDoiMessage msg) { if (HttpStatus.SC_REQUEST_TOO_LONG == e.getStatus()) { LOG.warn( DOI_SMTP, - "Metadata of length {} is exceeding max datacite limit in attempt #{} " + "Metadata of length {} is exceeding max DataCite limit in attempt #{} " + "while updating {} to {} with target {}. " + "Trying again {}", msg.getMetadata().length(), @@ -206,14 +206,19 @@ private void reserve(DOI doi, String xml, DoiData currState) throws DoiException * @param currState current state of the DOI in the database */ private void delete(DOI doi, DoiData currState) throws DoiException { + // delete from DataCite + // findable DOIs will not be deleted + if (doiService.exists(doi)) { + doiService.delete(doi); + } + if (currState.getStatus() == DoiStatus.REGISTERED) { + // if registered - mark as deleted DoiData newState = new DoiData(DoiStatus.DELETED, currState.getTarget()); doiMapper.update(doi, newState, null); LOG.info("Marked registered doi {} as deleted", doi); } else { - if (doiService.exists(doi)) { - doiService.delete(doi); - } + // otherwise, erase it from database doiMapper.delete(doi); LOG.info("Deleted doi {}", doi); } @@ -269,7 +274,7 @@ private void registerOrUpdate(DOI doi, URI target, String xml, DoiData currState * to fix a RESERVED DOI that should be updated (will be rejected). As opposed to * registerOrUpdate, this method will ask the doiService for the status of the DOI since when the * status is FAILED we loose the 'real' status before the failure. If the DOI doesn't exist on the - * DOI Service (e.g. Datacite) it will register it. If the DOI already exist it will try an + * DOI Service (e.g. DataCite) it will register it. If the DOI already exist it will try an * update. If any error occurs it will be logged and the will method with false. * * @param doi Digital Object Identifier @@ -288,7 +293,7 @@ private boolean retryRegisterOrUpdate(DOI doi, URI target, String xml) throws Do LOG.info("Updated doi {} with target {}", doi, target); } else { LOG.info( - "Failed to update doi {} with target {}. Only doi with state REGISTERED can be retried. Datacite status: {}. ", + "Failed to update doi {} with target {}. Only doi with state REGISTERED can be retried. DataCite status: {}. ", doi, target, doiServiceData.getStatus()); From ae7fbfa2db9120d72199339ece0b70e568e0bd39 Mon Sep 17 00:00:00 2001 From: Mikhail Podolskiy Date: Mon, 28 Feb 2022 10:30:44 +0100 Subject: [PATCH 06/10] #409 fix test, DataCite state should be also DELETED (DataCite's registered) --- .../org/gbif/registry/cli/doiupdater/DoiUpdaterListenerIT.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/registry-cli/src/test/java/org/gbif/registry/cli/doiupdater/DoiUpdaterListenerIT.java b/registry-cli/src/test/java/org/gbif/registry/cli/doiupdater/DoiUpdaterListenerIT.java index 88395a9514..6e60dac909 100644 --- a/registry-cli/src/test/java/org/gbif/registry/cli/doiupdater/DoiUpdaterListenerIT.java +++ b/registry-cli/src/test/java/org/gbif/registry/cli/doiupdater/DoiUpdaterListenerIT.java @@ -45,6 +45,7 @@ import io.zonky.test.db.postgres.junit5.EmbeddedPostgresExtension; import io.zonky.test.db.postgres.junit5.PreparedDbExtension; +import static org.gbif.api.model.common.DoiStatus.DELETED; import static org.gbif.api.model.common.DoiStatus.FAILED; import static org.gbif.api.model.common.DoiStatus.NEW; import static org.gbif.api.model.common.DoiStatus.REGISTERED; @@ -183,7 +184,7 @@ public void handleMessageRegisteredDoiAndMessageStatusDeletedShouldMarkDoiAsDele // then assertEquals(new DoiData(DoiStatus.DELETED, TEST_TARGET), getActualInDb(doi)); - assertEquals(new DoiData(REGISTERED, TEST_TARGET), getActualInDataCite(doi)); + assertEquals(new DoiData(DELETED, TEST_TARGET), getActualInDataCite(doi)); } @Test From d71794ee1224195bfee0068dbbbcfd9e8b80374b Mon Sep 17 00:00:00 2001 From: Marcos Lopez Gonzalez Date: Mon, 28 Feb 2022 13:43:03 +0100 Subject: [PATCH 07/10] updated gbif-api version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c6060c8241..d6473c5396 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ 2.2.8.RELEASE - 0.165 + 0.166-SNAPSHOT 0.52 1.1 1.19 From c856d13bd0ff3c6bd0396d016ab1bf93a953fdf0 Mon Sep 17 00:00:00 2001 From: Mikhail Podolskiy Date: Mon, 28 Feb 2022 15:13:08 +0100 Subject: [PATCH 08/10] #409 Add delete method to DatasetResource to manage DOIs properly --- .../doi/DatasetDoiDataCiteHandlingService.java | 5 +++++ .../doi/DatasetDoiDataCiteHandlingServiceImpl.java | 5 +++++ .../gbif/registry/ws/resources/DatasetResource.java | 13 +++++++++++++ 3 files changed, 23 insertions(+) diff --git a/registry-doi/src/main/java/org/gbif/registry/doi/DatasetDoiDataCiteHandlingService.java b/registry-doi/src/main/java/org/gbif/registry/doi/DatasetDoiDataCiteHandlingService.java index fb1502dd9e..d6b1369b80 100644 --- a/registry-doi/src/main/java/org/gbif/registry/doi/DatasetDoiDataCiteHandlingService.java +++ b/registry-doi/src/main/java/org/gbif/registry/doi/DatasetDoiDataCiteHandlingService.java @@ -36,6 +36,11 @@ public interface DatasetDoiDataCiteHandlingService { */ void datasetChanged(Dataset dataset, @Nullable final DOI previousDoi); + /** + * Called when dataset to be deleted, tries to deactivate DOI. + */ + void datasetDeleted(DOI doi); + /** * Directly schedule the registration of a Dataset DOI. */ diff --git a/registry-doi/src/main/java/org/gbif/registry/doi/DatasetDoiDataCiteHandlingServiceImpl.java b/registry-doi/src/main/java/org/gbif/registry/doi/DatasetDoiDataCiteHandlingServiceImpl.java index fdc6dde4ed..9071bb139d 100644 --- a/registry-doi/src/main/java/org/gbif/registry/doi/DatasetDoiDataCiteHandlingServiceImpl.java +++ b/registry-doi/src/main/java/org/gbif/registry/doi/DatasetDoiDataCiteHandlingServiceImpl.java @@ -105,6 +105,11 @@ public void datasetChanged(Dataset dataset, @Nullable DOI previousDoi) { } } + @Override + public void datasetDeleted(DOI doi) { + doiMessageManagingService.delete(doi); + } + @Override public void scheduleDatasetRegistration(DOI doi, DataCiteMetadata metadata, UUID datasetKey) { try { diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/DatasetResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/DatasetResource.java index 947b10598b..ad29c38984 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/DatasetResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/DatasetResource.java @@ -310,6 +310,19 @@ public byte[] getMetadataDocumentAsBytes(@PathVariable("key") UUID datasetKey) { return null; } + @DeleteMapping("{key}") + @Secured({ADMIN_ROLE, EDITOR_ROLE, IPT_ROLE}) + @Transactional + @Override + public void delete(@PathVariable UUID key) { + Dataset dataset = get(key); + super.delete(key); + + if (dataset != null && dataset.getDoi() != null) { + doiDataCiteHandlingService.datasetDeleted(dataset.getDoi()); + } + } + @PostMapping(value = "{key}/document", consumes = MediaType.APPLICATION_XML_VALUE) @Secured({ADMIN_ROLE, EDITOR_ROLE}) public Metadata insertMetadata( From a276ce3eee855ed79efc43f62363b46503b0697a Mon Sep 17 00:00:00 2001 From: Mikhail Podolskiy Date: Mon, 28 Feb 2022 15:33:25 +0100 Subject: [PATCH 09/10] #409 Add missing method to stub class --- .../common/stubs/DatasetDoiDataCiteHandlingServiceStub.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/registry-cli/src/main/java/org/gbif/registry/cli/common/stubs/DatasetDoiDataCiteHandlingServiceStub.java b/registry-cli/src/main/java/org/gbif/registry/cli/common/stubs/DatasetDoiDataCiteHandlingServiceStub.java index f72cfcb84a..dfdd4be8ce 100644 --- a/registry-cli/src/main/java/org/gbif/registry/cli/common/stubs/DatasetDoiDataCiteHandlingServiceStub.java +++ b/registry-cli/src/main/java/org/gbif/registry/cli/common/stubs/DatasetDoiDataCiteHandlingServiceStub.java @@ -32,6 +32,9 @@ public class DatasetDoiDataCiteHandlingServiceStub implements DatasetDoiDataCite @Override public void datasetChanged(Dataset dataset, @Nullable DOI previousDoi) {} + @Override + public void datasetDeleted(DOI doi) {} + @Override public void scheduleDatasetRegistration(DOI doi, DataCiteMetadata metadata, UUID datasetKey) {} From 86670096b6dea2428c7684c64b479a66f990efac Mon Sep 17 00:00:00 2001 From: fmendezh Date: Tue, 1 Mar 2022 11:19:32 +0100 Subject: [PATCH 10/10] restrict data updates based on specified rules --- pom.xml | 2 +- .../resources/BaseNetworkEntityResource.java | 18 +++-- .../ws/resources/DatasetResource.java | 16 +++- .../ws/resources/InstallationResource.java | 33 ++++++-- .../ws/resources/NetworkResource.java | 10 ++- .../registry/ws/resources/NodeResource.java | 6 +- .../ws/resources/OrganizationResource.java | 18 ++++- .../ws/resources/RestrictionsHandler.java | 76 +++++++++++++++++++ .../ws/resources/legacy/IptResource.java | 11 ++- .../legacy/LegacyDatasetResource.java | 8 +- .../src/main/resources/application.yml | 2 + 11 files changed, 177 insertions(+), 23 deletions(-) create mode 100644 registry-ws/src/main/java/org/gbif/registry/ws/resources/RestrictionsHandler.java diff --git a/pom.xml b/pom.xml index d6473c5396..c6060c8241 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ 2.2.8.RELEASE - 0.166-SNAPSHOT + 0.165 0.52 1.1 1.19 diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/BaseNetworkEntityResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/BaseNetworkEntityResource.java index bcc6d1a54e..be28d5363c 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/BaseNetworkEntityResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/BaseNetworkEntityResource.java @@ -113,12 +113,15 @@ public class BaseNetworkEntityResource implements Netwo private final WithMyBatis withMyBatis; private final Class objectClass; + private final RestrictionsHandler restrictionsHandler; + protected BaseNetworkEntityResource( - BaseNetworkEntityMapper mapper, - MapperServiceLocator mapperServiceLocator, - Class objectClass, - EventManager eventManager, - WithMyBatis withMyBatis) { + BaseNetworkEntityMapper mapper, + MapperServiceLocator mapperServiceLocator, + Class objectClass, + EventManager eventManager, + WithMyBatis withMyBatis, + RestrictionsHandler restrictionsHandler) { this.mapper = mapper; this.commentMapper = mapperServiceLocator.getCommentMapper(); this.machineTagMapper = mapperServiceLocator.getMachineTagMapper(); @@ -129,6 +132,7 @@ protected BaseNetworkEntityResource( this.objectClass = objectClass; this.eventManager = eventManager; this.withMyBatis = withMyBatis; + this.restrictionsHandler = restrictionsHandler; } /** @@ -643,4 +647,8 @@ protected PagingResponse pagingResponse(Pageable page, Long count, List(page, count, result); } + + public RestrictionsHandler getRestrictionsHandler() { + return restrictionsHandler; + } } diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/DatasetResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/DatasetResource.java index ad29c38984..4a0175a511 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/DatasetResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/DatasetResource.java @@ -152,6 +152,7 @@ public class DatasetResource extends BaseNetworkEntityResource private final TagMapper tagMapper; private final NetworkMapper networkMapper; private final DatasetProcessStatusMapper datasetProcessStatusMapper; + private final RestrictionsHandler restrictionsHandler; private final DatasetDoiDataCiteHandlingService doiDataCiteHandlingService; private final DataCiteMetadataBuilderService metadataBuilderService; private final DoiIssuingService doiIssuingService; @@ -169,13 +170,15 @@ public DatasetResource( DataCiteMetadataBuilderService metadataBuilderService, DoiIssuingService doiIssuingService, WithMyBatis withMyBatis, - @Autowired(required = false) MessagePublisher messagePublisher) { + @Autowired(required = false) MessagePublisher messagePublisher, + RestrictionsHandler restrictionsHandler) { super( mapperServiceLocator.getDatasetMapper(), mapperServiceLocator, Dataset.class, eventManager, - withMyBatis); + withMyBatis, + restrictionsHandler); this.registryDatasetService = registryDatasetService; this.searchService = searchService; this.metadataMapper = mapperServiceLocator.getMetadataMapper(); @@ -190,6 +193,7 @@ public DatasetResource( this.doiIssuingService = doiIssuingService; this.messagePublisher = messagePublisher; this.withMyBatis = withMyBatis; + this.restrictionsHandler = restrictionsHandler; } @GetMapping("search") @@ -457,6 +461,9 @@ private Dataset preserveGBIFDatasetProperties(Dataset updatedDataset, Dataset ex */ public void updateFromPreferredMetadata(UUID uuid, String user) { Dataset dataset = super.get(uuid); + + restrictionsHandler.checkDenyPublisher(dataset.getPublishingOrganizationKey()); + if (dataset == null) { throw new NotFoundException( "Dataset " + uuid + " not existing", URI.create("/dataset/{key}/document")); @@ -585,6 +592,8 @@ public UUID create(@RequestBody @Trim Dataset dataset) { dataset.setLicense(License.CC_BY_4_0); } + restrictionsHandler.checkDenyPublisher(dataset.getPublishingOrganizationKey()); + final UUID key = super.create(dataset); // now that we have a UUID schedule to scheduleRegistration the DOI // to get the latest timestamps we need to read a new copy of the dataset @@ -599,6 +608,9 @@ public void update(Dataset dataset) { if (old == null) { throw new IllegalArgumentException("Dataset " + dataset.getKey() + " not existing"); } + + restrictionsHandler.checkDenyPublisher(dataset.getPublishingOrganizationKey()); + // replace current license? Only if dataset being updated has a supported license if (!replaceLicense(dataset.getLicense())) { LOG.warn( diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/InstallationResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/InstallationResource.java index c76d199edb..6b21271296 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/InstallationResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/InstallationResource.java @@ -20,6 +20,7 @@ import org.gbif.api.model.registry.Dataset; import org.gbif.api.model.registry.Installation; import org.gbif.api.model.registry.Organization; +import org.gbif.api.model.registry.PrePersist; import org.gbif.api.model.registry.metasync.MetasyncHistory; import org.gbif.api.model.registry.search.KeyTitleResult; import org.gbif.api.service.registry.InstallationService; @@ -45,6 +46,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import javax.validation.groups.Default; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; @@ -72,6 +74,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static org.gbif.registry.security.UserRoles.ADMIN_ROLE; +import static org.gbif.registry.security.UserRoles.EDITOR_ROLE; +import static org.gbif.registry.security.UserRoles.IPT_ROLE; @Validated @Primary @@ -91,16 +95,18 @@ public class InstallationResource extends BaseNetworkEntityResource listByType(InstallationType type, Pageable p long total = installationMapper.countWithFilter(type); return pagingResponse(page, total, installationMapper.listWithFilter(type, page)); } + + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) + @Validated({PrePersist.class, Default.class}) + @Trim + @Transactional + @Secured({ADMIN_ROLE, EDITOR_ROLE, IPT_ROLE}) + @Override + public UUID create(Installation entity) { + getRestrictionsHandler().checkDenyPublisher(entity.getOrganizationKey()); + return super.create(entity); + } + + @Override + public void update(Installation entity) { + getRestrictionsHandler().checkDenyPublisher(entity.getOrganizationKey()); + super.update(entity); + } } diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/NetworkResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/NetworkResource.java index 46047f3a33..c0b7af0837 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/NetworkResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/NetworkResource.java @@ -67,15 +67,17 @@ public class NetworkResource extends BaseNetworkEntityResource implemen private final EventManager eventManager; public NetworkResource( - MapperServiceLocator mapperServiceLocator, - EventManager eventManager, - WithMyBatis withMyBatis) { + MapperServiceLocator mapperServiceLocator, + EventManager eventManager, + WithMyBatis withMyBatis, + RestrictionsHandler restrictionsHandler) { super( mapperServiceLocator.getNetworkMapper(), mapperServiceLocator, Network.class, eventManager, - withMyBatis); + withMyBatis, + restrictionsHandler); this.eventManager = eventManager; this.datasetMapper = mapperServiceLocator.getDatasetMapper(); this.networkMapper = mapperServiceLocator.getNetworkMapper(); diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/NodeResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/NodeResource.java index 0e12059dfa..5b8747452a 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/NodeResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/NodeResource.java @@ -75,13 +75,15 @@ public NodeResource( MapperServiceLocator mapperServiceLocator, EventManager eventManager, Augmenter nodeAugmenter, - WithMyBatis withMyBatis) { + WithMyBatis withMyBatis, + RestrictionsHandler restrictionsHandler) { super( mapperServiceLocator.getNodeMapper(), mapperServiceLocator, Node.class, eventManager, - withMyBatis); + withMyBatis, + restrictionsHandler); this.nodeMapper = mapperServiceLocator.getNodeMapper(); this.organizationMapper = mapperServiceLocator.getOrganizationMapper(); this.nodeAugmenter = nodeAugmenter; diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/OrganizationResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/OrganizationResource.java index 5b4e67f8e0..2304eabe52 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/OrganizationResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/OrganizationResource.java @@ -55,6 +55,7 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -99,13 +100,15 @@ public OrganizationResource( OrganizationEndorsementService organizationEndorsementService, EventManager eventManager, EditorAuthorizationService userAuthService, - WithMyBatis withMyBatis) { + WithMyBatis withMyBatis, + RestrictionsHandler restrictionsHandler) { super( mapperServiceLocator.getOrganizationMapper(), mapperServiceLocator, Organization.class, eventManager, - withMyBatis); + withMyBatis, + restrictionsHandler); this.datasetMapper = mapperServiceLocator.getDatasetMapper(); this.organizationMapper = mapperServiceLocator.getOrganizationMapper(); this.installationMapper = mapperServiceLocator.getInstallationMapper(); @@ -133,6 +136,9 @@ public Organization get(@PathVariable UUID key) { @Trim @Override public UUID create(@RequestBody @Trim Organization organization) { + + getRestrictionsHandler().checkCountryDenied(organization.getCountry()); + final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); organization.setPassword(generatePassword()); UUID newOrganization = super.create(organization); @@ -154,6 +160,13 @@ public UUID create(@RequestBody @Trim Organization organization) { return newOrganization; } + @Transactional + @Override + public void update(Organization entity) { + getRestrictionsHandler().checkCountryDenied(entity.getCountry()); + super.update(entity); + } + /** * Randomly generates a shared token (password) for an organization. * @@ -375,6 +388,7 @@ public ResponseEntity confirmEndorsementEndpoint( public boolean confirmEndorsement(UUID organizationKey) { Organization organization = super.get(organizationKey); checkNotNull(organization, "Organization not found"); + getRestrictionsHandler().checkCountryDenied(organization.getCountry()); return organizationEndorsementService.confirmEndorsement(organizationKey); } diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/RestrictionsHandler.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/RestrictionsHandler.java new file mode 100644 index 0000000000..cb4d3666e4 --- /dev/null +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/RestrictionsHandler.java @@ -0,0 +1,76 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gbif.registry.ws.resources; + +import org.gbif.api.model.registry.Organization; +import org.gbif.api.vocabulary.Country; +import org.gbif.registry.persistence.mapper.OrganizationMapper; +import org.gbif.ws.WebApplicationException; + +import java.util.List; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Utility class to restrict updates of data. + */ +@Component +public class RestrictionsHandler { + + private final List denyCountries; + + private final OrganizationMapper organizationMapper; + + @Autowired + public RestrictionsHandler( + @Value("${registry.denyCountries}") List denyCountries, OrganizationMapper organizationMapper + ) { + this.denyCountries = denyCountries; + this.organizationMapper = organizationMapper; + } + + /** + * Is the country in the list of denials. + */ + public void checkCountryDenied(Country country) { + if (country != null && denyCountries != null && (denyCountries.contains(country.getIso2LetterCode()) || denyCountries.contains(country.getIso3LetterCode()))) { + throw new WebApplicationException("Illegal entity data", HttpStatus.FORBIDDEN); + } + } + + /** + * Is the organization is the list of denials. + */ + public void checkDenyPublisher(UUID organizationKey) { + if (organizationKey != null) { + Organization organization = organizationMapper.get(organizationKey); + if (organization != null) { + checkCountryDenied(organization.getCountry()); + } + } + } + + /** + * Is the organization is the list of denials. + */ + public void checkDenyPublisher(String organizationKey) { + if (organizationKey != null) { + checkDenyPublisher(UUID.fromString(organizationKey)); + } + } +} diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/IptResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/IptResource.java index 4e5bb4a379..d987db3bfb 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/IptResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/IptResource.java @@ -26,6 +26,7 @@ import org.gbif.registry.domain.ws.IptEntityResponse; import org.gbif.registry.domain.ws.LegacyDataset; import org.gbif.registry.domain.ws.LegacyInstallation; +import org.gbif.registry.ws.resources.RestrictionsHandler; import org.gbif.registry.ws.util.LegacyResourceUtils; import java.util.List; @@ -60,15 +61,18 @@ public class IptResource { private final InstallationService installationService; private final OrganizationService organizationService; private final DatasetService datasetService; + private final RestrictionsHandler restrictionsHandler; private static final Long ONE = 1L; public IptResource( InstallationService installationService, OrganizationService organizationService, - DatasetService datasetService) { + DatasetService datasetService, + RestrictionsHandler restrictionsHandler) { this.installationService = installationService; this.organizationService = organizationService; this.datasetService = datasetService; + this.restrictionsHandler = restrictionsHandler; } /** @@ -85,7 +89,9 @@ public IptResource( produces = MediaType.APPLICATION_XML_VALUE) public ResponseEntity registerIpt( @RequestParam LegacyInstallation installation, Authentication authentication) { + if (installation != null) { + restrictionsHandler.checkDenyPublisher(installation.getHostingOrganizationKey()); // set required fields String user = authentication.getName(); installation.setCreatedBy(user); @@ -149,6 +155,7 @@ public ResponseEntity updateIpt( @RequestParam LegacyInstallation installation, Authentication authentication) { if (installation != null && installationKey != null) { + restrictionsHandler.checkDenyPublisher(installation.getHostingOrganizationKey()); // set required fields String user = authentication.getName(); installation.setCreatedBy(user); @@ -233,6 +240,7 @@ public ResponseEntity updateIpt( public ResponseEntity registerDataset( @RequestParam LegacyDataset dataset, Authentication authentication) { if (dataset != null) { + restrictionsHandler.checkDenyPublisher(dataset.getPublishingOrganizationKey()); // set required fields String user = authentication.getName(); dataset.setCreatedBy(user); @@ -316,6 +324,7 @@ public ResponseEntity updateDataset( @RequestParam LegacyDataset dataset, Authentication authentication) { if (dataset != null) { + restrictionsHandler.checkDenyPublisher(dataset.getPublishingOrganizationKey()); // set required fields String user = authentication.getName(); dataset.setCreatedBy(user); diff --git a/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/LegacyDatasetResource.java b/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/LegacyDatasetResource.java index fe980ed4c4..d8e6f397d3 100644 --- a/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/LegacyDatasetResource.java +++ b/registry-ws/src/main/java/org/gbif/registry/ws/resources/legacy/LegacyDatasetResource.java @@ -27,6 +27,7 @@ import org.gbif.registry.domain.ws.LegacyDatasetResponse; import org.gbif.registry.domain.ws.LegacyDatasetResponseListWrapper; import org.gbif.registry.domain.ws.util.LegacyResourceConstants; +import org.gbif.registry.ws.resources.RestrictionsHandler; import org.gbif.registry.ws.util.LegacyResourceUtils; import org.gbif.ws.NotFoundException; import org.gbif.ws.util.CommonWsUtils; @@ -70,18 +71,21 @@ public class LegacyDatasetResource { private final InstallationService installationService; private final IptResource iptResource; private final NetworkService networkService; + private final RestrictionsHandler restrictionsHandler; public LegacyDatasetResource( OrganizationService organizationService, DatasetService datasetService, IptResource iptResource, InstallationService installationService, - NetworkService networkService) { + NetworkService networkService, + RestrictionsHandler restrictionsHandler) { this.organizationService = organizationService; this.datasetService = datasetService; this.iptResource = iptResource; this.installationService = installationService; this.networkService = networkService; + this.restrictionsHandler = restrictionsHandler; } /** @@ -100,6 +104,7 @@ public LegacyDatasetResource( public ResponseEntity registerDataset( @RequestParam LegacyDataset dataset, Authentication authentication) { // reuse existing subresource + restrictionsHandler.checkDenyPublisher(dataset.getOrganizationKey()); return iptResource.registerDataset(dataset, authentication); } @@ -130,6 +135,7 @@ public ResponseEntity updateDataset( dataset.setKey(datasetKey); // retrieve existing dataset Dataset existing = datasetService.get(datasetKey); + restrictionsHandler.checkDenyPublisher(dataset.getOrganizationKey()); // populate dataset with existing primary contact so it gets updated, not duplicated dataset.setContacts(existing.getContacts()); // if primary contact wasn't supplied, set existing one here so that it doesn't respond diff --git a/registry-ws/src/main/resources/application.yml b/registry-ws/src/main/resources/application.yml index fc56f2222a..d82fccdd2c 100644 --- a/registry-ws/src/main/resources/application.yml +++ b/registry-ws/src/main/resources/application.yml @@ -117,6 +117,8 @@ indexing: # Database registry: + denyCountries: > + XX, YY datasource: url: @registry-it.db.url@ password: @registry-it.db.password@