package jnpf.elnService.template; import jnpf.database.util.TenantDataSourceUtil; import jnpf.elnEntity.ElnDocumentFileVo; import jnpf.elnEntity.template.ElnTemplateVersionEntity; import jnpf.elnMapper.ElnTemplateMapper; import jnpf.util.JsonUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @Service public class TemplateAnnotationAuthorizer { private static final String DRAFT = "DRAFT"; private static final String ENABLED = "enabled"; private final TemplateAnnotationTicketService ticketService; private final TemplateLookup templateLookup; private final AnnotationAccess annotationAccess; private final TenantRoute tenantRoute; @Autowired public TemplateAnnotationAuthorizer(TemplateAnnotationTicketService ticketService, ElnTemplateMapper templateMapper, ElnTemplateAnnotationAccessService annotationAccessService) { this(ticketService, templateMapper::selectById, annotationAccessService::canAnnotate, new TenantRoute() { @Override public void switchTo(String tenantId) { TenantDataSourceUtil.switchTenant(tenantId); } @Override public void clear() { TenantDataSourceUtil.clearLocalTenantInfo(); } }); } TemplateAnnotationAuthorizer(TemplateAnnotationTicketService ticketService, TemplateLookup templateLookup, AnnotationAccess annotationAccess, TenantRoute tenantRoute) { this.ticketService = ticketService; this.templateLookup = templateLookup; this.annotationAccess = annotationAccess; this.tenantRoute = tenantRoute; } public TemplateAnnotationAuthorization authorize(String ticket, String templateId) { return authorize(ticket, templateId, false); } public TemplateAnnotationAuthorization authorize(String ticket) { return authorize(ticket, null, true); } private TemplateAnnotationAuthorization authorize(String ticket, String templateId, boolean useTicketTemplateId) { boolean authorized = false; try { TemplateAnnotationTicketService.AnnotationTicketContext context = ticketService.parse(ticket); String expectedTemplateId = useTicketTemplateId ? context.getTemplateId() : templateId; if (!Objects.equals(context.getTemplateId(), expectedTemplateId)) { throw unauthorized(); } if (!annotationAccess.canAnnotate(context.getTenantId(), context.getUserId(), context.getTemplateId(), context.getFileId())) { throw forbidden(); } switchTenant(context.getTenantId()); ElnTemplateVersionEntity template = findTemplate(expectedTemplateId); if (template == null) { throw conflict(); } if (!Objects.equals(context.getTenantId(), template.getFTenantId()) || !Objects.equals(context.getTemplateId(), template.getId())) { throw unauthorized(); } String fileId = uniqueDocxFileId(template.getMubanFile()); if (!Objects.equals(context.getFileId(), fileId)) { throw unauthorized(); } if ((template.getFDeleteMark() != null && template.getFDeleteMark() != 0) || !DRAFT.equals(template.getBizStatus()) || !ENABLED.equals(template.getBizEnabled())) { throw conflict(); } TemplateAnnotationAuthorization authorization = new TemplateAnnotationAuthorization( context.getTenantId(), context.getUserId(), template.getId(), fileId); authorized = true; return authorization; } finally { if (!authorized) { tenantRoute.clear(); } } } private void switchTenant(String tenantId) { try { tenantRoute.switchTo(tenantId); } catch (RuntimeException e) { throw unauthorized(); } } private ElnTemplateVersionEntity findTemplate(String templateId) { try { return templateLookup.findById(templateId); } catch (RuntimeException e) { throw conflict(); } } private String uniqueDocxFileId(String attachments) { try { List files = JsonUtil.getJsonToList(attachments, ElnDocumentFileVo.class); if (files == null) { throw conflict(); } List docxFileIds = files.stream() .filter(Objects::nonNull) .filter(file -> "docx".equalsIgnoreCase(file.getFileExtension())) .map(ElnDocumentFileVo::getFileId) .filter(StringUtils::hasText) .collect(Collectors.toList()); if (docxFileIds.size() != 1) { throw conflict(); } return docxFileIds.get(0); } catch (AnnotationAuthorizationException e) { throw e; } catch (RuntimeException e) { throw conflict(); } } private AnnotationAuthorizationException unauthorized() { return new AnnotationAuthorizationException(401, "标注 Ticket 无效"); } private AnnotationAuthorizationException forbidden() { return new AnnotationAuthorizationException(403, "当前请求无模板标注权限"); } private AnnotationAuthorizationException conflict() { return new AnnotationAuthorizationException(409, "模板当前不可标注"); } interface TemplateLookup { ElnTemplateVersionEntity findById(String templateId); } interface AnnotationAccess { boolean canAnnotate(String tenantId, String userId, String templateId, String fileId); } interface TenantRoute { void switchTo(String tenantId); void clear(); } public static class AnnotationAuthorizationException extends RuntimeException { private static final long serialVersionUID = 1L; private final int status; private AnnotationAuthorizationException(int status, String message) { super(message); this.status = status; } public int getStatus() { return status; } } }