刘光辉
4 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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());
        }
    }
}