package jnpf.dmsService;
|
|
import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity;
|
import jnpf.dmsEntity.storage.approval.*;
|
import jnpf.dmsIntegration.audit.DmsAuditAdapter;
|
import jnpf.dmsMapper.DmsApprovedReadAccessMapper;
|
import jnpf.dmsPermission.DmsPermissionProperties;
|
import jnpf.exception.DataException;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Propagation;
|
import org.springframework.transaction.annotation.Transactional;
|
import java.util.*;
|
|
/** Internal activation participant. No endpoint and no relaxation of the permission administrator API. */
|
@Service
|
@RequiredArgsConstructor
|
public class DmsApprovedReadAccessService {
|
public static final String SERVICE_ID = "dms-approved-read";
|
private final DmsApprovedReadAccessMapper mapper;
|
private final DmsAuditAdapter audit;
|
private final DmsPermissionProperties properties;
|
|
@Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
|
public void apply(DmsApprovedBatch batch, List<DmsApprovedItem> items, List<DmsApprovedItem> currentSource) {
|
if (batch.getId() == null || batch.getTenantId() == null || batch.getActivatedAt() == null)
|
throw new DataException("查阅授权必须在批准文件实际生效事务内执行");
|
Map<String, DmsApprovedItem> current = new HashMap<>();
|
for (DmsApprovedItem item : currentSource) {
|
if (current.put(item.getSourceKey(), item) != null) throw new DataException("批准文件来源重复");
|
}
|
Map<DmsApprovedItem, List<DmsApprovedDepartmentScope.Department>> scopes = new LinkedHashMap<>();
|
Set<String> departmentIds = new TreeSet<>();
|
int count = 0;
|
for (DmsApprovedItem item : items) {
|
DmsApprovedItem source = current.remove(item.getSourceKey());
|
if (source == null || !Objects.equals(item.getChangeType(), source.getChangeType())
|
|| !Objects.equals(item.getBaseFileVersionId(), source.getBaseFileVersionId()))
|
throw new DataException("查阅授权文件与批准来源不一致");
|
if ("RETIRE".equals(item.getChangeType())) continue;
|
if (!Objects.equals(DmsApprovedDepartmentScope.normalize(item.getReadAccessScope()),
|
DmsApprovedDepartmentScope.normalize(source.getReadAccessScope())))
|
throw new DataException("查阅授权范围与批准快照不一致");
|
if (!Set.of("CREATE", "REVISE", "REUSE").contains(item.getChangeType()) || item.getFileVersionId() == null)
|
throw new DataException("查阅授权文件版本无效");
|
List<DmsApprovedDepartmentScope.Department> scope = DmsApprovedDepartmentScope.parse(item.getReadAccessScope());
|
count += scope.size();
|
if (count > properties.getMaxGrantBatchSize()) throw new DataException("批准文件查阅授权超出批量上限");
|
scopes.put(item, scope);
|
scope.forEach(d -> departmentIds.add(d.id()));
|
}
|
if (!current.isEmpty()) throw new DataException("查阅授权文件集合不完整");
|
if (!departmentIds.isEmpty()) {
|
Set<String> actual = new HashSet<>();
|
mapper.departments(batch.getTenantId(), new ArrayList<>(departmentIds)).forEach(d -> actual.add(d.id()));
|
if (!actual.equals(departmentIds)) throw new DataException("查阅授权部门不存在、已停用或不属于当前租户");
|
}
|
// Center activation has already locked all documents in deterministic order in this same transaction.
|
for (var entry : scopes.entrySet()) {
|
DmsApprovedItem item = entry.getKey();
|
// fileVersionId is the target activated by this review; never use baseFileVersionId for permissions.
|
String sourceId = "approved-read:" + batch.getId() + ":" + item.getFileVersionId();
|
List<DmsFilePermissionEntity> old = mapper.owned(batch.getTenantId(), item.getFileVersionId());
|
if (old.stream().anyMatch(p -> sourceId.equals(p.getSourceId())))
|
throw new DataException("批准查阅授权已存在,禁止重复激活或复活已撤销权限");
|
List<DmsFilePermissionEntity> revoked = new ArrayList<>();
|
for (DmsFilePermissionEntity p : old) {
|
if (p.getRevokedAt() != null) continue;
|
if (!"REUSE".equals(item.getChangeType())) throw new DataException("新版本已有其他批准查阅授权");
|
if (mapper.revoke(batch.getTenantId(), p.getId()) != 1) throw new DataException("替换批准查阅授权失败");
|
revoked.add(p);
|
}
|
List<DmsFilePermissionEntity> created = new ArrayList<>();
|
for (var department : entry.getValue()) {
|
DmsFilePermissionEntity p = new DmsFilePermissionEntity();
|
p.setTenantId(batch.getTenantId()); p.setResourceType("FILE_VERSION");
|
p.setResourceId(item.getFileVersionId()); p.setResourceScope("SELF");
|
p.setPrincipalType("ORG"); p.setPrincipalId(department.id());
|
p.setIncludeChildOrgs("DESCENDANTS".equals(department.scope()));
|
p.setApprovedOrgScope(department.scope()); p.setActionCode("READ");
|
p.setSourceType("WORKFLOW"); p.setSourceId(sourceId);
|
p.setValidFrom(batch.getActivatedAt());
|
p.setGrantReason("文件审核正式生效:" + batch.getAuditId() + ";部门范围:" + department.scope());
|
p.setGrantedByType("SERVICE"); p.setGrantedById(SERVICE_ID);
|
created.add(mapper.insert(p));
|
}
|
if (!revoked.isEmpty() || !created.isEmpty())
|
audit.permissionChange("PERMISSION_GRANT", "更新文件审核查阅授权", old,
|
mapper.owned(batch.getTenantId(), item.getFileVersionId()), Collections.emptyList());
|
}
|
}
|
}
|