Merge remote-tracking branch 'origin/feature/REQ-3540' into feature/REQ-3540
This commit is contained in:
commit
4c0bd16765
@ -14,6 +14,6 @@ public class DirectoryAttributes {
|
||||
/**
|
||||
* 是否为资料库文件夹
|
||||
*/
|
||||
private boolean isTemplateDatabaseDir;
|
||||
private Boolean isTemplateDatabaseDir;
|
||||
|
||||
}
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
package cn.axzo.nanopart.doc.api.domain;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -18,7 +18,7 @@ public class IndexNodeAttributes {
|
||||
/**
|
||||
* 是否为自定义的图标
|
||||
*/
|
||||
private boolean customIcon;
|
||||
private Boolean customIcon;
|
||||
|
||||
/**
|
||||
* 数据库属性
|
||||
|
||||
@ -4,6 +4,7 @@ package cn.axzo.nanopart.doc.api.domain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.IndexNodeContext;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
@ -56,6 +57,11 @@ public class IndexNodeInfo implements NodeValue, ValueContainer<IndexNodeInfo> {
|
||||
*/
|
||||
private IndexNodeType nodeType;
|
||||
|
||||
/**
|
||||
* 上下文. NONE: 无上下文, SYSTEM: 系统内置, FILE_TEMPLATE: 文件模版, TEMPLATE_DATABASE: 模版数据库, FILE_DATABASE: 数据库
|
||||
*/
|
||||
private IndexNodeContext context;
|
||||
|
||||
/**
|
||||
* 作用范围. NONE: 无, ENT_DATABASE: 企业数据库, PROJECT_DATABASE: 项目数据库, PERSONAL_DATABASE: 个人数据库
|
||||
*/
|
||||
|
||||
@ -14,4 +14,11 @@ public interface IndexNodeParentScope {
|
||||
return "";
|
||||
}
|
||||
|
||||
IndexNodeParentScope TEMPLATE_DATABASE_ROOT = new IndexNodeParentScope() {
|
||||
@Override
|
||||
public IndexNodeScope nodeScope() {
|
||||
return IndexNodeScope.TEMPLATE_DATABASE;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -11,5 +11,7 @@ public enum FileDatabaseState {
|
||||
// 已开通
|
||||
ACTIVATED,
|
||||
// 已到期
|
||||
EXPIRED
|
||||
EXPIRED,
|
||||
// 容量已满
|
||||
CAPACITY_EXHAUSTED
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package cn.axzo.nanopart.doc.api.filedb;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseRenewRequest;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -40,6 +41,12 @@ public interface FileDatabaseApi {
|
||||
@PostMapping("/api/fileDatabase/expandCapacity")
|
||||
CommonResponse<Void> expandCapacity(@RequestBody @Valid FileDatabaseExpandCapacityRequest request);
|
||||
|
||||
/**
|
||||
* 续费
|
||||
*/
|
||||
@PostMapping("/api/fileDatabase/renew")
|
||||
CommonResponse<Void> renew(@RequestBody @Valid FileDatabaseRenewRequest request);
|
||||
|
||||
/**
|
||||
* 移除
|
||||
*/
|
||||
|
||||
@ -4,6 +4,7 @@ package cn.axzo.nanopart.doc.api.filedb.request;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.util.BizAssertions;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -31,4 +32,8 @@ public class FileDatabaseActiveRequest {
|
||||
*/
|
||||
@NotNull(message = "expiredDateMs不能为空")
|
||||
private Long expiredDateMs;
|
||||
|
||||
public void checkExpiredDate() {
|
||||
BizAssertions.assertTrue(expiredDateMs > System.currentTimeMillis(), "expiredDateMs不能小于当前时间");
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.api.filedb.request;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public class FileDatabaseRenewRequest extends FileDatabaseActiveRequest {
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.api.filetemplate.request;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.util.DefaultIcons;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -13,11 +13,6 @@ import lombok.Setter;
|
||||
@Getter
|
||||
public class FileTemplateCreateDirRequest extends NodeCreateFileTemplate {
|
||||
|
||||
@Override
|
||||
public String icon() {
|
||||
return DefaultIcons.DIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
|
||||
@ -6,7 +6,6 @@ import javax.validation.constraints.NotNull;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.FileFormat;
|
||||
import cn.axzo.nanopart.doc.api.util.DefaultIcons;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -23,11 +22,6 @@ public class FileTemplateCreateFileRequest extends NodeCreateFileTemplate {
|
||||
@NotNull(message = "文件格式不能为空")
|
||||
private FileFormat format;
|
||||
|
||||
@Override
|
||||
public String icon() {
|
||||
return DefaultIcons.defaultFileIcon(format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
|
||||
@ -5,6 +5,8 @@ import java.util.List;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.templatedb.domain.DatabaseInfo;
|
||||
import cn.axzo.nanopart.doc.api.templatedb.reqeust.TemplateDatabaseSearchRequest;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -97,6 +99,12 @@ public interface TemplateDatabaseApi {
|
||||
@PostMapping("/api/templateDatabase/search")
|
||||
CommonResponse<Page<IndexNodeInfo>> search(@RequestBody @Valid IndexNodeSearchRequest request);
|
||||
|
||||
/**
|
||||
* 搜索资料库
|
||||
*/
|
||||
@PostMapping("/api/templateDatabase/searchDatabase")
|
||||
CommonResponse<Page<DatabaseInfo>> searchDatabase(@RequestBody @Valid TemplateDatabaseSearchRequest request);
|
||||
|
||||
/**
|
||||
* 项企资料库: 获取资料库或文件夹信息
|
||||
*/
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.api.templatedb.domain;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.domain.DatabaseFeeConfig;
|
||||
import cn.axzo.nanopart.doc.api.enums.DatabaseType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class DatabaseInfo {
|
||||
|
||||
/**
|
||||
* 资料库名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 资料库编译
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 类型. CREATED_BY_SYSTEM: 平台资料库, CREATED_BY_USER_FOR_ENT: 专属资料库
|
||||
*/
|
||||
private DatabaseType databaseType;
|
||||
|
||||
/**
|
||||
* 费用配置
|
||||
*/
|
||||
private DatabaseFeeConfig feeConfig;
|
||||
|
||||
}
|
||||
@ -7,7 +7,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.CooperationType;
|
||||
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
|
||||
import cn.axzo.nanopart.doc.api.util.DefaultIcons;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -31,7 +30,7 @@ public class TemplateDatabaseCreateDatabaseRequest extends TemplateDatabaseCreat
|
||||
private CooperationType coopType;
|
||||
|
||||
public String icon() {
|
||||
return StringUtils.isBlank(getIcon()) ? DefaultIcons.DATABASE : getIcon();
|
||||
return StringUtils.isBlank(getIcon()) ? "" : getIcon();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ import javax.validation.constraints.NotBlank;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeAttributes;
|
||||
import cn.axzo.nanopart.doc.api.util.DefaultIcons;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -39,7 +38,7 @@ public class TemplateDatabaseCreateDirRequest extends NodeCreateTemplateDatabase
|
||||
private boolean customIcon;
|
||||
|
||||
public String icon() {
|
||||
return StringUtils.isBlank(icon) ? DefaultIcons.DIR : icon;
|
||||
return StringUtils.isBlank(icon) ? "" : icon;
|
||||
}
|
||||
|
||||
public String bizCode() {
|
||||
@ -53,7 +52,7 @@ public class TemplateDatabaseCreateDirRequest extends NodeCreateTemplateDatabase
|
||||
@Override
|
||||
public IndexNodeAttributes attributes() {
|
||||
IndexNodeAttributes attributes = IndexNodeAttributes.create();
|
||||
attributes.getDirectoryAttributes().setTemplateDatabaseDir(true);
|
||||
attributes.getOrCreateDirectoryAttributes().setIsTemplateDatabaseDir(true);
|
||||
attributes.setCustomIcon(customIcon);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ package cn.axzo.nanopart.doc.api.templatedb.reqeust;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.FileFormat;
|
||||
import cn.axzo.nanopart.doc.api.util.DefaultIcons;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -21,9 +20,4 @@ public class TemplateDatabaseCreateFileRequest extends NodeCreateTemplateDatabas
|
||||
@NotNull(message = "文件格式不能为空")
|
||||
private FileFormat format;
|
||||
|
||||
@Override
|
||||
public String icon() {
|
||||
return DefaultIcons.defaultFileIcon(format);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.api.templatedb.reqeust;
|
||||
|
||||
import cn.axzo.basics.common.page.PageRequest;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class TemplateDatabaseSearchRequest extends PageRequest {
|
||||
|
||||
/**
|
||||
* 搜索的名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
}
|
||||
@ -128,7 +128,7 @@ public class BizAssertions {
|
||||
if (response == null || response.getCode() != HttpStatus.HTTP_OK) {
|
||||
ServiceException e = new ServiceException(
|
||||
messageOrTemplateMessage(response == null ? null : response.getMsg(), message, args));
|
||||
log.warn("remote call response with error", e);
|
||||
log.warn("remote call response with error, response={}", JSON.toJSONString(response), e);
|
||||
throw e;
|
||||
}
|
||||
return response.getData();
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.api.util;
|
||||
|
||||
import static cn.axzo.nanopart.doc.api.util.BizAssertions.fail;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.FileFormat;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public class DefaultIcons {
|
||||
|
||||
// TODO(yl): WHAT
|
||||
public static final String DIR = "default_dir_icon";
|
||||
// TODO(yl): WHAT
|
||||
public static final String DATABASE = "default_database_icon";
|
||||
// TODO(yl): WHAT
|
||||
public static final String FILE_EXCEL = "default_excel_icon";
|
||||
// TODO(yl): WHAT
|
||||
public static final String FILE_WORD = "default_word_icon";
|
||||
// TODO(yl): WHAT
|
||||
public static final String FILE_PDF = "default_pdf_icon";
|
||||
|
||||
public static String defaultFileIcon(FileFormat fileFormat) {
|
||||
if (fileFormat == FileFormat.EXCEL)
|
||||
return DefaultIcons.FILE_EXCEL;
|
||||
if (fileFormat == FileFormat.WORD)
|
||||
return DefaultIcons.FILE_WORD;
|
||||
if (fileFormat == FileFormat.PDF)
|
||||
return DefaultIcons.FILE_PDF;
|
||||
throw fail("不支持的文件格式: {}", fileFormat);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,13 +1,11 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.config;
|
||||
|
||||
import static cn.axzo.nanopart.doc.api.util.BizAssertions.fail;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.FileFormat;
|
||||
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;
|
||||
|
||||
@ -28,15 +26,21 @@ public class DocProps {
|
||||
private int indexNodeMaxDepth = 10;
|
||||
private int indexNodeMaxCopyFileSize = 1000;
|
||||
private String ossAppCode = "ent-workspace-doc";
|
||||
private int asyncTimeoutSeconds = 5;
|
||||
private String defaultIconDir = "default_dir_icon";
|
||||
private String defaultIconExcel = "default_excel_icon";
|
||||
private String defaultIconWord = "default_word_icon";
|
||||
private String defaultIconPdf = "default_pdf_icon";
|
||||
private int asyncTimeoutSeconds = 10;
|
||||
private String defaultIconDatabase = "https://axzo-obs-public.obs.cn-north-4.myhuaweicloud.com:443/doc/doc/image-30.png";
|
||||
private String defaultIconDir = "https://axzo-obs-public.obs.cn-north-4.myhuaweicloud.com:443/doc/doc/image-30.png";
|
||||
private String defaultIconExcel = "https://axzo-obs-public.obs.cn-north-4.myhuaweicloud.com:443/doc/doc/excel.png";
|
||||
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) {
|
||||
return format == FileFormat.WORD //
|
||||
? getCreateFileWordOssFileKey() //
|
||||
: getCreateFileExcelFileKey();
|
||||
if (format == FileFormat.WORD)
|
||||
return createFileWordOssFileKey;
|
||||
if (format == FileFormat.EXCEL)
|
||||
return createFileExcelFileKey;
|
||||
if (format == FileFormat.PDF)
|
||||
return createFilePptFileKey;
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.dao;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.FileDatabaseState;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.enums.DatabaseScope;
|
||||
import cn.axzo.nanopart.doc.api.enums.FileDatabaseState;
|
||||
import cn.axzo.nanopart.doc.api.util.BizAssertions;
|
||||
import cn.axzo.nanopart.doc.entity.FileDatabase;
|
||||
import cn.axzo.nanopart.doc.mapper.FileDatabaseMapper;
|
||||
@ -35,11 +35,22 @@ public class FileDatabaseDao extends ServiceImpl<FileDatabaseMapper, FileDatabas
|
||||
}
|
||||
|
||||
public FileDatabase getOrThrow(String code) {
|
||||
FileDatabase db = lambdaQuery() //
|
||||
FileDatabase db = findOrNull(code);
|
||||
BizAssertions.assertNotNull(db, "找不到资料库: {}", code);
|
||||
return db;
|
||||
}
|
||||
|
||||
public FileDatabase findOrNull(String code) {
|
||||
return lambdaQuery() //
|
||||
.eq(FileDatabase::getCode, code) //
|
||||
.one();
|
||||
BizAssertions.assertNotNull(code, "找不到资料库: {}", code);
|
||||
return db;
|
||||
}
|
||||
|
||||
public FileDatabase findForUpdateOrNull(String code) {
|
||||
return lambdaQuery() //
|
||||
.eq(FileDatabase::getCode, code) //
|
||||
.last("FOR UPDATE") //
|
||||
.one();
|
||||
}
|
||||
|
||||
public void deleteByCode(String code) {
|
||||
@ -48,10 +59,18 @@ public class FileDatabaseDao extends ServiceImpl<FileDatabaseMapper, FileDatabas
|
||||
.remove();
|
||||
}
|
||||
|
||||
public void setActivated(String code) {
|
||||
public void updateUsedCapacity(String code, int usedFileSize) {
|
||||
lambdaUpdate() //
|
||||
.eq(FileDatabase::getCode, code) //
|
||||
.set(FileDatabase::getState, FileDatabaseState.ACTIVATED) //
|
||||
.set(FileDatabase::getUsedCapacity, usedFileSize) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public void updateState(String code, FileDatabaseState state) {
|
||||
lambdaUpdate() //
|
||||
.eq(FileDatabase::getCode, code) //
|
||||
.set(FileDatabase::getState, state) //
|
||||
.update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -68,12 +68,12 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
|
||||
.one();
|
||||
}
|
||||
|
||||
public List<IndexNode> findValidChildrenNameRightLike(IndexNodeParentScope parentNode, IndexNodeType nodeType,
|
||||
String name) {
|
||||
public List<IndexNode> findValidChildrenNameRightLike(IndexNodeParentScope parentNode, IndexNode node) {
|
||||
return parentOrScopeRootQuery(parentNode) //
|
||||
.likeRight(IndexNode::getName, name) //
|
||||
.eq(IndexNode::getNodeType, nodeType) //
|
||||
.likeRight(IndexNode::getName, node.getName()) //
|
||||
.eq(IndexNode::getNodeType, node.getNodeType()) //
|
||||
.eq(IndexNode::getState, IndexNodeState.VALID) //
|
||||
.select(IndexNode::getId, IndexNode::getName, IndexNode::getParentId, IndexNode::getCode) //
|
||||
.list();
|
||||
}
|
||||
|
||||
@ -136,11 +136,12 @@ public class IndexNodeDao extends ServiceImpl<IndexNodeMapper, IndexNode> {
|
||||
public void updateFileSize(String code, long size) {
|
||||
lambdaUpdate() //
|
||||
.eq(IndexNode::getCode, code) //
|
||||
.eq(IndexNode::getNodeType, IndexNodeType.FILE) //
|
||||
.set(IndexNode::getSize, size) //
|
||||
.update();
|
||||
}
|
||||
|
||||
private LambdaQueryChainWrapper<IndexNode> parentOrScopeRootQuery(IndexNodeParentScope parentScope) {
|
||||
public LambdaQueryChainWrapper<IndexNode> parentOrScopeRootQuery(IndexNodeParentScope parentScope) {
|
||||
if (StringUtils.isBlank(parentScope.parentCode()))
|
||||
return scopeQuery(parentScope.nodeScope()).eq(IndexNode::getParentCode, "");
|
||||
return lambdaQuery().eq(IndexNode::getParentCode, parentScope.parentCode());
|
||||
|
||||
@ -3,6 +3,7 @@ package cn.axzo.nanopart.doc.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import cn.axzo.nanopart.doc.entity.domain.IndexNodeCodeProvider;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
@ -20,7 +21,7 @@ import lombok.Setter;
|
||||
@Setter
|
||||
@Getter
|
||||
@TableName(value = "doc_file_database", autoResultMap = true)
|
||||
public class FileDatabase extends BaseEntity<FileDatabase> implements IndexNodeScope {
|
||||
public class FileDatabase extends BaseEntity<FileDatabase> implements IndexNodeScope, IndexNodeCodeProvider {
|
||||
|
||||
/**
|
||||
* 编码, 和index_node中对应的节点的scope一致
|
||||
@ -76,6 +77,10 @@ public class FileDatabase extends BaseEntity<FileDatabase> implements IndexNodeS
|
||||
return state == FileDatabaseState.ACTIVATED;
|
||||
}
|
||||
|
||||
public boolean isCapacityExhausted() {
|
||||
return usedCapacity >= allowedCapacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String scopeCode() {
|
||||
// I'm a scope of the index node
|
||||
@ -97,4 +102,9 @@ public class FileDatabase extends BaseEntity<FileDatabase> implements IndexNodeS
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String indexNodeCode() {
|
||||
return templateDatabaseCode;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package cn.axzo.nanopart.doc.entity;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.MappedJdbcTypes;
|
||||
import org.apache.ibatis.type.MappedTypes;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@MappedTypes({Object.class})
|
||||
@MappedJdbcTypes(JdbcType.VARCHAR)
|
||||
@RequiredArgsConstructor
|
||||
public class IgnorePropsJsonTypeHandler extends AbstractJsonTypeHandler<Object> {
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
@Override
|
||||
protected Object parse(String json) {
|
||||
if (StringUtils.isBlank(json))
|
||||
return null;
|
||||
return JSON.parseObject(json, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toJson(Object obj) {
|
||||
return JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,7 +7,6 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import cn.axzo.maokai.api.vo.response.tree.NodeValue;
|
||||
@ -115,7 +114,7 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeValue, Index
|
||||
/**
|
||||
* 属性. 不同node_type的属性可能不一样
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
@TableField(typeHandler = IgnorePropsJsonTypeHandler.class)
|
||||
private IndexNodeAttributes attributes;
|
||||
|
||||
// !! helper field
|
||||
@ -131,6 +130,12 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeValue, Index
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public FileAttributes getOrCreateFileAttributes() {
|
||||
return getOrCreateAttributes().getOrCreateFileAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Attributes中fileAttribute
|
||||
*/
|
||||
@ -152,6 +157,12 @@ public class IndexNode extends BaseEntity<IndexNode> implements NodeValue, Index
|
||||
return Objects.equals(n1.getId(), n2.getId());
|
||||
}
|
||||
|
||||
public static void setScope(IndexNode indexNode, IndexNodeScope scope) {
|
||||
indexNode.setContext(scope.context());
|
||||
indexNode.setScope(scope.scope());
|
||||
indexNode.setScopeCode(scope.scopeCode());
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public boolean isFile() {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.entity;
|
||||
|
||||
import cn.axzo.nanopart.doc.entity.domain.IndexNodeCodeProvider;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
@ -23,7 +24,7 @@ import lombok.Setter;
|
||||
@Setter
|
||||
@Getter
|
||||
@TableName(value = "doc_template_database", autoResultMap = true)
|
||||
public class TemplateDatabase extends BaseEntity<TemplateDatabase> {
|
||||
public class TemplateDatabase extends BaseEntity<TemplateDatabase> implements IndexNodeCodeProvider {
|
||||
|
||||
/**
|
||||
* 编码, 和index_node中对应节点的编码保持一致
|
||||
@ -73,6 +74,11 @@ public class TemplateDatabase extends BaseEntity<TemplateDatabase> {
|
||||
return accessConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String indexNodeCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.entity.domain;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public interface IndexNodeCodeProvider {
|
||||
|
||||
String indexNodeCode();
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@ import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseActiveRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseAddWorkspaceRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseExpandCapacityRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseRemoveRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseRenewRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseSearchRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.response.FileDatabaseInfoResponse;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
@ -27,30 +28,42 @@ public class FileDatabaseApiController implements FileDatabaseApi {
|
||||
|
||||
@Override
|
||||
public CommonResponse<Void> addWorkspace(FileDatabaseAddWorkspaceRequest request) {
|
||||
log.info("add workspace: {}", request);
|
||||
fileDatabaseService.addWorkspace(request);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Void> active(FileDatabaseActiveRequest request) {
|
||||
log.info("active workspace: {}", request);
|
||||
fileDatabaseService.active(request);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Void> expandCapacity(FileDatabaseExpandCapacityRequest request) {
|
||||
log.info("expand capacity: {}", request);
|
||||
fileDatabaseService.expandCapacity(request);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Void> renew(FileDatabaseRenewRequest request) {
|
||||
log.info("renew workspace: {}", request);
|
||||
fileDatabaseService.renew(request);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Void> remove(FileDatabaseRemoveRequest request) {
|
||||
log.info("remove workspace: {}", request);
|
||||
fileDatabaseService.remove(request);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Page<FileDatabaseInfoResponse>> search(FileDatabaseSearchRequest request) {
|
||||
log.info("search workspace: {}", request);
|
||||
return CommonResponse.success(fileDatabaseService.search(request));
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
|
||||
|
||||
import cn.axzo.apollo.workspace.api.workspace.WorkspaceApi;
|
||||
import cn.axzo.apollo.workspace.api.workspace.req.GetSimpleWorkspaceReqV2;
|
||||
@ -30,18 +31,20 @@ import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseActiveRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseAddWorkspaceRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseExpandCapacityRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseRemoveRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseRenewRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.request.FileDatabaseSearchRequest;
|
||||
import cn.axzo.nanopart.doc.api.filedb.response.FileDatabaseInfoResponse;
|
||||
import cn.axzo.nanopart.doc.api.util.BizAssertions;
|
||||
import cn.axzo.nanopart.doc.api.util.UUIDUtil;
|
||||
import cn.axzo.nanopart.doc.dao.DocLogDao;
|
||||
import cn.axzo.nanopart.doc.dao.FileDatabaseDao;
|
||||
import cn.axzo.nanopart.doc.entity.FileDatabase;
|
||||
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.CopyFileVisitor;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.SetScopeProcessor;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.CopiedOssFiles;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.SetCopyCopyFileVisitor;
|
||||
import cn.axzo.nanopart.doc.file.index.domain.IndexNodes;
|
||||
import cn.axzo.nanopart.doc.file.templatedb.TemplateDatabaseManager;
|
||||
import cn.axzo.nanopart.doc.utils.AsyncUtils;
|
||||
@ -64,9 +67,11 @@ public class FileDatabaseService {
|
||||
private final IndexManager indexManager;
|
||||
private final TransactionTemplate transaction;
|
||||
private final AsyncUtils asyncUtils;
|
||||
private final DocLogDao docLogDao;
|
||||
|
||||
@BizTransactional
|
||||
public void addWorkspace(FileDatabaseAddWorkspaceRequest request) {
|
||||
docLogDao.logRequest("addWorkspace", request.getWorkspaceId(), request);
|
||||
String scopeUniqueCode = String.valueOf(request.getWorkspaceId());
|
||||
TemplateDatabase templateDatabase = templateDatabaseManager.getOrThrow(request.getTemplateDatabaseCode());
|
||||
FileDatabase savedDb = fileDatabaseDao.findForUpdateOrNull(templateDatabase.getScope(), scopeUniqueCode);
|
||||
@ -82,40 +87,75 @@ public class FileDatabaseService {
|
||||
db.setExpireDate(new Date(request.getExpiredDateMs()));
|
||||
db.setAllowedCapacity(request.getAllowedCapacity());
|
||||
db.setUsedCapacity(0);
|
||||
db.setCreateAt(new Date());
|
||||
db.setUpdateAt(new Date());
|
||||
fileDatabaseDao.save(db);
|
||||
}
|
||||
|
||||
public void active(FileDatabaseActiveRequest request) {
|
||||
request.checkExpiredDate();
|
||||
docLogDao.logRequest("active", request.getCode(), request);
|
||||
FileDatabase db = fileDatabaseDao.getOrThrow(request.getCode());
|
||||
if (db.isActivated())
|
||||
return;
|
||||
IndexNode template = indexManager.getOrThrow(db.getTemplateDatabaseCode());
|
||||
Future<?> future = indexManager.async(() -> {
|
||||
// don't inline in transaction
|
||||
CopyFileVisitor copyFileVisitor = indexManager.createCopyFileVisitor(template, new SetScopeProcessor(db));
|
||||
CopiedOssFiles copiedOssFiles = indexManager.copySubtreeOssFiles(template);
|
||||
transaction.executeWithoutResult(unused -> {
|
||||
FileDatabase reload = fileDatabaseDao.getForUpdateOrThrow(request.getCode());
|
||||
if (reload.isActivated())
|
||||
return;
|
||||
indexManager.copySubTree(template, null, copyFileVisitor);
|
||||
fileDatabaseDao.setActivated(reload.getCode());
|
||||
indexManager.copySubTree(template, null, new SetCopyCopyFileVisitor(copiedOssFiles, db));
|
||||
fileDatabaseDao.updateState(db.getCode(), FileDatabaseState.ACTIVATED);
|
||||
});
|
||||
});
|
||||
asyncUtils.getOrTimeout(future, "激活等待超时, 激活任务在后台运行, 请稍后刷新查看");
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void expandCapacity(FileDatabaseExpandCapacityRequest request) {
|
||||
public void fileSizeChanged(String indexNodeCode) {
|
||||
IndexNode indexNode = indexManager.findOrNull(indexNodeCode);
|
||||
if (indexNode == null || !indexNode.isFile())
|
||||
return;
|
||||
FileDatabase db = fileDatabaseDao.findForUpdateOrNull(indexNode.scopeCode());
|
||||
if (db == null)
|
||||
return;
|
||||
fileDatabaseDao.updateUsedCapacity(db.getCode(), indexQueryService.getUsedFileSize(db));
|
||||
db = fileDatabaseDao.findOrNull(db.getCode());
|
||||
if (db.isActivated() && db.isCapacityExhausted())
|
||||
fileDatabaseDao.updateState(db.getCode(), FileDatabaseState.CAPACITY_EXHAUSTED);
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void renew(FileDatabaseRenewRequest request) {
|
||||
request.checkExpiredDate();
|
||||
docLogDao.logRequest("renew", request.getCode(), request);
|
||||
FileDatabase db = fileDatabaseDao.getForUpdateOrThrow(request.getCode());
|
||||
BizAssertions.assertTrue(db.isActivated(), "只有激活状态的资料库才能扩容");
|
||||
fileDatabaseDao.lambdaUpdate() //
|
||||
.eq(FileDatabase::getCode, request.getCode()) //
|
||||
.set(FileDatabase::getAllowedCapacity, request.getAllowedCapacity()) //
|
||||
.set(FileDatabase::getExpireDate, new Date(request.getExpiredDateMs())) //
|
||||
updateCapacity(request) //
|
||||
.set(FileDatabase::getState,
|
||||
db.isCapacityExhausted() ? FileDatabaseState.CAPACITY_EXHAUSTED : FileDatabaseState.ACTIVATED) //
|
||||
.update();
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void expandCapacity(FileDatabaseExpandCapacityRequest request) {
|
||||
request.checkExpiredDate();
|
||||
docLogDao.logRequest("expandCapacity", request.getCode(), request);
|
||||
FileDatabase db = fileDatabaseDao.getForUpdateOrThrow(request.getCode());
|
||||
BizAssertions.assertTrue(db.isActivated(), "只有激活状态的资料库才能扩容");
|
||||
updateCapacity(request).update();
|
||||
}
|
||||
|
||||
private LambdaUpdateChainWrapper<FileDatabase> updateCapacity(FileDatabaseActiveRequest request) {
|
||||
return fileDatabaseDao.lambdaUpdate() //
|
||||
.eq(FileDatabase::getCode, request.getCode()) //
|
||||
.set(FileDatabase::getAllowedCapacity, request.getAllowedCapacity()) //
|
||||
.set(FileDatabase::getExpireDate, new Date(request.getExpiredDateMs()));
|
||||
}
|
||||
|
||||
public void remove(FileDatabaseRemoveRequest request) {
|
||||
docLogDao.logRequest("remove", request.getCode(), request);
|
||||
fileDatabaseDao.deleteByCode(request.getCode());
|
||||
}
|
||||
|
||||
@ -157,9 +197,7 @@ public class FileDatabaseService {
|
||||
.orderByDesc(FileDatabase::getId)
|
||||
.page(request.toPage());
|
||||
// @formatter:on
|
||||
IndexNodes indexNodes = IndexNodes.wrap(indexQueryService.get(page.getRecords().stream() //
|
||||
.map(FileDatabase::getTemplateDatabaseCode) //
|
||||
.collect(toList())));
|
||||
IndexNodes indexNodes = IndexNodes.wrap(indexQueryService.get(page.getRecords()));
|
||||
Map<Long, SimpleWorkspaceRes> id2Workspace = new HashMap<>();
|
||||
List<Long> resultWorkspaceIds = page.getRecords().stream() //
|
||||
.map(FileDatabase::getWorkspaceId) //
|
||||
@ -189,5 +227,4 @@ public class FileDatabaseService {
|
||||
.collect(toList());
|
||||
return Page.toPage(request.getPage(), request.getPageSize(), page.getTotal(), records);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -47,9 +47,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class FileTemplateApiController implements FileTemplateApi {
|
||||
|
||||
private final FileTemplateManager fileTemplateManager;
|
||||
private final IndexManager indexManager;;
|
||||
private final IndexManager indexManager;
|
||||
private final IndexQueryService indexQueryService;
|
||||
private final AsyncUtils asyncUtils;
|
||||
private final IndexNodeTreeUtils indexNodeTreeUtils;
|
||||
|
||||
@Override
|
||||
public CommonResponse<String> createDir(FileTemplateCreateDirRequest request) {
|
||||
@ -101,7 +102,7 @@ public class FileTemplateApiController implements FileTemplateApi {
|
||||
public CommonResponse<List<IndexNodeInfo>> getTree() {
|
||||
List<IndexNode> subtreeNodes = indexQueryService.getTree(IndexNodeScope.FILE_TEMPLATE);
|
||||
FileTemplates fileTemplates = buildFileTemplates(subtreeNodes);
|
||||
RootNode<IndexNodeInfo> root = IndexNodeTreeUtils.transform(subtreeNodes);
|
||||
RootNode<IndexNodeInfo> root = indexNodeTreeUtils.transform(subtreeNodes);
|
||||
root.walkDown(new ValueNodeRecursiveVisitor<IndexNodeInfo>() {
|
||||
@Override
|
||||
public WalkingDecision visit(ValueNode<IndexNodeInfo> node) {
|
||||
@ -109,7 +110,7 @@ public class FileTemplateApiController implements FileTemplateApi {
|
||||
return WalkingDecision.CONTINUE;
|
||||
}
|
||||
});
|
||||
return CommonResponse.success(IndexNodeTreeUtils.collectSortedValueRoots(root));
|
||||
return CommonResponse.success(indexNodeTreeUtils.valueRoots(root));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -4,12 +4,9 @@ package cn.axzo.nanopart.doc.file.index;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope;
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
@ -19,12 +16,15 @@ import cn.axzo.maokai.api.util.Ref;
|
||||
import cn.axzo.maokai.api.vo.response.tree.RootNode;
|
||||
import cn.axzo.maokai.api.vo.response.tree.TreeBuilder;
|
||||
import cn.axzo.maokai.api.vo.response.tree.TreeUtils;
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope;
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
|
||||
import cn.axzo.nanopart.doc.api.domain.NodeCreate;
|
||||
import cn.axzo.nanopart.doc.api.domain.OssFile;
|
||||
import cn.axzo.nanopart.doc.api.enums.FileFormat;
|
||||
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
|
||||
import cn.axzo.nanopart.doc.api.util.BizAssertions;
|
||||
import cn.axzo.nanopart.doc.config.DocProps;
|
||||
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;
|
||||
@ -52,6 +52,7 @@ public class IndexManager {
|
||||
private final DocProps docProps;
|
||||
private final FileBroadcaster fileBroadcaster;
|
||||
private final TransactionTemplate transaction;
|
||||
private final DocLogDao docLogDao;
|
||||
|
||||
@BizTransactional
|
||||
public IndexNode createDatabase(NodeCreate create) {
|
||||
@ -85,6 +86,7 @@ public class IndexManager {
|
||||
BizAssertions.assertNotBlank(ossFile.getExtension(), "extension不能为空");
|
||||
IndexNode fileNode = createFile(node, ossFile);
|
||||
indexNodeDao.updateFileSize(fileNode.getCode(), ossFile.getSize());
|
||||
fileBroadcaster.fireFileSizeChanged(fileNode.getCode());
|
||||
return fileNode;
|
||||
}
|
||||
|
||||
@ -103,10 +105,10 @@ public class IndexManager {
|
||||
}
|
||||
String operatorId = node.operatorId() == null ? "" : node.operatorId() + "";
|
||||
IndexNode fileNode = indexSupport.createNode(node, IndexNodeType.FILE);
|
||||
fileNode.getOrCreateAttributes().getOrCreateFileAttributes().setOssFileKey(ossFile.getOssFileKey());
|
||||
fileNode.getOrCreateAttributes().getOrCreateFileAttributes().setFileFormat(ossFile.getFormat());
|
||||
fileNode.getOrCreateAttributes().getOrCreateFileAttributes().setFileExtension(ossFile.getExtension());
|
||||
fileNode.getOrCreateAttributes().getOrCreateFileAttributes().setCreatorId(operatorId);
|
||||
fileNode.getOrCreateFileAttributes().setOssFileKey(ossFile.getOssFileKey());
|
||||
fileNode.getOrCreateFileAttributes().setFileFormat(ossFile.getFormat());
|
||||
fileNode.getOrCreateFileAttributes().setFileExtension(ossFile.getExtension());
|
||||
fileNode.getOrCreateFileAttributes().setCreatorId(operatorId);
|
||||
indexNodeDao.updateAttributes(fileNode);
|
||||
return findOrNull(fileNode.getCode());
|
||||
});
|
||||
@ -123,6 +125,7 @@ public class IndexManager {
|
||||
IndexNode indexNode = getOrThrow(code);
|
||||
if (indexNode.getName().equals(newName))
|
||||
return;
|
||||
docLogDao.log("indexNodeRename", code, "newName", newName);
|
||||
indexSupport.lockParentAndReleaseOnCommit(indexNode);
|
||||
indexSupport.ensureChildNameNotUsed(indexNode, indexNode.getNodeType(), newName);
|
||||
indexNodeDao.rename(code, newName);
|
||||
@ -136,6 +139,7 @@ public class IndexManager {
|
||||
@BizTransactional
|
||||
public List<IndexNode> delete(String code) {
|
||||
IndexNode indexNode = getOrThrow(code);
|
||||
docLogDao.log("deleteIndexNode", code);
|
||||
List<IndexNode> subtree = indexNodeDao.collectValidSubtreeNodes(indexNode);
|
||||
indexNodeDao.stateDeleteSubtree(indexNode);
|
||||
return subtree;
|
||||
@ -151,17 +155,16 @@ public class IndexManager {
|
||||
IndexNode destParentNode = findOrNull(destParentCode);
|
||||
return async(() -> {
|
||||
// don't inline in transaction
|
||||
CopyFileVisitor copyNodeVisitor = createCopyFileVisitor(srcNode, null);
|
||||
CopyFileVisitor copyNodeVisitor = new CopyFileVisitor(copySubtreeOssFiles(srcNode));
|
||||
//noinspection SpringTransactionalMethodCallsInspection
|
||||
return transaction.execute(unused -> copySubTree(srcNode, destParentNode, copyNodeVisitor));
|
||||
});
|
||||
}
|
||||
|
||||
public CopyFileVisitor createCopyFileVisitor(IndexNode srcNode, @Nullable Consumer<IndexNode> copyPostProcessor) {
|
||||
public CopiedOssFiles copySubtreeOssFiles(IndexNode srcNode) {
|
||||
BizAssertions.assertFalse(TransactionSynchronizationManager.isActualTransactionActive(), "不能在事务中使用");
|
||||
List<String> ossFileKeys = indexNodeDao.collectValidSubtreeFileOssKeys(srcNode);
|
||||
CopiedOssFiles copiedOssFiles = new CopiedOssFiles(ossClient.copy(ossFileKeys));
|
||||
return new CopyFileVisitor(copiedOssFiles, copyPostProcessor);
|
||||
return new CopiedOssFiles(ossClient.copy(ossFileKeys));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -174,7 +177,10 @@ public class IndexManager {
|
||||
BizAssertions.assertFalse(srcNode.isDirectory() && destParentNode.isFile(), "不能移动文件夹到文件下");
|
||||
return async(() -> {
|
||||
RootNode<IndexNode> moveRoot = TreeBuilder.build(collectValidSubtreeAsValueRoot(srcNode));
|
||||
return transaction.execute(unused -> connectNodes(moveRoot, destParentNode));
|
||||
return transaction.execute(unused -> {
|
||||
docLogDao.log("indexNodeMove", srcCode, "srcCode", srcCode, "destParentCode", destParentCode);
|
||||
return connectNodes(moveRoot, destParentNode);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -201,11 +207,11 @@ public class IndexManager {
|
||||
// rebuild parent id, parent code and the most important path
|
||||
connectRoot.walkDown(new ConnectNodeVisitor(destParent));
|
||||
indexNodeDao.connectNodes(TreeUtils.collectValues(connectRoot));
|
||||
IndexNode copiedRoot = connectRoot.getChildren().get(0).<IndexNode> asValueNode().getValue();
|
||||
IndexNode rootNode = connectRoot.getChildren().get(0).<IndexNode> asValueNode().getValue();
|
||||
IndexNodeParentScope nameScope = new IndexNodeParentScope() {
|
||||
@Override
|
||||
public IndexNodeScope nodeScope() {
|
||||
return copiedRoot;
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -214,9 +220,9 @@ public class IndexManager {
|
||||
}
|
||||
};
|
||||
// resolve the name issue
|
||||
indexSupport.incrNameIfDuplicate(nameScope, copiedRoot.getNodeType(), copiedRoot);
|
||||
indexSupport.incrNameIfDuplicate(nameScope, rootNode);
|
||||
// get the coped root with full props
|
||||
return indexNodeDao.findOrNull(copiedRoot.getCode());
|
||||
return indexNodeDao.findOrNull(rootNode.getCode());
|
||||
}
|
||||
|
||||
public IndexNode findOrNull(String code) {
|
||||
|
||||
@ -1,21 +1,29 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.file.index;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope;
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
|
||||
import cn.axzo.nanopart.doc.api.enums.FileFormat;
|
||||
import cn.axzo.nanopart.doc.api.enums.IndexNodeState;
|
||||
import cn.axzo.nanopart.doc.api.enums.IndexNodeType;
|
||||
import cn.axzo.nanopart.doc.api.index.request.IndexNodeSearchRequest;
|
||||
import cn.axzo.nanopart.doc.config.DocProps;
|
||||
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
|
||||
import cn.axzo.nanopart.doc.entity.IndexNode;
|
||||
import cn.axzo.nanopart.doc.entity.domain.IndexNodeCodeProvider;
|
||||
import cn.azxo.framework.common.model.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@ -27,11 +35,14 @@ import lombok.RequiredArgsConstructor;
|
||||
public class IndexQueryService {
|
||||
|
||||
private final IndexNodeDao indexNodeDao;
|
||||
private final DocProps docProps;
|
||||
|
||||
public List<IndexNode> getTree(IndexNodeScope nodeScope) {
|
||||
return indexNodeDao.scopeQuery(nodeScope) //
|
||||
List<IndexNode> indexNodes = indexNodeDao.scopeQuery(nodeScope) //
|
||||
.eq(IndexNode::getState, IndexNodeState.VALID) //
|
||||
.list();
|
||||
setIcons(indexNodes);
|
||||
return indexNodes;
|
||||
}
|
||||
|
||||
public Page<IndexNode> search(IndexNodeScope nodeScope, IndexNodeSearchRequest search) {
|
||||
@ -40,6 +51,7 @@ public class IndexQueryService {
|
||||
.like(IndexNode::getName, search.getName()) //
|
||||
.in(CollectionUtils.isNotEmpty(search.getNodeTypes()), IndexNode::getNodeType, search.getNodeTypes()) //
|
||||
.page(search.toPage());
|
||||
setIcons(page.getRecords());
|
||||
return Page.toPage(page.getPages(), page.getSize(), page.getTotal(), page.getRecords());
|
||||
}
|
||||
|
||||
@ -51,10 +63,57 @@ public class IndexQueryService {
|
||||
.list();
|
||||
}
|
||||
|
||||
public List<IndexNode> get(List<String> codes) {
|
||||
public List<IndexNode> getNameLike(IndexNodeParentScope parentScope, String name, IndexNodeType... nodeTypes) {
|
||||
List<IndexNodeType> effectiveNodeTypes = nodeTypes == null ? Collections.emptyList() : Arrays.asList(nodeTypes);
|
||||
return indexNodeDao.parentOrScopeRootQuery(parentScope) //
|
||||
.like(IndexNode::getName, name) //
|
||||
.in(!effectiveNodeTypes.isEmpty(), IndexNode::getNodeType, effectiveNodeTypes) //
|
||||
.list();
|
||||
}
|
||||
|
||||
public int getUsedFileSize(IndexNodeScope nodeScope) {
|
||||
IndexNode sum = indexNodeDao.getBaseMapper().selectOne(new QueryWrapper<IndexNode>() //
|
||||
.select("SUM(size)") //
|
||||
.lambda() //
|
||||
.eq(IndexNode::getContext, nodeScope.context()) //
|
||||
.eq(IndexNode::getScope, nodeScope.scope()) //
|
||||
.eq(IndexNode::getScopeCode, nodeScope.scopeCode()) //
|
||||
.eq(IndexNode::getState, IndexNodeState.VALID));
|
||||
return sum == null ? 0 : sum.getSize();
|
||||
}
|
||||
|
||||
public List<IndexNode> get(List<? extends IndexNodeCodeProvider> nodes) {
|
||||
if (CollectionUtils.isEmpty(nodes))
|
||||
return Collections.emptyList();
|
||||
List<String> codes = nodes.stream() //
|
||||
.map(IndexNodeCodeProvider::indexNodeCode) //
|
||||
.filter(StringUtils::isNotBlank) //
|
||||
.collect(toList());
|
||||
if (CollectionUtils.isEmpty(codes))
|
||||
return Collections.emptyList();
|
||||
return indexNodeDao.lambdaQuery().in(IndexNode::getCode, codes).list();
|
||||
}
|
||||
|
||||
private void setIcons(List<IndexNode> indexNodes) {
|
||||
for (IndexNode indexNode : indexNodes) {
|
||||
if (StringUtils.isBlank(indexNode.getIcon()))
|
||||
indexNode.setIcon(determineDefaultIcon(indexNode));
|
||||
}
|
||||
}
|
||||
|
||||
private String determineDefaultIcon(IndexNode indexNode) {
|
||||
if (indexNode.getNodeType() == IndexNodeType.DATABASE)
|
||||
return docProps.getDefaultIconDatabase();
|
||||
if (indexNode.getNodeType() == IndexNodeType.DIRECTORY)
|
||||
return docProps.getDefaultIconDir();
|
||||
FileFormat fileFormat = indexNode.getOrCreateFileAttributes().getFileFormat();
|
||||
if (fileFormat == FileFormat.EXCEL)
|
||||
indexNode.setIcon(docProps.getDefaultIconExcel());
|
||||
else if (fileFormat == FileFormat.WORD)
|
||||
indexNode.setIcon(docProps.getDefaultIconWord());
|
||||
else if (fileFormat == FileFormat.PDF)
|
||||
indexNode.setIcon(docProps.getDefaultIconPdf());
|
||||
return "no-icon";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -30,7 +30,6 @@ import cn.axzo.nanopart.doc.dao.DocLockDao;
|
||||
import cn.axzo.nanopart.doc.dao.IndexNodeDao;
|
||||
import cn.axzo.nanopart.doc.entity.IndexNode;
|
||||
import cn.axzo.nanopart.doc.entity.domain.Path;
|
||||
import cn.axzo.nanopart.doc.file.index.copy.SetScopeProcessor;
|
||||
import cn.axzo.nanopart.doc.file.index.domain.NameUsedException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -56,7 +55,7 @@ class IndexSupport {
|
||||
validateBeforeCreateChild(parent, create, nodeType);
|
||||
}
|
||||
IndexNode child = new IndexNode();
|
||||
new SetScopeProcessor(create.nodeScope()).accept(child);
|
||||
IndexNode.setScope(child, create.nodeScope());
|
||||
child.setCode(UUIDUtil.uuidString());
|
||||
child.setParentId(parent == null ? IndexNode.TREE_ROOT_NODE_ID : parent.getId());
|
||||
child.setParentCode(parent == null ? IndexNode.TREE_ROOT_NOE_CODE : parent.getCode());
|
||||
@ -82,28 +81,27 @@ class IndexSupport {
|
||||
}
|
||||
|
||||
private void validateBeforeCreateChild(IndexNode parent, NodeCreate child, IndexNodeType nodeType) {
|
||||
BizAssertions.assertTrue(
|
||||
indexNodeDao.validChildrenCount(parent.getCode()) < docProps.getIndexNodeMaxChildrenSize(),
|
||||
"创建失败, 子节点数量不能超过 {}", docProps.getIndexNodeMaxChildrenSize());
|
||||
BizAssertions.assertTrue(parent.path().depth() < docProps.getIndexNodeMaxDepth(), //
|
||||
"节点深度超过限制{}, 无法再创建新节点", docProps.getIndexNodeMaxDepth());
|
||||
if (nodeType == IndexNodeType.DIRECTORY)
|
||||
BizAssertions.assertFalse(parent.isFile(), "不能在文件下建立文件夹");
|
||||
BizAssertions.assertEquals(parent.getContext(), child.nodeScope().context(), //
|
||||
"创建子节点时父子context不匹配: {}", child.parentCode());
|
||||
BizAssertions.assertEquals(parent.getScope(), child.nodeScope().scope(), //
|
||||
"创建子节点时父子scope不匹配: {}", child.nodeScope().scope());
|
||||
BizAssertions.assertEquals(parent.getScopeCode(), child.nodeScope().scopeCode(), //
|
||||
"创建子节点时父子scopeCode不匹配: {}", child.parentCode());
|
||||
if (nodeType == IndexNodeType.DIRECTORY)
|
||||
BizAssertions.assertFalse(parent.isFile(), "不能在文件下建立文件夹");
|
||||
BizAssertions.assertTrue(
|
||||
indexNodeDao.validChildrenCount(parent.getCode()) < docProps.getIndexNodeMaxChildrenSize(),
|
||||
"创建失败, 子节点数量不能超过 {}", docProps.getIndexNodeMaxChildrenSize());
|
||||
BizAssertions.assertTrue(parent.path().depth() < docProps.getIndexNodeMaxDepth(), //
|
||||
"节点深度超过限制{}, 无法再创建新节点", docProps.getIndexNodeMaxDepth());
|
||||
}
|
||||
|
||||
void incrNameIfDuplicate(IndexNodeParentScope parentScope, IndexNodeType nodeType, IndexNode rename) {
|
||||
void incrNameIfDuplicate(IndexNodeParentScope parentScope, IndexNode rename) {
|
||||
lockParentAndReleaseOnCommit(parentScope);
|
||||
List<IndexNode> nameLikeNodes = indexNodeDao.findValidChildrenNameRightLike(parentScope, nodeType,
|
||||
rename.getName());
|
||||
List<IndexNode> nameLikeNodes = indexNodeDao.findValidChildrenNameRightLike(parentScope, rename);
|
||||
if (nameLikeNodes.size() == 1 && IndexNode.idEquals(rename, nameLikeNodes.get(0)))
|
||||
return;
|
||||
Pattern pattern = Pattern.compile(Pattern.quote(rename.getName()) + "\\((\\d+)\\)");
|
||||
Pattern pattern = Pattern.compile(Pattern.quote(rename.getName()) + "\\(副本(\\d+)\\)");
|
||||
int maxSeq = 0;
|
||||
for (IndexNode indexNode : nameLikeNodes) {
|
||||
if (indexNode.getId().equals(rename.getId()))
|
||||
@ -115,8 +113,7 @@ class IndexSupport {
|
||||
maxSeq = seq;
|
||||
}
|
||||
}
|
||||
maxSeq = maxSeq == 0 ? 1 : maxSeq + 1;
|
||||
String newName = String.format("%s(%d)", rename.getName(), maxSeq);
|
||||
String newName = String.format("%s(副本%d)", rename.getName(), maxSeq == 0 ? 1 : maxSeq + 1);
|
||||
indexNodeDao.rename(rename.getCode(), newName);
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.file.index.copy;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import cn.axzo.maokai.api.vo.response.tree.ValueNode;
|
||||
import cn.axzo.maokai.api.vo.response.tree.WalkingDecision;
|
||||
import cn.axzo.nanopart.doc.api.domain.FileAttributes;
|
||||
@ -18,8 +14,6 @@ import lombok.RequiredArgsConstructor;
|
||||
public class CopyFileVisitor extends CopyNodeVisitor {
|
||||
|
||||
private final CopiedOssFiles copiedOssFiles;
|
||||
@Nullable
|
||||
private final Consumer<IndexNode> copyPostProcessor;
|
||||
|
||||
@Override
|
||||
public WalkingDecision visit(ValueNode<IndexNode> node) {
|
||||
@ -29,8 +23,6 @@ public class CopyFileVisitor extends CopyNodeVisitor {
|
||||
String newOssFileKey = copiedOssFiles.getCopyOssFileKey(fileAttributes.getOssFileKey());
|
||||
fileAttributes.setOssFileKey(newOssFileKey);
|
||||
}
|
||||
if (copyPostProcessor != null)
|
||||
copyPostProcessor.accept(copy);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,10 @@ public class CopyNodeVisitor extends ValueNodeRecursiveVisitor<IndexNode> {
|
||||
public WalkingDecision visit(ValueNode<IndexNode> node) {
|
||||
IndexNode copy = node.getValue();
|
||||
copy.setId(0L);
|
||||
copy.setRootCode("");
|
||||
copy.setParentId(0L);
|
||||
copy.setParentCode("");
|
||||
copy.setPath("");
|
||||
copy.setCode(UUIDUtil.uuidString());
|
||||
return WalkingDecision.CONTINUE;
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.file.index.copy;
|
||||
|
||||
import cn.axzo.maokai.api.vo.response.tree.ValueNode;
|
||||
import cn.axzo.maokai.api.vo.response.tree.WalkingDecision;
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
|
||||
import cn.axzo.nanopart.doc.entity.IndexNode;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public class SetCopyCopyFileVisitor extends CopyFileVisitor {
|
||||
|
||||
private final IndexNodeScope nodeScope;
|
||||
|
||||
public SetCopyCopyFileVisitor(CopiedOssFiles copiedOssFiles, IndexNodeScope nodeScope) {
|
||||
super(copiedOssFiles);
|
||||
this.nodeScope = nodeScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WalkingDecision visit(ValueNode<IndexNode> node) {
|
||||
IndexNode.setScope(node.getValue(), nodeScope);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.file.index.copy;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeScope;
|
||||
import cn.axzo.nanopart.doc.entity.IndexNode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class SetScopeProcessor implements Consumer<IndexNode> {
|
||||
|
||||
private final IndexNodeScope nodeScope;;
|
||||
|
||||
@Override
|
||||
public void accept(IndexNode indexNode) {
|
||||
indexNode.setContext(nodeScope.context());
|
||||
indexNode.setScope(nodeScope.scope());
|
||||
indexNode.setScopeCode(nodeScope.scopeCode());
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ import org.springframework.stereotype.Component;
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventProducer;
|
||||
import cn.axzo.nanopart.doc.file.mq.message.DeleteOssFileMessage;
|
||||
import cn.axzo.nanopart.doc.file.mq.message.FileSizeChangeMessage;
|
||||
import cn.axzo.nanopart.doc.file.mq.message.RenameIndexNodeOssFileMessage;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@ -43,4 +44,16 @@ public class FileBroadcaster {
|
||||
.build());
|
||||
}
|
||||
|
||||
public void fireFileSizeChanged(String indexNodeCode) {
|
||||
FileSizeChangeMessage message = new FileSizeChangeMessage();
|
||||
message.setIndexNodeCode(indexNodeCode);
|
||||
eventProducer.send(Event.builder() //
|
||||
.eventCode(FileInternalEvent.INDEX_NODE_FILE_SIZE_CHANGED.getEventCode()) //
|
||||
.shardingKey(indexNodeCode) //
|
||||
.targetId(indexNodeCode) //
|
||||
.targetType("index-node") //
|
||||
.data(message) //
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -13,7 +13,9 @@ import lombok.RequiredArgsConstructor;
|
||||
public enum FileInternalEvent {
|
||||
|
||||
INDEX_NODE_RENAME_OSS_FILE("nanopart-doc", "index-node-rename-oss-file", "修改index node oss文件名"),
|
||||
OSS_FILE_DELETE("nanopart-doc", "oss-file-delete", "删除oss文件"),;
|
||||
INDEX_NODE_FILE_SIZE_CHANGED("nanopart-doc", "index-node-file-size-changed", "修改index node文件大小发生变化"),
|
||||
OSS_FILE_DELETE("nanopart-doc", "oss-file-delete", "删除oss文件"),
|
||||
;
|
||||
|
||||
FileInternalEvent(String model, String name, String desc) {
|
||||
this.eventCode = Event.EventCode.builder().module(model).name(name).build();
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.file.mq.filehandler;
|
||||
|
||||
import cn.axzo.nanopart.doc.file.filedb.FileDatabaseService;
|
||||
import cn.axzo.nanopart.doc.file.mq.message.FileSizeChangeMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.nanopart.doc.file.mq.FileInternalEvent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UpdateFileDatabaseCapacityHandler implements EventHandler, InitializingBean {
|
||||
|
||||
private final EventConsumer eventConsumer;
|
||||
private final FileDatabaseService fileDatabaseService;
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event, EventConsumer.Context context) {
|
||||
log.info("receive file change message: {}", event);
|
||||
FileSizeChangeMessage message = event.normalizedData(FileSizeChangeMessage.class);
|
||||
fileDatabaseService.fileSizeChanged(message.getIndexNodeCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(FileInternalEvent.INDEX_NODE_FILE_SIZE_CHANGED.getEventCode(), this);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package cn.axzo.nanopart.doc.file.mq.message;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class FileSizeChangeMessage extends MqMessage {
|
||||
|
||||
private String indexNodeCode;
|
||||
|
||||
}
|
||||
@ -4,6 +4,8 @@ package cn.axzo.nanopart.doc.file.templatedb;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.templatedb.domain.DatabaseInfo;
|
||||
import cn.axzo.nanopart.doc.api.templatedb.reqeust.TemplateDatabaseSearchRequest;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
@ -46,6 +48,7 @@ public class TemplateDatabaseApiController implements TemplateDatabaseApi {
|
||||
private final TemplateDatabaseQueryService templateDatabaseQueryService;
|
||||
private final IndexQueryService indexQueryService;
|
||||
private final AsyncUtils asyncUtils;
|
||||
private final IndexNodeTreeUtils indexNodeTreeUtils;
|
||||
|
||||
@Override
|
||||
public CommonResponse<String> createDatabase(TemplateDatabaseCreateDatabaseRequest request) {
|
||||
@ -98,8 +101,8 @@ public class TemplateDatabaseApiController implements TemplateDatabaseApi {
|
||||
@Override
|
||||
public CommonResponse<List<IndexNodeInfo>> getTree() {
|
||||
List<IndexNode> subtreeNodes = indexQueryService.getTree(IndexNodeScope.TEMPLATE_DATABASE);
|
||||
RootNode<IndexNodeInfo> root = IndexNodeTreeUtils.transform(subtreeNodes);
|
||||
return CommonResponse.success(IndexNodeTreeUtils.collectSortedValueRoots(root));
|
||||
RootNode<IndexNodeInfo> root = indexNodeTreeUtils.transform(subtreeNodes);
|
||||
return CommonResponse.success(indexNodeTreeUtils.valueRoots(root));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -110,6 +113,11 @@ public class TemplateDatabaseApiController implements TemplateDatabaseApi {
|
||||
return CommonResponse.success(infoPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<Page<DatabaseInfo>> searchDatabase(TemplateDatabaseSearchRequest request) {
|
||||
return CommonResponse.success(templateDatabaseQueryService.searchDatabase(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResponse<TemplateDatabaseGetDatabaseOrDirInfoResponse> getDatabaseOrDirInfo(
|
||||
TemplateDatabaseGetDatabaseOrDirInfoRequest request) {
|
||||
|
||||
@ -23,6 +23,8 @@ import cn.axzo.nanopart.doc.file.index.domain.IndexNodes;
|
||||
import cn.axzo.nanopart.doc.utils.BizTransactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@ -41,6 +43,8 @@ public class TemplateDatabaseManager {
|
||||
db.setCode(indexNode.getCode());
|
||||
db.setScope(request.getScope());
|
||||
db.setCoopType(request.getCoopType());
|
||||
db.setCreateAt(new Date());
|
||||
db.setUpdateAt(new Date());
|
||||
templateDatabaseDao.save(db);
|
||||
return indexNode.getCode();
|
||||
}
|
||||
|
||||
@ -1,14 +1,28 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.file.templatedb;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeParentScope;
|
||||
import cn.axzo.nanopart.doc.api.enums.TemplateDatabaseState;
|
||||
import cn.axzo.nanopart.doc.api.templatedb.domain.DatabaseInfo;
|
||||
import cn.axzo.nanopart.doc.api.templatedb.reqeust.TemplateDatabaseGetDatabaseOrDirInfoRequest;
|
||||
import cn.axzo.nanopart.doc.api.templatedb.reqeust.TemplateDatabaseSearchRequest;
|
||||
import cn.axzo.nanopart.doc.api.templatedb.response.TemplateDatabaseGetDatabaseOrDirInfoResponse;
|
||||
import cn.axzo.nanopart.doc.dao.TemplateDatabaseDao;
|
||||
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.domain.IndexNodes;
|
||||
import cn.azxo.framework.common.model.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -22,6 +36,7 @@ public class TemplateDatabaseQueryService {
|
||||
|
||||
private final IndexManager indexManager;;
|
||||
private final TemplateDatabaseDao templateDatabaseDao;
|
||||
private final IndexQueryService indexQueryService;
|
||||
|
||||
public TemplateDatabaseGetDatabaseOrDirInfoResponse getDatabaseOrDirInfo(
|
||||
TemplateDatabaseGetDatabaseOrDirInfoRequest request) {
|
||||
@ -34,7 +49,7 @@ public class TemplateDatabaseQueryService {
|
||||
response.getDatabaseOrDirInfo().setBizCode(indexNode.getBizCode());
|
||||
response.getDatabaseOrDirInfo().setDescription(indexNode.getDescription());
|
||||
response.getDatabaseOrDirInfo().setIcon(indexNode.getIcon());
|
||||
response.getDatabaseOrDirInfo().setCustomIcon(indexNode.getOrCreateAttributes().isCustomIcon());
|
||||
response.getDatabaseOrDirInfo().setCustomIcon(indexNode.getOrCreateAttributes().getCustomIcon());
|
||||
if (indexNode.isDatabase()) {
|
||||
TemplateDatabase template = templateDatabaseDao.findOrNull(request.getCode());
|
||||
if (template != null) {
|
||||
@ -46,4 +61,32 @@ public class TemplateDatabaseQueryService {
|
||||
return response;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Page<DatabaseInfo> searchDatabase(TemplateDatabaseSearchRequest request) {
|
||||
List<String> codes = null;
|
||||
if (StringUtils.isNotBlank(request.getName())) {
|
||||
codes = indexQueryService.getNameLike( //
|
||||
IndexNodeParentScope.TEMPLATE_DATABASE_ROOT, request.getName()).stream() //
|
||||
.map(IndexNode::getCode) //
|
||||
.collect(toList());
|
||||
if (codes.isEmpty())
|
||||
return Page.zero();
|
||||
}
|
||||
IPage<TemplateDatabase> page = templateDatabaseDao.lambdaQuery() //
|
||||
.eq(TemplateDatabase::getState, TemplateDatabaseState.VALID) //
|
||||
.in(codes != null, TemplateDatabase::getCode, codes) //
|
||||
.page(request.toPage());
|
||||
IndexNodes indexNodes = IndexNodes.wrap(indexQueryService.get(page.getRecords()));
|
||||
List<DatabaseInfo> infoList = page.getRecords().stream().map(db -> {
|
||||
IndexNode indexNode = indexNodes.findOrNull(db.getCode());
|
||||
DatabaseInfo info = new DatabaseInfo();
|
||||
info.setName(indexNode == null ? "" : indexNode.getName());
|
||||
info.setCode(db.getCode());
|
||||
info.setDatabaseType(db.getScope().getDatabaseType());
|
||||
info.setFeeConfig(db.getFeeConfig());
|
||||
return info;
|
||||
}).collect(toList());
|
||||
return Page.toPage(request.getPage(), page.getSize(), page.getTotal(), infoList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -24,6 +24,12 @@ import cn.axzo.oss.http.model.copyobject.ServerFileBatchCopyObjectRequest;
|
||||
import cn.axzo.oss.http.model.copyobject.ServerFileBatchCopyObjectRequest.ServerFileCopyObjectRequest;
|
||||
import cn.axzo.oss.http.model.copyobject.ServerFileBatchCopyObjectResponse;
|
||||
import cn.axzo.oss.http.model.copyobject.ServerFileBatchCopyObjectResponse.ServerFileCopyObjectResponse;
|
||||
import cn.axzo.oss.http.model.copyobject.ServerFileBatchDeleteObjectRequest;
|
||||
import cn.axzo.oss.http.model.copyobject.ServerFileBatchDeleteObjectRequest.ServerFileDeleteObjectRequest;
|
||||
import cn.axzo.oss.http.model.copyobject.ServerFileBatchDeleteObjectResponse;
|
||||
import cn.axzo.oss.http.model.file.FileRenameRequest;
|
||||
import cn.axzo.oss.http.model.file.FileRenameResponse;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -52,7 +58,7 @@ public class OssClient {
|
||||
BizAssertions.assertNotEmpty(copyResponse.getResponses(), "单个拷贝oss文件失败, 返回了空列表结果");
|
||||
}
|
||||
finally {
|
||||
log.info("单个拷贝oss文件, request={}, response={}", JSON.toJSONString(copyRequest),
|
||||
log.info("oss copy, request={}, response={}", JSON.toJSONString(copyRequest),
|
||||
JSON.toJSONString(copyResponse));
|
||||
}
|
||||
return copyResponse.getResponses().get(0).getTargetFileKey();
|
||||
@ -83,7 +89,7 @@ public class OssClient {
|
||||
BizAssertions.assertNotEmpty(copyResponse.getResponses(), "批量拷贝oss文件失败, 返回了空列表结果");
|
||||
}
|
||||
finally {
|
||||
log.info("批量拷贝oss文件, request={}, response={}", JSON.toJSONString(copyRequest),
|
||||
log.info("oss batch copy, request={}, response={}", JSON.toJSONString(copyRequest),
|
||||
JSON.toJSONString(copyResponse));
|
||||
}
|
||||
return copyResponse.getResponses().stream().collect(
|
||||
@ -91,11 +97,31 @@ public class OssClient {
|
||||
}
|
||||
|
||||
public void rename(String ossFileKey, String newFullName) {
|
||||
// TODO(yl): finish this
|
||||
FileRenameRequest request = new FileRenameRequest();
|
||||
request.setFileKey(ossFileKey);
|
||||
request.setNewName(newFullName);
|
||||
CommonResponse<FileRenameResponse> response = null;
|
||||
try {
|
||||
response = serverFileServiceApi.rename(request);
|
||||
}
|
||||
finally {
|
||||
log.info("oss rename, request={}, response={}", JSON.toJSONString(request), JSON.toJSONString(response));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(yl): finish this
|
||||
public void delete(String ossFileKey) {
|
||||
ServerFileDeleteObjectRequest itemRequest = new ServerFileDeleteObjectRequest();
|
||||
itemRequest.setFileKey(ossFileKey);
|
||||
ServerFileBatchDeleteObjectRequest request = new ServerFileBatchDeleteObjectRequest();
|
||||
request.setAppCode(docProps.getOssAppCode());
|
||||
request.setDeleteObjects(Sets.newHashSet(itemRequest));
|
||||
CommonResponse<ServerFileBatchDeleteObjectResponse> response = null;
|
||||
try {
|
||||
response = serverFileServiceApi.batchDeleteObject(request);
|
||||
}
|
||||
finally {
|
||||
log.info("oss delete, request={}, response={}", JSON.toJSONString(request), JSON.toJSONString(response));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,31 +1,49 @@
|
||||
|
||||
package cn.axzo.nanopart.doc.utils;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.axzo.maokai.api.vo.response.tree.RootNode;
|
||||
import cn.axzo.maokai.api.vo.response.tree.TreeUtils;
|
||||
import cn.axzo.maokai.api.vo.response.tree.ValueNode;
|
||||
import cn.axzo.maokai.api.vo.response.tree.ValueNodeRecursiveVisitor;
|
||||
import cn.axzo.maokai.api.vo.response.tree.WalkingDecision;
|
||||
import cn.axzo.nanopart.doc.api.domain.IndexNodeInfo;
|
||||
import cn.axzo.nanopart.doc.config.DocProps;
|
||||
import cn.axzo.nanopart.doc.entity.IndexNode;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor_ = { @Autowired })
|
||||
public class IndexNodeTreeUtils {
|
||||
|
||||
public static RootNode<IndexNodeInfo> transform(List<IndexNode> subtreeNodes) {
|
||||
private final DocProps docProps;
|
||||
|
||||
public RootNode<IndexNodeInfo> transform(List<IndexNode> subtreeNodes) {
|
||||
RootNode<IndexNodeInfo> root = TreeUtils.transform(subtreeNodes, IndexNodeInfo.class);
|
||||
TreeUtils.connectValueChildren(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
public static List<IndexNodeInfo> collectSortedValueRoots(RootNode<IndexNodeInfo> root) {
|
||||
public List<IndexNodeInfo> valueRoots(RootNode<IndexNodeInfo> root) {
|
||||
Comparator<IndexNodeInfo> comparator = Comparator.comparingLong(IndexNodeInfo::getId);
|
||||
TreeUtils.sortChildren(root, comparator);
|
||||
root.walkDown(new ValueNodeRecursiveVisitor<IndexNodeInfo>() {
|
||||
@Override
|
||||
public WalkingDecision visit(ValueNode<IndexNodeInfo> node) {
|
||||
node.getValue().setAddMoreChildren(node.getChildren().size() < docProps.getIndexNodeMaxChildrenSize());
|
||||
return WalkingDecision.CONTINUE;
|
||||
}
|
||||
});
|
||||
return TreeUtils.collectValueRoots(root).stream().sorted(comparator).collect(toList());
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user