diff --git a/src/main/java/org/ohdsi/webapi/service/CDMResultsService.java b/src/main/java/org/ohdsi/webapi/service/CDMResultsService.java index 0c8e54f00..bb35221b9 100644 --- a/src/main/java/org/ohdsi/webapi/service/CDMResultsService.java +++ b/src/main/java/org/ohdsi/webapi/service/CDMResultsService.java @@ -269,7 +269,7 @@ public JobExecutionResource warmCache(@PathVariable("sourceKey") final String so * @return The job execution resource */ @GetMapping(value = "/{sourceKey}/refreshCache", produces = MediaType.APPLICATION_JSON_VALUE) - @PreAuthorize("isPermitted('write:source') or hasSourceAccess(#sourceKey, WRITE)") + @PreAuthorize("isPermitted('admin:cache')") public JobExecutionResource refreshCache(@PathVariable("sourceKey") final String sourceKey) { Source source = getSourceRepository().findBySourceKey(sourceKey); JobExecutionResource jobExecutionResource = jobService.findJobByName(Constants.WARM_CACHE, getWarmCacheJobName(String.valueOf(source.getSourceId()),sourceKey)); @@ -292,7 +292,7 @@ public JobExecutionResource refreshCache(@PathVariable("sourceKey") final String */ @PostMapping(value = "/{sourceKey}/clearCache") @Transactional() - @PreAuthorize("isPermitted('write:source') or hasSourceAccess(#sourceKey, WRITE)") + @PreAuthorize("isPermitted('admin:cache')") public void clearCacheForSource(@PathVariable("sourceKey") final String sourceKey) { Source source = getSourceRepository().findBySourceKey(sourceKey); cacheService.clearCache(source); diff --git a/src/main/java/org/ohdsi/webapi/service/VocabularyService.java b/src/main/java/org/ohdsi/webapi/service/VocabularyService.java index 4f674063c..93beb4355 100644 --- a/src/main/java/org/ohdsi/webapi/service/VocabularyService.java +++ b/src/main/java/org/ohdsi/webapi/service/VocabularyService.java @@ -1058,7 +1058,7 @@ private void addRelationships(final Map concepts, final Re * @param sourceKey The source containing the vocabulary * @return The vocabulary info */ - @PreAuthorize("isAnyPermitted(anyOf('read:source','write:source')) or hasSourceAccess(#sourceKey, READ)") + @PreAuthorize("isAnyPermitted(anyOf('read:source','write:source','admin:source')) or hasSourceAccess(#sourceKey, READ)") @GetMapping(value = "/{sourceKey}/info", produces = MediaType.APPLICATION_JSON_VALUE) public VocabularyInfo getInfo(@PathVariable("sourceKey") String sourceKey) { diff --git a/src/main/java/org/ohdsi/webapi/source/SourceService.java b/src/main/java/org/ohdsi/webapi/source/SourceService.java index cd4520909..c981114c1 100644 --- a/src/main/java/org/ohdsi/webapi/source/SourceService.java +++ b/src/main/java/org/ohdsi/webapi/source/SourceService.java @@ -231,28 +231,6 @@ public ResponseEntity createSource( throw new SourceDuplicateKeyException("The source key has been already used."); } Source sourceEntity = conversionService.convert(source, Source.class); - if (sourceEntity.getDaimons() != null) { - // First source should get priority = 1 - Iterable sources = sourceRepository.findAll(); - sourceEntity.getDaimons() - .stream() - .filter(sd -> sd.getPriority() <= 0) - .filter(sd -> { - boolean accept = true; - // Check if source daimon of given type with priority > 0 already exists in other sources - for (Source innerSource : sources) { - accept = !innerSource.getDaimons() - .stream() - .anyMatch(innerDaimon -> innerDaimon.getPriority() > 0 - && innerDaimon.getDaimonType().equals(sd.getDaimonType())); - if (!accept) { - break; - } - } - return accept; - }) - .forEach(sd -> sd.setPriority(1)); - } Source original = new Source(); original.setSourceDialect(sourceEntity.getSourceDialect()); setKeyfileData(sourceEntity, original, keyfile); @@ -312,10 +290,11 @@ public ResponseEntity updateSource( updated.setModifiedBy(getCurrentUserEntity()); updated.setModifiedDate(new Date()); - reuseDeletedDaimons(updated, existingSource); + reuseExistingDaimonIds(updated, existingSource); List removed = existingSource.getDaimons().stream() - .filter(d -> !updated.getDaimons().contains(d)) + .filter(existingDaimon -> updated.getDaimons().stream() + .noneMatch(updatedDaimon -> existingDaimon.getDaimonType() == updatedDaimon.getDaimonType())) .collect(Collectors.toList()); // Delete MUST be called after fetching user or source data to prevent autoflush (see DefaultPersistEventListener.onPersist) sourceDaimonRepository.deleteAll(removed); @@ -505,28 +484,15 @@ protected UserEntity getCurrentUserEntity() { return userRepository.findById(authorizationService.getAuthenticatedPrincipal().getUserId()).orElseThrow(); } - private void reuseDeletedDaimons(Source updated, Source source) { - List daimons = updated.getDaimons().stream().filter(d -> source.getDaimons().contains(d)) - .collect(Collectors.toList()); - List newDaimons = updated.getDaimons().stream().filter(d -> !source.getDaimons().contains(d)) - .collect(Collectors.toList()); + private void reuseExistingDaimonIds(Source updated, Source existing) { + List existingDaimons = sourceDaimonRepository.findBySource(existing); - List allDaimons = sourceDaimonRepository.findBySource(source); - - for (SourceDaimon newSourceDaimon : newDaimons) { - Optional reusedDaimonOpt = allDaimons.stream() - .filter(d -> d.equals(newSourceDaimon)) - .findFirst(); - if (reusedDaimonOpt.isPresent()) { - SourceDaimon reusedDaimon = reusedDaimonOpt.get(); - reusedDaimon.setPriority(newSourceDaimon.getPriority()); - reusedDaimon.setTableQualifier(newSourceDaimon.getTableQualifier()); - daimons.add(reusedDaimon); - } else { - daimons.add(newSourceDaimon); - } + for (SourceDaimon updatedDaimon : updated.getDaimons()) { + existingDaimons.stream() + .filter(existingDaimon -> existingDaimon.getDaimonType() == updatedDaimon.getDaimonType()) + .findFirst() + .ifPresent(existingDaimon -> updatedDaimon.setSourceDaimonId(existingDaimon.getSourceDaimonId())); } - updated.setDaimons(daimons); } private void transformIfRequired(Source source) { diff --git a/src/test/java/org/ohdsi/webapi/test/SourceAccessIT.java b/src/test/java/org/ohdsi/webapi/test/SourceAccessIT.java index 2787dd7c5..29e57075a 100644 --- a/src/test/java/org/ohdsi/webapi/test/SourceAccessIT.java +++ b/src/test/java/org/ohdsi/webapi/test/SourceAccessIT.java @@ -329,6 +329,26 @@ public void limitedUserDeniedGlobalCdmResultsCacheClear() { ); } + @Test + public void limitedUserDeniedSourceCdmResultsCacheClear() { + ResponseEntity r = postAsLimitedUser("/cdmresults/" + SOURCE_KEY + "/clearCache"); + assertEquals( + "Limited user (no admin:cache permission) should be denied with 403 Forbidden on source CDMResults cache clear", + HttpStatus.FORBIDDEN, + HttpStatus.valueOf(r.getStatusCode().value()) + ); + } + + @Test + public void limitedUserDeniedSourceCdmResultsCacheRefresh() { + ResponseEntity r = getAsLimitedUser("/cdmresults/" + SOURCE_KEY + "/refreshCache"); + assertEquals( + "Limited user (no admin:cache permission) should be denied with 403 Forbidden on source CDMResults cache refresh", + HttpStatus.FORBIDDEN, + HttpStatus.valueOf(r.getStatusCode().value()) + ); + } + /** * A limited user (authenticated, but with no source grant) must receive * HTTP 403 Forbidden when accessing the source-scoped EvidenceService info