Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MODEXPW-488 - Central tenant view permissions handling #565

Merged
merged 61 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
ca03968
MODEXPW-488 - permissions-self-check
alekGbuz Sep 4, 2024
c6cd6a9
MODEXPW-488 - permissions components
alekGbuz Sep 4, 2024
a4c451a
MODEXPW-488 - add permissions validation to the entities fetchers
alekGbuz Sep 5, 2024
03960f5
MODEXPW-488 - add permissions validation to the holdings processor
alekGbuz Sep 5, 2024
75e948b
MODEXPW-488 - add permissions validation to the holdings processor
alekGbuz Sep 5, 2024
9ea0e6b
MODEXPW-488 - should return desired permissions test
alekGbuz Sep 5, 2024
7955215
MODEXPW-488 - should return desired permissions test
alekGbuz Sep 5, 2024
7e00905
MODEXPW-488 - instance fetcher read permissions test
alekGbuz Sep 5, 2024
f60239d
MODEXPW-488 - fix tests failures
alekGbuz Sep 5, 2024
f75cd64
MODEXPW-488 - update tests
alekGbuz Sep 6, 2024
1e3ce0c
MODEXPW-488 - permissions resolver and validation tests
alekGbuz Sep 6, 2024
fff461b
MODEXPW-488 - fix sonar
alekGbuz Sep 6, 2024
e9e0293
MODEXPW-488 - reduce logic complexity
alekGbuz Sep 6, 2024
4d00b49
MODEXPW-488 - split desired permissions
alekGbuz Sep 9, 2024
645bc64
MODEXPW-488 - rename tests
alekGbuz Sep 10, 2024
cf1d131
MODEXPW-488 - add logging
alekGbuz Sep 10, 2024
9a03d5a
MODEXPW-488 - check read permissions for item and holdings local tenant
alekGbuz Sep 10, 2024
564e101
MODEXPW-488 - fix tests
alekGbuz Sep 10, 2024
90b0c22
MODEXPW-488 - update permissions
alekGbuz Sep 10, 2024
0bac6bc
MODEXPW-488 - update permissions
alekGbuz Sep 10, 2024
5731530
MODEXPW-488 - debug level for desired permissions
alekGbuz Sep 10, 2024
996e822
MODEXPW-488 - permissions to set
alekGbuz Sep 11, 2024
192758e
MODEXPW-488 - update instance processor
alekGbuz Sep 11, 2024
a5a5d9f
MODEXPW-488 - update permission set
alekGbuz Sep 11, 2024
164c891
MODEXPW-488 - update permissions desired
alekGbuz Sep 12, 2024
898c88d
MODEXPW-488 - update permissions desired
alekGbuz Sep 12, 2024
960a481
Merge branch 'master' into MODEXPW-488
alekGbuz Sep 13, 2024
865003e
MODEXPW-488 - update tests
alekGbuz Sep 13, 2024
0dbfbc3
Merge branch 'MODEXPW-488' of https://github.com/folio-org/mod-data-e…
alekGbuz Sep 13, 2024
5db74cf
MODEXPW-488 - bulk-edit prefix to permissions self check endpoint
alekGbuz Sep 16, 2024
9019266
MODEXPW-488 - bulk-edit prefix to permissions self check endpoint
alekGbuz Sep 16, 2024
54de389
MODEXPW-488 - check inventory permissions
alekGbuz Sep 16, 2024
7b8270f
MODEXPW-488 - remove desired section, use inventory permissions for s…
alekGbuz Sep 17, 2024
522cf4f
MODEXPW-488 - update logging
alekGbuz Sep 17, 2024
cba334a
MODEXPW-488 - update logging
alekGbuz Sep 17, 2024
8018cbe
MODEXPW-488 - fix tests
alekGbuz Sep 17, 2024
ee0dc96
MODEXPW-488 - clean module descriptor
alekGbuz Sep 17, 2024
18d9416
MODEXPW-488 - fix tests
alekGbuz Sep 17, 2024
f781a76
MODEXPW-488 - update permissions check
alekGbuz Sep 18, 2024
3e193b0
MODEXPW-488 - update permissions check
alekGbuz Sep 18, 2024
8e833c6
MODEXPW-488 - add logging
alekGbuz Sep 18, 2024
23ffaca
MODEXPW-488 - change permission edit
alekGbuz Sep 18, 2024
d3954b2
MODEXPW-488 - change permission view
alekGbuz Sep 18, 2024
a3b2b37
MODEXPW-488 - reduce bulk edit interface
alekGbuz Sep 18, 2024
24f131c
MODEXPW-488 - copy headers for context switching
alekGbuz Sep 19, 2024
02c3158
MODEXPW-488 - copy headers for context switching
alekGbuz Sep 19, 2024
82ba0e7
MODEXPW-488 - update permissions checking
alekGbuz Sep 19, 2024
3305647
MODEXPW-488 - update permissions
alekGbuz Sep 19, 2024
0b39147
MODEXPW-488 - update tests
alekGbuz Sep 19, 2024
1cfc238
MODEXPW-488 - update permissions
alekGbuz Sep 19, 2024
9ce1cdd
MODEXPW-488 - update module descriptor
alekGbuz Sep 19, 2024
23df14d
MODEXPW-488 - updates checking permissions
alekGbuz Sep 20, 2024
1b0866f
MODEXPW-488 - updates tests
alekGbuz Sep 20, 2024
ed0946f
fix conflicts
alekGbuz Sep 20, 2024
1766c64
MODEXPW-488 - item fetcher synch
alekGbuz Sep 20, 2024
b03ed43
MODEXPW-488 - item fetcher synch
alekGbuz Sep 20, 2024
02580bf
MODEXPW-488 - update pool size for test
alekGbuz Sep 20, 2024
0952868
MODEXPW-488 - update pool size for test
alekGbuz Sep 20, 2024
0b3057f
MODEXPW-488 - fix sonar
alekGbuz Sep 20, 2024
183954e
MODEXPW-507 - add permissions interface
alekGbuz Sep 23, 2024
8eb344b
MODEXPW-488 - update bulk-edit interface
alekGbuz Sep 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,16 @@
{
"id": "instance-note-types",
"version": "1.0"
},
{
"id": "permissions",
"version": "5.6"
}
],
"provides": [
{
"id": "bulk-edit",
"version": "4.0",
"version": "4.1",
"handlers": [
{
"methods": [ "POST" ],
Expand Down Expand Up @@ -207,7 +211,8 @@
"source-storage.sourceRecords.get",
"user-tenants.collection.get",
"consortium-search.holdings.collection.get",
"consortium-search.items.collection.get"
"consortium-search.items.collection.get",
"bulk-edit.permissions-self-check.get"
]
},
{
Expand Down Expand Up @@ -259,7 +264,8 @@
"inventory-storage.ill-policies.item.get",
"inventory-storage.holdings-sources.collection.get",
"inventory-storage.holdings-sources.item.get",
"inventory-storage.holdings.item.put"
"inventory-storage.holdings.item.put",
"bulk-edit.permissions-self-check.get"
]
},
{
Expand All @@ -268,6 +274,12 @@
"permissionsRequired": [ "bulk-edit.errors.collection.get" ],
"modulePermissions": []
},
{
"methods": [ "GET" ],
"pathPattern": "/bulk-edit/permissions-self-check",
"permissionsRequired": ["bulk-edit.permissions-self-check.get"],
"modulePermissions": ["perms.users.get"]
},
{
"methods": [ "GET" ],
"pathPattern": "/refresh-presigned-url",
Expand Down Expand Up @@ -338,6 +350,11 @@
"displayName" : "get errors for preview",
"description" : "Get errors for preview"
},
{
"permissionName" : "bulk-edit.permissions-self-check.get",
"displayName" : "Set of users permissions for self check",
"description" : "Set of users permissions for self check"
},
{
"permissionName" : "refresh-presigned-url.get",
"displayName" : "Get refreshed presigned url for export file",
Expand All @@ -350,7 +367,8 @@
"subPermissions" : [
"bulk-edit.item.post",
"bulk-edit.start.item.post",
"bulk-edit.errors.collection.get"
"bulk-edit.errors.collection.get",
"bulk-edit.permissions-self-check.get"
]
},
{
Expand Down
203 changes: 101 additions & 102 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
<refresh-presigned-url.yaml.file>
${project.basedir}/src/main/resources/swagger.api/refresh-presigned-url.yaml
</refresh-presigned-url.yaml.file>

<folio-spring-base.version>8.1.0</folio-spring-base.version>
<folio-service-tools.version>3.1.0</folio-service-tools.version>
<folio-spring-cql.version>8.1.0</folio-spring-cql.version>
Expand Down Expand Up @@ -513,110 +512,110 @@
</configuration>
</execution>
<execution>
<id>bursar-export-worker-schedule-parameters</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${bursar-export.yaml.file}</inputSpec>
<output>${project.build.directory}/generated-sources</output>
<generatorName>spring</generatorName>
<modelPackage>${project.groupId}.dew.domain.dto</modelPackage>
<generateApis>false</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>false</generateApiDocumentation>
<generateModels>true</generateModels>
<modelsToGenerate>ScheduleParameters</modelsToGenerate>
<generateModelTests>false</generateModelTests>
<generateSupportingFiles>false</generateSupportingFiles>
<generateModelDocumentation>true</generateModelDocumentation>
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
<configOptions>
<java8>true</java8>
<dateLibrary>java8</dateLibrary>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
</configOptions>
</configuration>
</execution>
<id>bursar-export-worker-schedule-parameters</id>
alekGbuz marked this conversation as resolved.
Show resolved Hide resolved
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${bursar-export.yaml.file}</inputSpec>
<output>${project.build.directory}/generated-sources</output>
<generatorName>spring</generatorName>
<modelPackage>${project.groupId}.dew.domain.dto</modelPackage>
<generateApis>false</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>false</generateApiDocumentation>
<generateModels>true</generateModels>
<modelsToGenerate>ScheduleParameters</modelsToGenerate>
<generateModelTests>false</generateModelTests>
<generateSupportingFiles>false</generateSupportingFiles>
<generateModelDocumentation>true</generateModelDocumentation>
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
<configOptions>
<java8>true</java8>
<dateLibrary>java8</dateLibrary>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
</configOptions>
</configuration>
</execution>
<execution>
<id>bulk-edit-worker</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${bulk-edit.yaml.file}</inputSpec>
<output>${project.build.directory}/generated-sources</output>
<generatorName>spring</generatorName>
<modelPackage>${project.groupId}.dew.domain.dto</modelPackage>
<generateApis>true</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>false</generateApiDocumentation>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<generateSupportingFiles>true</generateSupportingFiles>
<generateModelDocumentation>true</generateModelDocumentation>
<configOptions>
<java8>true</java8>
<dateLibrary>java</dateLibrary>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
<serializableModel>true</serializableModel>
</configOptions>
</configuration>
</execution>
<id>bulk-edit-worker</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${bulk-edit.yaml.file}</inputSpec>
<output>${project.build.directory}/generated-sources</output>
<generatorName>spring</generatorName>
<modelPackage>${project.groupId}.dew.domain.dto</modelPackage>
<generateApis>true</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>false</generateApiDocumentation>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<generateSupportingFiles>true</generateSupportingFiles>
<generateModelDocumentation>true</generateModelDocumentation>
<configOptions>
<java8>true</java8>
<dateLibrary>java</dateLibrary>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
<serializableModel>true</serializableModel>
</configOptions>
</configuration>
</execution>
<execution>
<id>refresh-presigned-url</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${refresh-presigned-url.yaml.file}</inputSpec>
<output>${project.build.directory}/generated-sources</output>
<generatorName>spring</generatorName>
<modelPackage>${project.groupId}.dew.domain.dto</modelPackage>
<generateApis>true</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>true</generateApiDocumentation>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<generateSupportingFiles>true</generateSupportingFiles>
<generateModelDocumentation>true</generateModelDocumentation>
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
<configOptions>
<java8>true</java8>
<dateLibrary>java</dateLibrary>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
</configOptions>
</configuration>
</execution>
<id>refresh-presigned-url</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${refresh-presigned-url.yaml.file}</inputSpec>
<output>${project.build.directory}/generated-sources</output>
<generatorName>spring</generatorName>
<modelPackage>${project.groupId}.dew.domain.dto</modelPackage>
<generateApis>true</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>true</generateApiDocumentation>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<generateSupportingFiles>true</generateSupportingFiles>
<generateModelDocumentation>true</generateModelDocumentation>
<supportingFilesToGenerate>ApiUtil.java</supportingFilesToGenerate>
<configOptions>
<java8>true</java8>
<dateLibrary>java</dateLibrary>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
</configOptions>
</configuration>
</execution>
<execution>
<id>order-export-worker</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${order-export.yaml.file}</inputSpec>
<output>${project.build.directory}/generated-sources</output>
<generatorName>spring</generatorName>
<modelPackage>${project.groupId}.dew.domain.dto</modelPackage>
<generateApis>true</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>false</generateApiDocumentation>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<generateSupportingFiles>true</generateSupportingFiles>
<generateModelDocumentation>true</generateModelDocumentation>
<configOptions>
<java8>true</java8>
<dateLibrary>java</dateLibrary>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
<serializableModel>true</serializableModel>
</configOptions>
</configuration>
</execution>
<id>order-export-worker</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${order-export.yaml.file}</inputSpec>
<output>${project.build.directory}/generated-sources</output>
<generatorName>spring</generatorName>
<modelPackage>${project.groupId}.dew.domain.dto</modelPackage>
<generateApis>true</generateApis>
<generateApiTests>false</generateApiTests>
<generateApiDocumentation>false</generateApiDocumentation>
<generateModels>true</generateModels>
<generateModelTests>false</generateModelTests>
<generateSupportingFiles>true</generateSupportingFiles>
<generateModelDocumentation>true</generateModelDocumentation>
<configOptions>
<java8>true</java8>
<dateLibrary>java</dateLibrary>
<interfaceOnly>true</interfaceOnly>
<useSpringBoot3>true</useSpringBoot3>
<serializableModel>true</serializableModel>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static org.folio.dew.utils.Constants.DUPLICATES_ACROSS_TENANTS;
import static org.folio.dew.utils.Constants.MULTIPLE_MATCHES_MESSAGE;
import static org.folio.dew.utils.Constants.NO_HOLDING_AFFILIATION;
import static org.folio.dew.utils.Constants.NO_HOLDING_VIEW_PERMISSIONS;
import static org.folio.dew.utils.Constants.NO_MATCH_FOUND_MESSAGE;
import static org.folio.dew.utils.SearchIdentifierTypeResolver.getSearchIdentifierType;

Expand All @@ -20,18 +21,21 @@
import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.folio.dew.batch.bulkedit.jobs.permissions.check.PermissionsValidator;
import org.folio.dew.client.HoldingClient;
import org.folio.dew.client.SearchClient;
import org.folio.dew.client.UserClient;
import org.folio.dew.domain.dto.BatchIdsDto;
import org.folio.dew.domain.dto.ConsortiumHolding;
import org.folio.dew.domain.dto.EntityType;
import org.folio.dew.domain.dto.ExtendedHoldingsRecord;
import org.folio.dew.domain.dto.ExtendedHoldingsRecordCollection;
import org.folio.dew.domain.dto.HoldingsFormat;
import org.folio.dew.domain.dto.HoldingsRecordCollection;
import org.folio.dew.domain.dto.IdentifierType;
import org.folio.dew.domain.dto.ItemIdentifier;
import org.folio.dew.error.BulkEditException;
import org.folio.dew.exceptions.ReadPermissionDoesNotExist;
import org.folio.dew.service.ConsortiaService;
import org.folio.dew.service.FolioExecutionContextManager;
import org.folio.dew.service.HoldingsReferenceService;
Expand Down Expand Up @@ -61,6 +65,7 @@ public class BulkEditHoldingsProcessor extends FolioExecutionContextManager impl
private final ConsortiaService consortiaService;
private final FolioExecutionContext folioExecutionContext;
private final UserClient userClient;
private final PermissionsValidator permissionsValidator;

@Value("#{jobParameters['identifierType']}")
private String identifierType;
Expand Down Expand Up @@ -123,6 +128,7 @@ private ExtendedHoldingsRecordCollection getHoldingsRecords(ItemIdentifier itemI
}
tenantIds.forEach(tenantId -> {
try (var context = new FolioExecutionContextSetter(refreshAndGetFolioExecutionContext(tenantId, folioExecutionContext))) {
permissionsValidator.checkBulkEditReadPermissions(tenantId, EntityType.HOLDINGS_RECORD);
var holdingsRecordCollection = getHoldingsRecordCollection(type, itemIdentifier);
extendedHoldingsRecordCollection.getExtendedHoldingsRecords().addAll(
holdingsRecordCollection.getHoldingsRecords().stream()
Expand All @@ -133,7 +139,10 @@ private ExtendedHoldingsRecordCollection getHoldingsRecords(ItemIdentifier itemI
if (e instanceof FeignException && ((FeignException) e).status() == 401) {
var user = userClient.getUserById(folioExecutionContext.getUserId().toString());
throw new BulkEditException(format(NO_HOLDING_AFFILIATION, user.getUsername(), resolveIdentifier(identifierType), identifier, tenantId));
} else {
} else if (e instanceof ReadPermissionDoesNotExist) {
var user = userClient.getUserById(folioExecutionContext.getUserId().toString());
throw new BulkEditException(format(NO_HOLDING_VIEW_PERMISSIONS, user.getUsername(), resolveIdentifier(identifierType), identifier, tenantId));
} else {
throw e;
}
}
Expand All @@ -144,13 +153,21 @@ private ExtendedHoldingsRecordCollection getHoldingsRecords(ItemIdentifier itemI
}
} else {
// Process local tenant case
checkReadPermissions(folioExecutionContext.getTenantId(), identifier);
var holdingsRecordCollection = getHoldingsRecordCollection(type, itemIdentifier);
return new ExtendedHoldingsRecordCollection().extendedHoldingsRecords(holdingsRecordCollection.getHoldingsRecords().stream()
.map(holdingsRecord -> new ExtendedHoldingsRecord().tenantId(folioExecutionContext.getTenantId()).entity(holdingsRecord)).toList())
.totalRecords(holdingsRecordCollection.getTotalRecords());
}
}

private void checkReadPermissions(String tenantId, String identifier) {
if (!permissionsValidator.isBulkEditReadPermissionExists(tenantId, EntityType.HOLDINGS_RECORD)) {
var user = userClient.getUserById(folioExecutionContext.getUserId().toString());
throw new BulkEditException(format(NO_HOLDING_VIEW_PERMISSIONS, user.getUsername(), resolveIdentifier(identifierType), identifier, tenantId));
}
}

private boolean isCurrentTenantCentral(String centralTenantId) {
return StringUtils.isNotEmpty(centralTenantId) && centralTenantId.equals(folioExecutionContext.getTenantId());
}
Expand Down
Loading
Loading