Merge remote-tracking branch 'origin/feature/REQ-3540' into feature/REQ-3540
# Conflicts: # doc/doc-server/src/main/java/cn/axzo/nanopart/doc/wps/wpsedit/WpsEditManager.java
This commit is contained in:
commit
ada74334f7
@ -11,4 +11,9 @@ import lombok.Setter;
|
||||
@Getter
|
||||
public class DirectoryAttributes {
|
||||
|
||||
/**
|
||||
* mock字段, 暂时避免序列化错误
|
||||
*/
|
||||
private boolean placeholder;
|
||||
|
||||
}
|
||||
|
||||
@ -19,26 +19,6 @@ public interface IndexNodeScope {
|
||||
return TREE_ROOT_NODE_CODE;
|
||||
}
|
||||
|
||||
default boolean isChildrenNameDuplicatable() {
|
||||
switch (context()) {
|
||||
case FILE_TEMPLATE:
|
||||
case TEMPLATE_DATABASE:
|
||||
return false;
|
||||
default:
|
||||
return scope().getChildNameDuplicatable();
|
||||
}
|
||||
}
|
||||
|
||||
default boolean isLimitChildrenCount() {
|
||||
switch (context()) {
|
||||
case FILE_TEMPLATE:
|
||||
case TEMPLATE_DATABASE:
|
||||
return true;
|
||||
default:
|
||||
return scope().getLimitChildrenCount();
|
||||
}
|
||||
}
|
||||
|
||||
String TREE_ROOT_NODE_CODE = "";
|
||||
|
||||
Long TREE_ROOT_NODE_ID = 0L;
|
||||
|
||||
@ -5,7 +5,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.FileFormat;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -21,7 +20,6 @@ public class DocProps {
|
||||
|
||||
private String createFileOssFileKeyWord = "ent-workspace-empty-docx";
|
||||
private String createFileFileKeyExcel = "ent-workspace-empty-xlsx";
|
||||
private String createFileFileKeyPpt = "ent-workspace-empty-pptx";
|
||||
private int indexNodeMaxChildrenSize = 200;
|
||||
private int indexNodeMaxDepth = 10;
|
||||
private int indexNodeMaxCopyFileSize = 1000;
|
||||
@ -35,14 +33,4 @@ public class DocProps {
|
||||
private String defaultIconWord = "https://axzo-obs-public.obs.cn-north-4.myhuaweicloud.com:443/doc/doc/word.png";
|
||||
private String defaultIconPdf = "https://axzo-obs-public.obs.cn-north-4.myhuaweicloud.com:443/doc/doc/pdf.png";
|
||||
|
||||
public String createFileOssFileKey(FileFormat format) {
|
||||
if (format == FileFormat.WORD)
|
||||
return createFileOssFileKeyWord;
|
||||
if (format == FileFormat.EXCEL)
|
||||
return createFileFileKeyExcel;
|
||||
if (format == FileFormat.PDF)
|
||||
return createFileFileKeyPpt;
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -239,4 +239,4 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeValue, Index
|
||||
// my parent scope
|
||||
return parentCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,7 +45,7 @@ import cn.axzo.nanopart.doc.entity.IndexNode;
|
||||
import cn.axzo.nanopart.doc.entity.TemplateDatabase;
|
||||
import cn.axzo.nanopart.doc.file.index.IndexManager;
|
||||
import cn.axzo.nanopart.doc.file.index.IndexQueryService;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.CopiedOssFiles;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.OssFilesCopy;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.SetScopeCopyFileVisitor;
|
||||
import cn.axzo.nanopart.doc.file.index.domain.IndexNodes;
|
||||
import cn.axzo.nanopart.doc.file.templatedb.TemplateDatabaseQueryService;
|
||||
@ -56,6 +56,8 @@ import cn.azxo.framework.common.model.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@ -118,19 +120,19 @@ public class FileDatabaseService {
|
||||
asyncUtils.getOrTimeout(future, "激活");
|
||||
}
|
||||
|
||||
private Future<?> asyncCopySubtree(FileDatabase db, IndexNode templateRoot, Runnable nullablePostProcessor) {
|
||||
private Future<?> asyncCopySubtree(FileDatabase db, IndexNode templateRoot, @Nullable Runnable postProcessor) {
|
||||
return indexManager.async(() -> {
|
||||
// don't inline in transaction
|
||||
CopiedOssFiles copiedOssFiles = indexManager.copySubtreeOssFiles(templateRoot);
|
||||
OssFilesCopy filesCopy = indexManager.copySubtreeOssFiles(templateRoot);
|
||||
transaction.executeWithoutResult(unused -> {
|
||||
FileDatabase reload = fileDatabaseDao.getForUpdateOrThrow(db.getCode());
|
||||
if (reload.isActivated())
|
||||
return;
|
||||
indexManager.copySubTree(templateRoot, null, new SetScopeCopyFileVisitor(copiedOssFiles, db));
|
||||
indexManager.copySubtree(templateRoot, null, new SetScopeCopyFileVisitor(filesCopy, db));
|
||||
fileDatabaseDao.updateState(db.getCode(), FileDatabaseState.ACTIVATED);
|
||||
fileDatabaseDao.setPurchaseTime(db.getCode(), new Date());
|
||||
if (nullablePostProcessor != null)
|
||||
nullablePostProcessor.run();
|
||||
if (postProcessor != null)
|
||||
postProcessor.run();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -25,9 +25,9 @@ import cn.axzo.nanopart.doc.dao.DocLogDao;
|
||||
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
|
||||
import cn.axzo.nanopart.doc.entity.IndexNode;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.ConnectNodeVisitor;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.CopiedOssFiles;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.CopyFileVisitor;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.CopyNodeVisitor;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.OssFilesCopy;
|
||||
import cn.axzo.nanopart.doc.file.index.domain.NameUsedException;
|
||||
import cn.axzo.nanopart.doc.file.mq.FileBroadcaster;
|
||||
import cn.axzo.nanopart.doc.integration.OssClient;
|
||||
@ -70,7 +70,9 @@ public class IndexManager {
|
||||
// check without lock
|
||||
ensureChildNameNotUsed(create, IndexNodeType.FILE, false);
|
||||
String fullFileName = String.format("%s.%s", create.name(), format.createFileExtension());
|
||||
String ossFileKey = ossClient.copy(docProps.createFileOssFileKey(format), fullFileName);
|
||||
String emptyOssFileKey = format == FileFormat.WORD ? docProps.getCreateFileOssFileKeyWord()
|
||||
: docProps.getCreateFileFileKeyExcel();
|
||||
String ossFileKey = ossClient.copy(emptyOssFileKey, fullFileName);
|
||||
return OssFile.create(format, format.createFileExtension(), 0, ossFileKey);
|
||||
}
|
||||
|
||||
@ -123,7 +125,7 @@ public class IndexManager {
|
||||
}
|
||||
|
||||
private void ensureChildNameNotUsed(NodeCreate create, IndexNodeType nodeType, boolean withLock) {
|
||||
if (create.nodeScope().isChildrenNameDuplicatable())
|
||||
if (indexSupport.isChildrenNameDuplicatable(create))
|
||||
return;
|
||||
if (withLock)
|
||||
indexSupport.lockParentAndReleaseOnCommit(create);
|
||||
@ -136,7 +138,7 @@ public class IndexManager {
|
||||
if (indexNode.getName().equals(newName))
|
||||
return;
|
||||
docLogDao.log("indexNode:rename", code, "newName", newName);
|
||||
if (!indexNode.isChildrenNameDuplicatable()) {
|
||||
if (!indexSupport.isChildrenNameDuplicatable(indexNode)) {
|
||||
indexSupport.lockParentAndReleaseOnCommit(indexNode);
|
||||
indexSupport.ensureChildNameNotUsed(indexNode, indexNode.getNodeType(), newName);
|
||||
}
|
||||
@ -157,10 +159,10 @@ public class IndexManager {
|
||||
return subtree;
|
||||
}
|
||||
|
||||
public CopiedOssFiles copySubtreeOssFiles(IndexNode srcNode) {
|
||||
public OssFilesCopy copySubtreeOssFiles(IndexNode srcNode) {
|
||||
BizAssertions.assertFalse(TransactionSynchronizationManager.isActualTransactionActive(), "不能在事务中使用");
|
||||
List<String> ossFileKeys = indexNodeDao.collectValidSubtreeFileOssKeys(srcNode);
|
||||
return new CopiedOssFiles(ossClient.copy(ossFileKeys));
|
||||
return new OssFilesCopy(ossClient.copy(ossFileKeys));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,7 +179,7 @@ public class IndexManager {
|
||||
return transaction.execute(unused -> {
|
||||
docLogDao.log("indexNode:asyncCopy", srcCode, "srcCode", srcCode, "destParentCode", destParentCode);
|
||||
//noinspection SpringTransactionalMethodCallsInspection
|
||||
return copySubTree(srcNode, destParentNode, copyNodeVisitor);
|
||||
return copySubtree(srcNode, destParentNode, copyNodeVisitor);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -209,7 +211,7 @@ public class IndexManager {
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public IndexNode copySubTree(IndexNode src, @Nullable IndexNode destParent, CopyNodeVisitor copyNodeVisitor) {
|
||||
public IndexNode copySubtree(IndexNode src, @Nullable IndexNode destParent, CopyNodeVisitor copyNodeVisitor) {
|
||||
List<IndexNode> subtreeNodes = indexSupport.collectValidSubtreeAsValueRoot(src);
|
||||
RootNode<IndexNode> srcRoot = TreeUtils.transform(subtreeNodes, IndexNode.class, true);
|
||||
srcRoot.walkDown(copyNodeVisitor);
|
||||
@ -226,7 +228,7 @@ public class IndexManager {
|
||||
indexNodeDao.connectNodes(TreeUtils.collectValues(connectRoot));
|
||||
IndexNode rootNode = connectRoot.getChildren().get(0).tryGetValue();
|
||||
// resolve the name issue
|
||||
if (!rootNode.isChildrenNameDuplicatable())
|
||||
if (!indexSupport.isChildrenNameDuplicatable(rootNode))
|
||||
indexSupport.incrNameIfDuplicate(rootNode);
|
||||
// get the coped root with full props
|
||||
return indexNodeDao.findOrNull(rootNode.getCode());
|
||||
|
||||
@ -96,7 +96,7 @@ public class IndexSupport {
|
||||
BizAssertions.assertTrue(
|
||||
indexNodeDao.validChildrenCount(parent.getCode()) < docProps.getIndexNodeMaxChildrenSize(),
|
||||
"创建失败, 子节点数量不能超过 {}", docProps.getIndexNodeMaxChildrenSize());
|
||||
if (!parent.isRoot() && parent.isLimitChildrenCount())
|
||||
if (!parent.isRoot() && isLimitChildrenCount(child))
|
||||
BizAssertions.assertTrue(parent.path().depth() < docProps.getIndexNodeMaxDepth(), //
|
||||
"节点深度超过限制{}, 无法再创建新节点", docProps.getIndexNodeMaxDepth());
|
||||
}
|
||||
@ -164,6 +164,28 @@ public class IndexSupport {
|
||||
.list();
|
||||
}
|
||||
|
||||
boolean isChildrenNameDuplicatable(IndexNodeParentScope parentScope) {
|
||||
IndexNodeScope nodeScope = parentScope.nodeScope();
|
||||
switch (nodeScope.context()) {
|
||||
case FILE_TEMPLATE:
|
||||
case TEMPLATE_DATABASE:
|
||||
return false;
|
||||
default:
|
||||
return nodeScope.scope().getChildNameDuplicatable();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isLimitChildrenCount(IndexNodeParentScope parentScope) {
|
||||
IndexNodeScope nodeScope = parentScope.nodeScope();
|
||||
switch (nodeScope.context()) {
|
||||
case FILE_TEMPLATE:
|
||||
case TEMPLATE_DATABASE:
|
||||
return true;
|
||||
default:
|
||||
return nodeScope.scope().getLimitChildrenCount();
|
||||
}
|
||||
}
|
||||
|
||||
<T> Future<T> submit(Callable<T> callable) {
|
||||
return executor.submit(() -> {
|
||||
try {
|
||||
|
||||
@ -46,12 +46,12 @@ public class ConnectNodeVisitor extends ValueNodeRecursiveVisitor<IndexNode> {
|
||||
continue;
|
||||
}
|
||||
// IMPORTANT: append REVERSED parent path but not parent id, because:
|
||||
// 1. We're walking the tree up
|
||||
// 1. We're walking up the tree
|
||||
// 2. The dest parent node may not be the tree root
|
||||
if (destParentNode != null)
|
||||
path = path.append(destParentNode.path().reverse());
|
||||
}
|
||||
// reserve the path because we're walking up the tree while building the path
|
||||
// reserve the path because we're walking up the tree while building the path
|
||||
return path.reverse();
|
||||
}
|
||||
|
||||
|
||||
@ -13,14 +13,14 @@ import lombok.RequiredArgsConstructor;
|
||||
@RequiredArgsConstructor
|
||||
public class CopyFileVisitor extends CopyNodeVisitor {
|
||||
|
||||
private final CopiedOssFiles copiedOssFiles;
|
||||
private final OssFilesCopy ossFilesCopy;
|
||||
|
||||
@Override
|
||||
public WalkingDecision visit(ValueNode<IndexNode> node) {
|
||||
IndexNode copy = node.getValue();
|
||||
if (copy.isFile()) {
|
||||
FileAttributes fileAttributes = copy.getOrCreateFileAttributes();
|
||||
String newOssFileKey = copiedOssFiles.getCopyOssFileKey(fileAttributes.getOssFileKey());
|
||||
String newOssFileKey = ossFilesCopy.getCopyOssFileKey(fileAttributes.getOssFileKey());
|
||||
fileAttributes.setOssFileKey(newOssFileKey);
|
||||
}
|
||||
return super.visit(node);
|
||||
|
||||
@ -9,7 +9,7 @@ import lombok.RequiredArgsConstructor;
|
||||
* @author yanglin
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class CopiedOssFiles {
|
||||
public class OssFilesCopy {
|
||||
|
||||
private final Map<String, String> old2newOssFileKey;
|
||||
|
||||
@ -13,8 +13,8 @@ public class SetScopeCopyFileVisitor extends CopyFileVisitor {
|
||||
|
||||
private final IndexNodeScope nodeScope;
|
||||
|
||||
public SetScopeCopyFileVisitor(CopiedOssFiles copiedOssFiles, IndexNodeScope nodeScope) {
|
||||
super(copiedOssFiles);
|
||||
public SetScopeCopyFileVisitor(OssFilesCopy ossFilesCopy, IndexNodeScope nodeScope) {
|
||||
super(ossFilesCopy);
|
||||
this.nodeScope = nodeScope;
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import com.alibaba.excel.util.StringUtils;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.domain.FileAttributes;
|
||||
import cn.axzo.nanopart.doc.api.wps.request.WpsEditUploadAddressRequest;
|
||||
import cn.axzo.nanopart.doc.api.wps.request.WpsEditUploadCompleteRequest;
|
||||
import cn.axzo.nanopart.doc.api.wps.request.WpsEditUploadPrepareRequest;
|
||||
@ -20,16 +21,15 @@ import cn.axzo.nanopart.doc.api.wps.response.WpsEditUploadCompleteResponse;
|
||||
import cn.axzo.nanopart.doc.api.wps.response.WpsEditUploadPrepareResponse;
|
||||
import cn.axzo.nanopart.doc.config.DocProps;
|
||||
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
|
||||
import cn.axzo.nanopart.doc.dao.TemplateDatabaseDao;
|
||||
import cn.axzo.nanopart.doc.entity.IndexNode;
|
||||
import cn.axzo.nanopart.doc.file.index.IndexManager;
|
||||
import cn.axzo.nanopart.doc.file.mq.FileBroadcaster;
|
||||
import cn.axzo.nanopart.doc.integration.DocOssGateway;
|
||||
import cn.axzo.nanopart.doc.utils.BizTransactional;
|
||||
import cn.axzo.oss.http.model.ApiSignUrlUploadRequest;
|
||||
import cn.axzo.oss.http.model.ApiSignUrlUploadResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 文档编辑
|
||||
@ -45,7 +45,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public class WpsEditManager {
|
||||
|
||||
private final IndexManager indexManager;
|
||||
private final TemplateDatabaseDao templateDatabaseDao;
|
||||
private final IndexNodeDao indexNodeDao;
|
||||
private final DocOssGateway docOssGateway;
|
||||
private final FileBroadcaster fileBroadcaster;
|
||||
@ -110,7 +109,7 @@ public class WpsEditManager {
|
||||
* 3 上传完成后,回调通知上传结果
|
||||
* 说明:WebOffice 在将新版本文件上传到指定地址后,将会回调通知接入方
|
||||
*/
|
||||
@Transactional
|
||||
@BizTransactional
|
||||
public WpsEditUploadCompleteResponse uploadComplete(WpsEditUploadCompleteRequest request) {
|
||||
log.info("wpsEditManager-uploadComplete-params,request:{}", request);
|
||||
//加锁
|
||||
@ -140,9 +139,7 @@ public class WpsEditManager {
|
||||
}
|
||||
fileAttributes.setVersion(fileAttributes.fetchVersion() + 1);
|
||||
indexNodeDao.updateAttributes(node);
|
||||
indexNodeDao.updateFileSize(request.getDocCode(), request.getSize());
|
||||
|
||||
fileBroadcaster.fireFileSizeChanged(request.getDocCode());
|
||||
indexManager.updateFileSize(node, request.getSize());
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user