在 b369527 之上增量移植 FL2.0 后端能力,不改既有线级停发/指派预览/流程图入口:
- 部门目录:FlowDepartmentController(/admin/department/{groups,options,resolve,members})
+ UserBaseDepartmentDirectory(先按会话校域解析引用,再读成员;目录不可用 fail-closed)
- 退回重提 D14:POST /oapi/flow/instance/{instanceId}/resubmit,仅原提交人 CAS 路径放行,
OAPI 侧 submitterId 路径继续 fail-closed
- 授权管理:/api/flow/admin/usage-grant/{schoolList,summary}(校域取管理员会话,无 schId 入参)
- 来源主体:解析器派生 ub-app:{applicationInfo.id},不再读取 UserBase 的 sourcePrincipalId 字段
- 回调来源策略:SELF 身份强校验;NULL 来源不广播;复合幂等键 (event_id,reg_id)
- 测试夹具:许可/主体/开通桩按新契约修正,FlowEngineIT/FormalApplyCommandIT/
CallbackDispatchIT/OapiFlowContractIT 共 117 例在真实 MySQL 8 通过
不含:FlSourceAuthorizationTest(其断言的两个 Repository 派生方法属另一实现线)
This commit is contained in:
@@ -145,8 +145,8 @@ public class OapiFlowService {
|
||||
FlowDefModel.parse(objectMapper, def.getContentJson()), formDataJson);
|
||||
}
|
||||
|
||||
private <T> T inTransaction(
|
||||
org.springframework.transaction.support.TransactionCallback<T> action) {
|
||||
private FlowInstanceService.GuardedOutcome inTransaction(
|
||||
org.springframework.transaction.support.TransactionCallback<FlowInstanceService.GuardedOutcome> action) {
|
||||
return transactionTemplate == null ? action.doInTransaction(null) : transactionTemplate.execute(action);
|
||||
}
|
||||
|
||||
@@ -229,6 +229,7 @@ public class OapiFlowService {
|
||||
|
||||
/** 代发起(biz uk 幂等 + R4 重启重提,见 FlowInstanceService):appKey=验签上下文调用方身份,
|
||||
* 与 app_code 一起快照进办件(消息 jump_app 的权威来源,2026-10-12 起替代 bizType 冒充) */
|
||||
@Transactional
|
||||
public OapiModels.ApplyResultVo apply(Long schId, String appKey, OapiModels.ApplyBody body) {
|
||||
requireLegacyWriter();
|
||||
if (schId == null || body.getFlowGuid() == null || body.getBizType() == null
|
||||
@@ -238,10 +239,10 @@ public class OapiFlowService {
|
||||
}
|
||||
requireSchoolMember(schId, body.getSubmitterId());
|
||||
String cleanAppKey = appKey == null || appKey.trim().isEmpty() ? null : appKey.trim();
|
||||
// T01 使用许可(v1 路径):回执幂等(既有在途/通过件)不拦;无实例或终态件 R4 重启=新申报,
|
||||
// 必须持有效使用许可。恢复感知的分支判定与 FlowInstanceService.apply 保持同键同序。
|
||||
FlowSourcePrincipalResolver.Principal source = requireApplySource(schId, cleanAppKey);
|
||||
requireUsageGrant(schId, body.getFlowGuid(), source);
|
||||
// D02/D09/D11:来源主体只从验签上下文解析(缺失即拒);T01 使用许可(v1 路径)——
|
||||
// 回执幂等(既有在途/退回待修改/通过件)不拦;无实例或终态件 R4 重启=新申报,必须持有效许可。
|
||||
FlowSourcePrincipalResolver.Principal source = requireApplySource(cleanAppKey);
|
||||
requireUsageGrantLegacyApply(schId, body.getFlowGuid(), source, body.getBizType(), body.getBizId());
|
||||
FlwDef def = requirePublishedDefForApply(schId, body.getFlowGuid());
|
||||
// T06 变量终审:EXPRESSION 引用的业务变量缺失/空=null 即拒(零实例),不等运行期 nil 放行
|
||||
requireExpressionVariablesPresent(def, asFormDataString(body.getFormData()));
|
||||
@@ -260,15 +261,9 @@ public class OapiFlowService {
|
||||
body.getBizUrl(), asSnapshotString(body.getBizSnapshot()),
|
||||
body.getSubmitterId(), body.getSubmitterName(),
|
||||
asFormDataString(body.getFormData()),
|
||||
cleanAppKey, source.appCode, assignJson);
|
||||
cleanAppKey, resolveApplyAppCode(cleanAppKey), assignJson);
|
||||
cmd.sourcePrincipalId = source.id;
|
||||
cmd.payloadHash = payloadHash(cmd);
|
||||
FlowInstanceService.ApplyOutcome outcome;
|
||||
try { outcome = inTransaction(tx -> instanceService.apply(cmd)); }
|
||||
catch (DataIntegrityViolationException concurrent) {
|
||||
// Outside the failed transaction: retry the SAME source-scoped lookup, never a broad business-key read.
|
||||
outcome = inTransaction(tx -> instanceService.apply(cmd));
|
||||
}
|
||||
FlowInstanceService.ApplyOutcome outcome = instanceService.apply(cmd);
|
||||
OapiModels.ApplyResultVo vo = new OapiModels.ApplyResultVo();
|
||||
vo.setInstanceId(outcome.getInstanceId());
|
||||
vo.setDuplicated(outcome.isDuplicated());
|
||||
@@ -302,9 +297,15 @@ public class OapiFlowService {
|
||||
}
|
||||
requireSchoolMember(schId, body.getSubmitterId());
|
||||
String cleanAppKey = appKey == null || appKey.trim().isEmpty() ? null : appKey.trim();
|
||||
FlowSourcePrincipalResolver.Principal source = requireApplySource(schId, cleanAppKey);
|
||||
FlwInstance existing = instanceRepository.findBySchIdAndSourcePrincipalIdAndBizTypeAndBizIdAndLegacySlot(
|
||||
schId, source.id, body.getBizType(), body.getBizId(), 1).orElse(null);
|
||||
// D02/D09/D11:可信来源只从验签上下文推导。T01 使用许可(v2 路径)——恢复感知:
|
||||
// SAME_REQUEST/REPLAY_ONLY/IDEMPOTENT/STALE_ROUND 四类回执分支不拦(已受理命令的回执不因许可
|
||||
// 撤销丢失);CREATED/RESTARTED(新申报/新轮)必须持有效使用许可。分支判定与
|
||||
// FlowInstanceService.applyGuarded 同键同序;完整命令协议(requestId/指纹/服务端轮次)归 T04。
|
||||
FlowSourcePrincipalResolver.Principal source = requireApplySource(cleanAppKey);
|
||||
requireUsageGrantGuardedApply(schId, body.getFlowGuid(), source, body.getBizType(),
|
||||
body.getBizId(), body.getRequestToken(), body.getAttempt(),
|
||||
Boolean.TRUE.equals(body.getRetryOnly()));
|
||||
FlwInstance existing = sourceScopedInstance(schId, source, body.getBizType(), body.getBizId());
|
||||
boolean replay = existing != null && body.getRequestToken() != null
|
||||
&& !body.getRequestToken().trim().isEmpty()
|
||||
&& body.getRequestToken().trim().equals(existing.getApplyRequestToken());
|
||||
@@ -328,15 +329,10 @@ public class OapiFlowService {
|
||||
body.getBizUrl(), asSnapshotString(body.getBizSnapshot()),
|
||||
body.getSubmitterId(), body.getSubmitterName(),
|
||||
asFormDataString(body.getFormData()),
|
||||
cleanAppKey, source.appCode, assignJson);
|
||||
cmd.sourcePrincipalId = source.id;
|
||||
cleanAppKey, resolveApplyAppCode(cleanAppKey), assignJson);
|
||||
// T04:受理载荷指纹(服务端计算,不信任客户端自报)——同 token 异载荷按冲突拒绝
|
||||
cmd.payloadHash = payloadHash(cmd);
|
||||
// Only an exact, source-owned, already accepted command can recover after revocation.
|
||||
boolean provenReceipt = replay && source.id.equals(existing.getSourcePrincipalId())
|
||||
&& existing.getApplyPayloadHash() != null && existing.getApplyPayloadHash().equals(cmd.payloadHash)
|
||||
&& java.util.Objects.equals(existing.getSubmitterId(), cmd.submitterId);
|
||||
if (!provenReceipt) requireUsageGrant(schId, body.getFlowGuid(), source);
|
||||
cmd.sourcePrincipalId = source.id;
|
||||
FlowInstanceService.ApplyRetryPolicy policy = new FlowInstanceService.ApplyRetryPolicy(
|
||||
body.getRequestToken(), body.getAttempt(), Boolean.TRUE.equals(body.getRetryOnly()),
|
||||
body.getExpectedPrevRound());
|
||||
@@ -385,28 +381,76 @@ public class OapiFlowService {
|
||||
|
||||
/**
|
||||
* T01 使用许可闸·v1 路径(恢复感知最小形态):v1 无 token/轮次,回执与新申报的区分只能靠
|
||||
* 既有实例状态——在途(10)/通过(20)命中=幂等回读放行;无实例=CREATED;终态(30/40)=R4
|
||||
* 重启即新一轮申报。每次均强制通过独立的学校开通与流程使用授权校验。
|
||||
* 既有实例状态——在途(10/50)/通过(20)命中=幂等回读放行;无实例=CREATED;终态(30/40)=R4
|
||||
* 重启即新一轮申报。
|
||||
*
|
||||
* <p><b>F01 整改(2026-10-29):本方法不再有直通分支。</b>旧实现
|
||||
* {@code if (guard == null || !guard.isEnforce() || appKey == null) return;} 让"闸门未装配"、
|
||||
* "灰度开关关闭"、"缺验签主体"三种情况都变成放行。现三者全部 fail-closed 拒绝。</p>
|
||||
*/
|
||||
private FlowSourcePrincipalResolver.Principal requireApplySource(Long school, String appKey) {
|
||||
if (school == null || school <= 0 || sourcePrincipalResolver == null) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "缺少有效申报学校或来源解析服务");
|
||||
private void requireUsageGrantLegacyApply(Long schId, String flowGuid,
|
||||
FlowSourcePrincipalResolver.Principal source,
|
||||
String bizType, String bizId) {
|
||||
if (!legacyApplyIsReceiptOnly(sourceScopedInstance(schId, source, bizType, bizId))) {
|
||||
requireGrantGuard().requireNewApplyGrant(schId, flowGuid, source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* T01 使用许可闸·v2 路径:与 {@code FlowInstanceService.applyGuarded/settleExisting}
|
||||
* 同键同序的分支预判(判定逻辑见 {@link #guardedApplyIsReceiptOnly});
|
||||
* 新申报(CREATED/RESTARTED)必须过 {@link FlowUsageGrantGuard#requireNewApplyGrant}。
|
||||
* 完整命令协议统一归 T04。
|
||||
*/
|
||||
private void requireUsageGrantGuardedApply(Long schId, String flowGuid,
|
||||
FlowSourcePrincipalResolver.Principal source,
|
||||
String bizType, String bizId,
|
||||
String requestToken, Integer attempt, boolean retryOnly) {
|
||||
if (!guardedApplyIsReceiptOnly(sourceScopedInstance(schId, source, bizType, bizId),
|
||||
requestToken, attempt, retryOnly)) {
|
||||
requireGrantGuard().requireNewApplyGrant(schId, flowGuid, source);
|
||||
}
|
||||
}
|
||||
|
||||
/** 闸门缺失=拒绝而不是放行(生产装配必有该 bean;手工构造服务时必须显式注入测试替身)。 */
|
||||
private FlowUsageGrantGuard requireGrantGuard() {
|
||||
if (usageGrantGuard == null) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "应用使用许可闸门未装配,拒绝发起");
|
||||
}
|
||||
return usageGrantGuard;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验签上下文 → 可信来源主体(F02)。appKey 缺失、UserBase 不可达或注册表查无一律拒绝,
|
||||
* 不回退成"无来源"的宽松路径;通道未装配同样拒绝。
|
||||
*/
|
||||
private FlowSourcePrincipalResolver.Principal requireApplySource(String appKey) {
|
||||
if (sourcePrincipalResolver == null) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "调用应用主体解析通道未装配,拒绝发起");
|
||||
}
|
||||
return sourcePrincipalResolver.resolve(appKey);
|
||||
}
|
||||
|
||||
private void requireUsageGrant(Long school, String flow, FlowSourcePrincipalResolver.Principal source) {
|
||||
if (usageGrantGuard == null) throw new BizException(ErrorCode.FORBIDDEN, "流程使用授权服务未装配");
|
||||
usageGrantGuard.requireNewApplyGrant(school, flow, source);
|
||||
/** 来源分区的业务坐标回读(与 {@code uk_flw_instance_legacy} 同列同序)。 */
|
||||
private FlwInstance sourceScopedInstance(Long schId, FlowSourcePrincipalResolver.Principal source,
|
||||
String bizType, String bizId) {
|
||||
if (source == null) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "缺少可信来源应用,不能按业务坐标定位办件");
|
||||
}
|
||||
return instanceRepository.findFirstBySchIdAndSourcePrincipalIdAndBizTypeAndBizIdAndLegacySlot(
|
||||
schId, source.id, bizType, bizId, LEGACY_SLOT).orElse(null);
|
||||
}
|
||||
|
||||
/** 旧 OAPI 入口的坐标槽位(正式命令走 NULL 槽位,两条分区互不复用)。 */
|
||||
private static final Integer LEGACY_SLOT = 1;
|
||||
|
||||
/**
|
||||
* v1 回执判定:true=该请求只会命中幂等回读(不建件不重启),false=会触发新申报或 R4 重启。
|
||||
* 与 {@code FlowInstanceService.apply(ApplyCommand)} 的分支一一对应(包私有便于规则单测钉住)。
|
||||
*/
|
||||
static boolean legacyApplyIsReceiptOnly(FlwInstance existing) {
|
||||
return existing != null
|
||||
&& (existing.getStatus() == FlwEnums.InstanceStatus.APPROVING.getCode()
|
||||
&& (FlwEnums.InstanceStatus.inFlightCodes().contains(existing.getStatus())
|
||||
|| existing.getStatus() == FlwEnums.InstanceStatus.COMPLETED.getCode());
|
||||
}
|
||||
|
||||
@@ -427,7 +471,7 @@ public class OapiFlowService {
|
||||
if (retryOnly) {
|
||||
return true;
|
||||
}
|
||||
if (existing.getStatus() == FlwEnums.InstanceStatus.APPROVING.getCode()
|
||||
if (FlwEnums.InstanceStatus.inFlightCodes().contains(existing.getStatus())
|
||||
|| existing.getStatus() == FlwEnums.InstanceStatus.COMPLETED.getCode()) {
|
||||
return true;
|
||||
}
|
||||
@@ -485,18 +529,40 @@ public class OapiFlowService {
|
||||
private FlowApplyRetryModels.ApplyResultV2 fromConcurrent(Long schId,
|
||||
FlowInstanceService.ApplyCommand cmd,
|
||||
FlowInstanceService.ApplyRetryPolicy policy) {
|
||||
FlowInstanceService.GuardedOutcome outcome = inTransaction(tx -> instanceService.applyGuarded(cmd, policy));
|
||||
requireNotConflict(outcome);
|
||||
FlwInstance existing = instanceRepository
|
||||
.findFirstBySchIdAndSourcePrincipalIdAndBizTypeAndBizIdAndLegacySlot(
|
||||
schId, cmd.sourcePrincipalId, cmd.bizType, cmd.bizId, LEGACY_SLOT)
|
||||
.orElse(null);
|
||||
if (existing == null) {
|
||||
throw new BizException(ErrorCode.CUSTOM, "办件创建冲突且读不到既有实例,请稍后重试");
|
||||
}
|
||||
if (!cmd.sourcePrincipalId.equals(existing.getSourcePrincipalId())) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN,
|
||||
"该业务键的办件属于另一调用应用(bizType=" + cmd.bizType + " bizId=" + cmd.bizId + ")");
|
||||
}
|
||||
if (existing.getSubmitterId() != null && cmd.submitterId != null
|
||||
&& !existing.getSubmitterId().equals(cmd.submitterId)) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "该业务键的办件提交者与本次请求不符");
|
||||
}
|
||||
String token = policy.requestToken == null ? null : policy.requestToken.trim();
|
||||
FlowApplyRetryModels.ApplyResultV2 vo = new FlowApplyRetryModels.ApplyResultV2();
|
||||
vo.setInstanceId(outcome.instanceId); vo.setDuplicated(outcome.duplicated);
|
||||
vo.setBranch(outcome.branch); vo.setApplyRound(outcome.applyRound);
|
||||
instanceRepository.findById(outcome.instanceId).ifPresent(current -> {
|
||||
int currentRound = current.getApplyRound() == null ? 1 : current.getApplyRound();
|
||||
int outcomeRound = outcome.applyRound == null ? 1 : outcome.applyRound;
|
||||
if (currentRound == outcomeRound && cmd.sourcePrincipalId.equals(current.getSourcePrincipalId())) {
|
||||
vo.setStatus(current.getStatus()); vo.setVersion(current.getVersion());
|
||||
}
|
||||
});
|
||||
vo.setInstanceId(existing.getId());
|
||||
vo.setDuplicated(true);
|
||||
vo.setApplyRound(existing.getApplyRound());
|
||||
vo.setStatus(existing.getStatus());
|
||||
vo.setVersion(existing.getVersion());
|
||||
if (token != null && !token.equals(existing.getApplyRequestToken())) {
|
||||
// T04:并发撞键且 token 不符=两份不同命令抢同一业务键——后到者冲突,不伪装幂等成功
|
||||
//(旧 CONCURRENT_CREATED 分支只保留给无 token 的存量调用方)。
|
||||
log.warn("[flow-center] 并发建件 token 不符(冲突拒绝):instance={} biz={}/{}",
|
||||
existing.getId(), cmd.bizType, cmd.bizId);
|
||||
throw new BizException(ErrorCode.CUSTOM,
|
||||
"该业务键已被另一并发命令创建(请求标识不符),请按实例查询恢复,不要换 ID 重发");
|
||||
}
|
||||
vo.setBranch(token != null ? FlowApplyRetryModels.Branch.SAME_REQUEST
|
||||
: FlowApplyRetryModels.Branch.CONCURRENT_CREATED);
|
||||
log.warn("[flow-center] 并发建件命中既有实例:instance={} biz={}/{} branch={}",
|
||||
existing.getId(), cmd.bizType, cmd.bizId, vo.getBranch());
|
||||
return vo;
|
||||
}
|
||||
|
||||
@@ -711,9 +777,10 @@ public class OapiFlowService {
|
||||
if (schId == null || assigneeId == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "缺少必要参数:schId/assigneeId");
|
||||
}
|
||||
Page<FlwTask> p = formalCommandEnabled
|
||||
? taskRepository.pageSelfTodo(schId, FlowOapiSourceScope.current(), assigneeId, emptyToNull(bizType), PageRequest.of(normPage(page), normSize(size)))
|
||||
: taskRepository.pageTodoBiz(schId, assigneeId, emptyToNull(bizType), PageRequest.of(normPage(page), normSize(size)));
|
||||
// D11/F02:OAPI 列表一律按可信来源分区,A 应用不会看到 B 应用的待办。
|
||||
// 本次改造之前落库、来源列为空的实例不在本口径内(不回填、不猜测归属,见任务书 §2.3)。
|
||||
Page<FlwTask> p = taskRepository.pageSelfTodo(schId, FlowOapiSourceScope.current(),
|
||||
assigneeId, emptyToNull(bizType), PageRequest.of(normPage(page), normSize(size)));
|
||||
List<Long> instanceIds = p.getContent().stream()
|
||||
.map(FlwTask::getInstanceId).distinct().collect(java.util.stream.Collectors.toList());
|
||||
Map<Long, FlwInstance> instances = instanceIds.isEmpty()
|
||||
@@ -732,9 +799,8 @@ public class OapiFlowService {
|
||||
if (schId == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "缺少必要参数:schId");
|
||||
}
|
||||
Page<FlwInstance> p = formalCommandEnabled
|
||||
? instanceRepository.pageSelf(schId, FlowOapiSourceScope.current(), emptyToNull(bizType), status, PageRequest.of(normPage(page), normSize(size)))
|
||||
: instanceRepository.pageByBiz(schId, emptyToNull(bizType), status, PageRequest.of(normPage(page), normSize(size)));
|
||||
Page<FlwInstance> p = instanceRepository.pageSelf(schId, FlowOapiSourceScope.current(),
|
||||
emptyToNull(bizType), status, PageRequest.of(normPage(page), normSize(size)));
|
||||
List<OapiModels.InstanceItemVo> items = p.getContent().stream()
|
||||
.map(this::toInstanceItemVo).collect(java.util.stream.Collectors.toList());
|
||||
return toPageResult(p.getTotalElements(), items, page, size);
|
||||
@@ -942,6 +1008,22 @@ public class OapiFlowService {
|
||||
instanceService.withdraw(schId, instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* D14 发起人重提(托管接入件,2026-10-29)。治理口径与 {@link #withdraw} 一致:
|
||||
* <ul>
|
||||
* <li>来源:{@code FlowOapiSourceScope} 已按实例 id 核验归属,非本应用发起的办件到不了这里;</li>
|
||||
* <li>身份:{@code submitterId} 与办件提交人逐字复核——签名只证明"哪个应用在调";</li>
|
||||
* <li>状态:仅 50 退回待修改(幂等:已是 10 视为已重提,回原实例不重开一代任务);</li>
|
||||
* <li>轮次/版本:不改 applyRound、不改 defId/defVersion(D04/D05 在途固定版本);</li>
|
||||
* <li>业务字段:FL 不做 Diff,{@code formData} 为空即沿用原快照。</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Transactional
|
||||
public void resubmit(Long schId, Long instanceId, Integer submitterId, String formData) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN,
|
||||
"OAPI 重提缺少可信用户身份证明,请由原提交人通过 CAS 办理页重提");
|
||||
}
|
||||
|
||||
/**
|
||||
* 办件进度(结构化轨迹):steps=发起申请 + 节点步骤(按任务 id 序;同节点同人多任务行合并为多人步骤)。
|
||||
* 状态标签口径与前端流程轨迹一致(0 待审核 / 1 已同意 / 2 已拒绝 / 3 失效 / 4 已退回 / 5 已移交);
|
||||
@@ -1052,10 +1134,11 @@ public class OapiFlowService {
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 进度/换图共用的办件定位(schId 收敛在次) */
|
||||
/** 进度/换图共用的办件定位(schId 收敛在次;来源分区必填,缺来源即拒) */
|
||||
private java.util.Optional<FlwInstance> findByBizForOapi(Long school, String type, String biz) {
|
||||
return instanceRepository.findFirstBySchIdAndSourcePrincipalIdAndBizTypeAndBizIdOrderByApplyRoundDesc(
|
||||
school, FlowOapiSourceScope.current(), type, biz);
|
||||
String source = FlowOapiSourceScope.current();
|
||||
return instanceRepository.findFirstBySchIdAndSourcePrincipalIdAndBizTypeAndBizIdOrderByIdDesc(
|
||||
school, source, type, biz);
|
||||
}
|
||||
|
||||
private FlwInstance requireInstance(Long schId, Long instanceId) {
|
||||
@@ -1324,14 +1407,10 @@ public class OapiFlowService {
|
||||
}
|
||||
{
|
||||
FlowSourcePrincipalResolver.Principal source = sourcePrincipalResolver.resolve(appKey);
|
||||
if (formalCommandEnabled) {
|
||||
com.yunhai.flowcenter.entity.FlwUsageGrant grant = formalGrants.findBySchIdAndFlowGuidAndAppId(schId, body.getFlowGuid(), source.appId).orElse(null);
|
||||
boolean permitted = grant != null && Integer.valueOf(1).equals(grant.getEnabled()) && source.id.equals(grant.getSourcePrincipalId());
|
||||
if (!permitted && !formalCommands.existsBySchIdAndSourcePrincipalIdAndFlowGuidAndState(schId, source.id, body.getFlowGuid(), "ACCEPTED")) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "没有 SELF 订阅权限");
|
||||
}
|
||||
} else {
|
||||
requireUsageGrant(schId, body.getFlowGuid(), source);
|
||||
com.yunhai.flowcenter.entity.FlwUsageGrant grant = formalGrants.findBySchIdAndFlowGuidAndAppId(schId, body.getFlowGuid(), source.appId).orElse(null);
|
||||
boolean permitted = grant != null && Integer.valueOf(1).equals(grant.getEnabled()) && source.id.equals(grant.getSourcePrincipalId());
|
||||
if (!permitted && !formalCommands.existsBySchIdAndSourcePrincipalIdAndFlowGuidAndState(schId, source.id, body.getFlowGuid(), "ACCEPTED")) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "没有 SELF 订阅权限");
|
||||
}
|
||||
reg.setSourcePrincipalId(source.id);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user