版本更新:V1.5.8

This commit is contained in:
liweiyi 2025-09-03 17:23:09 +08:00
parent c847340220
commit a3261f18cb
470 changed files with 8262 additions and 4444 deletions

8
Jenkinsfile vendored
View File

@ -121,20 +121,17 @@ pipeline {
dir('./ChestnutCMS') { dir('./ChestnutCMS') {
withCredentials([usernamePassword(credentialsId: 'ALIYUN-DOCKER-REGISTRY-LWY', passwordVariable: 'DOCKERPWD', usernameVariable: 'DOCKERUSER')]) { withCredentials([usernamePassword(credentialsId: 'ALIYUN-DOCKER-REGISTRY-LWY', passwordVariable: 'DOCKERPWD', usernameVariable: 'DOCKERUSER')]) {
sh ''' sh '''
cp -f bin/docker-deploy.sh ${APP_PATH} cp -f bin/docker-deploy.sh ${APP_PATH}/docker-deploy.sh
cp -f docker/docker-compose_${DEPLOY_ENV}.yml ${APP_PATH}/docker-compose.yml
cd ${APP_PATH} cd ${APP_PATH}
cp -f ../bin/docker-deploy.sh docker-deploy.sh
sed -i "s/{{DOCKERUSER}}/${DOCKERUSER}/g" docker-deploy.sh sed -i "s/{{DOCKERUSER}}/${DOCKERUSER}/g" docker-deploy.sh
sed -i "s/{{DOCKERPWD}}/${DOCKERPWD}/g" docker-deploy.sh sed -i "s/{{DOCKERPWD}}/${DOCKERPWD}/g" docker-deploy.sh
sed -i "s/{{DOCKER_HUB_URL}}/${DOCKER_HUB_URL}/g" docker-deploy.sh sed -i "s/{{DOCKER_HUB_URL}}/${DOCKER_HUB_URL}/g" docker-deploy.sh
sed -i "s/{{IMAGE_REPOSITORY}}/${DOCKER_HUB_WORKSPACE}\\/${APP_NAME}/g" docker-deploy.sh sed -i "s/{{IMAGE_REPOSITORY}}/${DOCKER_HUB_WORKSPACE}\\/${APP_NAME}/g" docker-deploy.sh
sed -i "s/{{IMAGE_TAG}}/${IMAGE_TAG}/g" docker-deploy.sh sed -i "s/{{IMAGE_TAG}}/${IMAGE_TAG}/g" docker-deploy.sh
cp -f docker/docker-compose_${DEPLOY_ENV}.yml docker-compose.yml
sed -i "s/{{DOCKER_IMAGE}}/${DOCKER_HUB_URL}\\/${DOCKER_HUB_WORKSPACE}\\/${APP_NAME}:${IMAGE_TAG}/g" docker-compose.yml sed -i "s/{{DOCKER_IMAGE}}/${DOCKER_HUB_URL}\\/${DOCKER_HUB_WORKSPACE}\\/${APP_NAME}:${IMAGE_TAG}/g" docker-compose.yml
''' '''
sshPublisher(publishers: [sshPublisherDesc(configName: 'GameCluster', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: ''' sshPublisher(publishers: [sshPublisherDesc(configName: 'GameCluster', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''
@ -203,7 +200,6 @@ pipeline {
usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)]) usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
sh 'rm -f ui.zip' sh 'rm -f ui.zip'
} }
} }
} }
} }

View File

@ -1,4 +1,4 @@
# ChestnutCMS v1.5.7 # ChestnutCMS v1.5.8
### 系统简介 ### 系统简介

View File

@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>chestnut</artifactId> <artifactId>chestnut</artifactId>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -5,7 +5,7 @@ chestnut:
# 代号 # 代号
alias: ChestnutCMS alias: ChestnutCMS
# 版本 # 版本
version: 1.5.7 version: 1.5.8
# 版权年份 # 版权年份
copyrightYear: 2022-2025 copyrightYear: 2022-2025
system: system:
@ -15,6 +15,8 @@ chestnut:
uploadPath: 'E:/dev/workspace_chestnut/uploadPath' uploadPath: 'E:/dev/workspace_chestnut/uploadPath'
member: member:
uploadPath: 'E:/dev/workspace_chestnut/_xy_member/' uploadPath: 'E:/dev/workspace_chestnut/_xy_member/'
image:
type: 'JDK'
cms: cms:
publish: publish:
strategy: ThreadPool strategy: ThreadPool
@ -24,7 +26,7 @@ chestnut:
# 开发环境配置 # 开发环境配置
server: server:
# 服务器的HTTP端口默认为8080 # 服务器的HTTP端口默认为9080
port: 9080 port: 9080
# 开启优雅停机 # 开启优雅停机
shutdown: graceful shutdown: graceful

View File

@ -5,7 +5,7 @@ chestnut:
# 代号 # 代号
alias: ChestnutCMS alias: ChestnutCMS
# 版本 # 版本
version: 1.5.7 version: 1.5.8
# 版权年份 # 版权年份
copyrightYear: 2022-2025 copyrightYear: 2022-2025
system: system:
@ -15,6 +15,8 @@ chestnut:
uploadPath: /home/app/uploadPath uploadPath: /home/app/uploadPath
freemarker: freemarker:
templateLoaderPath: /home/app/statics templateLoaderPath: /home/app/statics
image:
type: 'JDK'
cms: cms:
resourceRoot: /home/app/wwwroot_release resourceRoot: /home/app/wwwroot_release
publish: publish:

View File

@ -5,7 +5,7 @@ chestnut:
# 代号 # 代号
alias: ChestnutCMS alias: ChestnutCMS
# 版本 # 版本
version: 1.5.7 version: 1.5.8
# 版权年份 # 版权年份
copyrightYear: 2022-2025 copyrightYear: 2022-2025
system: system:
@ -13,12 +13,17 @@ chestnut:
demoMode: true demoMode: true
# 文件路径 示例( Windows配置D:/chestnut/uploadPathLinux配置 /home/app/uploadPath # 文件路径 示例( Windows配置D:/chestnut/uploadPathLinux配置 /home/app/uploadPath
uploadPath: /home/app/uploadPath uploadPath: /home/app/uploadPath
# 验证码类型 math 数组计算 char 字符验证
captchaType: math
freemarker: freemarker:
templateLoaderPath: /home/app/statics templateLoaderPath: /home/app/statics
image:
type: 'JDK'
cms: cms:
resourceRoot: /home/app/wwwroot_release resourceRoot: /home/app/wwwroot_release
publish:
strategy: ThreadPool
pool:
threadNamePrefix: "CMS-PUBLISH-"
queueCapacity: 10000
# 开发环境配置 # 开发环境配置
server: server:

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-advertisement</artifactId> <artifactId>chestnut-cms-advertisement</artifactId>

View File

@ -16,6 +16,7 @@
package com.chestnut.advertisement.listener; package com.chestnut.advertisement.listener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chestnut.advertisement.domain.CmsAdvertisement; import com.chestnut.advertisement.domain.CmsAdvertisement;
import com.chestnut.advertisement.service.IAdvertisementService; import com.chestnut.advertisement.service.IAdvertisementService;
import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.async.AsyncTaskManager;
@ -26,6 +27,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j @Slf4j
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
@ -41,10 +44,21 @@ public class AdvertisementListener {
try { try {
long total = this.advertisementService long total = this.advertisementService
.count(new LambdaQueryWrapper<CmsAdvertisement>().eq(CmsAdvertisement::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsAdvertisement>().eq(CmsAdvertisement::getSiteId, site.getSiteId()));
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除广告数据:" + (i * pageSize) + "/" + total); AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除广告数据:" + (i * pageSize) + "/" + total);
this.advertisementService.remove(new LambdaQueryWrapper<CmsAdvertisement>() Page<CmsAdvertisement> advertisements = this.advertisementService.lambdaQuery()
.eq(CmsAdvertisement::getSiteId, site.getSiteId()).last("limit " + pageSize)); .select(CmsAdvertisement::getAdvertisementId)
.eq(CmsAdvertisement::getSiteId, site.getSiteId())
.gt(CmsAdvertisement::getAdvertisementId, lastId)
.orderByAsc(CmsAdvertisement::getAdvertisementId)
.page(Page.of(1, pageSize, false));
if (!advertisements.getRecords().isEmpty()) {
List<Long> advertisementIds = advertisements.getRecords().stream()
.map(CmsAdvertisement::getAdvertisementId).toList();
this.advertisementService.removeBatchByIds(advertisementIds);
lastId = advertisementIds.get(advertisementIds.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除广告数据错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除广告数据错误:" + e.getMessage());

View File

@ -8,9 +8,9 @@ ADVERTISEMENT.TYPE.image=圖片
FREEMARKER.TAG.cms_advertisement.NAME=廣告列表標籤 FREEMARKER.TAG.cms_advertisement.NAME=廣告列表標籤
FREEMARKER.TAG.cms_advertisement.DESC=獲取廣告數據列表,內嵌`<#list DataList as ad>${ad.name}</#list>`遍曆數據 FREEMARKER.TAG.cms_advertisement.DESC=獲取廣告數據列表,內嵌`<#list DataList as ad>${ad.name}</#list>`遍曆數據
FREEMARKER.TAG.cms_advertisement.code=廣告位編碼 FREEMARKER.TAG.cms_advertisement.code=廣告位編碼
FREEMARKER.TAG.cms_advertisement.type=廣告鏈接類型 FREEMARKER.TAG.cms_advertisement.type=廣告連結類型
FREEMARKER.TAG.cms_advertisement.type.None=原始鏈接 FREEMARKER.TAG.cms_advertisement.type.None=原始連結
FREEMARKER.TAG.cms_advertisement.type.Stat=統計鏈接 FREEMARKER.TAG.cms_advertisement.type.Stat=統計連結
# 統計菜單 # 統計菜單
STAT.MENU.CmsAdv=廣告數據統計 STAT.MENU.CmsAdv=廣告數據統計
@ -23,7 +23,7 @@ SCHEDULED_TASK.AdvertisementStatJob=廣告統計任務
SCHEDULED_TASK.AdvertisementPublishJob=廣告定時發布下線任務 SCHEDULED_TASK.AdvertisementPublishJob=廣告定時發布下線任務
MONITORED.CACHE.AD_ID2NAME=廣告名稱 MONITORED.CACHE.AD_ID2NAME=廣告名稱
MONITORED.CACHE.AD_ID2URL=廣告跳轉鏈接 MONITORED.CACHE.AD_ID2URL=廣告跳轉連結
CMS.AD.ID=廣告ID CMS.AD.ID=廣告ID
CMS.AD.SPACE_ID=所屬廣告版位頁面部件ID CMS.AD.SPACE_ID=所屬廣告版位頁面部件ID
@ -34,7 +34,7 @@ CMS.AD.KEYWORDS=關鍵詞
CMS.AD.STATE=狀態 CMS.AD.STATE=狀態
CMS.AD.ONLINE_DATE=上線時間 CMS.AD.ONLINE_DATE=上線時間
CMS.AD.OFFLINE_DATE=下線時間 CMS.AD.OFFLINE_DATE=下線時間
CMS.AD.REDIRECT_URL=原始跳轉鏈接 CMS.AD.REDIRECT_URL=原始跳轉連結
CMS.AD.LINK=實際跳轉鏈接(可設置為中轉地址) CMS.AD.LINK=實際跳轉連結(可設置為中轉地址)
CMS.AD.RESOURCE_PATH=廣告素材源路徑 CMS.AD.RESOURCE_PATH=廣告素材源路徑
CMS.AD.RESOURCE_SRC=廣告素材訪問鏈接 CMS.AD.RESOURCE_SRC=廣告素材訪問地址

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-article</artifactId> <artifactId>chestnut-cms-article</artifactId>

View File

@ -10,6 +10,7 @@ FREEMARKER.FUNC.dealArticleBody.DESC=文章正文處理函數,主要用來處
FREEMARKER.FUNC.dealArticleBody.Arg1.Name=文章正文內容 FREEMARKER.FUNC.dealArticleBody.Arg1.Name=文章正文內容
FREEMARKER.FUNC.dealArticleBody.Arg2.Name=文章正文格式 FREEMARKER.FUNC.dealArticleBody.Arg2.Name=文章正文格式
# 固定字典項
ArticleBodyFormat.RichText=富文本 ArticleBodyFormat.RichText=富文本
CMS.ARTICLE.FORMAT=文章正文格式 CMS.ARTICLE.FORMAT=文章正文格式

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-block</artifactId> <artifactId>chestnut-cms-block</artifactId>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-comment</artifactId> <artifactId>chestnut-cms-comment</artifactId>

View File

@ -7,19 +7,19 @@ FREEMARKER.TAG.cms_comment.type=來源類型
CMS.COMMENT.ID=評論ID CMS.COMMENT.ID=評論ID
CMS.COMMENT.UID=評論用戶ID CMS.COMMENT.UID=評論用戶ID
CMS.COMMENT.PARENT_ID=父級評論ID CMS.COMMENT.PARENT_ID=父級評論ID
CMS.COMMENT.REPLY_UID=的用戶ID CMS.COMMENT.REPLY_UID=的用戶ID
CMS.COMMENT.REPLY_COUNT= CMS.COMMENT.REPLY_COUNT=
CMS.COMMENT.SOURCE_TYPE=來源分類 CMS.COMMENT.SOURCE_TYPE=來源分類
CMS.COMMENT.SOURCE_ID=來源唯一標識 CMS.COMMENT.SOURCE_ID=來源唯一標識
CMS.COMMENT.SOURCE_TITLE=來源標題 CMS.COMMENT.SOURCE_TITLE=來源標題
CMS.COMMENT.SOURCE_URL=來源URL CMS.COMMENT.SOURCE_URL=來源URL
CMS.COMMENT.CONTENT=評論內容 CMS.COMMENT.CONTENT=評論內容
CMS.COMMENT.LIKE_COUNT= CMS.COMMENT.LIKE_COUNT=
CMS.COMMENT.AUDIT_STATUS=評論審核狀態 CMS.COMMENT.AUDIT_STATUS=評論審核狀態
CMS.COMMENT.COMMENT_TIME=評論提交時間 CMS.COMMENT.COMMENT_TIME=評論提交時間
CMS.COMMENT.DEL_FLAG=刪除標識 CMS.COMMENT.DEL_FLAG=刪除標識
CMS.COMMENT.IP=用戶ID CMS.COMMENT.IP=用戶IP
CMS.COMMENT.REGION=用戶歸屬地 CMS.COMMENT.REGION=用戶歸屬地
CMS.COMMENT.CLIENT_TYPE=客戶端類型 CMS.COMMENT.CLIENT_TYPE=客戶端類型
CMS.COMMENT.USER_AGENT=UserAgent CMS.COMMENT.USER_AGENT=UserAgent
CMS.COMMENT.REPLY_LIST=列表 CMS.COMMENT.REPLY_LIST=列表

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-contentcore</artifactId> <artifactId>chestnut-cms-contentcore</artifactId>

View File

@ -84,8 +84,8 @@ public class CatalogMonitoredCache implements IMonitoredCache<CmsCatalog> {
return redisCache.getCacheObject(cacheKeyByAlias(siteId, alias), CmsCatalog.class, supplier); return redisCache.getCacheObject(cacheKeyByAlias(siteId, alias), CmsCatalog.class, supplier);
} }
public void clear(CmsCatalog catalog) { public void clear(Long siteId, Long catalogId, String catalogAlias) {
this.redisCache.deleteObject(cacheKeyById(catalog.getCatalogId())); this.redisCache.deleteObject(cacheKeyById(catalogId));
this.redisCache.deleteObject(cacheKeyByAlias(catalog.getSiteId(), catalog.getAlias())); this.redisCache.deleteObject(cacheKeyByAlias(siteId, catalogAlias));
} }
} }

View File

@ -28,6 +28,7 @@ import com.chestnut.common.log.annotation.Log;
import com.chestnut.common.log.enums.BusinessType; import com.chestnut.common.log.enums.BusinessType;
import com.chestnut.common.security.anno.Priv; import com.chestnut.common.security.anno.Priv;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.LoginUser;
import com.chestnut.common.security.domain.Operator;
import com.chestnut.common.security.web.BaseRestController; import com.chestnut.common.security.web.BaseRestController;
import com.chestnut.common.utils.*; import com.chestnut.common.utils.*;
import com.chestnut.contentcore.core.ICatalogType; import com.chestnut.contentcore.core.ICatalogType;
@ -270,7 +271,7 @@ public class CatalogController extends BaseRestController {
throw ContentCoreErrorCode.CATALOG_CANNOT_PUBLISH.exception(); throw ContentCoreErrorCode.CATALOG_CANNOT_PUBLISH.exception();
} }
AsyncTask task = this.publishService.publishCatalog(catalog, dto.getPublishChild(), dto.getPublishDetail(), AsyncTask task = this.publishService.publishCatalog(catalog, dto.getPublishChild(), dto.getPublishDetail(),
dto.getPublishStatus(), StpAdminUtil.getLoginUser()); dto.getPublishStatus(), Operator.of(StpAdminUtil.getLoginUser()));
return R.ok(task.getTaskId()); return R.ok(task.getTaskId());
} }

View File

@ -25,6 +25,7 @@ import com.chestnut.common.log.annotation.Log;
import com.chestnut.common.log.enums.BusinessType; import com.chestnut.common.log.enums.BusinessType;
import com.chestnut.common.security.anno.Priv; import com.chestnut.common.security.anno.Priv;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.LoginUser;
import com.chestnut.common.security.domain.Operator;
import com.chestnut.common.security.web.BaseRestController; import com.chestnut.common.security.web.BaseRestController;
import com.chestnut.common.security.web.PageRequest; import com.chestnut.common.security.web.PageRequest;
import com.chestnut.common.utils.IdUtils; import com.chestnut.common.utils.IdUtils;
@ -171,12 +172,11 @@ public class ContentController extends BaseRestController {
@PostMapping @PostMapping
public R<?> addContent(@RequestParam("contentType") String contentType, HttpServletRequest request) public R<?> addContent(@RequestParam("contentType") String contentType, HttpServletRequest request)
throws IOException { throws IOException {
LoginUser loginUser = StpAdminUtil.getLoginUser();
IContentType ct = ContentCoreUtils.getContentType(contentType); IContentType ct = ContentCoreUtils.getContentType(contentType);
IContent<?> content = ct.readFrom(request.getInputStream()); IContent<?> content = ct.readFrom(request.getInputStream());
content.setOperator(StpAdminUtil.getLoginUser()); PermissionUtils.checkPermission(CatalogPrivItem.AddContent.getPermissionKey(content.getCatalogId()), loginUser);
PermissionUtils.checkPermission(CatalogPrivItem.AddContent.getPermissionKey(content.getCatalogId()), content.setOperator(Operator.of(loginUser));
content.getOperator());
AsyncTask task = this.contentService.addContent(content); AsyncTask task = this.contentService.addContent(content);
return R.ok(Map.of("taskId", task.getTaskId())); return R.ok(Map.of("taskId", task.getTaskId()));
@ -187,12 +187,13 @@ public class ContentController extends BaseRestController {
@PutMapping @PutMapping
public R<?> saveContent(@RequestParam("contentType") String contentType, HttpServletRequest request) public R<?> saveContent(@RequestParam("contentType") String contentType, HttpServletRequest request)
throws IOException { throws IOException {
LoginUser loginUser = StpAdminUtil.getLoginUser();
IContentType ct = ContentCoreUtils.getContentType(contentType); IContentType ct = ContentCoreUtils.getContentType(contentType);
IContent<?> content = ct.readFrom(request.getInputStream()); IContent<?> content = ct.readFrom(request.getInputStream());
content.setOperator(StpAdminUtil.getLoginUser()); content.setOperator(Operator.of(loginUser));
PermissionUtils.checkPermission(CatalogPrivItem.EditContent.getPermissionKey(content.getCatalogId()), PermissionUtils.checkPermission(CatalogPrivItem.EditContent.getPermissionKey(content.getCatalogId()),
content.getOperator()); StpAdminUtil.getLoginUser());
AsyncTask task = this.contentService.saveContent(content); AsyncTask task = this.contentService.saveContent(content);
return R.ok(Map.of("taskId", task.getTaskId())); return R.ok(Map.of("taskId", task.getTaskId()));

View File

@ -89,13 +89,13 @@ public class CoreController extends BaseRestController {
IInternalDataType internalDataType = ContentCoreUtils.getInternalDataType(dataType); IInternalDataType internalDataType = ContentCoreUtils.getInternalDataType(dataType);
Assert.notNull(internalDataType, () -> ContentCoreErrorCode.UNSUPPORTED_INTERNAL_DATA_TYPE.exception(dataType)); Assert.notNull(internalDataType, () -> ContentCoreErrorCode.UNSUPPORTED_INTERNAL_DATA_TYPE.exception(dataType));
try {
IInternalDataType.RequestData data = new IInternalDataType.RequestData(dataId, pageIndex, publishPipe, IInternalDataType.RequestData data = new IInternalDataType.RequestData(dataId, pageIndex, publishPipe,
true, ServletUtils.getParamMap(ServletUtils.getRequest())); true, ServletUtils.getParamMap(ServletUtils.getRequest()));
String pageData = internalDataType.getPageData(data); try {
response.getWriter().write(pageData); internalDataType.processPageData(data, response.getWriter());
} catch (Exception e) { } catch (Exception e) {
response.getWriter().write(e.getMessage()); // Ignore
e.printStackTrace(response.getWriter());
} }
} }

View File

@ -32,6 +32,7 @@ import com.chestnut.common.utils.ServletUtils;
import com.chestnut.common.utils.StringUtils; import com.chestnut.common.utils.StringUtils;
import com.chestnut.contentcore.core.IResourceType; import com.chestnut.contentcore.core.IResourceType;
import com.chestnut.contentcore.core.impl.InternalDataType_Resource; import com.chestnut.contentcore.core.impl.InternalDataType_Resource;
import com.chestnut.contentcore.core.impl.ResourceType_Image;
import com.chestnut.contentcore.domain.CmsResource; import com.chestnut.contentcore.domain.CmsResource;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.domain.dto.ResourceUploadDTO; import com.chestnut.contentcore.domain.dto.ResourceUploadDTO;
@ -118,7 +119,11 @@ public class ResourceController extends BaseRestController {
if (r.getPath().startsWith("http://") || r.getPath().startsWith("https://")) { if (r.getPath().startsWith("http://") || r.getPath().startsWith("https://")) {
r.setSrc(r.getPath()); r.setSrc(r.getPath());
} else { } else {
if (ResourceType_Image.isImage(r.getResourceType())) {
resourceService.dealDefaultThumbnail(site, r.getInternalUrl(), r::setSrc); resourceService.dealDefaultThumbnail(site, r.getInternalUrl(), r::setSrc);
} else {
r.setSrc(InternalUrlUtils.getActualPreviewUrl(r.getInternalUrl()));
}
} }
}); });
} }
@ -192,7 +197,7 @@ public class ResourceController extends BaseRestController {
return R.ok(resource); return R.ok(resource);
} }
@GetMapping("/downlad/{resourceId}") @GetMapping("/download/{resourceId}")
public void downloadResourceFile(@PathVariable @LongId Long resourceId, HttpServletResponse response) { public void downloadResourceFile(@PathVariable @LongId Long resourceId, HttpServletResponse response) {
CmsResource resource = this.resourceService.getById(resourceId); CmsResource resource = this.resourceService.getById(resourceId);
Assert.notNull(resource, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("resourceId", resourceId)); Assert.notNull(resource, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("resourceId", resourceId));

View File

@ -26,6 +26,7 @@ import com.chestnut.common.log.annotation.Log;
import com.chestnut.common.log.enums.BusinessType; import com.chestnut.common.log.enums.BusinessType;
import com.chestnut.common.security.anno.Priv; import com.chestnut.common.security.anno.Priv;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.LoginUser;
import com.chestnut.common.security.domain.Operator;
import com.chestnut.common.security.web.BaseRestController; import com.chestnut.common.security.web.BaseRestController;
import com.chestnut.common.security.web.PageRequest; import com.chestnut.common.security.web.PageRequest;
import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.Assert;
@ -257,7 +258,7 @@ public class SiteController extends BaseRestController {
Assert.notNull(site, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("siteId", dto.getSiteId())); Assert.notNull(site, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("siteId", dto.getSiteId()));
if (!dto.isPublishIndex()) { if (!dto.isPublishIndex()) {
AsyncTask task = publishService.publishAll(site, dto.getContentStatus(), StpAdminUtil.getLoginUser()); AsyncTask task = publishService.publishAll(site, dto.getContentStatus(), Operator.of(StpAdminUtil.getLoginUser()));
return R.ok(task.getTaskId()); return R.ok(task.getTaskId());
} }
publishService.publishSiteIndex(site); publishService.publishSiteIndex(site);

View File

@ -29,6 +29,7 @@ import com.chestnut.common.security.web.PageRequest;
import com.chestnut.common.staticize.StaticizeService; import com.chestnut.common.staticize.StaticizeService;
import com.chestnut.common.utils.*; import com.chestnut.common.utils.*;
import com.chestnut.common.utils.file.FileExUtils; import com.chestnut.common.utils.file.FileExUtils;
import com.chestnut.common.validation.RegexConsts;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.domain.CmsTemplate; import com.chestnut.contentcore.domain.CmsTemplate;
import com.chestnut.contentcore.domain.dto.TemplateAddDTO; import com.chestnut.contentcore.domain.dto.TemplateAddDTO;
@ -182,7 +183,7 @@ public class TemplateController extends BaseRestController {
fileName = FileExUtils.normalizePath(fileName); fileName = FileExUtils.normalizePath(fileName);
String[] split = fileName.substring(0, fileName.indexOf(suffix)).split("/"); String[] split = fileName.substring(0, fileName.indexOf(suffix)).split("/");
for (String item : split) { for (String item : split) {
if (StringUtils.isEmpty(item) || !Pattern.matches("^[a-zA-Z0-9_]+$", item)) { if (StringUtils.isEmpty(item) || !Pattern.matches(RegexConsts.REGEX_CODE, item)) {
return false; return false;
} }
} }

View File

@ -16,8 +16,9 @@
package com.chestnut.contentcore.core; package com.chestnut.contentcore.core;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chestnut.common.exception.CommonErrorCode; import com.chestnut.common.exception.CommonErrorCode;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.Operator;
import com.chestnut.common.utils.*; import com.chestnut.common.utils.*;
import com.chestnut.contentcore.domain.CmsCatalog; import com.chestnut.contentcore.domain.CmsCatalog;
import com.chestnut.contentcore.domain.CmsContent; import com.chestnut.contentcore.domain.CmsContent;
@ -30,7 +31,6 @@ import com.chestnut.contentcore.listener.event.AfterContentSaveEvent;
import com.chestnut.contentcore.listener.event.BeforeContentSaveEvent; import com.chestnut.contentcore.listener.event.BeforeContentSaveEvent;
import com.chestnut.contentcore.listener.event.OnContentCopyEvent; import com.chestnut.contentcore.listener.event.OnContentCopyEvent;
import com.chestnut.contentcore.listener.event.OnContentMoveEvent; import com.chestnut.contentcore.listener.event.OnContentMoveEvent;
import com.chestnut.contentcore.perms.CatalogPermissionType;
import com.chestnut.contentcore.properties.PublishedContentEditProperty; import com.chestnut.contentcore.properties.PublishedContentEditProperty;
import com.chestnut.contentcore.service.ICatalogService; import com.chestnut.contentcore.service.ICatalogService;
import com.chestnut.contentcore.service.IContentService; import com.chestnut.contentcore.service.IContentService;
@ -40,7 +40,6 @@ import com.chestnut.contentcore.util.ContentCoreUtils;
import com.chestnut.contentcore.util.ContentLogUtils; import com.chestnut.contentcore.util.ContentLogUtils;
import com.chestnut.contentcore.util.InternalUrlUtils; import com.chestnut.contentcore.util.InternalUrlUtils;
import com.chestnut.system.fixed.dict.YesOrNo; import com.chestnut.system.fixed.dict.YesOrNo;
import com.chestnut.system.permission.PermissionUtils;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.MapUtils;
@ -73,7 +72,7 @@ public abstract class AbstractContent<T> implements IContent<T> {
@Setter @Setter
private Map<String, Object> params; private Map<String, Object> params;
private LoginUser operator; private Operator operator;
@Override @Override
public CmsSite getSite() { public CmsSite getSite() {
@ -122,12 +121,12 @@ public abstract class AbstractContent<T> implements IContent<T> {
} }
@Override @Override
public LoginUser getOperator() { public Operator getOperator() {
return this.operator; return this.operator;
} }
@Override @Override
public void setOperator(LoginUser operator) { public void setOperator(Operator operator) {
this.operator = operator; this.operator = operator;
} }
@ -274,9 +273,6 @@ public abstract class AbstractContent<T> implements IContent<T> {
this.getContentEntity().getTitle())) { this.getContentEntity().getTitle())) {
throw ContentCoreErrorCode.TITLE_REPLEAT.exception(); throw ContentCoreErrorCode.TITLE_REPLEAT.exception();
} }
// 校验权限
PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(toCatalog.getCatalogId()), this.getOperator());
CmsContent newContent = new CmsContent(); CmsContent newContent = new CmsContent();
BeanUtils.copyProperties(this.getContentEntity(), newContent, "contentId", "template", "staticPath", "topFlag", BeanUtils.copyProperties(this.getContentEntity(), newContent, "contentId", "template", "staticPath", "topFlag",
"topDate", "isLock", "lockUser"); "topDate", "isLock", "lockUser");
@ -316,8 +312,6 @@ public abstract class AbstractContent<T> implements IContent<T> {
this.getContentEntity().getTitle())) { this.getContentEntity().getTitle())) {
throw ContentCoreErrorCode.TITLE_REPLEAT.exception(); throw ContentCoreErrorCode.TITLE_REPLEAT.exception();
} }
// 校验权限
PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(toCatalog.getCatalogId()), this.getOperator());
CmsCatalog fromCatalog = this.getCatalogService().getCatalog(content.getCatalogId()); CmsCatalog fromCatalog = this.getCatalogService().getCatalog(content.getCatalogId());
// 重置内容信息 // 重置内容信息
@ -377,12 +371,12 @@ public abstract class AbstractContent<T> implements IContent<T> {
} }
LambdaQueryWrapper<CmsContent> q = new LambdaQueryWrapper<CmsContent>() LambdaQueryWrapper<CmsContent> q = new LambdaQueryWrapper<CmsContent>()
.eq(CmsContent::getCatalogId, next.getCatalogId()).gt(CmsContent::getSortFlag, next.getSortFlag()) .eq(CmsContent::getCatalogId, next.getCatalogId()).gt(CmsContent::getSortFlag, next.getSortFlag())
.orderByAsc(CmsContent::getSortFlag).last("limit 1"); .orderByAsc(CmsContent::getSortFlag);
CmsContent prev = this.getContentService().dao().getOne(q); Page<CmsContent> prev = this.getContentService().dao().page(Page.of(1, 1, false), q);
if (prev == null) { if (prev.getRecords().isEmpty()) {
this.content.setSortFlag(SortUtils.getDefaultSortValue()); this.content.setSortFlag(SortUtils.getDefaultSortValue());
} else { } else {
this.content.setSortFlag((next.getSortFlag() + prev.getSortFlag()) / 2); this.content.setSortFlag((next.getSortFlag() + prev.getRecords().get(0).getSortFlag()) / 2);
} }
this.getContentEntity().updateBy(this.getOperatorUName()); this.getContentEntity().updateBy(this.getOperatorUName());
this.getContentService().dao().updateById(content); this.getContentService().dao().updateById(content);

View File

@ -15,7 +15,7 @@
*/ */
package com.chestnut.contentcore.core; package com.chestnut.contentcore.core;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.Operator;
import com.chestnut.contentcore.domain.CmsCatalog; import com.chestnut.contentcore.domain.CmsCatalog;
import com.chestnut.contentcore.domain.CmsContent; import com.chestnut.contentcore.domain.CmsContent;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
@ -95,7 +95,7 @@ public interface IContent<T> {
/** /**
* 获取操作人信息 * 获取操作人信息
*/ */
LoginUser getOperator(); Operator getOperator();
/** /**
* 获取操作人用户名 * 获取操作人用户名
@ -111,7 +111,7 @@ public interface IContent<T> {
/** /**
* 设置操作人信息 * 设置操作人信息
*/ */
void setOperator(LoginUser operator); void setOperator(Operator operator);
/** /**
* 复制内容到指定栏目 * 复制内容到指定栏目

View File

@ -22,6 +22,7 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
import java.util.Map; import java.util.Map;
/** /**
@ -93,6 +94,8 @@ public interface IInternalDataType {
return StringUtils.EMPTY; return StringUtils.EMPTY;
} }
default void processPageData(RequestData requestData, Writer writer) throws TemplateException, IOException {}
/** /**
* 访问链接 * 访问链接
* *

View File

@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
import java.util.Objects; import java.util.Objects;
/** /**
@ -56,6 +57,14 @@ public class InternalDataType_Catalog implements IInternalDataType {
return this.publishService.getCatalogPageData(catalog, requestData, listFlag); return this.publishService.getCatalogPageData(catalog, requestData, listFlag);
} }
@Override
public void processPageData(RequestData requestData, Writer writer) throws TemplateException, IOException {
CmsCatalog catalog = catalogService.getCatalog(requestData.getDataId());
boolean listFlag = YesOrNo.isYes(requestData.getParams().get("list"));
this.publishService.processCatalogPage(catalog, requestData, listFlag, writer);
}
@Override @Override
public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) { public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) {
CmsCatalog catalog = catalogService.getCatalog(internalUrl.getId()); CmsCatalog catalog = catalogService.getCatalog(internalUrl.getId());

View File

@ -27,6 +27,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
import java.util.Objects; import java.util.Objects;
/** /**
@ -58,6 +59,14 @@ public class InternalDataType_Content implements IInternalDataType {
return this.publishService.getContentPageData(content, requestData); return this.publishService.getContentPageData(content, requestData);
} }
@Override
public void processPageData(RequestData requestData, Writer writer) throws TemplateException, IOException {
CmsContent content = contentService.dao().getById(requestData.getDataId());
Assert.notNull(content, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("contentId", requestData.getDataId()));
this.publishService.processContentPage(content, requestData, writer);
}
@Override @Override
public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) { public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) {
CmsContent content = contentService.dao().getById(internalUrl.getId()); CmsContent content = contentService.dao().getById(internalUrl.getId());

View File

@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
/** /**
* 内部数据类型页面组件 * 内部数据类型页面组件
@ -53,6 +54,14 @@ public class InternalDataType_PageWidget implements IInternalDataType {
CmsPageWidget pageWidget = pageWidgetService.getById(data.getDataId()); CmsPageWidget pageWidget = pageWidgetService.getById(data.getDataId());
Assert.notNull(pageWidget, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("pageWidgetId", data.getDataId())); Assert.notNull(pageWidget, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("pageWidgetId", data.getDataId()));
return this.publishService.getPageWidgetPageData(pageWidget, data.getPublishPipeCode(), data.isPreview()); return this.publishService.getPageWidgetPageData(pageWidget, data);
}
@Override
public void processPageData(RequestData data, Writer writer) throws TemplateException, IOException {
CmsPageWidget pageWidget = pageWidgetService.getById(data.getDataId());
Assert.notNull(pageWidget, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("pageWidgetId", data.getDataId()));
this.publishService.processPageWidget(pageWidget, data, writer);
} }
} }

View File

@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
/** /**
* 内部数据类型站点 * 内部数据类型站点
@ -54,6 +55,12 @@ public class InternalDataType_Site implements IInternalDataType {
return this.publishService.getSitePageData(site, requestData); return this.publishService.getSitePageData(site, requestData);
} }
@Override
public void processPageData(RequestData requestData, Writer writer) throws TemplateException, IOException {
CmsSite site = siteService.getSite(requestData.getDataId());
this.publishService.processSitePage(site, requestData, writer);
}
@Override @Override
public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) { public String getLink(InternalURL internalUrl, int pageIndex, String publishPipeCode, boolean isPreview) {
CmsSite site = siteService.getSite(internalUrl.getId()); CmsSite site = siteService.getSite(internalUrl.getId());

View File

@ -15,6 +15,7 @@
*/ */
package com.chestnut.contentcore.core.impl; package com.chestnut.contentcore.core.impl;
import com.chestnut.common.utils.StringUtils;
import com.chestnut.contentcore.core.IPublishPipeProp; import com.chestnut.contentcore.core.IPublishPipeProp;
import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -59,7 +60,10 @@ public class PublishPipeProp_RelativePrefix implements IPublishPipeProp {
public static String getValue(String publishPipeCode, Map<String, Map<String, Object>> publishPipeProps) { public static String getValue(String publishPipeCode, Map<String, Map<String, Object>> publishPipeProps) {
if (Objects.nonNull(publishPipeProps)) { if (Objects.nonNull(publishPipeProps)) {
return MapUtils.getString(publishPipeProps.get(publishPipeCode), KEY); String v = MapUtils.getString(publishPipeProps.get(publishPipeCode), KEY);
if (StringUtils.isNotBlank(v)) {
return v;
}
} }
return DEFAULT_VALUE; return DEFAULT_VALUE;
} }

View File

@ -65,7 +65,8 @@ public class CmsContentDAO extends BackupServiceImpl<CmsContentMapper, CmsConten
} }
LambdaQueryWrapper<CmsContent> q = new LambdaQueryWrapper<CmsContent>() LambdaQueryWrapper<CmsContent> q = new LambdaQueryWrapper<CmsContent>()
.select(StringUtils.isNotEmpty(columns), columns) .select(StringUtils.isNotEmpty(columns), columns)
.eq(CmsContent::getSiteId, siteId); .eq(CmsContent::getSiteId, siteId)
.orderByAsc(CmsContent::getContentId);
return this.page(page, q); return this.page(page, q);
} }
@ -83,7 +84,8 @@ public class CmsContentDAO extends BackupServiceImpl<CmsContentMapper, CmsConten
} }
return this.getBackupMapper().selectPage(page, new LambdaQueryWrapper<BCmsContent>() return this.getBackupMapper().selectPage(page, new LambdaQueryWrapper<BCmsContent>()
.select(StringUtils.isNotEmpty(columns), columns) .select(StringUtils.isNotEmpty(columns), columns)
.eq(BCmsContent::getSiteId, siteId)); .eq(BCmsContent::getSiteId, siteId)
.orderByAsc(BCmsContent::getBackupId));
} }
public void removeBackupBatchByIds(List<Long> backupIds) { public void removeBackupBatchByIds(List<Long> backupIds) {

View File

@ -19,8 +19,8 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.chestnut.common.db.domain.BaseEntity; import com.chestnut.common.db.domain.BaseEntity;
import com.chestnut.common.validation.RegexConsts;
import com.chestnut.system.fixed.dict.EnableOrDisable; import com.chestnut.system.fixed.dict.EnableOrDisable;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
@ -64,7 +64,7 @@ public class CmsPublishPipe extends BaseEntity {
/** /**
* 编码 * 编码
*/ */
@Pattern(regexp = "[A-Za-z0-9_]+") @Pattern(regexp = RegexConsts.REGEX_CODE)
private String code; private String code;
/** /**

View File

@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.chestnut.common.annotation.XComment; import com.chestnut.common.annotation.XComment;
import com.chestnut.common.db.domain.BaseEntity; import com.chestnut.common.db.domain.BaseEntity;
import com.chestnut.common.validation.RegexConsts;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import lombok.Getter; import lombok.Getter;
@ -55,7 +56,7 @@ public class CmsSiteProperty extends BaseEntity {
private String propName; private String propName;
@XComment("属性编码") @XComment("属性编码")
@Pattern(regexp = "[A-Za-z0-9_]+", message = "{VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR}") @Pattern(regexp = RegexConsts.REGEX_CODE)
private String propCode; private String propCode;
@XComment("属性值") @XComment("属性值")

View File

@ -16,7 +16,7 @@
package com.chestnut.contentcore.domain.dto; package com.chestnut.contentcore.domain.dto;
import com.chestnut.common.security.domain.BaseDTO; import com.chestnut.common.security.domain.BaseDTO;
import com.chestnut.common.validation.RegexConsts;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import lombok.Getter; import lombok.Getter;
@ -46,14 +46,14 @@ public class CatalogAddDTO extends BaseDTO {
* 栏目别名 * 栏目别名
*/ */
@NotBlank @NotBlank
@Pattern(regexp = "^[A-Za-z0-9_]+$", message = "栏目别名只能使用大小写字母、数字、下划线组合") @Pattern(regexp = RegexConsts.REGEX_CODE)
private String alias; private String alias;
/** /**
* 栏目目录 * 栏目目录
*/ */
@NotBlank @NotBlank
@Pattern(regexp = "^[A-Za-z0-9_\\/]+$", message = "栏目路径只能使用大小写字母、数字、下划线组合") @Pattern(regexp = RegexConsts.REGEX_PATH)
private String path; private String path;
/** /**

View File

@ -16,6 +16,7 @@
package com.chestnut.contentcore.domain.dto; package com.chestnut.contentcore.domain.dto;
import com.chestnut.common.security.domain.BaseDTO; import com.chestnut.common.security.domain.BaseDTO;
import com.chestnut.common.validation.RegexConsts;
import com.chestnut.contentcore.domain.pojo.PublishPipeProps; import com.chestnut.contentcore.domain.pojo.PublishPipeProps;
import com.chestnut.system.fixed.dict.YesOrNo; import com.chestnut.system.fixed.dict.YesOrNo;
import com.chestnut.system.validator.Dict; import com.chestnut.system.validator.Dict;
@ -54,14 +55,14 @@ public class CatalogUpdateDTO extends BaseDTO {
* 栏目别名 * 栏目别名
*/ */
@NotBlank @NotBlank
@Pattern(regexp = "^[A-Za-z0-9_]+$", message = "栏目别名只能使用大小写字母、数字、下划线组合") @Pattern(regexp = RegexConsts.REGEX_CODE, message = "栏目别名只能使用大小写字母、数字、下划线组合")
private String alias; private String alias;
/** /**
* 栏目目录 * 栏目目录
*/ */
@NotBlank @NotBlank
@Pattern(regexp = "^[A-Za-z0-9_\\/]+$", message = "栏目路径只能使用大小写字母、数字、下划线组合") @Pattern(regexp = RegexConsts.REGEX_PATH, message = "栏目路径只能使用大小写字母、数字、下划线组合")
private String path; private String path;
/* /*

View File

@ -1,3 +1,18 @@
/*
* Copyright 2022-2025 兮玥(190785909@qq.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chestnut.contentcore.enums; package com.chestnut.contentcore.enums;
import com.chestnut.common.i18n.I18nUtils; import com.chestnut.common.i18n.I18nUtils;

View File

@ -60,8 +60,6 @@ public class ContentCoreListener {
private final IPublishService publishService; private final IPublishService publishService;
private final AsyncTaskManager asyncTaskManager;
@EventListener @EventListener
public void beforeSiteDelete(BeforeSiteDeleteEvent event) { public void beforeSiteDelete(BeforeSiteDeleteEvent event) {
CmsSite site = event.getSite(); CmsSite site = event.getSite();
@ -74,27 +72,37 @@ public class ContentCoreListener {
// 删除内容数据 // 删除内容数据
try { try {
long total = this.contentService.dao().countBySiteId(site.getSiteId()); long total = this.contentService.dao().countBySiteId(site.getSiteId());
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除内容数据:" + (i * pageSize) + "/" + total); AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除内容数据:" + (i * pageSize) + "/" + total);
List<Long> contentIds = this.contentService.dao() Page<CmsContent> page = this.contentService.dao().lambdaQuery()
.pageBySiteId( .select(CmsContent::getContentId)
new Page<>(0, pageSize, false), .eq(CmsContent::getSiteId, site.getSiteId())
site.getSiteId(), .gt(CmsContent::getContentId, lastId)
List.of(CmsContent::getContentId) .orderByAsc(CmsContent::getContentId)
).getRecords().stream().map(CmsContent::getContentId).toList(); .page(Page.of(0, pageSize, false));
if (!page.getRecords().isEmpty()) {
List<Long> contentIds = page.getRecords().stream().map(CmsContent::getContentId).toList();
this.contentService.dao().removeBatchByIds(contentIds); this.contentService.dao().removeBatchByIds(contentIds);
lastId = contentIds.get(contentIds.size() - 1);
}
} }
// 删除备份内容数据 // 删除备份内容数据
total = this.contentService.dao().countBackupBySiteId(site.getSiteId()); total = this.contentService.dao().countBackupBySiteId(site.getSiteId());
lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除内容备份数据:" + (i * pageSize) + "/" + total); AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除内容备份数据:" + (i * pageSize) + "/" + total);
List<Long> backupIds = this.contentService.dao() Page<BCmsContent> page = this.contentService.dao().getBackupMapper()
.pageBackupBySiteId( .selectPage(Page.of(0, pageSize, false), new LambdaQueryWrapper<BCmsContent>()
new Page<>(0, pageSize, false), .select(BCmsContent::getBackupId)
site.getSiteId(), .eq(BCmsContent::getSiteId, site.getSiteId())
List.of(BCmsContent::getContentId) .gt(BCmsContent::getBackupId, lastId)
).getRecords().stream().map(BCmsContent::getBackupId).toList(); .orderByAsc(BCmsContent::getBackupId));
if (!page.getRecords().isEmpty()) {
List<Long> backupIds = page.getRecords().stream().map(BCmsContent::getBackupId).toList();
this.contentService.dao().removeBackupBatchByIds(backupIds); this.contentService.dao().removeBackupBatchByIds(backupIds);
lastId = backupIds.get(backupIds.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除内容错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除内容错误:" + e.getMessage());
@ -104,10 +112,20 @@ public class ContentCoreListener {
try { try {
long total = this.resourceService long total = this.resourceService
.count(new LambdaQueryWrapper<CmsResource>().eq(CmsResource::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsResource>().eq(CmsResource::getSiteId, site.getSiteId()));
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除资源数据:" + (i * pageSize) + "/" + total); AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除资源数据:" + (i * pageSize) + "/" + total);
this.resourceService.remove(new LambdaQueryWrapper<CmsResource>() Page<CmsResource> resources = this.resourceService.lambdaQuery()
.eq(CmsResource::getSiteId, site.getSiteId()).last("limit " + pageSize)); .select(CmsResource::getResourceId)
.eq(CmsResource::getSiteId, site.getSiteId())
.gt(CmsResource::getResourceId, lastId)
.orderByAsc(CmsResource::getResourceId)
.page(Page.of(0, pageSize, false));
if (!resources.getRecords().isEmpty()) {
List<Long> resourceIds = resources.getRecords().stream().map(CmsResource::getResourceId).toList();
this.resourceService.removeBatchByIds(resourceIds);
lastId = resourceIds.get(resourceIds.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除资源数据错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除资源数据错误:" + e.getMessage());
@ -117,10 +135,20 @@ public class ContentCoreListener {
try { try {
long total = this.catalogService long total = this.catalogService
.count(new LambdaQueryWrapper<CmsCatalog>().eq(CmsCatalog::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsCatalog>().eq(CmsCatalog::getSiteId, site.getSiteId()));
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除栏目数据:" + (i * pageSize) + "/" + total); AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除栏目数据:" + (i * pageSize) + "/" + total);
this.catalogService.remove(new LambdaQueryWrapper<CmsCatalog>() Page<CmsCatalog> catalogs = this.catalogService.lambdaQuery()
.eq(CmsCatalog::getSiteId, site.getSiteId()).last("limit " + pageSize)); .select(CmsCatalog::getCatalogId)
.eq(CmsCatalog::getSiteId, site.getSiteId())
.gt(CmsCatalog::getCatalogId, lastId)
.orderByAsc(CmsCatalog::getCatalogId)
.page(Page.of(0, pageSize, false));
if (!catalogs.getRecords().isEmpty()) {
List<Long> catalogIds = catalogs.getRecords().stream().map(CmsCatalog::getCatalogId).toList();
this.catalogService.removeBatchByIds(catalogIds);
lastId = catalogIds.get(catalogIds.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除栏目数据错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除栏目数据错误:" + e.getMessage());
@ -130,10 +158,20 @@ public class ContentCoreListener {
try { try {
long total = this.sitePropertyService long total = this.sitePropertyService
.count(new LambdaQueryWrapper<CmsSiteProperty>().eq(CmsSiteProperty::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsSiteProperty>().eq(CmsSiteProperty::getSiteId, site.getSiteId()));
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除站点扩展属性数据:" + (i * pageSize) + "/" + total); AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除站点扩展属性数据:" + (i * pageSize) + "/" + total);
this.sitePropertyService.remove(new LambdaQueryWrapper<CmsSiteProperty>() Page<CmsSiteProperty> siteProperties = this.sitePropertyService.lambdaQuery()
.eq(CmsSiteProperty::getSiteId, site.getSiteId()).last("limit " + pageSize)); .select(CmsSiteProperty::getPropertyId)
.eq(CmsSiteProperty::getSiteId, site.getSiteId())
.gt(CmsSiteProperty::getPropertyId, lastId)
.orderByAsc(CmsSiteProperty::getPropertyId)
.page(Page.of(0, pageSize, false));
if (!siteProperties.getRecords().isEmpty()) {
List<Long> ids = siteProperties.getRecords().stream().map(CmsSiteProperty::getPropertyId).toList();
this.sitePropertyService.removeBatchByIds(ids);
lastId = ids.get(ids.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除站点扩展属性错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除站点扩展属性错误:" + e.getMessage());
@ -143,10 +181,20 @@ public class ContentCoreListener {
try { try {
long total = this.templateService long total = this.templateService
.count(new LambdaQueryWrapper<CmsTemplate>().eq(CmsTemplate::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsTemplate>().eq(CmsTemplate::getSiteId, site.getSiteId()));
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除模板数据:" + (i * pageSize) + "/" + total); AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在删除模板数据:" + (i * pageSize) + "/" + total);
this.templateService.remove(new LambdaQueryWrapper<CmsTemplate>() Page<CmsTemplate> templates = this.templateService.lambdaQuery()
.eq(CmsTemplate::getSiteId, site.getSiteId()).last("limit " + pageSize)); .select(CmsTemplate::getTemplateId)
.eq(CmsTemplate::getSiteId, site.getSiteId())
.gt(CmsTemplate::getTemplateId, lastId)
.orderByAsc(CmsTemplate::getTemplateId)
.page(Page.of(0, pageSize, false));
if (!templates.getRecords().isEmpty()) {
List<Long> ids = templates.getRecords().stream().map(CmsTemplate::getTemplateId).toList();
this.templateService.removeBatchByIds(ids);
lastId = ids.get(ids.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除模板数据错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除模板数据错误:" + e.getMessage());
@ -156,10 +204,21 @@ public class ContentCoreListener {
try { try {
long total = this.contentRelaService long total = this.contentRelaService
.count(new LambdaQueryWrapper<CmsContentRela>().eq(CmsContentRela::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsContentRela>().eq(CmsContentRela::getSiteId, site.getSiteId()));
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), "正在内容关联表数据:" + (i * pageSize) + "/" + total); AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total),
this.contentRelaService.remove(new LambdaQueryWrapper<CmsContentRela>() "正在内容关联表数据:" + (i * pageSize) + "/" + total);
.eq(CmsContentRela::getSiteId, site.getSiteId()).last("limit " + pageSize)); Page<CmsContentRela> templates = this.contentRelaService.lambdaQuery()
.select(CmsContentRela::getRelaContentId)
.eq(CmsContentRela::getSiteId, site.getSiteId())
.gt(CmsContentRela::getRelaContentId, lastId)
.orderByAsc(CmsContentRela::getRelaContentId)
.page(Page.of(0, pageSize, false));
if (!templates.getRecords().isEmpty()) {
List<Long> ids = templates.getRecords().stream().map(CmsContentRela::getRelaContentId).toList();
this.contentRelaService.removeBatchByIds(ids);
lastId = ids.get(ids.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除内容关联表数据错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除内容关联表数据错误:" + e.getMessage());

View File

@ -17,6 +17,7 @@ package com.chestnut.contentcore.service;
import com.chestnut.common.async.AsyncTask; import com.chestnut.common.async.AsyncTask;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.LoginUser;
import com.chestnut.common.security.domain.Operator;
import com.chestnut.contentcore.core.IContent; import com.chestnut.contentcore.core.IContent;
import com.chestnut.contentcore.core.IInternalDataType; import com.chestnut.contentcore.core.IInternalDataType;
import com.chestnut.contentcore.core.IPageWidget; import com.chestnut.contentcore.core.IPageWidget;
@ -27,6 +28,7 @@ import com.chestnut.contentcore.domain.CmsSite;
import freemarker.template.TemplateException; import freemarker.template.TemplateException;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
import java.util.List; import java.util.List;
public interface IPublishService { public interface IPublishService {
@ -50,7 +52,7 @@ public interface IPublishService {
* @param contentStatus 内容状态 * @param contentStatus 内容状态
* @return 结果 * @return 结果
*/ */
AsyncTask publishAll(CmsSite site, final String contentStatus, final LoginUser operator); AsyncTask publishAll(CmsSite site, final String contentStatus, final Operator operator);
/** /**
* 站点首页页面内容 * 站点首页页面内容
@ -64,6 +66,8 @@ public interface IPublishService {
String getSitePageData(CmsSite site, IInternalDataType.RequestData requestData) String getSitePageData(CmsSite site, IInternalDataType.RequestData requestData)
throws IOException, TemplateException; throws IOException, TemplateException;
void processSitePage(CmsSite site, IInternalDataType.RequestData requestData, Writer writer) throws TemplateException, IOException;
/** /**
* 获取栏目模板页面内容 * 获取栏目模板页面内容
* *
@ -77,6 +81,9 @@ public interface IPublishService {
String getCatalogPageData(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag) String getCatalogPageData(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag)
throws IOException, TemplateException; throws IOException, TemplateException;
void processCatalogPage(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag, Writer writer)
throws IOException, TemplateException;
/** /**
* 发布栏目异步任务 * 发布栏目异步任务
* *
@ -87,7 +94,7 @@ public interface IPublishService {
* @return 结果 * @return 结果
*/ */
AsyncTask publishCatalog(CmsCatalog catalog, boolean publishChild, boolean publishDetail, AsyncTask publishCatalog(CmsCatalog catalog, boolean publishChild, boolean publishDetail,
String publishStatus, final LoginUser operator); String publishStatus, final Operator operator);
/** /**
* 获取内容模板页面结果 * 获取内容模板页面结果
@ -108,6 +115,9 @@ public interface IPublishService {
*/ */
void asyncStaticizeContent(IContent<?> content); void asyncStaticizeContent(IContent<?> content);
String processContentPage(CmsContent content, IInternalDataType.RequestData requestData, Writer writer)
throws IOException, TemplateException;
/** /**
* 发布内容 * 发布内容
* *
@ -116,7 +126,7 @@ public interface IPublishService {
*/ */
AsyncTask publishContents(List<CmsContent> contents, LoginUser operator); AsyncTask publishContents(List<CmsContent> contents, LoginUser operator);
void publishContent(CmsContent content, LoginUser operator); void publishContent(CmsContent content, Operator operator);
/** /**
* 获取内容扩展模板解析内容 * 获取内容扩展模板解析内容
@ -135,13 +145,15 @@ public interface IPublishService {
* 获取页面部件模板解析内容 * 获取页面部件模板解析内容
* *
* @param pageWidget 页面部件 * @param pageWidget 页面部件
* @param publishPipeCode 发布通道编码 * @param data 请求数据
* @param isPreview 是否预览
* @return 结果 * @return 结果
* @throws IOException e1 * @throws IOException e1
* @throws TemplateException e2 * @throws TemplateException e2
*/ */
String getPageWidgetPageData(CmsPageWidget pageWidget, String publishPipeCode, boolean isPreview) throws IOException, TemplateException; String getPageWidgetPageData(CmsPageWidget pageWidget, IInternalDataType.RequestData data) throws IOException, TemplateException;
void processPageWidget(CmsPageWidget pageWidget, IInternalDataType.RequestData data, Writer writer)
throws IOException, TemplateException;
/** /**
* 页面部件静态化 * 页面部件静态化

View File

@ -277,6 +277,7 @@ public class CatalogServiceImpl extends ServiceImpl<CmsCatalogMapper, CmsCatalog
checkRedirectUrl(dto.getCatalogType(), dto.getRedirectUrl()); checkRedirectUrl(dto.getCatalogType(), dto.getRedirectUrl());
String oldPath = catalog.getPath(); String oldPath = catalog.getPath();
String oldAlias = catalog.getAlias();
BeanUtils.copyProperties(dto, catalog); BeanUtils.copyProperties(dto, catalog);
// 发布通道数据处理 // 发布通道数据处理
Map<String, Map<String, Object>> publishPipeProps = dto.getPublishPipeDatas().stream() Map<String, Map<String, Object>> publishPipeProps = dto.getPublishPipeDatas().stream()
@ -285,7 +286,7 @@ public class CatalogServiceImpl extends ServiceImpl<CmsCatalogMapper, CmsCatalog
catalog.updateBy(dto.getOperator().getUsername()); catalog.updateBy(dto.getOperator().getUsername());
this.updateById(catalog); this.updateById(catalog);
this.clearCache(catalog); this.clearCache(catalog.getSiteId(), catalog.getCatalogId(), oldAlias);
this.applicationContext.publishEvent(new AfterCatalogSaveEvent(this, catalog, oldPath, dto.getParams())); this.applicationContext.publishEvent(new AfterCatalogSaveEvent(this, catalog, oldPath, dto.getParams()));
return catalog; return catalog;
} }
@ -404,7 +405,11 @@ public class CatalogServiceImpl extends ServiceImpl<CmsCatalogMapper, CmsCatalog
@Override @Override
public void clearCache(CmsCatalog catalog) { public void clearCache(CmsCatalog catalog) {
this.catalogCache.clear(catalog); this.catalogCache.clear(catalog.getSiteId(), catalog.getCatalogId(), catalog.getAlias());
}
private void clearCache(Long siteId, Long catalogId, String alias) {
this.catalogCache.clear(siteId, catalogId, alias);
} }
@Override @Override

View File

@ -21,6 +21,7 @@ import com.chestnut.common.async.AsyncTask;
import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.async.AsyncTaskManager;
import com.chestnut.common.exception.CommonErrorCode; import com.chestnut.common.exception.CommonErrorCode;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.LoginUser;
import com.chestnut.common.security.domain.Operator;
import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.Assert;
import com.chestnut.common.utils.SpringUtils; import com.chestnut.common.utils.SpringUtils;
import com.chestnut.common.utils.StringUtils; import com.chestnut.common.utils.StringUtils;
@ -40,6 +41,7 @@ import com.chestnut.contentcore.exception.ContentCoreErrorCode;
import com.chestnut.contentcore.fixed.dict.ContentOpType; import com.chestnut.contentcore.fixed.dict.ContentOpType;
import com.chestnut.contentcore.fixed.dict.ContentStatus; import com.chestnut.contentcore.fixed.dict.ContentStatus;
import com.chestnut.contentcore.listener.event.*; import com.chestnut.contentcore.listener.event.*;
import com.chestnut.contentcore.perms.CatalogPermissionType;
import com.chestnut.contentcore.perms.CatalogPermissionType.CatalogPrivItem; import com.chestnut.contentcore.perms.CatalogPermissionType.CatalogPrivItem;
import com.chestnut.contentcore.properties.RepeatTitleCheckProperty; import com.chestnut.contentcore.properties.RepeatTitleCheckProperty;
import com.chestnut.contentcore.publish.IContentPathRule; import com.chestnut.contentcore.publish.IContentPathRule;
@ -104,20 +106,16 @@ public class ContentServiceImpl implements IContentService {
} }
@Override @Override
public void deleteContent(CmsContent cmsContent, LoginUser operator, Map<String, Object> params) { public void deleteContent(CmsContent cmsContent, LoginUser loginUser, Map<String, Object> params) {
boolean canDelete = ContentStatus.isDraft(cmsContent.getStatus()) || ContentStatus.isOffline(cmsContent.getStatus()); boolean canDelete = ContentStatus.isDraft(cmsContent.getStatus()) || ContentStatus.isOffline(cmsContent.getStatus());
Assert.isTrue(canDelete, ContentCoreErrorCode.DEL_CONTENT_ERR::exception); Assert.isTrue(canDelete, ContentCoreErrorCode.DEL_CONTENT_ERR::exception);
IContentType contentType = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContentType contentType = ContentCoreUtils.getContentType(cmsContent.getContentType());
IContent<?> content = contentType.loadContent(cmsContent); IContent<?> content = contentType.loadContent(cmsContent);
content.setOperator(operator); content.setOperator(Operator.of(loginUser));
content.setParams(params); content.setParams(params);
transactionTemplate.executeWithoutResult(transactionStatus -> deleteContent0(content)); transactionTemplate.executeWithoutResult(transactionStatus -> deleteContent0(content));
SpringUtils.publishEvent(new AfterContentDeleteEvent(this, content)); SpringUtils.publishEvent(new AfterContentDeleteEvent(this, content));
}
private void deleteContent0(IContent<?> content) {
content.delete();
// 删除映射内容 // 删除映射内容
List<CmsContent> mappingList = this.dao().lambdaQuery() List<CmsContent> mappingList = this.dao().lambdaQuery()
.eq(CmsContent::getCopyType, ContentCopyType.Mapping) .eq(CmsContent::getCopyType, ContentCopyType.Mapping)
@ -126,15 +124,21 @@ public class ContentServiceImpl implements IContentService {
for (CmsContent mappingContent : mappingList) { for (CmsContent mappingContent : mappingList) {
log.debug("CC.Content[{}].delete: mapping content delete", content.getContentEntity().getContentId()); log.debug("CC.Content[{}].delete: mapping content delete", content.getContentEntity().getContentId());
try { try {
deleteContent(mappingContent, content.getOperator(), Map.of( IContentType mappingContentType = ContentCoreUtils.getContentType(cmsContent.getContentType());
IContent.PARAM_IS_DELETE_BY_CATALOG, content.getParams().get(IContent.PARAM_IS_DELETE_BY_CATALOG) IContent<?> mappingIContent = mappingContentType.loadContent(cmsContent);
)); mappingIContent.setOperator(Operator.of(loginUser));
mappingIContent.setParams(params);
transactionTemplate.executeWithoutResult(transactionStatus -> deleteContent0(mappingIContent));
SpringUtils.publishEvent(new AfterContentDeleteEvent(this, mappingIContent));
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.DELETING_MAPPING_CONTENT.locale( AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.DELETING_MAPPING_CONTENT.locale(
mappingContent.getTitle(), mappingContent.getContentId())); mappingContent.getTitle(), mappingContent.getContentId()));
} }
} }
// 删除相关内容 }
private void deleteContent0(IContent<?> content) {
content.delete();
contentRelaService.onContentDelete(content.getContentEntity().getContentId()); contentRelaService.onContentDelete(content.getContentEntity().getContentId());
// TODO 删除内容历史版本 // TODO 删除内容历史版本
} }
@ -170,13 +174,13 @@ public class ContentServiceImpl implements IContentService {
} }
@Override @Override
public void deleteContentsByCatalog(CmsCatalog catalog, boolean includeChild, LoginUser operator) { public void deleteContentsByCatalog(CmsCatalog catalog, boolean includeChild, LoginUser loginUser) {
long pageSize = 100; long pageSize = 100;
long total = this.dao().lambdaQuery() long total = this.dao().lambdaQuery()
.eq(!includeChild, CmsContent::getCatalogId, catalog.getCatalogId()) .eq(!includeChild, CmsContent::getCatalogId, catalog.getCatalogId())
.likeRight(includeChild, CmsContent::getCatalogAncestors, catalog.getAncestors()) .likeRight(includeChild, CmsContent::getCatalogAncestors, catalog.getAncestors())
.count(); .count();
Operator operator = Operator.of(loginUser);
for (int i = 0; i * pageSize < total; i++) { for (int i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize / total), AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize / total),
"正在栏目删除内容:" + (i * pageSize) + " / " + total); "正在栏目删除内容:" + (i * pageSize) + " / " + total);
@ -307,6 +311,8 @@ public class ContentServiceImpl implements IContentService {
CmsContent cmsContent = dao().getById(contentId); CmsContent cmsContent = dao().getById(contentId);
if (Objects.nonNull(cmsContent)) { if (Objects.nonNull(cmsContent)) {
for (CmsCatalog catalog : catalogs) { for (CmsCatalog catalog : catalogs) {
// 校验权限
PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(catalog.getCatalogId()), dto.getOperator());
CmsContent copyContent = copy0(cmsContent, catalog, dto.getCopyType(), dto.getOperator()); CmsContent copyContent = copy0(cmsContent, catalog, dto.getCopyType(), dto.getOperator());
SpringUtils.publishEvent(new AfterContentCopyEvent(this, cmsContent, copyContent)); SpringUtils.publishEvent(new AfterContentCopyEvent(this, cmsContent, copyContent));
} }
@ -321,12 +327,12 @@ public class ContentServiceImpl implements IContentService {
} }
private CmsContent copy0(CmsContent cmsContent, CmsCatalog toCatalog, Integer copyType, LoginUser operator) { private CmsContent copy0(CmsContent cmsContent, CmsCatalog toCatalog, Integer copyType, LoginUser loginUser) {
AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.COPYING_CONTENT.locale(AsyncTaskManager.getLocale(), AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.COPYING_CONTENT.locale(AsyncTaskManager.getLocale(),
cmsContent.getTitle(), toCatalog.getName())); cmsContent.getTitle(), toCatalog.getName()));
IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType());
IContent<?> content = ct.loadContent(cmsContent); IContent<?> content = ct.loadContent(cmsContent);
content.setOperator(operator); content.setOperator(Operator.of(loginUser));
return transactionTemplate.execute(transactionStatus -> content.copyTo(toCatalog, copyType)); return transactionTemplate.execute(transactionStatus -> content.copyTo(toCatalog, copyType));
} }
@ -357,7 +363,9 @@ public class ContentServiceImpl implements IContentService {
} }
@Override @Override
public void moveContent(CmsContent cmsContent, CmsCatalog toCatalog, LoginUser operator) { public void moveContent(CmsContent cmsContent, CmsCatalog toCatalog, LoginUser loginUser) {
// 校验权限
PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(toCatalog.getCatalogId()), loginUser);
if (cmsContent.getCatalogId().equals(toCatalog.getCatalogId())) { if (cmsContent.getCatalogId().equals(toCatalog.getCatalogId())) {
log.warn("Cannot move content to source catalog!"); log.warn("Cannot move content to source catalog!");
return; return;
@ -366,7 +374,7 @@ public class ContentServiceImpl implements IContentService {
cmsContent.getTitle(), toCatalog.getName())); cmsContent.getTitle(), toCatalog.getName()));
IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType());
IContent<?> content = ct.loadContent(cmsContent); IContent<?> content = ct.loadContent(cmsContent);
content.setOperator(operator); content.setOperator(Operator.of(loginUser));
transactionTemplate.executeWithoutResult(transactionStatus -> content.moveTo(toCatalog)); transactionTemplate.executeWithoutResult(transactionStatus -> content.moveTo(toCatalog));
} }
@ -376,7 +384,7 @@ public class ContentServiceImpl implements IContentService {
for (CmsContent c : contents) { for (CmsContent c : contents) {
IContentType ct = ContentCoreUtils.getContentType(c.getContentType()); IContentType ct = ContentCoreUtils.getContentType(c.getContentType());
IContent<?> content = ct.loadContent(c); IContent<?> content = ct.loadContent(c);
content.setOperator(dto.getOperator()); content.setOperator(Operator.of(dto.getOperator()));
transactionTemplate.executeWithoutResult(transactionStatus -> content.setTop(dto.getTopEndTime())); transactionTemplate.executeWithoutResult(transactionStatus -> content.setTop(dto.getTopEndTime()));
SpringUtils.publishEvent(new AfterContentTopSetEvent(this, content)); SpringUtils.publishEvent(new AfterContentTopSetEvent(this, content));
} }
@ -391,7 +399,7 @@ public class ContentServiceImpl implements IContentService {
for (CmsContent c : contents) { for (CmsContent c : contents) {
IContentType ct = ContentCoreUtils.getContentType(c.getContentType()); IContentType ct = ContentCoreUtils.getContentType(c.getContentType());
IContent<?> content = ct.loadContent(c); IContent<?> content = ct.loadContent(c);
content.setOperator(operator); content.setOperator(Operator.of(operator));
transactionTemplate.executeWithoutResult(transactionStatus -> content.cancelTop()); transactionTemplate.executeWithoutResult(transactionStatus -> content.cancelTop());
SpringUtils.publishEvent(new AfterContentTopCancelEvent(this, content)); SpringUtils.publishEvent(new AfterContentTopCancelEvent(this, content));
} }
@ -420,11 +428,11 @@ public class ContentServiceImpl implements IContentService {
offline0(cmsContent, operator, LocaleContextHolder.getLocale()); offline0(cmsContent, operator, LocaleContextHolder.getLocale());
} }
private void offline0(CmsContent cmsContent, LoginUser operator, Locale locale) { private void offline0(CmsContent cmsContent, LoginUser loginUser, Locale locale) {
AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.OFFLINE_CONTENT.locale(locale, cmsContent.getTitle())); AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.OFFLINE_CONTENT.locale(locale, cmsContent.getTitle()));
IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType());
IContent<?> content = ct.loadContent(cmsContent); IContent<?> content = ct.loadContent(cmsContent);
content.setOperator(operator); content.setOperator(Operator.of(loginUser));
transactionTemplate.executeWithoutResult(transactionStatus -> content.offline()); transactionTemplate.executeWithoutResult(transactionStatus -> content.offline());
// 映射关联内容同步下线 // 映射关联内容同步下线
if (!cmsContent.isLinkContent() && !ContentCopyType.isMapping(cmsContent.getCopyType())) { if (!cmsContent.isLinkContent() && !ContentCopyType.isMapping(cmsContent.getCopyType())) {
@ -435,7 +443,7 @@ public class ContentServiceImpl implements IContentService {
for (CmsContent c : mappingList) { for (CmsContent c : mappingList) {
log.debug("CC.Content[{}].offline: mapping content offline", cmsContent.getContentId()); log.debug("CC.Content[{}].offline: mapping content offline", cmsContent.getContentId());
AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.OFFLINE_MAPPING_CONTENT.locale(locale, c.getTitle())); AsyncTaskManager.setTaskTenPercentProgressInfo(ContentTips.OFFLINE_MAPPING_CONTENT.locale(locale, c.getTitle()));
offline0(c, operator, locale); offline0(c, loginUser, locale);
} }
} }
SpringUtils.publishEvent(new AfterContentOfflineEvent(this, content)); SpringUtils.publishEvent(new AfterContentOfflineEvent(this, content));
@ -447,7 +455,7 @@ public class ContentServiceImpl implements IContentService {
CmsContent c = this.dao().getById(dto.getContentId()); CmsContent c = this.dao().getById(dto.getContentId());
IContentType ct = ContentCoreUtils.getContentType(c.getContentType()); IContentType ct = ContentCoreUtils.getContentType(c.getContentType());
IContent<?> content = ct.loadContent(c); IContent<?> content = ct.loadContent(c);
content.setOperator(dto.getOperator()); content.setOperator(Operator.of(dto.getOperator()));
content.sort(dto.getTargetContentId()); content.sort(dto.getTargetContentId());
} }
@ -460,10 +468,10 @@ public class ContentServiceImpl implements IContentService {
} }
@Override @Override
public void toPublish(CmsContent cmsContent, LoginUser operator) { public void toPublish(CmsContent cmsContent, LoginUser loginUser) {
IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType()); IContentType ct = ContentCoreUtils.getContentType(cmsContent.getContentType());
IContent<?> content = ct.loadContent(cmsContent); IContent<?> content = ct.loadContent(cmsContent);
content.setOperator(operator); content.setOperator(Operator.of(loginUser));
transactionTemplate.executeWithoutResult(transactionStatus -> content.toPublish()); transactionTemplate.executeWithoutResult(transactionStatus -> content.toPublish());
SpringUtils.publishEvent(new AfterContentToPublishEvent(this, content)); SpringUtils.publishEvent(new AfterContentToPublishEvent(this, content));
} }

View File

@ -15,12 +15,12 @@
*/ */
package com.chestnut.contentcore.service.impl; package com.chestnut.contentcore.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.async.AsyncTaskManager;
import com.chestnut.common.exception.CommonErrorCode; import com.chestnut.common.exception.CommonErrorCode;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.LoginUser;
import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.Assert;
import com.chestnut.common.utils.IdUtils;
import com.chestnut.contentcore.cache.PageWidgetMonitoredCache; import com.chestnut.contentcore.cache.PageWidgetMonitoredCache;
import com.chestnut.contentcore.core.IPageWidget; import com.chestnut.contentcore.core.IPageWidget;
import com.chestnut.contentcore.core.IPageWidgetType; import com.chestnut.contentcore.core.IPageWidgetType;
@ -76,11 +76,10 @@ public class PageWidgetServiceImpl extends ServiceImpl<CmsPageWidgetMapper, CmsP
@Override @Override
public boolean checkCodeUnique(Long siteId, String code, Long pageWidgetId) { public boolean checkCodeUnique(Long siteId, String code, Long pageWidgetId) {
LambdaQueryWrapper<CmsPageWidget> q = new LambdaQueryWrapper<CmsPageWidget>().eq(CmsPageWidget::getCode, code) return this.lambdaQuery().eq(CmsPageWidget::getCode, code)
.eq(CmsPageWidget::getSiteId, siteId) .eq(CmsPageWidget::getSiteId, siteId)
.ne(pageWidgetId != null && pageWidgetId > 0, CmsPageWidget::getPageWidgetId, pageWidgetId) .ne(IdUtils.validate(pageWidgetId), CmsPageWidget::getPageWidgetId, pageWidgetId)
.last("limit 1"); .count() == 0;
return this.count(q) == 0;
} }
@Override @Override

View File

@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chestnut.common.async.AsyncTask; import com.chestnut.common.async.AsyncTask;
import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.async.AsyncTaskManager;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.LoginUser;
import com.chestnut.common.security.domain.Operator;
import com.chestnut.common.staticize.StaticizeService; import com.chestnut.common.staticize.StaticizeService;
import com.chestnut.common.staticize.core.TemplateContext; import com.chestnut.common.staticize.core.TemplateContext;
import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.Assert;
@ -61,6 +62,7 @@ import org.springframework.transaction.support.TransactionTemplate;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer;
import java.util.*; import java.util.*;
@Service @Service
@ -92,6 +94,14 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
@Override @Override
public String getSitePageData(CmsSite site, IInternalDataType.RequestData requestData) public String getSitePageData(CmsSite site, IInternalDataType.RequestData requestData)
throws IOException, TemplateException { throws IOException, TemplateException {
try (StringWriter writer = new StringWriter()) {
processSitePage(site, requestData, writer);
return writer.toString();
}
}
@Override
public void processSitePage(CmsSite site, IInternalDataType.RequestData requestData, Writer writer) throws TemplateException, IOException {
String indexTemplate = site.getIndexTemplate(requestData.getPublishPipeCode()); String indexTemplate = site.getIndexTemplate(requestData.getPublishPipeCode());
File templateFile = this.templateService.findTemplateFile(site, indexTemplate, requestData.getPublishPipeCode()); File templateFile = this.templateService.findTemplateFile(site, indexTemplate, requestData.getPublishPipeCode());
if (Objects.isNull(templateFile)) { if (Objects.isNull(templateFile)) {
@ -108,9 +118,8 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
templateType.initTemplateData(site.getSiteId(), context); templateType.initTemplateData(site.getSiteId(), context);
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
try (StringWriter writer = new StringWriter()) { try {
this.staticizeService.process(context, writer); this.staticizeService.process(context, writer);
return writer.toString();
} finally { } finally {
logger.debug("[{}]Parse index template: {}\t, cost: {}ms", requestData.getPublishPipeCode(), site.getName(), System.currentTimeMillis() - s); logger.debug("[{}]Parse index template: {}\t, cost: {}ms", requestData.getPublishPipeCode(), site.getName(), System.currentTimeMillis() - s);
} }
@ -126,7 +135,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
} }
@Override @Override
public AsyncTask publishAll(CmsSite site, final String contentStatus, final LoginUser operator) { public AsyncTask publishAll(CmsSite site, final String contentStatus, final Operator operator) {
AsyncTask asyncTask = new AsyncTask() { AsyncTask asyncTask = new AsyncTask() {
@Override @Override
@ -162,7 +171,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
content.setContentEntity(xContent); content.setContentEntity(xContent);
content.setOperator(operator); content.setOperator(operator);
Boolean published = transactionTemplate.execute(callback -> content.publish()); Boolean published = transactionTemplate.execute(callback -> content.publish());
if (published) { if (Boolean.TRUE.equals(published)) {
applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content)); applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content));
} }
this.checkInterrupt(); this.checkInterrupt();
@ -200,6 +209,15 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
@Override @Override
public String getCatalogPageData(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag) public String getCatalogPageData(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag)
throws IOException, TemplateException { throws IOException, TemplateException {
try (StringWriter writer = new StringWriter()) {
this.processCatalogPage(catalog, requestData, listFlag, writer);
return writer.toString();
}
}
@Override
public void processCatalogPage(CmsCatalog catalog, IInternalDataType.RequestData requestData, boolean listFlag, Writer writer)
throws IOException, TemplateException {
if (CatalogType_Link.ID.equals(catalog.getCatalogType())) { if (CatalogType_Link.ID.equals(catalog.getCatalogType())) {
throw new RuntimeException("链接类型栏目无独立页面:" + catalog.getName()); throw new RuntimeException("链接类型栏目无独立页面:" + catalog.getName());
} }
@ -240,9 +258,8 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
templateContext.setFirstFileName(catalogLink); templateContext.setFirstFileName(catalogLink);
templateContext.setOtherFileName(TemplateUtils.appendPageIndexParam(catalogLink, TemplateContext.PlaceHolder_PageNo)); templateContext.setOtherFileName(TemplateUtils.appendPageIndexParam(catalogLink, TemplateContext.PlaceHolder_PageNo));
} }
try (StringWriter writer = new StringWriter()) { try {
this.staticizeService.process(templateContext, writer); this.staticizeService.process(templateContext, writer);
return writer.toString();
} finally { } finally {
logger.debug("[{}]栏目页模板解析:{},耗时:{}ms", requestData.getPublishPipeCode(), catalog.getName(), logger.debug("[{}]栏目页模板解析:{},耗时:{}ms", requestData.getPublishPipeCode(), catalog.getName(),
(System.currentTimeMillis() - s)); (System.currentTimeMillis() - s));
@ -251,7 +268,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
@Override @Override
public AsyncTask publishCatalog(CmsCatalog catalog, boolean publishChild, boolean publishDetail, public AsyncTask publishCatalog(CmsCatalog catalog, boolean publishChild, boolean publishDetail,
final String publishStatus, final LoginUser operator) { final String publishStatus, final Operator operator) {
List<CmsPublishPipe> publishPipes = publishPipeService.getPublishPipes(catalog.getSiteId()); List<CmsPublishPipe> publishPipes = publishPipeService.getPublishPipes(catalog.getSiteId());
Assert.isTrue(!publishPipes.isEmpty(), ContentCoreErrorCode.NO_PUBLISHPIPE::exception); Assert.isTrue(!publishPipes.isEmpty(), ContentCoreErrorCode.NO_PUBLISHPIPE::exception);
@ -296,7 +313,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
content.setContentEntity(xContent); content.setContentEntity(xContent);
content.setOperator(operator); content.setOperator(operator);
Boolean published = transactionTemplate.execute(callback -> content.publish()); Boolean published = transactionTemplate.execute(callback -> content.publish());
if (published) { if (Boolean.TRUE.equals(published)) {
applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content)); applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content));
} }
this.checkInterrupt(); this.checkInterrupt();
@ -386,23 +403,64 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
templateContext.setFirstFileName(contentLink); templateContext.setFirstFileName(contentLink);
templateContext.setOtherFileName(TemplateUtils.appendPageIndexParam(contentLink, TemplateContext.PlaceHolder_PageNo)); templateContext.setOtherFileName(TemplateUtils.appendPageIndexParam(contentLink, TemplateContext.PlaceHolder_PageNo));
// staticize // staticize
this.staticizeService.process(templateContext, writer); this.processContentPage(content, requestData, writer);
logger.debug("[{}][{}]内容模板解析:{},耗时:{}", requestData.getPublishPipeCode(), contentType.getId(), content.getTitle(), logger.debug("[{}][{}]内容模板解析:{},耗时:{}", requestData.getPublishPipeCode(), contentType.getId(), content.getTitle(),
System.currentTimeMillis() - s); System.currentTimeMillis() - s);
return writer.toString(); return writer.toString();
} }
} }
@Override
public String processContentPage(CmsContent content, IInternalDataType.RequestData requestData, Writer writer)
throws IOException, TemplateException {
CmsSite site = this.siteService.getById(content.getSiteId());
CmsCatalog catalog = this.catalogService.getCatalog(content.getCatalogId());
if (content.isLinkContent()) {
throw new RuntimeException("标题内容:" + content.getTitle() + ",跳转链接:" + content.getRedirectUrl());
}
// 查找模板
final String detailTemplate = getDetailTemplate(site, catalog, content, requestData.getPublishPipeCode());
File templateFile = this.templateService.findTemplateFile(site, detailTemplate, requestData.getPublishPipeCode());
Assert.notNull(templateFile,
() -> ContentCoreErrorCode.TEMPLATE_EMPTY.exception(requestData.getPublishPipeCode(), detailTemplate));
IContentType contentType = ContentCoreUtils.getContentType(content.getContentType());
long s = System.currentTimeMillis();
// 生成静态页面
try {
// 模板ID = 通道:站点目录:模板文件名
String templateKey = SiteUtils.getTemplateKey(site, requestData.getPublishPipeCode(), detailTemplate);
TemplateContext templateContext = new TemplateContext(templateKey, requestData.isPreview(), requestData.getPublishPipeCode());
templateContext.setPageIndex(requestData.getPageIndex());
templateContext.getVariables().put(TemplateUtils.TemplateVariable_Request, Objects.requireNonNullElse(requestData.getParams(), Map.of()));
// init template datamode
TemplateUtils.initGlobalVariables(site, templateContext);
// init templateType data to datamode
ITemplateType templateType = this.templateService.getTemplateType(ContentTemplateType.TypeId);
templateType.initTemplateData(content.getContentId(), templateContext);
// 分页链接
String contentLink = this.contentService.getContentLink(content, 1, requestData.getPublishPipeCode(), requestData.isPreview());
templateContext.setFirstFileName(contentLink);
templateContext.setOtherFileName(TemplateUtils.appendPageIndexParam(contentLink, TemplateContext.PlaceHolder_PageNo));
// staticize
this.staticizeService.process(templateContext, writer);
return writer.toString();
} finally {
logger.debug("[{}][{}]内容模板解析:{},耗时:{}", requestData.getPublishPipeCode(), contentType.getId(), content.getTitle(),
System.currentTimeMillis() - s);
}
}
/** /**
* 内容发布 * 内容发布
*/ */
@Override @Override
public AsyncTask publishContents(List<CmsContent> contents, LoginUser operator) { public AsyncTask publishContents(List<CmsContent> contents, LoginUser loginUser) {
Locale locale = LocaleContextHolder.getLocale(); Locale locale = LocaleContextHolder.getLocale();
AsyncTask task = new AsyncTask() { AsyncTask task = new AsyncTask() {
@Override @Override
public void run0() { public void run0() {
publishContents0(contents, operator, locale); publishContents0(contents, Operator.of(loginUser), locale);
} }
}; };
task.setType("PublishContents"); task.setType("PublishContents");
@ -411,11 +469,11 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
} }
@Override @Override
public void publishContent(CmsContent content, LoginUser operator) { public void publishContent(CmsContent content, Operator operator) {
publishContents0(List.of(content), operator, null); publishContents0(List.of(content), operator, null);
} }
private void publishContents0(List<CmsContent> contents, LoginUser operator, Locale locale) { private void publishContents0(List<CmsContent> contents, Operator operator, Locale locale) {
if (contents.isEmpty()) { if (contents.isEmpty()) {
return; return;
} }
@ -427,7 +485,7 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
IContent<?> content = contentType.loadContent(cmsContent); IContent<?> content = contentType.loadContent(cmsContent);
content.setOperator(operator); content.setOperator(operator);
Boolean published = transactionTemplate.execute(callback -> content.publish()); Boolean published = transactionTemplate.execute(callback -> content.publish());
if (published) { if (Boolean.TRUE.equals(published)) {
applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content)); applicationContext.publishEvent(new AfterContentPublishEvent(contentType, content));
} }
catalogIds.add(cmsContent.getCatalogId()); catalogIds.add(cmsContent.getCatalogId());
@ -517,20 +575,29 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
} }
@Override @Override
public String getPageWidgetPageData(CmsPageWidget pageWidget, String publishPipeCode, boolean isPreview) public String getPageWidgetPageData(CmsPageWidget pageWidget, IInternalDataType.RequestData data)
throws IOException, TemplateException {
try (StringWriter writer = new StringWriter()) {
processPageWidget(pageWidget, data, writer);
return writer.toString();
}
}
@Override
public void processPageWidget(CmsPageWidget pageWidget, IInternalDataType.RequestData data, Writer writer)
throws IOException, TemplateException { throws IOException, TemplateException {
CmsSite site = this.siteService.getById(pageWidget.getSiteId()); CmsSite site = this.siteService.getById(pageWidget.getSiteId());
String template = MapUtils.getString(pageWidget.getTemplates(), publishPipeCode, ""); String template = MapUtils.getString(pageWidget.getTemplates(), data.getPublishPipeCode(), "");
File templateFile = this.templateService.findTemplateFile(site, template, File templateFile = this.templateService.findTemplateFile(site, template,
publishPipeCode); data.getPublishPipeCode());
Assert.notNull(templateFile, () -> ContentCoreErrorCode.TEMPLATE_EMPTY.exception(template)); Assert.notNull(templateFile, () -> ContentCoreErrorCode.TEMPLATE_EMPTY.exception(template));
// 生成静态页面 // 生成静态页面
try (StringWriter writer = new StringWriter()) {
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
try {
// 模板ID = 通道:站点目录:模板文件名 // 模板ID = 通道:站点目录:模板文件名
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, template); String templateKey = SiteUtils.getTemplateKey(site, data.getPublishPipeCode(), template);
TemplateContext templateContext = new TemplateContext(templateKey, isPreview, publishPipeCode); TemplateContext templateContext = new TemplateContext(templateKey, data.isPreview(), data.getPublishPipeCode());
// init template global variables // init template global variables
TemplateUtils.initGlobalVariables(site, templateContext); TemplateUtils.initGlobalVariables(site, templateContext);
templateContext.getVariables().put(TemplateUtils.TemplateVariable_PageWidget, pageWidget); templateContext.getVariables().put(TemplateUtils.TemplateVariable_PageWidget, pageWidget);
@ -539,9 +606,9 @@ public class PublishServiceImpl implements IPublishService, ApplicationContextAw
templateType.initTemplateData(site.getSiteId(), templateContext); templateType.initTemplateData(site.getSiteId(), templateContext);
// staticize // staticize
this.staticizeService.process(templateContext, writer); this.staticizeService.process(templateContext, writer);
logger.debug("[{}]页面部件【{}#{}】模板解析耗时:{}ms", publishPipeCode, pageWidget.getName(), } finally {
logger.debug("[{}]页面部件【{}#{}】模板解析耗时:{}ms", data.getPublishPipeCode(), pageWidget.getName(),
pageWidget.getCode(), System.currentTimeMillis() - s); pageWidget.getCode(), System.currentTimeMillis() - s);
return writer.toString();
} }
} }

View File

@ -15,8 +15,7 @@
*/ */
package com.chestnut.contentcore.template.exception; package com.chestnut.contentcore.template.exception;
import com.chestnut.common.utils.StringUtils; import com.chestnut.common.i18n.I18nUtils;
import freemarker.core.Environment; import freemarker.core.Environment;
import freemarker.template.TemplateException; import freemarker.template.TemplateException;
@ -24,7 +23,7 @@ public class CatalogNotFoundException extends TemplateException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public CatalogNotFoundException(String tag, long catalogId, String alias, Environment env) { public CatalogNotFoundException(long catalogId, String alias, Environment env) {
super(StringUtils.messageFormat("<@{0}>[id: {1}, alias: {2}]", tag, catalogId, alias), env); super(I18nUtils.parse("FREEMARKER.ERR.CatalogNotFound", env.getLocale(), catalogId, alias), env);
} }
} }

View File

@ -85,7 +85,7 @@ public class CmsCatalogTag extends AbstractListTag {
} }
String level = MapUtils.getString(attrs, ATTR_LEVEL); String level = MapUtils.getString(attrs, ATTR_LEVEL);
if (!CatalogTagLevel.isRoot(level) && Objects.isNull(catalog)) { if (!CatalogTagLevel.isRoot(level) && Objects.isNull(catalog)) {
throw new CatalogNotFoundException(getTagName(), catalogId, alias, env); throw new CatalogNotFoundException(catalogId, alias, env);
} }
String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition); String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition);

View File

@ -25,10 +25,16 @@ import com.chestnut.common.staticize.tag.TagAttr;
import com.chestnut.common.staticize.tag.TagAttrOption; import com.chestnut.common.staticize.tag.TagAttrOption;
import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.Assert;
import com.chestnut.common.utils.StringUtils; import com.chestnut.common.utils.StringUtils;
import com.chestnut.contentcore.domain.CmsCatalog;
import com.chestnut.contentcore.domain.CmsContent; import com.chestnut.contentcore.domain.CmsContent;
import com.chestnut.contentcore.domain.vo.TagContentVO; import com.chestnut.contentcore.domain.vo.TagContentVO;
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
import com.chestnut.contentcore.fixed.dict.ContentStatus; import com.chestnut.contentcore.fixed.dict.ContentStatus;
import com.chestnut.contentcore.service.ICatalogService;
import com.chestnut.contentcore.service.IContentService; import com.chestnut.contentcore.service.IContentService;
import com.chestnut.contentcore.template.exception.CatalogNotFoundException;
import com.chestnut.contentcore.util.CatalogUtils;
import com.chestnut.contentcore.util.TemplateUtils;
import freemarker.core.Environment; import freemarker.core.Environment;
import freemarker.template.TemplateException; import freemarker.template.TemplateException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -37,6 +43,7 @@ import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
@ -47,35 +54,82 @@ public class CmsContentClosestTag extends AbstractListTag {
public final static String DESC = "{FREEMARKER.TAG." + TAG_NAME + ".DESC}"; public final static String DESC = "{FREEMARKER.TAG." + TAG_NAME + ".DESC}";
public final static String ATTR_USAGE_CONTENT_ID = "{FREEMARKER.TAG." + TAG_NAME + ".contentId}"; public final static String ATTR_USAGE_CONTENT_ID = "{FREEMARKER.TAG." + TAG_NAME + ".contentId}";
public final static String ATTR_USAGE_TYPE = "{FREEMARKER.TAG." + TAG_NAME + ".type}"; public final static String ATTR_USAGE_TYPE = "{FREEMARKER.TAG." + TAG_NAME + ".type}";
public final static String ATTR_USAGE_SORT = "{FREEMARKER.TAG." + TAG_NAME + ".sort}";
public final static String ATTR_OPTION_TYPE_PREV = "{FREEMARKER.TAG." + TAG_NAME + ".type.Prev}"; public final static String ATTR_OPTION_TYPE_PREV = "{FREEMARKER.TAG." + TAG_NAME + ".type.Prev}";
public final static String ATTR_OPTION_TYPE_NEXT = "{FREEMARKER.TAG." + TAG_NAME + ".type.Next}"; public final static String ATTR_OPTION_TYPE_NEXT = "{FREEMARKER.TAG." + TAG_NAME + ".type.Next}";
final static String ATTR_CONTENT_ID = "contentid"; final static String ATTR_CONTENT_ID = "contentid";
final static String ATTR_SORT = "sort";
final static String ATTR_TYPE = "type"; final static String ATTR_TYPE = "type";
public final static String ATTR_CATALOG_ID = "catalogid";
public final static String ATTR_CATALOG_ALIAS = "catalogalias";
public final static String ATTR_LEVEL = "level";
public final static String ATTR_SORT = "sort";
public final static String ATTR_HAS_ATTRIBUTE = "hasattribute";
public final static String ATTR_NO_ATTRIBUTE = "noattribute";
public final static String ATTR_STATUS = "status";
public final static String ATTR_TOP_FLAG = "topflag";
private final ICatalogService catalogService;
private final IContentService contentService; private final IContentService contentService;
@Override @Override
public TagPageData prepareData(Environment env, Map<String, String> attrs, boolean page, int size, int pageIndex) throws TemplateException { public TagPageData prepareData(Environment env, Map<String, String> attrs, boolean page, int size, int pageIndex) throws TemplateException {
boolean isNext = TypeTagAttr.isNext(attrs.get(ATTR_TYPE)); boolean isNext = TypeTagAttr.isNext(attrs.get(ATTR_TYPE));
String sort = attrs.get(ATTR_SORT);
Long contentId = MapUtils.getLong(attrs, ATTR_CONTENT_ID); Long contentId = MapUtils.getLong(attrs, ATTR_CONTENT_ID);
CmsContent content = this.contentService.dao().getById(contentId); CmsContent content = this.contentService.dao().getById(contentId);
Assert.notNull(content, () -> new TemplateException(StringUtils.messageFormat("Tag attr[contentid={0}] data not found.", contentId), env)); Assert.notNull(content, () -> new TemplateException(StringUtils.messageFormat("Tag attr[contentid={0}] data not found.", contentId), env));
LambdaQueryWrapper<CmsContent> q = new LambdaQueryWrapper<CmsContent>() CmsCatalog catalog = null;
.eq(CmsContent::getCatalogId, content.getCatalogId()) long catalogId = MapUtils.getLongValue(attrs, ATTR_CATALOG_ID);
.eq(CmsContent::getStatus, ContentStatus.PUBLISHED); if (catalogId > 0) {
if (CmsContentTag.SortTagAttr.isRecent(sort)) { catalog = this.catalogService.getCatalog(catalogId);
}
long siteId = TemplateUtils.evalSiteId(env);
String alias = MapUtils.getString(attrs, ATTR_CATALOG_ALIAS);
if (Objects.isNull(catalog) && StringUtils.isNotEmpty(alias)) {
catalog = this.catalogService.getCatalogByAlias(siteId, alias);
}
String level = MapUtils.getString(attrs, ATTR_LEVEL);
if (!CmsContentTag.LevelTagAttr.isRoot(level) && Objects.isNull(catalog)) {
throw new CatalogNotFoundException(catalogId, alias, env);
}
String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition);
String status = MapUtils.getString(attrs, ATTR_STATUS, ContentStatus.PUBLISHED);
LambdaQueryWrapper<CmsContent> q = new LambdaQueryWrapper<>();
q.eq(CmsContent::getSiteId, siteId).eq(!"-1".equals(status), CmsContent::getStatus, status);
if (Objects.nonNull(catalog)) {
if (CmsContentTag.LevelTagAttr.isCurrent(level)) {
q.eq(CmsContent::getCatalogId, catalog.getCatalogId());
} else if (CmsContentTag.LevelTagAttr.isChild(level)) {
q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors() + CatalogUtils.ANCESTORS_SPLITER);
} else if (CmsContentTag.LevelTagAttr.isCurrentAndChild(level)) {
q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors());
}
}
String hasAttribute = MapUtils.getString(attrs, ATTR_HAS_ATTRIBUTE);
if (StringUtils.isNotEmpty(hasAttribute)) {
int attrTotal = ContentAttribute.convertInt(hasAttribute.split(","));
q.apply(attrTotal > 0, "attributes&{0}={1}", attrTotal, attrTotal);
}
String noAttribute = MapUtils.getString(attrs, ATTR_NO_ATTRIBUTE);
if (StringUtils.isNotEmpty(noAttribute)) {
String[] contentAttrs = noAttribute.split(",");
int attrTotal = ContentAttribute.convertInt(contentAttrs);
for (String attr : contentAttrs) {
int bit = ContentAttribute.bit(attr);
q.apply(bit > 0, "attributes&{0}<>{1}", attrTotal, bit);
}
}
q.apply(StringUtils.isNotEmpty(condition), condition);
String sortType = MapUtils.getString(attrs, ATTR_SORT);
q.orderByDesc(MapUtils.getBooleanValue(attrs, ATTR_TOP_FLAG, true), CmsContent::getTopFlag);
if (CmsContentTag.SortTagAttr.isRecent(sortType)) {
q.gt(isNext, CmsContent::getPublishDate, content.getPublishDate()); q.gt(isNext, CmsContent::getPublishDate, content.getPublishDate());
q.lt(!isNext, CmsContent::getPublishDate, content.getPublishDate()); q.lt(!isNext, CmsContent::getPublishDate, content.getPublishDate());
q.orderBy(true, isNext, CmsContent::getPublishDate); q.orderBy(true, isNext, CmsContent::getPublishDate);
} else if(CmsContentTag.SortTagAttr.isViews(sort)) { } else if(CmsContentTag.SortTagAttr.isViews(sortType)) {
q.gt(isNext, CmsContent::getViewCount, content.getViewCount()); q.gt(isNext, CmsContent::getViewCount, content.getViewCount());
q.lt(!isNext, CmsContent::getViewCount, content.getViewCount()); q.lt(!isNext, CmsContent::getViewCount, content.getViewCount());
q.orderBy(true, isNext, CmsContent::getViewCount); q.orderBy(true, isNext, CmsContent::getViewCount);
@ -120,11 +174,18 @@ public class CmsContentClosestTag extends AbstractListTag {
@Override @Override
public List<TagAttr> getTagAttrs() { public List<TagAttr> getTagAttrs() {
return List.of( List<TagAttr> tagAttrs = super.getTagAttrs();
new TagAttr(ATTR_CONTENT_ID, true, TagAttrDataType.INTEGER, ATTR_USAGE_CONTENT_ID), tagAttrs.add(new TagAttr(ATTR_CONTENT_ID, true, TagAttrDataType.INTEGER, ATTR_USAGE_CONTENT_ID));
new TagAttr(ATTR_TYPE, true, TagAttrDataType.STRING, ATTR_USAGE_TYPE, TypeTagAttr.toTagAttrOptions(), TypeTagAttr.Prev.name()), tagAttrs.add(new TagAttr(ATTR_TYPE, true, TagAttrDataType.STRING, ATTR_USAGE_TYPE, TypeTagAttr.toTagAttrOptions(), TypeTagAttr.Prev.name()));
new TagAttr(ATTR_SORT, false, TagAttrDataType.STRING, ATTR_USAGE_SORT, CmsContentTag.SortTagAttr.toTagAttrOptions(), CmsContentTag.SortTagAttr.Default.name()) tagAttrs.add(new TagAttr(ATTR_CATALOG_ID, false, TagAttrDataType.INTEGER, CmsContentTag.ATTR_USAGE_CATALOG_ID));
); tagAttrs.add(new TagAttr(ATTR_CATALOG_ALIAS, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_CATALOG_ALIAS));
tagAttrs.add(new TagAttr(ATTR_LEVEL, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_LEVEL, CmsContentTag.LevelTagAttr.toTagAttrOptions(), CmsContentTag.LevelTagAttr.Current.name()));
tagAttrs.add(new TagAttr(ATTR_SORT, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_SORT, CmsContentTag.SortTagAttr.toTagAttrOptions(), CmsContentTag.SortTagAttr.Default.name()));
tagAttrs.add(new TagAttr(ATTR_HAS_ATTRIBUTE, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_HAS_ATTRIBUTE));
tagAttrs.add(new TagAttr(ATTR_NO_ATTRIBUTE, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_NO_ATTRIBUTE));
tagAttrs.add(new TagAttr(ATTR_STATUS, false, TagAttrDataType.STRING, CmsContentTag.ATTR_USAGE_STATUS));
tagAttrs.add(new TagAttr(ATTR_TOP_FLAG, false, TagAttrDataType.BOOLEAN, CmsContentTag.ATTR_USAGE_TOP_FLAG, Boolean.TRUE.toString()));
return tagAttrs;
} }
enum TypeTagAttr { enum TypeTagAttr {

View File

@ -109,7 +109,7 @@ public class CmsContentTag extends AbstractListTag {
} }
String level = MapUtils.getString(attrs, ATTR_LEVEL); String level = MapUtils.getString(attrs, ATTR_LEVEL);
if (!LevelTagAttr.isRoot(level) && Objects.isNull(catalog)) { if (!LevelTagAttr.isRoot(level) && Objects.isNull(catalog)) {
throw new CatalogNotFoundException(getTagName(), catalogId, alias, env); throw new CatalogNotFoundException(catalogId, alias, env);
} }
String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition); String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition);
String status = MapUtils.getString(attrs, ATTR_STATUS, ContentStatus.PUBLISHED); String status = MapUtils.getString(attrs, ATTR_STATUS, ContentStatus.PUBLISHED);

View File

@ -23,7 +23,10 @@ import com.chestnut.common.staticize.tag.AbstractTag;
import com.chestnut.common.staticize.tag.TagAttr; import com.chestnut.common.staticize.tag.TagAttr;
import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.Assert;
import com.chestnut.common.utils.StringUtils; import com.chestnut.common.utils.StringUtils;
import com.chestnut.contentcore.core.impl.PublishPipeProp_PrefixMode;
import com.chestnut.contentcore.core.impl.PublishPipeProp_RelativePrefix;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.enums.SitePrefixMode;
import com.chestnut.contentcore.properties.EnableSSIProperty; import com.chestnut.contentcore.properties.EnableSSIProperty;
import com.chestnut.contentcore.service.ISiteService; import com.chestnut.contentcore.service.ISiteService;
import com.chestnut.contentcore.service.ITemplateService; import com.chestnut.contentcore.service.ITemplateService;
@ -160,7 +163,7 @@ public class CmsIncludeTag extends AbstractTag {
} }
} }
if (ssi) { if (ssi) {
String prefix = SiteUtils.getPublishPipePrefix(site, context.getPublishPipeCode(), context.isPreview()); String prefix = getIncludePathPrefix(context.getPublishPipeCode(), site);
env.getOut().write(StringUtils.messageFormat(SSI_INCLUDE_TAG, prefix + staticFilePath)); env.getOut().write(StringUtils.messageFormat(SSI_INCLUDE_TAG, prefix + staticFilePath));
} else { } else {
env.getOut().write(staticContent); env.getOut().write(staticContent);
@ -169,6 +172,18 @@ public class CmsIncludeTag extends AbstractTag {
return null; return null;
} }
public static String getIncludePathPrefix(String publishPipeCode, CmsSite site) {
String prefix = null;
String prefixMode = PublishPipeProp_PrefixMode.getValue(publishPipeCode, site.getPublishPipeProps());
if (SitePrefixMode.isRelative(prefixMode)) {
prefix = PublishPipeProp_RelativePrefix.getValue(publishPipeCode, site.getPublishPipeProps());
}
if (StringUtils.isEmpty(prefix)) {
prefix = "/";
}
return prefix;
}
private Map<String, String> mergeRequestVariable(Environment env, Map<String, String> params) throws TemplateModelException { private Map<String, String> mergeRequestVariable(Environment env, Map<String, String> params) throws TemplateModelException {
TemplateModel variable = env.getVariable(TemplateUtils.TemplateVariable_Request); TemplateModel variable = env.getVariable(TemplateUtils.TemplateVariable_Request);
if (Objects.nonNull(variable)) { if (Objects.nonNull(variable)) {

View File

@ -124,19 +124,19 @@ public class CmsPageWidgetTag extends AbstractTag {
String siteRoot = SiteUtils.getSiteRoot(site, context.getPublishPipeCode()); String siteRoot = SiteUtils.getSiteRoot(site, context.getPublishPipeCode());
String staticFileName = PageWidgetUtils.getStaticFileName(pw, site.getStaticSuffix(context.getPublishPipeCode())); String staticFileName = PageWidgetUtils.getStaticFileName(pw, site.getStaticSuffix(context.getPublishPipeCode()));
String staticFilePath = pw.getPath() + staticFileName; String staticFilePath = pw.getPath() + staticFileName;
if (ssi) {
// 读取页面部件静态化内容
String staticContent = templateService.getTemplateStaticContentCache(templateKey); String staticContent = templateService.getTemplateStaticContentCache(templateKey);
if (Objects.isNull(staticContent) || !new File(siteRoot + staticFilePath).exists()) { if (Objects.isNull(staticContent) || !new File(siteRoot + staticFilePath).exists()) {
staticContent = this.processTemplate(env, pw, templateKey); staticContent = this.processTemplate(env, pw, templateKey);
FileUtils.writeStringToFile(new File(siteRoot + staticFilePath), staticContent, StandardCharsets.UTF_8);
this.templateService.setTemplateStaticContentCache(templateKey, staticContent); this.templateService.setTemplateStaticContentCache(templateKey, staticContent);
if (ssi) {
FileUtils.writeStringToFile(new File(siteRoot + staticFilePath), staticContent, StandardCharsets.UTF_8);
} }
String prefix = SiteUtils.getPublishPipePrefix(site, context.getPublishPipeCode(), context.isPreview()); }
if (ssi) {
String prefix = CmsIncludeTag.getIncludePathPrefix(context.getPublishPipeCode(), site);
env.getOut().write(StringUtils.messageFormat(CmsIncludeTag.SSI_INCLUDE_TAG, prefix + staticFilePath)); env.getOut().write(StringUtils.messageFormat(CmsIncludeTag.SSI_INCLUDE_TAG, prefix + staticFilePath));
} else { } else {
// 非ssi模式无法使用缓存
String staticContent = this.processTemplate(env, pw, templateKey);
env.getOut().write(staticContent); env.getOut().write(staticContent);
} }
} }

View File

@ -88,7 +88,7 @@ public class CatalogUtils {
publishPipeCode, pageIndex); publishPipeCode, pageIndex);
return BackendContext.getValue() + catalogPath; return BackendContext.getValue() + catalogPath;
} }
String prefix = SiteUtils.getPublishPipePrefix(site, publishPipeCode, isPreview); String prefix = SiteUtils.getPublishPipePrefix(site, publishPipeCode, false);
if (catalog.isStaticize()) { if (catalog.isStaticize()) {
return prefix + catalog.getPath(); return prefix + catalog.getPath();
} else { } else {

View File

@ -16,7 +16,7 @@
package com.chestnut.contentcore.util; package com.chestnut.contentcore.util;
import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.async.AsyncTaskManager;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.Operator;
import com.chestnut.common.utils.IdUtils; import com.chestnut.common.utils.IdUtils;
import com.chestnut.common.utils.SpringUtils; import com.chestnut.common.utils.SpringUtils;
import com.chestnut.contentcore.domain.CmsContent; import com.chestnut.contentcore.domain.CmsContent;
@ -39,7 +39,7 @@ public class ContentLogUtils {
private static final AsyncTaskManager asyncTaskManager = SpringUtils.getBean(AsyncTaskManager.class); private static final AsyncTaskManager asyncTaskManager = SpringUtils.getBean(AsyncTaskManager.class);
public static void addLog(String opType, CmsContent content, LoginUser operator) { public static void addLog(String opType, CmsContent content, Operator operator) {
addLog(opType, content, null, operator.getUserType(), operator.getUsername()); addLog(opType, content, null, operator.getUserType(), operator.getUsername());
} }

View File

@ -21,6 +21,7 @@ import com.chestnut.contentcore.config.CMSConfig;
import com.chestnut.contentcore.core.IInternalDataType; import com.chestnut.contentcore.core.IInternalDataType;
import com.chestnut.contentcore.core.impl.InternalDataType_Site; import com.chestnut.contentcore.core.impl.InternalDataType_Site;
import com.chestnut.contentcore.core.impl.PublishPipeProp_PrefixMode; import com.chestnut.contentcore.core.impl.PublishPipeProp_PrefixMode;
import com.chestnut.contentcore.core.impl.PublishPipeProp_RelativePrefix;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.enums.SitePrefixMode; import com.chestnut.contentcore.enums.SitePrefixMode;
import com.chestnut.system.fixed.config.BackendContext; import com.chestnut.system.fixed.config.BackendContext;
@ -48,7 +49,7 @@ public class SiteUtils {
} }
String pathMode = PublishPipeProp_PrefixMode.getValue(publishPipeCode, site.getPublishPipeProps()); String pathMode = PublishPipeProp_PrefixMode.getValue(publishPipeCode, site.getPublishPipeProps());
if (SitePrefixMode.isRelative(pathMode)) { if (SitePrefixMode.isRelative(pathMode)) {
return "/"; return PublishPipeProp_RelativePrefix.getValue(publishPipeCode, site.getPublishPipeProps());
} }
return site.getUrl(publishPipeCode); return site.getUrl(publishPipeCode);
} }
@ -81,7 +82,7 @@ public class SiteUtils {
} }
/** /**
* 获取站点资源文件访问链接前缀 * 获取站点资源文件访问链接前缀非预览模式为设置资源域名则使用指定发布通道域名
* *
* @param site 站点 * @param site 站点
* @param publishPipeCode 发布通道编码 * @param publishPipeCode 发布通道编码

View File

@ -149,7 +149,6 @@ FREEMARKER.TAG.cms_content_closest.contentId=內容ID
FREEMARKER.TAG.cms_content_closest.type=类型 FREEMARKER.TAG.cms_content_closest.type=类型
FREEMARKER.TAG.cms_content_closest.type.Prev=上一篇 FREEMARKER.TAG.cms_content_closest.type.Prev=上一篇
FREEMARKER.TAG.cms_content_closest.type.Next=下一篇 FREEMARKER.TAG.cms_content_closest.type.Next=下一篇
FREEMARKER.TAG.cms_content_closest.sort=排序值
FREEMARKER.TAG.cms_content_rela.NAME=相关内容标签 FREEMARKER.TAG.cms_content_rela.NAME=相关内容标签
FREEMARKER.TAG.cms_content_rela.DESC=相关内容标签,内嵌`<#list DataList as content>${content.name}</#list>`遍历数据 FREEMARKER.TAG.cms_content_rela.DESC=相关内容标签,内嵌`<#list DataList as content>${content.name}</#list>`遍历数据
FREEMARKER.TAG.cms_content_rela.contentId=内容ID FREEMARKER.TAG.cms_content_rela.contentId=内容ID
@ -195,6 +194,8 @@ FREEMARKER.FUNC.fileExtractor.DESC=提取html文本中的文件资源链接
FREEMARKER.FUNC.fileExtractor.Arg1.Name=Html文本内容 FREEMARKER.FUNC.fileExtractor.Arg1.Name=Html文本内容
FREEMARKER.FUNC.fileExtractor.Arg2.Name=文件类型/后缀 FREEMARKER.FUNC.fileExtractor.Arg2.Name=文件类型/后缀
FREEMARKER.ERR.CatalogNotFound=栏目数据不存在:[栏目ID: {0}], [栏目别名: {1}]
# 校验规则 # 校验规则
VALIDATOR.CMS.SITE.PUBLISH_PIPE_PROPS_EMPTY=发布通道配置不能为空 VALIDATOR.CMS.SITE.PUBLISH_PIPE_PROPS_EMPTY=发布通道配置不能为空
VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR=属性编码只能使用大小写字母、数字和下划线 VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR=属性编码只能使用大小写字母、数字和下划线

View File

@ -149,7 +149,6 @@ FREEMARKER.TAG.cms_content_closest.contentId=Target content id
FREEMARKER.TAG.cms_content_closest.type=Type FREEMARKER.TAG.cms_content_closest.type=Type
FREEMARKER.TAG.cms_content_closest.type.Prev=Prev FREEMARKER.TAG.cms_content_closest.type.Prev=Prev
FREEMARKER.TAG.cms_content_closest.type.Next=Next FREEMARKER.TAG.cms_content_closest.type.Next=Next
FREEMARKER.TAG.cms_content_closest.sort=Sort Value
FREEMARKER.TAG.cms_content_rela.NAME=Related content tag FREEMARKER.TAG.cms_content_rela.NAME=Related content tag
FREEMARKER.TAG.cms_content_rela.DESC=Fetch related contents by contentId, use `<#list>` in tag like `<#list DataList as content>${content.title}</#list>` to walk through the list of contents. FREEMARKER.TAG.cms_content_rela.DESC=Fetch related contents by contentId, use `<#list>` in tag like `<#list DataList as content>${content.title}</#list>` to walk through the list of contents.
FREEMARKER.TAG.cms_content_rela.contentId=Target content id FREEMARKER.TAG.cms_content_rela.contentId=Target content id
@ -195,6 +194,8 @@ FREEMARKER.FUNC.fileExtractor.DESC=Get file link list from html text.
FREEMARKER.FUNC.fileExtractor.Arg1.Name=Html text FREEMARKER.FUNC.fileExtractor.Arg1.Name=Html text
FREEMARKER.FUNC.fileExtractor.Arg2.Name=File type or suffix FREEMARKER.FUNC.fileExtractor.Arg2.Name=File type or suffix
FREEMARKER.ERR.CatalogNotFound=Missing catalog: [id: {0}], [alias: {1}]
# 校验规则 # 校验规则
VALIDATOR.CMS.SITE.PUBLISH_PIPE_PROPS_EMPTY=The site publish pipe props cannot be empty. VALIDATOR.CMS.SITE.PUBLISH_PIPE_PROPS_EMPTY=The site publish pipe props cannot be empty.
VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR=The code can only use uppercase/lowercase letters, numbers and underscores. VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR=The code can only use uppercase/lowercase letters, numbers and underscores.

View File

@ -32,13 +32,13 @@ DICT.CMSStaticSuffix.html=html
DICT.CMSStaticSuffix.xml=xml DICT.CMSStaticSuffix.xml=xml
DICT.CMSStaticSuffix.json=json DICT.CMSStaticSuffix.json=json
DICT.CMSContentOpType=內容操作類型 DICT.CMSContentOpType=內容操作類型
DICT.CMSContentOpType.ADD= DICT.CMSContentOpType.ADD=
DICT.CMSContentOpType.UPDATE=修改 DICT.CMSContentOpType.UPDATE=修改
DICT.CMSContentOpType.DELETE=刪除 DICT.CMSContentOpType.DELETE=刪除
DICT.CMSContentOpType.LOCK=鎖定 DICT.CMSContentOpType.LOCK=鎖定
DICT.CMSContentOpType.UNLOCK=解鎖 DICT.CMSContentOpType.UNLOCK=解鎖
DICT.CMSContentOpType.TO_PUBLISH=待發 DICT.CMSContentOpType.TO_PUBLISH=待發
DICT.CMSContentOpType.PUBLISH= DICT.CMSContentOpType.PUBLISH=
DICT.CMSContentOpType.OFFLINE=下線 DICT.CMSContentOpType.OFFLINE=下線
DICT.CMSContentOpType.SORT=排序 DICT.CMSContentOpType.SORT=排序
DICT.CMSContentOpType.TOP=置頂 DICT.CMSContentOpType.TOP=置頂
@ -53,7 +53,7 @@ CONFIG.SiteApiUrl=站點API地址
CONFIG.ResourceUploadAcceptSize=素材庫資源上傳大小限制 CONFIG.ResourceUploadAcceptSize=素材庫資源上傳大小限制
# 錯誤資訊 # 錯誤資訊
ERRCODE.CMS.CONTENTCORE.NO_SITE=無站點數據,請先去站點管理菜單建站點 ERRCODE.CMS.CONTENTCORE.NO_SITE=無站點數據,請先去站點管理菜單站點
ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_PAGE_WIDGET_TYPE=未知頁面部件類型:{0} ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_PAGE_WIDGET_TYPE=未知頁面部件類型:{0}
ERRCODE.CMS.CONTENTCORE.TEMPLATE_EMPTY=模板未配置或模板檔案不存在 ERRCODE.CMS.CONTENTCORE.TEMPLATE_EMPTY=模板未配置或模板檔案不存在
ERRCODE.CMS.CONTENTCORE.TEMPLATE_FILE_NOT_FOUND=模板檔案“{0}”不存在 ERRCODE.CMS.CONTENTCORE.TEMPLATE_FILE_NOT_FOUND=模板檔案“{0}”不存在
@ -63,7 +63,7 @@ ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_CATALOG_TYPE=未知欄目類型:{0}
ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_INTERNAL_DATA_TYPE=未知內部數據類型:{0} ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_INTERNAL_DATA_TYPE=未知內部數據類型:{0}
ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_RESOURCE_TYPE=未知資源類型:{0} ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_RESOURCE_TYPE=未知資源類型:{0}
ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_DYNAMIC_PAGE_TYPE=未知動態模板類型:{0} ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_DYNAMIC_PAGE_TYPE=未知動態模板類型:{0}
ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_CONTENT_PATH_RULE=未知內容詳情頁路徑規則:{0} ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_CONTENT_PATH_RULE=未知內容詳情頁路徑規則:{0}
ERRCODE.CMS.CONTENTCORE.DEL_CHILD_FIRST=請先刪除子欄目 ERRCODE.CMS.CONTENTCORE.DEL_CHILD_FIRST=請先刪除子欄目
ERRCODE.CMS.CONTENTCORE.CONFLICT_CATALOG=欄目名稱/別名/目錄重複 ERRCODE.CMS.CONTENTCORE.CONFLICT_CATALOG=欄目名稱/別名/目錄重複
ERRCODE.CMS.CONTENTCORE.CATALOG_MAX_TREE_LEVEL=欄目層級超出上限 ERRCODE.CMS.CONTENTCORE.CATALOG_MAX_TREE_LEVEL=欄目層級超出上限
@ -84,11 +84,11 @@ ERRCODE.CMS.CONTENTCORE.FILE_ALREADY_EXISTS=檔案已存在
ERRCODE.CMS.CONTENTCORE.CATALOG_SORT_VALUE_ZERO=欄目排序值不能為0 ERRCODE.CMS.CONTENTCORE.CATALOG_SORT_VALUE_ZERO=欄目排序值不能為0
ERRCODE.CMS.CONTENTCORE.SITE_EXPORT_TASK_EXISTS=站點導出任務正在進行中 ERRCODE.CMS.CONTENTCORE.SITE_EXPORT_TASK_EXISTS=站點導出任務正在進行中
ERRCODE.CMS.CONTENTCORE.DEL_CONTENT_ERR=只能刪除初稿和已下線內容 ERRCODE.CMS.CONTENTCORE.DEL_CONTENT_ERR=只能刪除初稿和已下線內容
ERRCODE.CMS.CONTENTCORE.RESOURCE_ACCEPT_SIZE_LIMIT=上傳文件大小超過限制 ERRCODE.CMS.CONTENTCORE.RESOURCE_ACCEPT_SIZE_LIMIT=上傳檔案大小超過限制
ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_RESOURCE_STORAGE=資源存儲方式與當前站點配置不一致 ERRCODE.CMS.CONTENTCORE.UNSUPPORTED_RESOURCE_STORAGE=資源存儲方式與當前站點配置不一致
ERRCODE.CMS.CONTENTCORE.MERGE_CATALOG_IS_EMPTY=被合欄目不存在 ERRCODE.CMS.CONTENTCORE.MERGE_CATALOG_IS_EMPTY=被合欄目不存在
ERRCODE.CMS.CONTENTCORE.MERGE_CATALOG_NOT_LEAF=被合欄目不能包含子欄目 ERRCODE.CMS.CONTENTCORE.MERGE_CATALOG_NOT_LEAF=被合欄目不能包含子欄目
ERRCODE.CMS.CONTENTCORE.DENY_LINK_TO_LINK_INTERNAL_DATA=不能链接到链接内容或栏 ERRCODE.CMS.CONTENTCORE.DENY_LINK_TO_LINK_INTERNAL_DATA=不能連結到連結內容或欄
# freemarker模板標籤 # freemarker模板標籤
FREEMARKER.TAG.cms_site.NAME=站點列表標籤 FREEMARKER.TAG.cms_site.NAME=站點列表標籤
@ -118,23 +118,23 @@ FREEMARKER.TAG.cms_content.level.Current=當前欄目
FREEMARKER.TAG.cms_content.level.Child=子欄目 FREEMARKER.TAG.cms_content.level.Child=子欄目
FREEMARKER.TAG.cms_content.level.CurrentAndChild=當前欄目及子欄目 FREEMARKER.TAG.cms_content.level.CurrentAndChild=當前欄目及子欄目
FREEMARKER.TAG.cms_content.sort=排序方式 FREEMARKER.TAG.cms_content.sort=排序方式
FREEMARKER.TAG.cms_content.sort.Recent=時間降序 FREEMARKER.TAG.cms_content.sort.Recent=時間降序
FREEMARKER.TAG.cms_content.sort.Views=瀏覽量降序 FREEMARKER.TAG.cms_content.sort.Views=瀏覽量降序
FREEMARKER.TAG.cms_content.sort.Default=排序字段降序(默認 FREEMARKER.TAG.cms_content.sort.Default=排序欄位降序(預設
FREEMARKER.TAG.cms_content.hasattribute=包含內容屬性,多個屬性英文逗號分隔 FREEMARKER.TAG.cms_content.hasattribute=包含內容屬性,多個屬性英文逗號分隔
FREEMARKER.TAG.cms_content.noattribute=不包含內容屬性,多個屬性英文逗號分隔 FREEMARKER.TAG.cms_content.noattribute=不包含內容屬性,多個屬性英文逗號分隔
FREEMARKER.TAG.cms_content.status=狀態,'-1'表示不限制狀態 FREEMARKER.TAG.cms_content.status=狀態,'-1'表示不限制狀態
FREEMARKER.TAG.cms_content.status.defaultValue=30: 已發 FREEMARKER.TAG.cms_content.status.defaultValue=30: 已發
FREEMARKER.TAG.cms_content.topflag=是否允許指定 FREEMARKER.TAG.cms_content.topflag=是否允許置頂
FREEMARKER.TAG.cms_site_property.NAME=站點自定義屬性標籤 FREEMARKER.TAG.cms_site_property.NAME=站點自定義屬性標籤
FREEMARKER.TAG.cms_site_property.DESC=獲取站點自定義屬性數據列表,內嵌`<#list DataList as prop>${prop.propName}</#list>`遍曆數據 FREEMARKER.TAG.cms_site_property.DESC=獲取站點自定義屬性數據列表,內嵌`<#list DataList as prop>${prop.propName}</#list>`遍曆數據
FREEMARKER.TAG.cms_site_property.siteid=站點ID默認從模板變量中獲取`${Site.siteId}` FREEMARKER.TAG.cms_site_property.siteid=站點ID預設從模板變數中獲取`${Site.siteId}`
FREEMARKER.TAG.cms_site_property.code=屬性編碼 FREEMARKER.TAG.cms_site_property.code=屬性編碼
FREEMARKER.TAG.cms_include.NAME=模板引用標籤 FREEMARKER.TAG.cms_include.NAME=模板引用標籤
FREEMARKER.TAG.cms_include.DESC=引用其他模板內容支援ssi引用標籤 FREEMARKER.TAG.cms_include.DESC=引用其他模板內容支援ssi引用標籤
FREEMARKER.TAG.cms_include.file=引用模板文件路徑相對模板目錄template/ FREEMARKER.TAG.cms_include.file=引用模板檔案路徑相對模板目錄template/
FREEMARKER.TAG.cms_include.ssi=是否啟用SSI FREEMARKER.TAG.cms_include.ssi=是否啟用SSI
FREEMARKER.TAG.cms_include.virtual=是否啟用Virtual模式 FREEMARKER.TAG.cms_include.virtual=是否啟用virtual模式此模式下區塊無法繼承當前頁面上限文變數需要通過參數傳入需要的變數
FREEMARKER.TAG.cms_include.cache=是否啟用緩存 FREEMARKER.TAG.cms_include.cache=是否啟用緩存
FREEMARKER.TAG.cms_pagewidget.NAME=頁面部件引用標籤 FREEMARKER.TAG.cms_pagewidget.NAME=頁面部件引用標籤
FREEMARKER.TAG.cms_pagewidget.DESC=引用頁面部件內容支援ssi引用標籤 FREEMARKER.TAG.cms_pagewidget.DESC=引用頁面部件內容支援ssi引用標籤
@ -149,7 +149,6 @@ FREEMARKER.TAG.cms_content_closest.contentId=內容ID
FREEMARKER.TAG.cms_content_closest.type=類型 FREEMARKER.TAG.cms_content_closest.type=類型
FREEMARKER.TAG.cms_content_closest.type.Prev=上一篇 FREEMARKER.TAG.cms_content_closest.type.Prev=上一篇
FREEMARKER.TAG.cms_content_closest.type.Next=下一篇 FREEMARKER.TAG.cms_content_closest.type.Next=下一篇
FREEMARKER.TAG.cms_content_closest.sort=排序方式
FREEMARKER.TAG.cms_content_rela.NAME=相關內容標籤 FREEMARKER.TAG.cms_content_rela.NAME=相關內容標籤
FREEMARKER.TAG.cms_content_rela.DESC=相關內容標籤,內嵌`<#list DataList as content>${content.name}</#list>`遍曆數據 FREEMARKER.TAG.cms_content_rela.DESC=相關內容標籤,內嵌`<#list DataList as content>${content.name}</#list>`遍曆數據
FREEMARKER.TAG.cms_content_rela.contentId=內容ID FREEMARKER.TAG.cms_content_rela.contentId=內容ID
@ -159,20 +158,20 @@ FREEMARKER.FUNC.htmlInternalUrl.DESC=將html文本中的內部連結地址“iur
FREEMARKER.FUNC.htmlInternalUrl.Arg1.Name=Html文本內容 FREEMARKER.FUNC.htmlInternalUrl.Arg1.Name=Html文本內容
FREEMARKER.FUNC.imageSize.DESC=獲得圖片縮放圖函數,不在的縮略圖會自動建立,例如:`${imageSize(content.logo, 300, 300)}` FREEMARKER.FUNC.imageSize.DESC=獲得圖片縮放圖函數,不在的縮略圖會自動建立,例如:`${imageSize(content.logo, 300, 300)}`
FREEMARKER.FUNC.imageSize.Arg1.Name=圖片資源內部路徑iurl:// FREEMARKER.FUNC.imageSize.Arg1.Name=圖片資源內部路徑iurl://
FREEMARKER.FUNC.imageSize.Arg1.Desc=僅支處理內部資源圖片iurl:// FREEMARKER.FUNC.imageSize.Arg1.Desc=僅支處理內部資源圖片iurl://
FREEMARKER.FUNC.imageSize.Arg2.Name=寬度 FREEMARKER.FUNC.imageSize.Arg2.Name=寬度
FREEMARKER.FUNC.imageSize.Arg3.Name=高度 FREEMARKER.FUNC.imageSize.Arg3.Name=高度
FREEMARKER.FUNC.internalUrl.DESC=將內部連結“iurl://”解析為正常http(s)訪問地址,例如:`${internalUrl(content.redirectUrl)}` FREEMARKER.FUNC.internalUrl.DESC=將內部連結“iurl://”解析為正常http(s)訪問地址,例如:`${internalUrl(content.redirectUrl)}`
FREEMARKER.FUNC.internalUrl.Arg1.Name=內部鏈接iurl:// FREEMARKER.FUNC.internalUrl.Arg1.Name=內部連結iurl://
FREEMARKER.FUNC.siteUrl.DESC=獲取站點指定發布通道訪問連結,例如:`${siteUrl(Site.siteId, 'h5')}` FREEMARKER.FUNC.siteUrl.DESC=獲取站點指定發布通道訪問連結,例如:`${siteUrl(Site.siteId, 'h5')}`
FREEMARKER.FUNC.siteUrl.Arg1.Name=站點ID FREEMARKER.FUNC.siteUrl.Arg1.Name=站點ID
FREEMARKER.FUNC.siteUrl.Arg2.Name=通道編碼 FREEMARKER.FUNC.siteUrl.Arg2.Name=通道編碼
FREEMARKER.FUNC.catalogUrl.DESC=獲取欄目指定發布通道訪問連結,例如:`${catalogUrl(Catalog.catalogId, 'h5')}` FREEMARKER.FUNC.catalogUrl.DESC=獲取欄目指定發布通道訪問連結,例如:`${catalogUrl(Catalog.catalogId, 'h5')}`
FREEMARKER.FUNC.catalogUrl.Arg1.Name=欄目ID FREEMARKER.FUNC.catalogUrl.Arg1.Name=欄目ID
FREEMARKER.FUNC.catalogUrl.Arg2.Name=通道編碼 FREEMARKER.FUNC.catalogUrl.Arg2.Name=通道編碼
FREEMARKER.FUNC.contentUrl.DESC=獲取內容指定發布通道訪問連結,例如:`${contentUrl(Content.contentId, 'h5')}` FREEMARKER.FUNC.contentUrl.DESC=獲取內容指定發布通道訪問連結,例如:`${contentUrl(Content.contentId, 'h5')}`
FREEMARKER.FUNC.contentUrl.Arg1.Name=內容ID FREEMARKER.FUNC.contentUrl.Arg1.Name=內容ID
FREEMARKER.FUNC.contentUrl.Arg2.Name=通道編碼 FREEMARKER.FUNC.contentUrl.Arg2.Name=通道編碼
FREEMARKER.FUNC.dynamicPageLink.DESC=動態頁面連結獲取函數,例如:`${dynamicPageLink('Search')}` FREEMARKER.FUNC.dynamicPageLink.DESC=動態頁面連結獲取函數,例如:`${dynamicPageLink('Search')}`
FREEMARKER.FUNC.dynamicPageLink.Arg1.Name=動態頁面類型 FREEMARKER.FUNC.dynamicPageLink.Arg1.Name=動態頁面類型
FREEMARKER.FUNC.dynamicPageLink.Arg2.Name=忽略`sid/pp`參數 FREEMARKER.FUNC.dynamicPageLink.Arg2.Name=忽略`sid/pp`參數
@ -184,21 +183,23 @@ FREEMARKER.FUNC.sysConfig.DESC=獲取系統參數配置值,例如:`${sysConf
FREEMARKER.FUNC.sysConfig.Arg1.Name=系統參數鍵名 FREEMARKER.FUNC.sysConfig.Arg1.Name=系統參數鍵名
FREEMARKER.FUNC.listHtmlInternalUrl.DESC=獲取html文本中的iurl列表例如`${listHtmlInternalUrl(ArticleContent)}` FREEMARKER.FUNC.listHtmlInternalUrl.DESC=獲取html文本中的iurl列表例如`${listHtmlInternalUrl(ArticleContent)}`
FREEMARKER.FUNC.listHtmlInternalUrl.Arg1.Name=Html文本內容 FREEMARKER.FUNC.listHtmlInternalUrl.Arg1.Name=Html文本內容
FREEMARKER.FUNC.contentPageLink.DESC=獲取內容分頁鏈接,例如:`${contentPageLink(content.link, 2)}` FREEMARKER.FUNC.contentPageLink.DESC=獲取內容分頁連結,例如:`${contentPageLink(content.link, 2)}`
FREEMARKER.FUNC.contentPageLink.Arg1.Name=內容鏈接 FREEMARKER.FUNC.contentPageLink.Arg1.Name=內容連結
FREEMARKER.FUNC.contentPageLink.Arg2.Name=頁碼 FREEMARKER.FUNC.contentPageLink.Arg2.Name=頁碼
FREEMARKER.FUNC.videoPlayer.DESC=將html文本中的視頻資源連結替換為<video>視頻播放器 FREEMARKER.FUNC.videoPlayer.DESC=將html文本中的視頻資源連結替換為`<video>`視頻播放器
FREEMARKER.FUNC.videoPlayer.Arg1.Name=Html文本內容 FREEMARKER.FUNC.videoPlayer.Arg1.Name=Html文本內容
FREEMARKER.FUNC.videoPlayer.Arg2.Name=視頻寬度 FREEMARKER.FUNC.videoPlayer.Arg2.Name=視頻寬度
FREEMARKER.FUNC.videoPlayer.Arg3.Name=視頻高度 FREEMARKER.FUNC.videoPlayer.Arg3.Name=視頻高度
FREEMARKER.FUNC.fileExtractor.DESC=提取html文本中的文件資源鏈接 FREEMARKER.FUNC.fileExtractor.DESC=提取html文本中的檔案資源連結
FREEMARKER.FUNC.fileExtractor.Arg1.Name=Html文本內容 FREEMARKER.FUNC.fileExtractor.Arg1.Name=Html文本內容
FREEMARKER.FUNC.fileExtractor.Arg2.Name=文件類型/後綴 FREEMARKER.FUNC.fileExtractor.Arg2.Name=檔案類型/尾碼
FREEMARKER.ERR.CatalogNotFound=欄目數據不存在:[欄目ID: {0}], [欄目別名: {1}]
# 校驗規則 # 校驗規則
VALIDATOR.CMS.SITE.PUBLISH_PIPE_PROPS_EMPTY=發布通道配置不能為空 VALIDATOR.CMS.SITE.PUBLISH_PIPE_PROPS_EMPTY=發布通道配置不能為空
VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR=屬性編碼只能使用大小寫字母、數字和下劃線 VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR=屬性編碼只能使用大小寫字母、數字和下劃線
VALIDATOR.CMS.FILE_NAME.REGEXP_ERR=文件名不能包含斜杠或反斜杠 VALIDATOR.CMS.FILE_NAME.REGEXP_ERR=檔案名不能包含斜杠或反斜杠
# 定時任務 # 定時任務
SCHEDULED_TASK.RecycleExpireJobHandler=資源回收筒過期內容刪除任務 SCHEDULED_TASK.RecycleExpireJobHandler=資源回收筒過期內容刪除任務
@ -206,20 +207,20 @@ SCHEDULED_TASK.SitePublishJobHandler=內容定時發布任務
SCHEDULED_TASK.ContentTopCancelJobHandler=內容置頂取消任務 SCHEDULED_TASK.ContentTopCancelJobHandler=內容置頂取消任務
SCHEDULED_TASK.UpdateDynamicDataJobHandler=保存內容動態數據任務 SCHEDULED_TASK.UpdateDynamicDataJobHandler=保存內容動態數據任務
SCHEDULED_TASK.ContentOfflineJobHandler=內容定時下線任務 SCHEDULED_TASK.ContentOfflineJobHandler=內容定時下線任務
SCHEDULED_TASK.ResourceChunkClearJobHandler=資源上傳分片文件過期刪除任務 SCHEDULED_TASK.ResourceChunkClearJobHandler=資源上傳分片檔案過期刪除任務
# 缓存监 # 緩存監
MONITORED.CACHE.SITE=站點 MONITORED.CACHE.SITE=站點
MONITORED.CACHE.CATALOG=欄目 MONITORED.CACHE.CATALOG=欄目
MONITORED.CACHE.PAGE_WIDGET=頁面部件 MONITORED.CACHE.PAGE_WIDGET=頁面部件
MONITORED.CACHE.TEMPLATE=模板 MONITORED.CACHE.TEMPLATE=模板
# 动态模板 # 動態模板
DYNAMIC_PAGE_TYPE.ARG.sid=站點ID DYNAMIC_PAGE_TYPE.ARG.sid=站點ID
DYNAMIC_PAGE_TYPE.ARG.pp=通道編碼 DYNAMIC_PAGE_TYPE.ARG.pp=通道編碼
DYNAMIC_PAGE_TYPE.ARG.preview=是否預覽模式 DYNAMIC_PAGE_TYPE.ARG.preview=是否預覽模式
# 内容静态化子目录划分规则 # 內容靜態化子目錄劃分規則
CONTENT_PATH_RULE.IdHash=按/內容ID分片/劃分 CONTENT_PATH_RULE.IdHash=按/內容ID分片/劃分
CONTENT_PATH_RULE.Year=按/年/劃分 CONTENT_PATH_RULE.Year=按/年/劃分
CONTENT_PATH_RULE.Month=按/年/月/劃分 CONTENT_PATH_RULE.Month=按/年/月/劃分
@ -230,12 +231,12 @@ TIP.CMS.CORE.DELETING_MAPPING_CONTENT=正在刪除關聯映射內容:{0}[ID
TIP.CMS.CORE.OFFLINE_CONTENT=正在下線內容:{0} TIP.CMS.CORE.OFFLINE_CONTENT=正在下線內容:{0}
TIP.CMS.CORE.OFFLINE_SUCCESS=下線成功 TIP.CMS.CORE.OFFLINE_SUCCESS=下線成功
TIP.CMS.CORE.OFFLINE_MAPPING_CONTENT=正在下線關聯映射內容:{0}[ID:{1}] TIP.CMS.CORE.OFFLINE_MAPPING_CONTENT=正在下線關聯映射內容:{0}[ID:{1}]
TIP.CMS.CORE.PUBLISHING_CONTENT=正在發內容:{0} TIP.CMS.CORE.PUBLISHING_CONTENT=正在發內容:{0}
TIP.CMS.CORE.PUBLISHING_CATALOG=正在發欄目:{0} TIP.CMS.CORE.PUBLISHING_CATALOG=正在發欄目:{0}
TIP.CMS.CORE.PUBLISHING_SITE=正在發站點:{0} TIP.CMS.CORE.PUBLISHING_SITE=正在發站點:{0}
TIP.CMS.CORE.PUBLISH_SUCCESS=成功 TIP.CMS.CORE.PUBLISH_SUCCESS=成功
TIP.CMS.CORE.COPYING_CONTENT=正在複製:{0} > {1} TIP.CMS.CORE.COPYING_CONTENT=正在複製:{0} > {1}
TIP.CMS.CORE.COPY_CONTENT_SUCCESS=製成功 TIP.CMS.CORE.COPY_CONTENT_SUCCESS=製成功
TIP.CMS.CORE.MOVING_CONTENT=正在移動:{0} > {1} TIP.CMS.CORE.MOVING_CONTENT=正在移動:{0} > {1}
TIP.CMS.CORE.MOVE_CONTENT_SUCCESS=移動成功 TIP.CMS.CORE.MOVE_CONTENT_SUCCESS=移動成功
@ -246,13 +247,13 @@ CMS.SITE.DESC=站點描述
CMS.SITE.LOGO=站點LOGO CMS.SITE.LOGO=站點LOGO
CMS.SITE.LOGO_SRC=LOGO訪問地址 CMS.SITE.LOGO_SRC=LOGO訪問地址
CMS.SITE.PATH=站點路徑 CMS.SITE.PATH=站點路徑
CMS.SITE.RESOURCE_URL=站點資源域名 CMS.SITE.RESOURCE_URL=站點資源功能變數名稱
CMS.SITE.DEPT_CODE=所屬機構編碼 CMS.SITE.DEPT_CODE=所屬機構編碼
CMS.SITE.SEO_KEYWORDS=SEO關鍵詞 CMS.SITE.SEO_KEYWORDS=SEO關鍵詞
CMS.SITE.SEO_DESC=SEO描述 CMS.SITE.SEO_DESC=SEO描述
CMS.SITE.SEO_TITLE=SEO標題 CMS.SITE.SEO_TITLE=SEO標題
CMS.SITE.CONFIG_PROPS=擴展配置 CMS.SITE.CONFIG_PROPS=擴展配置
CMS.SITE.LINK=鏈接地址 CMS.SITE.LINK=連結地址
CMS.SITE.PROP.ID=站點屬性ID CMS.SITE.PROP.ID=站點屬性ID
CMS.SITE.PROP.SITE_ID=所屬站點ID CMS.SITE.PROP.SITE_ID=所屬站點ID
@ -272,16 +273,16 @@ CMS.CATALOG.DESC=欄目簡介
CMS.CATALOG.DEPT_CODE=所屬部門編碼 CMS.CATALOG.DEPT_CODE=所屬部門編碼
CMS.CATALOG.TYPE=欄目類型 CMS.CATALOG.TYPE=欄目類型
CMS.CATALOG.PATH=欄目目錄 CMS.CATALOG.PATH=欄目目錄
CMS.CATALOG.REDIRECT_URL=欄目跳轉地址 CMS.CATALOG.REDIRECT_URL=標題欄目跳轉地址
CMS.CATALOG.TREE_LEVEL=欄目層級 CMS.CATALOG.TREE_LEVEL=欄目層級
CMS.CATALOG.CHILD_COUNT=子欄目數 CMS.CATALOG.CHILD_COUNT=子欄目數
CMS.CATALOG.CONTENT_COUNT=內容數量 CMS.CATALOG.CONTENT_COUNT=內容數量
CMS.CATALOG.SEO_KEYWORDS=SEO關鍵詞 CMS.CATALOG.SEO_KEYWORDS=SEO關鍵詞
CMS.CATALOG.SEO_DESC=SEO描述 CMS.CATALOG.SEO_DESC=SEO描述
CMS.CATALOG.SEO_TITLE=SEO標題 CMS.CATALOG.SEO_TITLE=SEO標題
CMS.CATALOG.CONFIG_PROPS=擴展配置 CMS.CATALOG.CONFIG_PROPS=擴展配置
CMS.CATALOG.LINK=欄目首頁鏈接 CMS.CATALOG.LINK=欄目首頁連結
CMS.CATALOG.LIST_LINK=欄目列表頁鏈接(無首頁模板時等同於首頁鏈接 CMS.CATALOG.LIST_LINK=欄目列表頁連結(無首頁模板時與首頁連結一致
CMS.CONTENT.ID=內容ID CMS.CONTENT.ID=內容ID
CMS.CONTENT.SITE_ID=所屬站點ID CMS.CONTENT.SITE_ID=所屬站點ID
@ -307,25 +308,25 @@ CMS.CONTENT.CONTRIBUTOR_ID=投稿用戶ID
CMS.CONTENT.SUMMARY=摘要 CMS.CONTENT.SUMMARY=摘要
CMS.CONTENT.ATTRS=內容屬性標識列表 CMS.CONTENT.ATTRS=內容屬性標識列表
CMS.CONTENT.STATUS=內容狀態 CMS.CONTENT.STATUS=內容狀態
CMS.CONTENT.LINK_FLAG=是否鏈接內容 CMS.CONTENT.LINK_FLAG=是否連結內容
CMS.CONTENT.REDIRECT_URL=跳轉鏈接 CMS.CONTENT.REDIRECT_URL=跳轉連結
CMS.CONTENT.TOP_FLAG=置頂標識 CMS.CONTENT.TOP_FLAG=置頂標識
CMS.CONTENT.TOP_DATE=置頂結束時間 CMS.CONTENT.TOP_DATE=置頂結束時間
CMS.CONTENT.KEYWORDS=關鍵詞 CMS.CONTENT.KEYWORDS=關鍵詞
CMS.CONTENT.TAGS=TAG CMS.CONTENT.TAGS=TAGs
CMS.CONTENT.PUBLISH_DATE=時間 CMS.CONTENT.PUBLISH_DATE=時間
CMS.CONTENT.SEO_TITLE=SEO標題 CMS.CONTENT.SEO_TITLE=SEO標題
CMS.CONTENT.SEO_KEYWORDS=SEO關鍵詞 CMS.CONTENT.SEO_KEYWORDS=SEO關鍵詞
CMS.CONTENT.SEO_DESC=SEO描述 CMS.CONTENT.SEO_DESC=SEO描述
CMS.CONTENT.LIKE=讚數(非實時) CMS.CONTENT.LIKE=贊數(非即時)
CMS.CONTENT.COMMENT=評論數(非時) CMS.CONTENT.COMMENT=評論數(非時)
CMS.CONTENT.FAVORITE=收藏數(非時) CMS.CONTENT.FAVORITE=收藏數(非時)
CMS.CONTENT.VIEW=瀏覽量(非實時) CMS.CONTENT.VIEW=文章瀏覽數(非即時)
CMS.CONTENT.PROP1=備用字段1 CMS.CONTENT.PROP1=備用欄位1
CMS.CONTENT.PROP2=備用字段2 CMS.CONTENT.PROP2=備用欄位2
CMS.CONTENT.PROP3=備用字段3 CMS.CONTENT.PROP3=備用欄位3
CMS.CONTENT.PROP4=備用字段4 CMS.CONTENT.PROP4=備用欄位4
CMS.CONTENT.LINK=內容鏈接 CMS.CONTENT.LINK=內容連結
CMS.PAGE_WIDGET.ID=頁面部件ID CMS.PAGE_WIDGET.ID=頁面部件ID
CMS.PAGE_WIDGET.SITE_ID=所屬站點ID CMS.PAGE_WIDGET.SITE_ID=所屬站點ID
@ -334,5 +335,5 @@ CMS.PAGE_WIDGET.CATALOG_ANCESTORS=所屬欄目祖級IDs
CMS.PAGE_WIDGET.TYPE=類型 CMS.PAGE_WIDGET.TYPE=類型
CMS.PAGE_WIDGET.NAME=名稱 CMS.PAGE_WIDGET.NAME=名稱
CMS.PAGE_WIDGET.CODE=編碼 CMS.PAGE_WIDGET.CODE=編碼
CMS.PAGE_WIDGET.PUBLISH_PIPE=通道 CMS.PAGE_WIDGET.PUBLISH_PIPE=通道
CMS.PAGE_WIDGET.CONTENT_OBJ=擴展數據 CMS.PAGE_WIDGET.CONTENT_OBJ=擴展數據

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-customform</artifactId> <artifactId>chestnut-cms-customform</artifactId>

View File

@ -177,7 +177,7 @@ public class CustomFormCoreDataHandler implements ICoreDataHandler {
for (CmsCustomFormData data : list) { for (CmsCustomFormData data : list) {
String oldKey = data.getModelId() + "-" + data.getDataId(); String oldKey = data.getModelId() + "-" + data.getDataId();
try { try {
data.setDataId(IdUtils.getSnowflakeId()); data.setDataId(IdUtils.getSnowflakeId()+"");
data.setModelId(customFormIdMapping.get(data.getModelId())); data.setModelId(customFormIdMapping.get(data.getModelId()));
// 处理图片和富文本内部链接 // 处理图片和富文本内部链接
MetaModel model = modelService.getMetaModel(data.getModelId()); MetaModel model = modelService.getMetaModel(data.getModelId());

View File

@ -31,8 +31,8 @@ import com.chestnut.contentcore.domain.pojo.PublishPipeTemplate;
import com.chestnut.contentcore.service.IPublishPipeService; import com.chestnut.contentcore.service.IPublishPipeService;
import com.chestnut.contentcore.service.ISiteService; import com.chestnut.contentcore.service.ISiteService;
import com.chestnut.customform.domain.CmsCustomForm; import com.chestnut.customform.domain.CmsCustomForm;
import com.chestnut.customform.domain.dto.CustomFormAddDTO; import com.chestnut.customform.domain.dto.CreateCustomFormRequest;
import com.chestnut.customform.domain.dto.CustomFormEditDTO; import com.chestnut.customform.domain.dto.UpdateCustomFormRequest;
import com.chestnut.customform.domain.vo.CustomFormVO; import com.chestnut.customform.domain.vo.CustomFormVO;
import com.chestnut.customform.permission.CustomFormPriv; import com.chestnut.customform.permission.CustomFormPriv;
import com.chestnut.customform.rule.ICustomFormLimitRule; import com.chestnut.customform.rule.ICustomFormLimitRule;
@ -109,27 +109,25 @@ public class CustomFormController extends BaseRestController {
@Log(title = "新增自定义表单", businessType = BusinessType.INSERT) @Log(title = "新增自定义表单", businessType = BusinessType.INSERT)
@Priv(type = AdminUserType.TYPE, value = CustomFormPriv.Add) @Priv(type = AdminUserType.TYPE, value = CustomFormPriv.Add)
@PostMapping @PostMapping
public R<?> add(@RequestBody @Validated CustomFormAddDTO dto) { public R<?> add(@RequestBody @Validated CreateCustomFormRequest req) {
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest()); CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());
dto.setOperator(StpAdminUtil.getLoginUser()); req.setSiteId(site.getSiteId());
dto.setSiteId(site.getSiteId()); this.customFormService.addCustomForm(req);
this.customFormService.addCustomForm(dto);
return R.ok(); return R.ok();
} }
@Log(title = "编辑自定义表单", businessType = BusinessType.UPDATE) @Log(title = "编辑自定义表单", businessType = BusinessType.UPDATE)
@Priv(type = AdminUserType.TYPE, value = {CustomFormPriv.Add, CustomFormPriv.Edit}) @Priv(type = AdminUserType.TYPE, value = {CustomFormPriv.Add, CustomFormPriv.Edit})
@PutMapping @PutMapping
public R<?> edit(@RequestBody @Validated CustomFormEditDTO dto) { public R<?> edit(@RequestBody @Validated UpdateCustomFormRequest req) {
dto.setOperator(StpAdminUtil.getLoginUser()); this.customFormService.editCustomForm(req);
this.customFormService.editCustomForm(dto);
return R.ok(); return R.ok();
} }
@Log(title = "删除自定义表单", businessType = BusinessType.DELETE) @Log(title = "删除自定义表单", businessType = BusinessType.DELETE)
@Priv(type = AdminUserType.TYPE, value = CustomFormPriv.Delete) @Priv(type = AdminUserType.TYPE, value = CustomFormPriv.Delete)
@PostMapping("/delete") @PostMapping("/delete")
public R<?> remove(@RequestBody @Validated @NotEmpty List<Long> formIds) { public R<?> remove(@RequestBody @NotEmpty List<Long> formIds) {
this.customFormService.deleteCustomForm(formIds); this.customFormService.deleteCustomForm(formIds);
return R.ok(); return R.ok();
} }
@ -137,7 +135,7 @@ public class CustomFormController extends BaseRestController {
@Log(title = "发布自定义表单", businessType = BusinessType.UPDATE) @Log(title = "发布自定义表单", businessType = BusinessType.UPDATE)
@Priv(type = AdminUserType.TYPE, value = { CustomFormPriv.Add, CustomFormPriv.Edit }) @Priv(type = AdminUserType.TYPE, value = { CustomFormPriv.Add, CustomFormPriv.Edit })
@PutMapping("/publish") @PutMapping("/publish")
public R<?> publish(@RequestBody @Validated @NotEmpty List<Long> formIds) { public R<?> publish(@RequestBody @NotEmpty List<Long> formIds) {
this.customFormService.publishCustomForms(formIds, StpAdminUtil.getLoginUser().getUsername()); this.customFormService.publishCustomForms(formIds, StpAdminUtil.getLoginUser().getUsername());
return R.ok(); return R.ok();
} }
@ -145,7 +143,7 @@ public class CustomFormController extends BaseRestController {
@Log(title = " 下线自定义表单", businessType = BusinessType.UPDATE) @Log(title = " 下线自定义表单", businessType = BusinessType.UPDATE)
@Priv(type = AdminUserType.TYPE, value = { CustomFormPriv.Add, CustomFormPriv.Edit }) @Priv(type = AdminUserType.TYPE, value = { CustomFormPriv.Add, CustomFormPriv.Edit })
@PutMapping("/offline") @PutMapping("/offline")
public R<?> offline(@RequestBody @Validated @NotEmpty List<Long> formIds) throws IOException { public R<?> offline(@RequestBody @NotEmpty List<Long> formIds) throws IOException {
this.customFormService.offlineCustomForms(formIds, StpAdminUtil.getLoginUser().getUsername()); this.customFormService.offlineCustomForms(formIds, StpAdminUtil.getLoginUser().getUsername());
return R.ok(); return R.ok();
} }

View File

@ -44,7 +44,7 @@ public class CmsCustomFormData extends BaseModelData implements Serializable {
public static final String TABLE_NAME = "cms_cfd_default"; public static final String TABLE_NAME = "cms_cfd_default";
@TableId(value = "data_id", type = IdType.INPUT) @TableId(value = "data_id", type = IdType.INPUT)
private Long dataId; private String dataId;
/** /**
* 关联表单ID元数据模型ID * 关联表单ID元数据模型ID
@ -74,7 +74,7 @@ public class CmsCustomFormData extends BaseModelData implements Serializable {
@Override @Override
public void setFieldValue(String fieldName, Object fieldValue) { public void setFieldValue(String fieldName, Object fieldValue) {
switch(fieldName) { switch(fieldName) {
case "data_id" -> this.setDataId(ConvertUtils.toLong(fieldValue)); case "data_id" -> this.setDataId(ConvertUtils.toStr(fieldValue));
case "model_id" -> this.setModelId(ConvertUtils.toLong(fieldValue)); case "model_id" -> this.setModelId(ConvertUtils.toLong(fieldValue));
case "site_id" -> this.setSiteId(ConvertUtils.toLong(fieldValue)); case "site_id" -> this.setSiteId(ConvertUtils.toLong(fieldValue));
case "client_ip" -> this.setClientIp(ConvertUtils.toStr(fieldValue)); case "client_ip" -> this.setClientIp(ConvertUtils.toStr(fieldValue));

View File

@ -19,9 +19,9 @@ import com.chestnut.common.security.domain.BaseDTO;
import com.chestnut.system.fixed.dict.YesOrNo; import com.chestnut.system.fixed.dict.YesOrNo;
import com.chestnut.system.validator.Dict; import com.chestnut.system.validator.Dict;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.hibernate.validator.constraints.Length;
/** /**
* 自定义表单添加DTO * 自定义表单添加DTO
@ -31,7 +31,7 @@ import lombok.Setter;
*/ */
@Getter @Getter
@Setter @Setter
public class CustomFormAddDTO extends BaseDTO { public class CreateCustomFormRequest extends BaseDTO {
/** /**
* 站点ID * 站点ID
@ -42,29 +42,34 @@ public class CustomFormAddDTO extends BaseDTO {
* 名称 * 名称
*/ */
@NotBlank @NotBlank
@Length(max = 100)
private String name; private String name;
/** /**
* 编码 * 编码
*/ */
@NotBlank @NotBlank
@Length(max = 50)
private String code; private String code;
/** /**
* 模型数据表 * 模型数据表
*/ */
@NotBlank @NotBlank
@Length(max = 100)
private String tableName; private String tableName;
/** /**
* 是否需要验证码 * 是否需要验证码
*/ */
@NotBlank
@Dict(YesOrNo.TYPE) @Dict(YesOrNo.TYPE)
private String needCaptcha; private String needCaptcha;
/** /**
* 是否需要会员登录 * 是否需要会员登录
*/ */
@NotBlank
@Dict(YesOrNo.TYPE) @Dict(YesOrNo.TYPE)
private String needLogin; private String needLogin;
@ -72,10 +77,12 @@ public class CustomFormAddDTO extends BaseDTO {
* 提交用户唯一性限制无限制IP浏览器指纹 * 提交用户唯一性限制无限制IP浏览器指纹
*/ */
@NotBlank @NotBlank
@Length(max = 20)
private String ruleLimit; private String ruleLimit;
/** /**
* 备注 * 备注
*/ */
@Length(max = 500)
private String remark; private String remark;
} }

View File

@ -0,0 +1,42 @@
/*
* Copyright 2022-2025 兮玥(190785909@qq.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chestnut.customform.domain.dto;
import com.chestnut.contentcore.domain.pojo.PublishPipeTemplate;
import com.chestnut.system.validator.LongId;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* 自定义表单编辑DTO
*
* @author 兮玥
* @email 190785909@qq.com
*/
@Getter
@Setter
public class UpdateCustomFormRequest extends CreateCustomFormRequest {
@LongId
private Long formId;
/**
* 模板配置
*/
private List<PublishPipeTemplate> templates;
}

View File

@ -17,11 +17,9 @@ package com.chestnut.customform.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.chestnut.customform.domain.CmsCustomForm; import com.chestnut.customform.domain.CmsCustomForm;
import com.chestnut.customform.domain.dto.CustomFormAddDTO; import com.chestnut.customform.domain.dto.CreateCustomFormRequest;
import com.chestnut.customform.domain.dto.CustomFormEditDTO; import com.chestnut.customform.domain.dto.UpdateCustomFormRequest;
import com.chestnut.customform.rule.ICustomFormLimitRule; import com.chestnut.customform.rule.ICustomFormLimitRule;
import com.chestnut.xmodel.domain.XModel;
import com.chestnut.xmodel.dto.XModelDTO;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -36,7 +34,7 @@ public interface ICustomFormService extends IService<CmsCustomForm> {
* @param dto * @param dto
* @return * @return
*/ */
void addCustomForm(CustomFormAddDTO dto); void addCustomForm(CreateCustomFormRequest dto);
/** /**
* 编辑自定义表单 * 编辑自定义表单
@ -44,7 +42,7 @@ public interface ICustomFormService extends IService<CmsCustomForm> {
* @param dto * @param dto
* @return * @return
*/ */
void editCustomForm(CustomFormEditDTO dto); void editCustomForm(UpdateCustomFormRequest dto);
/** /**
* 删除自定义表单 * 删除自定义表单

View File

@ -36,8 +36,8 @@ import com.chestnut.contentcore.util.TemplateUtils;
import com.chestnut.customform.CmsCustomFormMetaModelType; import com.chestnut.customform.CmsCustomFormMetaModelType;
import com.chestnut.customform.CustomFormConsts; import com.chestnut.customform.CustomFormConsts;
import com.chestnut.customform.domain.CmsCustomForm; import com.chestnut.customform.domain.CmsCustomForm;
import com.chestnut.customform.domain.dto.CustomFormAddDTO; import com.chestnut.customform.domain.dto.CreateCustomFormRequest;
import com.chestnut.customform.domain.dto.CustomFormEditDTO; import com.chestnut.customform.domain.dto.UpdateCustomFormRequest;
import com.chestnut.customform.fixed.dict.CustomFormStatus; import com.chestnut.customform.fixed.dict.CustomFormStatus;
import com.chestnut.customform.mapper.CustomFormMapper; import com.chestnut.customform.mapper.CustomFormMapper;
import com.chestnut.customform.publishpipe.PublishPipeProp_CustomFormTemplate; import com.chestnut.customform.publishpipe.PublishPipeProp_CustomFormTemplate;
@ -84,7 +84,7 @@ public class CustomFormServiceImpl extends ServiceImpl<CustomFormMapper, CmsCust
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void addCustomForm(CustomFormAddDTO dto) { public void addCustomForm(CreateCustomFormRequest dto) {
CmsCustomForm customForm = new CmsCustomForm(); CmsCustomForm customForm = new CmsCustomForm();
customForm.setFormId(IdUtils.getSnowflakeId()); customForm.setFormId(IdUtils.getSnowflakeId());
customForm.setSiteId(dto.getSiteId()); customForm.setSiteId(dto.getSiteId());
@ -111,7 +111,7 @@ public class CustomFormServiceImpl extends ServiceImpl<CustomFormMapper, CmsCust
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void editCustomForm(CustomFormEditDTO dto) { public void editCustomForm(UpdateCustomFormRequest dto) {
CmsCustomForm form = this.getById(dto.getFormId()); CmsCustomForm form = this.getById(dto.getFormId());
Assert.notNull(form, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("formId", dto.getFormId())); Assert.notNull(form, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("formId", dto.getFormId()));

View File

@ -114,19 +114,19 @@ public class CmsCustomFormTag extends AbstractTag {
String siteRoot = SiteUtils.getSiteRoot(site, context.getPublishPipeCode()); String siteRoot = SiteUtils.getSiteRoot(site, context.getPublishPipeCode());
String staticFileName = form.getCode() + "." + site.getStaticSuffix(context.getPublishPipeCode()); String staticFileName = form.getCode() + "." + site.getStaticSuffix(context.getPublishPipeCode());
String staticFilePath = CustomFormConsts.STATICIZE_DIRECTORY + staticFileName; String staticFilePath = CustomFormConsts.STATICIZE_DIRECTORY + staticFileName;
if (ssi) {
// 读取自定义表单静态化内容
String staticContent = templateService.getTemplateStaticContentCache(templateKey); String staticContent = templateService.getTemplateStaticContentCache(templateKey);
if (Objects.isNull(staticContent) || !new File(siteRoot + staticFilePath).exists()) { if (Objects.isNull(staticContent) || !new File(siteRoot + staticFilePath).exists()) {
staticContent = this.processTemplate(env, form, site, context.getPublishPipeCode(), templateKey); staticContent = this.processTemplate(env, form, site, context.getPublishPipeCode(), templateKey);
FileUtils.writeStringToFile(new File(siteRoot + staticFilePath), staticContent, StandardCharsets.UTF_8);
this.templateService.setTemplateStaticContentCache(templateKey, staticContent); this.templateService.setTemplateStaticContentCache(templateKey, staticContent);
if (ssi) {
FileUtils.writeStringToFile(new File(siteRoot + staticFilePath), staticContent, StandardCharsets.UTF_8);
} }
String prefix = SiteUtils.getPublishPipePrefix(site, context.getPublishPipeCode(), context.isPreview()); }
if (ssi) {
String prefix = CmsIncludeTag.getIncludePathPrefix(context.getPublishPipeCode(), site);
env.getOut().write(StringUtils.messageFormat(CmsIncludeTag.SSI_INCLUDE_TAG, prefix + staticFilePath)); env.getOut().write(StringUtils.messageFormat(CmsIncludeTag.SSI_INCLUDE_TAG, prefix + staticFilePath));
} else { } else {
// 非ssi模式无法使用缓存
String staticContent = this.processTemplate(env, form, site, context.getPublishPipeCode(), templateKey);
env.getOut().write(staticContent); env.getOut().write(staticContent);
} }
} }

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-dynamic</artifactId> <artifactId>chestnut-cms-dynamic</artifactId>

View File

@ -16,6 +16,7 @@
package com.chestnut.cms.dynamic.listener; package com.chestnut.cms.dynamic.listener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chestnut.cms.dynamic.domain.CmsDynamicPage; import com.chestnut.cms.dynamic.domain.CmsDynamicPage;
import com.chestnut.cms.dynamic.service.IDynamicPageService; import com.chestnut.cms.dynamic.service.IDynamicPageService;
import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.async.AsyncTaskManager;
@ -26,6 +27,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j @Slf4j
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
@ -40,11 +43,21 @@ public class DynamicListener {
try { try {
long total = this.dynamicPageService long total = this.dynamicPageService
.count(new LambdaQueryWrapper<CmsDynamicPage>().eq(CmsDynamicPage::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsDynamicPage>().eq(CmsDynamicPage::getSiteId, site.getSiteId()));
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total),
"正在删除自定义动态模板页面数据:" + (i * pageSize) + "/" + total); "正在删除自定义动态模板页面数据:" + (i * pageSize) + "/" + total);
this.dynamicPageService.remove(new LambdaQueryWrapper<CmsDynamicPage>().eq(CmsDynamicPage::getSiteId, site.getSiteId()) Page<CmsDynamicPage> pages = this.dynamicPageService.lambdaQuery()
.last("limit " + pageSize)); .select(CmsDynamicPage::getPageId)
.eq(CmsDynamicPage::getSiteId, site.getSiteId())
.gt(CmsDynamicPage::getPageId, lastId)
.orderByAsc(CmsDynamicPage::getPageId)
.page(Page.of(1, pageSize, false));
if (!pages.getRecords().isEmpty()) {
List<Long> pageIds = pages.getRecords().stream().map(CmsDynamicPage::getPageId).toList();
this.dynamicPageService.removeBatchByIds(pageIds);
lastId = pageIds.get(pageIds.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除自定义动态模板页面数据错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除自定义动态模板页面数据错误:" + e.getMessage());

View File

@ -1,9 +1,9 @@
DYNAMIC_PAGE_INIT_DATA.Member=登錄會員 DYNAMIC_PAGE_INIT_DATA.Member=登錄會員
DYNAMIC_PAGE_INIT_DATA.Pagination=分頁參數 DYNAMIC_PAGE_INIT_DATA.Pagination=分頁參數
FREEMARKER.FUNC.customDynamicPageLink.DESC=獲取自定義動態模板頁面鏈接,例如:`${customDynamicPageLink('Test','a=1&b=2',true)}` FREEMARKER.FUNC.customDynamicPageLink.DESC=獲取自定義動態模板頁面連結,例如:`${customDynamicPageLink('Test','a=1&b=2',true)}`
FREEMARKER.FUNC.customDynamicPageLink.Arg1.Name=自定義動態模板編碼 FREEMARKER.FUNC.customDynamicPageLink.Arg1.Name=自定義動態模板編碼
FREEMARKER.FUNC.customDynamicPageLink.Arg2.Name=鏈接參數 FREEMARKER.FUNC.customDynamicPageLink.Arg2.Name=連結參數
FREEMARKER.FUNC.customDynamicPageLink.Arg3.Name=忽略`sid/pp`參數 FREEMARKER.FUNC.customDynamicPageLink.Arg3.Name=忽略`sid/pp`參數
MONITORED.CACHE.DYNAMIC_PAGE=動態模板頁 MONITORED.CACHE.DYNAMIC_PAGE=動態模板頁

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-exmodel</artifactId> <artifactId>chestnut-cms-exmodel</artifactId>

View File

@ -168,14 +168,14 @@ public class EXModelCoreDataHandler implements ICoreDataHandler {
try { try {
Long dataId = switch (data.getDataType()) { Long dataId = switch (data.getDataType()) {
case ExtendModelDataType.SITE -> context.getSite().getSiteId(); case ExtendModelDataType.SITE -> context.getSite().getSiteId();
case ExtendModelDataType.CATALOG -> context.getCatalogIdMap().get(data.getDataId()); case ExtendModelDataType.CATALOG -> context.getCatalogIdMap().get(ConvertUtils.toLong(data.getDataId()));
case ExtendModelDataType.CONTENT -> context.getContentIdMap().get(data.getDataId()); case ExtendModelDataType.CONTENT -> context.getContentIdMap().get(ConvertUtils.toLong(data.getDataId()));
default -> null; default -> null;
}; };
if (Objects.isNull(dataId)) { if (Objects.isNull(dataId)) {
throw new RuntimeException("Old `data_id` linked data is missing."); throw new RuntimeException("Old `data_id` linked data is missing.");
} }
data.setDataId(dataId); data.setDataId(dataId.toString());
data.setModelId(modelIdMapping.get(data.getModelId())); data.setModelId(modelIdMapping.get(data.getModelId()));
// 处理图片和富文本内部链接 // 处理图片和富文本内部链接
MetaModel model = modelService.getMetaModel(data.getModelId()); MetaModel model = modelService.getMetaModel(data.getModelId());

View File

@ -32,10 +32,10 @@ import com.chestnut.exmodel.CmsExtendMetaModelType;
import com.chestnut.exmodel.permission.EXModelPriv; import com.chestnut.exmodel.permission.EXModelPriv;
import com.chestnut.exmodel.service.ExModelService; import com.chestnut.exmodel.service.ExModelService;
import com.chestnut.system.security.AdminUserType; import com.chestnut.system.security.AdminUserType;
import com.chestnut.system.security.StpAdminUtil;
import com.chestnut.system.validator.LongId; import com.chestnut.system.validator.LongId;
import com.chestnut.xmodel.domain.XModel; import com.chestnut.xmodel.domain.XModel;
import com.chestnut.xmodel.dto.XModelDTO; import com.chestnut.xmodel.dto.CreateXModelRequest;
import com.chestnut.xmodel.dto.UpdateXModelRequest;
import com.chestnut.xmodel.dto.XModelFieldDataDTO; import com.chestnut.xmodel.dto.XModelFieldDataDTO;
import com.chestnut.xmodel.service.IModelService; import com.chestnut.xmodel.service.IModelService;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
@ -95,29 +95,26 @@ public class EXModelController extends BaseRestController {
@Log(title = "新增扩展模型", businessType = BusinessType.INSERT) @Log(title = "新增扩展模型", businessType = BusinessType.INSERT)
@Priv(type = AdminUserType.TYPE, value = EXModelPriv.Add) @Priv(type = AdminUserType.TYPE, value = EXModelPriv.Add)
@PostMapping @PostMapping
public R<?> add(@RequestBody @Validated XModelDTO dto) { public R<?> add(@RequestBody @Validated CreateXModelRequest req) {
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest()); CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());
dto.setOwnerType(CmsExtendMetaModelType.TYPE); req.setOwnerType(CmsExtendMetaModelType.TYPE);
dto.setOwnerId(site.getSiteId().toString()); req.setOwnerId(site.getSiteId().toString());
dto.setOperator(StpAdminUtil.getLoginUser()); this.modelService.addModel(req);
this.modelService.addModel(dto);
return R.ok(); return R.ok();
} }
@Log(title = "编辑扩展模板", businessType = BusinessType.UPDATE) @Log(title = "编辑扩展模板", businessType = BusinessType.UPDATE)
@Priv(type = AdminUserType.TYPE, value = { EXModelPriv.Add, EXModelPriv.Edit }) @Priv(type = AdminUserType.TYPE, value = { EXModelPriv.Add, EXModelPriv.Edit })
@PutMapping @PutMapping
public R<?> edit(@RequestBody @Validated XModelDTO dto) { public R<?> edit(@RequestBody @Validated UpdateXModelRequest req) {
dto.setOperator(StpAdminUtil.getLoginUser()); this.modelService.editModel(req);
this.modelService.editModel(dto);
return R.ok(); return R.ok();
} }
@Log(title = "删除扩展模型", businessType = BusinessType.DELETE) @Log(title = "删除扩展模型", businessType = BusinessType.DELETE)
@Priv(type = AdminUserType.TYPE, value = EXModelPriv.Delete) @Priv(type = AdminUserType.TYPE, value = EXModelPriv.Delete)
@PostMapping("/delete") @PostMapping("/delete")
public R<?> remove(@RequestBody @Validated @NotEmpty List<XModelDTO> dtoList) { public R<?> remove(@RequestBody @Validated @NotEmpty List<Long> modelIds) {
List<Long> modelIds = dtoList.stream().map(XModelDTO::getModelId).toList();
this.modelService.deleteModel(modelIds); this.modelService.deleteModel(modelIds);
return R.ok(); return R.ok();
} }

View File

@ -36,7 +36,7 @@ public class CmsExtendModelData extends BaseModelData {
/** /**
* 关联数据ID联合主键 * 关联数据ID联合主键
*/ */
private Long dataId; private String dataId;
/** /**
* 关联数据类型联合主键 * 关联数据类型联合主键
@ -51,7 +51,7 @@ public class CmsExtendModelData extends BaseModelData {
@Override @Override
public void setFieldValue(String fieldName, Object fieldValue) { public void setFieldValue(String fieldName, Object fieldValue) {
switch(fieldName) { switch(fieldName) {
case "data_id" -> this.setDataId(ConvertUtils.toLong(fieldValue)); case "data_id" -> this.setDataId(ConvertUtils.toStr(fieldValue));
case "data_type" -> this.setDataType(ConvertUtils.toStr(fieldValue)); case "data_type" -> this.setDataType(ConvertUtils.toStr(fieldValue));
case "model_id" -> this.setModelId(ConvertUtils.toLong(fieldValue)); case "model_id" -> this.setModelId(ConvertUtils.toLong(fieldValue));
default -> super.setFieldValue(fieldName, fieldValue); default -> super.setFieldValue(fieldName, fieldValue);

View File

@ -22,4 +22,4 @@ DICT.ExtendModelDataType.content=內容
META.CONTROL_TYPE.CMSImage=圖片上傳 META.CONTROL_TYPE.CMSImage=圖片上傳
META.CONTROL_TYPE.UEditor=富文本編輯器 META.CONTROL_TYPE.UEditor=富文本編輯器
META.CONTROL_TYPE.CMSContentSelect=內容選擇 META.CONTROL_TYPE.CMSContentSelect=內容選擇
META.CONTROL_TYPE.CMSResource=資源文件上傳 META.CONTROL_TYPE.CMSResource=資源檔案上傳

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-image</artifactId> <artifactId>chestnut-cms-image</artifactId>

View File

@ -11,15 +11,14 @@ CMS.IMAGE.CONTENT_ID=所屬內容ID
CMS.IMAGE.SITE_ID=所屬站點ID CMS.IMAGE.SITE_ID=所屬站點ID
CMS.IMAGE.TITLE=標題 CMS.IMAGE.TITLE=標題
CMS.IMAGE.DESC=簡介 CMS.IMAGE.DESC=簡介
CMS.IMAGE.FILE_NAME=圖片文件 CMS.IMAGE.FILE_NAME=圖片原檔案
CMS.IMAGE.PATH=圖片資源路徑 CMS.IMAGE.PATH=圖片資源路徑
CMS.IMAGE.SRC=圖片訪問路徑 CMS.IMAGE.SRC=圖片訪問路徑
CMS.IMAGE.TYPE=圖片類型 CMS.IMAGE.TYPE=圖片類型
CMS.IMAGE.FILE_SIZE=圖片大小 CMS.IMAGE.FILE_SIZE=圖片大小
CMS.IMAGE.WIDTH=圖片寬度 CMS.IMAGE.WIDTH=圖片寬度
CMS.IMAGE.HEIGHT=圖片高度 CMS.IMAGE.HEIGHT=圖片高度
CMS.IMAGE.REDIRECT_URL=跳轉鏈接 CMS.IMAGE.REDIRECT_URL=跳轉連結

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-link</artifactId> <artifactId>chestnut-cms-link</artifactId>

View File

@ -28,6 +28,6 @@ import freemarker.template.TemplateException;
public class LinkGroupNotFoundTemplateException extends TemplateException { public class LinkGroupNotFoundTemplateException extends TemplateException {
public LinkGroupNotFoundTemplateException(String linkGroupCode, Environment env) { public LinkGroupNotFoundTemplateException(String linkGroupCode, Environment env) {
super(I18nUtils.get("FREEMARKER.ERR.LinkGroupNotFound"), env); super(I18nUtils.parse("FREEMARKER.ERR.LinkGroupNotFound", env.getLocale(), linkGroupCode), env);
} }
} }

View File

@ -16,6 +16,7 @@
package com.chestnut.link.listener; package com.chestnut.link.listener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chestnut.common.async.AsyncTaskManager; import com.chestnut.common.async.AsyncTaskManager;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.listener.event.BeforeSiteDeleteEvent; import com.chestnut.contentcore.listener.event.BeforeSiteDeleteEvent;
@ -28,6 +29,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j @Slf4j
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
@ -45,20 +48,40 @@ public class LinkListener {
// 删除友链数据 // 删除友链数据
long total = this.linkService long total = this.linkService
.count(new LambdaQueryWrapper<CmsLink>().eq(CmsLink::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsLink>().eq(CmsLink::getSiteId, site.getSiteId()));
long lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total),
"正在删除友链数据:" + (i * pageSize) + "/" + total); "正在删除友链数据:" + (i * pageSize) + "/" + total);
this.linkService.remove(new LambdaQueryWrapper<CmsLink>().eq(CmsLink::getSiteId, site.getSiteId()) Page<CmsLink> links = this.linkService.lambdaQuery()
.last("limit " + pageSize)); .select(CmsLink::getLinkId)
.eq(CmsLink::getSiteId, site.getSiteId())
.gt(CmsLink::getLinkId, lastId)
.orderByAsc(CmsLink::getLinkId)
.page(Page.of(1, pageSize, false));
if (!links.getRecords().isEmpty()) {
List<Long> linkIds = links.getRecords().stream().map(CmsLink::getLinkId).toList();
this.linkService.removeBatchByIds(linkIds);
lastId = linkIds.get(linkIds.size() - 1);
}
} }
// 删除友链分组数据 // 删除友链分组数据
total = this.linkGroupService total = this.linkGroupService
.count(new LambdaQueryWrapper<CmsLinkGroup>().eq(CmsLinkGroup::getSiteId, site.getSiteId())); .count(new LambdaQueryWrapper<CmsLinkGroup>().eq(CmsLinkGroup::getSiteId, site.getSiteId()));
lastId = 0;
for (long i = 0; i * pageSize < total; i++) { for (long i = 0; i * pageSize < total; i++) {
AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total), AsyncTaskManager.setTaskProgressInfo((int) (i * pageSize * 100 / total),
"正在删除友链分组数据:" + (i * pageSize) + "/" + total); "正在删除友链分组数据:" + (i * pageSize) + "/" + total);
this.linkGroupService.remove(new LambdaQueryWrapper<CmsLinkGroup>() Page<CmsLinkGroup> linkGroups = this.linkGroupService.lambdaQuery()
.eq(CmsLinkGroup::getSiteId, site.getSiteId()).last("limit " + pageSize)); .select(CmsLinkGroup::getLinkGroupId)
.eq(CmsLinkGroup::getSiteId, site.getSiteId())
.gt(CmsLinkGroup::getLinkGroupId, lastId)
.orderByAsc(CmsLinkGroup::getLinkGroupId)
.page(Page.of(1, pageSize, false));
if (!linkGroups.getRecords().isEmpty()) {
List<Long> linkGroupIds = linkGroups.getRecords().stream().map(CmsLinkGroup::getLinkGroupId).toList();
this.linkGroupService.removeBatchByIds(linkGroupIds);
lastId = linkGroupIds.get(linkGroupIds.size() - 1);
}
} }
} catch (Exception e) { } catch (Exception e) {
AsyncTaskManager.addErrMessage("删除友链数据错误:" + e.getMessage()); AsyncTaskManager.addErrMessage("删除友链数据错误:" + e.getMessage());

View File

@ -8,7 +8,7 @@ FREEMARKER.TAG.cms_link.NAME=友链列表标签
FREEMARKER.TAG.cms_link.DESC=获取友链数据列表,内嵌`<#list DataList as link>${link.name}</#list>`遍历数据 FREEMARKER.TAG.cms_link.DESC=获取友链数据列表,内嵌`<#list DataList as link>${link.name}</#list>`遍历数据
FREEMARKER.TAG.cms_link.code=友链分组编码 FREEMARKER.TAG.cms_link.code=友链分组编码
FREEMARKER.ERR.LinkGroupNotFound=友链分组数据不存在。 FREEMARKER.ERR.LinkGroupNotFound=友链分组`{0}`不存在。
CMS.LINK_GROUP.ID=友链分组ID CMS.LINK_GROUP.ID=友链分组ID
CMS.LINK_GROUP.SITE_ID=所属站点ID CMS.LINK_GROUP.SITE_ID=所属站点ID

View File

@ -8,7 +8,7 @@ FREEMARKER.TAG.cms_link.NAME=Friend-link list tag
FREEMARKER.TAG.cms_link.DESC=Fetch friend-link list, use `<#list>` in tag like `<#list DataList as link>${link.name}</#list>` to walk through the list of friend-links. FREEMARKER.TAG.cms_link.DESC=Fetch friend-link list, use `<#list>` in tag like `<#list DataList as link>${link.name}</#list>` to walk through the list of friend-links.
FREEMARKER.TAG.cms_link.code=Friend-link group code FREEMARKER.TAG.cms_link.code=Friend-link group code
FREEMARKER.ERR.LinkGroupNotFound=Friend-link group not exists. FREEMARKER.ERR.LinkGroupNotFound=Friend-link group `{0}` not exists.
CMS.LINK_GROUP.ID=ID CMS.LINK_GROUP.ID=ID
CMS.LINK_GROUP.SITE_ID=Site ID CMS.LINK_GROUP.SITE_ID=Site ID

View File

@ -8,7 +8,7 @@ FREEMARKER.TAG.cms_link.NAME=友鏈列表標籤
FREEMARKER.TAG.cms_link.DESC=獲取友鏈數據列表,內嵌`<#list DataList as link>${link.name}</#list>`遍曆數據 FREEMARKER.TAG.cms_link.DESC=獲取友鏈數據列表,內嵌`<#list DataList as link>${link.name}</#list>`遍曆數據
FREEMARKER.TAG.cms_link.code=友鏈分組編碼 FREEMARKER.TAG.cms_link.code=友鏈分組編碼
FREEMARKER.ERR.LinkGroupNotFound=友鏈分組數據不存在。 FREEMARKER.ERR.LinkGroupNotFound=友鏈分組`{0}`不存在。
CMS.LINK_GROUP.ID=友鏈分組ID CMS.LINK_GROUP.ID=友鏈分組ID
CMS.LINK_GROUP.SITE_ID=所屬站點ID CMS.LINK_GROUP.SITE_ID=所屬站點ID
@ -16,14 +16,12 @@ CMS.LINK_GROUP.NAME=分組名稱
CMS.LINK_GROUP.CODE=分組編碼 CMS.LINK_GROUP.CODE=分組編碼
CMS.LINK.ID=友鏈ID CMS.LINK.ID=友鏈ID
CMS.LINK.SITE_ID=所屬站點ID CMS.LINK.SITE_ID=站點ID
CMS.LINK.GROUP_ID=所屬分組ID CMS.LINK.GROUP_ID=分組ID
CMS.LINK.NAME=名稱 CMS.LINK.NAME=名稱
CMS.LINK.URL=鏈接 CMS.LINK.URL=連結
CMS.LINK.LOGO=Logo CMS.LINK.LOGO=Logo
CMS.LINK.SRC=Logo src CMS.LINK.SRC=Logo訪問地址

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-media</artifactId> <artifactId>chestnut-cms-media</artifactId>

View File

@ -11,25 +11,25 @@ FREEMARKER.TAG.cms_video.DESC=獲取視頻集視頻數據列表,內嵌`<#list
FREEMARKER.TAG.cms_video.contentId=視頻內容ID FREEMARKER.TAG.cms_video.contentId=視頻內容ID
CMS.MEDIA.AUDIO.ID=音頻ID CMS.MEDIA.AUDIO.ID=音頻ID
CMS.MEDIA.AUDIO.CONTENT_ID=關聯內容ID CMS.MEDIA.AUDIO.CONTENT_ID=所屬內容ID
CMS.MEDIA.AUDIO.SITE_ID=關聯站點ID CMS.MEDIA.AUDIO.SITE_ID=所屬站點ID
CMS.MEDIA.AUDIO.TITLE=音頻標題 CMS.MEDIA.AUDIO.TITLE=音頻標題
CMS.MEDIA.AUDIO.AUTHOR=作者 CMS.MEDIA.AUDIO.AUTHOR=作者
CMS.MEDIA.AUDIO.DESC=簡介 CMS.MEDIA.AUDIO.DESC=簡介
CMS.MEDIA.AUDIO.TYPE=音頻類型 CMS.MEDIA.AUDIO.TYPE=音頻類型
CMS.MEDIA.AUDIO.PATH=音頻資源路徑 CMS.MEDIA.AUDIO.PATH=音頻資源路徑
CMS.MEDIA.AUDIO.SRC=音頻訪問地址 CMS.MEDIA.AUDIO.SRC=音頻訪問地址
CMS.MEDIA.AUDIO.FILE_SIZE=文件大小,單位:字節 CMS.MEDIA.AUDIO.FILE_SIZE=檔案大小,單位:位元組
CMS.MEDIA.AUDIO.FORMAT=音頻格式 CMS.MEDIA.AUDIO.FORMAT=音頻格式
CMS.MEDIA.AUDIO.DURATION=時長,單位:毫秒 CMS.MEDIA.AUDIO.DURATION=時長,單位:毫秒
CMS.MEDIA.AUDIO.DECODER=編碼方式 CMS.MEDIA.AUDIO.DECODER=編碼方式
CMS.MEDIA.AUDIO.CHANNELS=聲道數 CMS.MEDIA.AUDIO.CHANNELS=聲道數
CMS.MEDIA.AUDIO.BIT_RATE=比特率 CMS.MEDIA.AUDIO.BIT_RATE=比特率
CMS.MEDIA.AUDIO.SAMPLING_RATE=樣率 CMS.MEDIA.AUDIO.SAMPLING_RATE=樣率
CMS.MEDIA.VIDEO.ID=視頻ID CMS.MEDIA.VIDEO.ID=視頻ID
CMS.MEDIA.VIDEO.CONTENT_ID=關聯內容ID CMS.MEDIA.VIDEO.CONTENT_ID=所屬內容ID
CMS.MEDIA.VIDEO.SITE_ID=關聯站點ID CMS.MEDIA.VIDEO.SITE_ID=所屬站點ID
CMS.MEDIA.VIDEO.COVER=視頻封面資源路徑 CMS.MEDIA.VIDEO.COVER=視頻封面資源路徑
CMS.MEDIA.VIDEO.COVER_SRC=視頻封面訪問地址 CMS.MEDIA.VIDEO.COVER_SRC=視頻封面訪問地址
CMS.MEDIA.VIDEO.TITLE=視頻標題 CMS.MEDIA.VIDEO.TITLE=視頻標題
@ -37,7 +37,7 @@ CMS.MEDIA.VIDEO.DESC=簡介
CMS.MEDIA.VIDEO.TYPE=視頻類型 CMS.MEDIA.VIDEO.TYPE=視頻類型
CMS.MEDIA.VIDEO.PATH=視頻資源路徑/第三方引用代碼 CMS.MEDIA.VIDEO.PATH=視頻資源路徑/第三方引用代碼
CMS.MEDIA.VIDEO.SRC=視頻訪問地址 CMS.MEDIA.VIDEO.SRC=視頻訪問地址
CMS.MEDIA.VIDEO.FILE_SIZE=文件大小,單位:字節 CMS.MEDIA.VIDEO.FILE_SIZE=檔案大小,單位:位元組
CMS.MEDIA.VIDEO.FORMAT=視頻格式 CMS.MEDIA.VIDEO.FORMAT=視頻格式
CMS.MEDIA.VIDEO.DURATION=時長,單位:毫秒 CMS.MEDIA.VIDEO.DURATION=時長,單位:毫秒
CMS.MEDIA.VIDEO.DECODER=編碼方式 CMS.MEDIA.VIDEO.DECODER=編碼方式

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-member</artifactId> <artifactId>chestnut-cms-member</artifactId>

View File

@ -19,7 +19,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chestnut.article.ArticleContent; import com.chestnut.article.ArticleContent;
import com.chestnut.article.ArticleContentType; import com.chestnut.article.ArticleContentType;
import com.chestnut.article.IArticleBodyFormat;
import com.chestnut.article.domain.CmsArticleDetail; import com.chestnut.article.domain.CmsArticleDetail;
import com.chestnut.article.format.ArticleBodyFormat_RichText;
import com.chestnut.article.service.IArticleService; import com.chestnut.article.service.IArticleService;
import com.chestnut.cms.member.domain.dto.ArticleContributeDTO; import com.chestnut.cms.member.domain.dto.ArticleContributeDTO;
import com.chestnut.cms.member.domain.vo.MemberContentVO; import com.chestnut.cms.member.domain.vo.MemberContentVO;
@ -27,7 +29,7 @@ import com.chestnut.cms.member.properties.EnableContributeProperty;
import com.chestnut.common.domain.R; import com.chestnut.common.domain.R;
import com.chestnut.common.exception.CommonErrorCode; import com.chestnut.common.exception.CommonErrorCode;
import com.chestnut.common.security.anno.Priv; import com.chestnut.common.security.anno.Priv;
import com.chestnut.common.security.domain.LoginUser; import com.chestnut.common.security.domain.Operator;
import com.chestnut.common.security.web.BaseRestController; import com.chestnut.common.security.web.BaseRestController;
import com.chestnut.common.utils.Assert; import com.chestnut.common.utils.Assert;
import com.chestnut.common.utils.IdUtils; import com.chestnut.common.utils.IdUtils;
@ -71,6 +73,7 @@ import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import static com.chestnut.common.utils.SortUtils.getDefaultSortValue; import static com.chestnut.common.utils.SortUtils.getDefaultSortValue;
@ -111,13 +114,14 @@ public class MemberContributeApiController extends BaseRestController implements
if (!ContentStatus.isDraft(xContent.getStatus())) { if (!ContentStatus.isDraft(xContent.getStatus())) {
return R.fail("只能删除待审核的初稿"); return R.fail("只能删除待审核的初稿");
} }
if (xContent.getContributorId() != StpMemberUtil.getLoginIdAsLong()) { Operator operator = Operator.of(StpMemberUtil.getLoginUser());
if (!Objects.equals(xContent.getContributorId(), operator.getUserId())) {
return R.fail("内容ID错误"); return R.fail("内容ID错误");
} }
IContentType contentType = ContentCoreUtils.getContentType(xContent.getContentType()); IContentType contentType = ContentCoreUtils.getContentType(xContent.getContentType());
IContent<?> content = contentType.loadContent(xContent); IContent<?> content = contentType.loadContent(xContent);
content.setOperator(StpMemberUtil.getLoginUser()); content.setOperator(operator);
transactionTemplate.executeWithoutResult(transactionStatus -> content.delete()); transactionTemplate.executeWithoutResult(transactionStatus -> content.delete());
applicationContext.publishEvent(new AfterContentDeleteEvent(this, content)); applicationContext.publishEvent(new AfterContentDeleteEvent(this, content));
return R.ok(); return R.ok();
@ -144,10 +148,10 @@ public class MemberContributeApiController extends BaseRestController implements
if (!EnableContributeProperty.getValue(catalog.getConfigProps())) { if (!EnableContributeProperty.getValue(catalog.getConfigProps())) {
return R.fail("参数`catalogId`异常:" + dto.getCatalogId()); return R.fail("参数`catalogId`异常:" + dto.getCatalogId());
} }
LoginUser loginUser = StpMemberUtil.getLoginUser(); Operator operator = Operator.of(StpMemberUtil.getLoginUser());
if (IdUtils.validate(dto.getContentId())) { if (IdUtils.validate(dto.getContentId())) {
CmsContent cmsContent = this.contentService.dao().getById(dto.getContentId()); CmsContent cmsContent = this.contentService.dao().getById(dto.getContentId());
if (!loginUser.getUserId().equals(cmsContent.getContributorId())) { if (!operator.getUserId().equals(cmsContent.getContributorId())) {
return R.fail("内容ID错误"); return R.fail("内容ID错误");
} }
if (!ContentStatus.isDraft(cmsContent.getStatus())) { if (!ContentStatus.isDraft(cmsContent.getStatus())) {
@ -163,7 +167,7 @@ public class MemberContributeApiController extends BaseRestController implements
cmsContent.setTags(dto.getTags().toArray(String[]::new)); cmsContent.setTags(dto.getTags().toArray(String[]::new));
// 重置发布状态 // 重置发布状态
cmsContent.setStatus(ContentStatus.DRAFT); cmsContent.setStatus(ContentStatus.DRAFT);
cmsContent.updateBy(loginUser.getUsername()); cmsContent.updateBy(operator.getUsername());
if (!dto.getCatalogId().equals(cmsContent.getCatalogId())) { if (!dto.getCatalogId().equals(cmsContent.getCatalogId())) {
CmsCatalog fromCatalog = this.catalogService.getCatalog(cmsContent.getCatalogId()); CmsCatalog fromCatalog = this.catalogService.getCatalog(cmsContent.getCatalogId());
CmsCatalog toCatalog = this.catalogService.getCatalog(dto.getCatalogId()); CmsCatalog toCatalog = this.catalogService.getCatalog(dto.getCatalogId());
@ -178,11 +182,16 @@ public class MemberContributeApiController extends BaseRestController implements
} }
CmsArticleDetail articleDetail = this.articleService.dao().getById(cmsContent.getContentId()); CmsArticleDetail articleDetail = this.articleService.dao().getById(cmsContent.getContentId());
articleDetail.setContentHtml(dto.getContentHtml()); articleDetail.setContentHtml(dto.getContentHtml());
IArticleBodyFormat articleBodyFormat = articleService.getArticleBodyFormat(dto.getFormat());
if (Objects.isNull(articleBodyFormat)) {
dto.setFormat(ArticleBodyFormat_RichText.ID);
}
articleDetail.setFormat(dto.getFormat());
ArticleContent content = new ArticleContent(); ArticleContent content = new ArticleContent();
content.setContentEntity(cmsContent); content.setContentEntity(cmsContent);
content.setExtendEntity(articleDetail); content.setExtendEntity(articleDetail);
content.setOperator(loginUser); content.setOperator(operator);
applicationContext.publishEvent(new BeforeContentSaveEvent(this, content, false)); applicationContext.publishEvent(new BeforeContentSaveEvent(this, content, false));
content.save(); content.save();
applicationContext.publishEvent(new AfterContentSaveEvent(this, content, false)); applicationContext.publishEvent(new AfterContentSaveEvent(this, content, false));
@ -218,7 +227,7 @@ public class MemberContributeApiController extends BaseRestController implements
if (content.hasExtendEntity() && StringUtils.isEmpty(extendEntity.getContentHtml())) { if (content.hasExtendEntity() && StringUtils.isEmpty(extendEntity.getContentHtml())) {
throw CommonErrorCode.NOT_EMPTY.exception("contentHtml"); throw CommonErrorCode.NOT_EMPTY.exception("contentHtml");
} }
content.setOperator(StpMemberUtil.getLoginUser()); content.setOperator(operator);
applicationContext.publishEvent(new BeforeContentSaveEvent(this, content, true)); applicationContext.publishEvent(new BeforeContentSaveEvent(this, content, true));
content.add(); content.add();
applicationContext.publishEvent(new AfterContentSaveEvent(this, content, true)); applicationContext.publishEvent(new AfterContentSaveEvent(this, content, true));

View File

@ -69,4 +69,9 @@ public class ArticleContributeDTO {
* 引导图 * 引导图
*/ */
private String logo; private String logo;
/**
* 文章格式
*/
private String format;
} }

View File

@ -4,10 +4,10 @@ ERRCODE.CMS.MEMBER.NO_CONTRIBUTE_PRIV=無投稿許可權
# freemarker模板標籤 # freemarker模板標籤
FREEMARKER.TAG.cms_favorite_content.NAME=收藏內容列表標籤 FREEMARKER.TAG.cms_favorite_content.NAME=收藏內容列表標籤
FREEMARKER.TAG.cms_favorite_content.DESC=獲取收藏內容數據列表,內嵌`<#list DataList as content>${content.title}</#list>`遍曆數據 FREEMARKER.TAG.cms_favorite_content.DESC=獲取收藏內容數據列表,內嵌`<#list DataList as content>${content.title}</#list>`遍曆數據
FREEMARKER.TAG.cms_favorite_content.uid=用户ID FREEMARKER.TAG.cms_favorite_content.uid=會員ID
FREEMARKER.TAG.cms_member_follow.NAME=關注/粉絲列表標籤 FREEMARKER.TAG.cms_member_follow.NAME=關注/粉絲列表標籤
FREEMARKER.TAG.cms_member_follow.DESC=獲取關注/粉絲數據列表,內嵌`<#list DataList as member>${member.displayName}</#list>`遍曆數據 FREEMARKER.TAG.cms_member_follow.DESC=獲取關注/粉絲數據列表,內嵌`<#list DataList as member>${member.displayName}</#list>`遍曆數據
FREEMARKER.TAG.cms_member_follow.uid=用户ID FREEMARKER.TAG.cms_member_follow.uid=會員ID
FREEMARKER.TAG.cms_member_follow.type=類型 FREEMARKER.TAG.cms_member_follow.type=類型
FREEMARKER.TAG.cms_member_follow.type.follow=關注 FREEMARKER.TAG.cms_member_follow.type.follow=關注
FREEMARKER.TAG.cms_member_follow.type.follower=粉絲 FREEMARKER.TAG.cms_member_follow.type.follower=粉絲
@ -18,7 +18,7 @@ FREEMARKER.FUNC.accountUrl.Arg1.Name=會員ID
FREEMARKER.FUNC.accountUrl.Arg2.Name=頁面類型 FREEMARKER.FUNC.accountUrl.Arg2.Name=頁面類型
FREEMARKER.FUNC.accountUrl.Arg3.Name=是否忽略`sid/pp`參數 FREEMARKER.FUNC.accountUrl.Arg3.Name=是否忽略`sid/pp`參數
# 动态模板 # 動態模板
DYNAMIC_PAGE_TYPE.AccountBindEmail.NAME=會員綁定郵箱頁 DYNAMIC_PAGE_TYPE.AccountBindEmail.NAME=會員綁定郵箱頁
DYNAMIC_PAGE_TYPE.AccountCentre.NAME=會員個人中心頁 DYNAMIC_PAGE_TYPE.AccountCentre.NAME=會員個人中心頁
DYNAMIC_PAGE_TYPE.AccountCentre.ARG.memberId=會員ID DYNAMIC_PAGE_TYPE.AccountCentre.ARG.memberId=會員ID
@ -38,4 +38,4 @@ CMS.MEMBER.SLOGAN=標語
CMS.MEMBER.STAT=統計數據<分類,數量> CMS.MEMBER.STAT=統計數據<分類,數量>
CMS.MEMBER.MENU=會員菜單 CMS.MEMBER.MENU=會員菜單
CMS.MEMBER.MENU.NAME=會員菜單名稱 CMS.MEMBER.MENU.NAME=會員菜單名稱
CMS.MEMBER.MENU.URL=會員菜單鏈接 CMS.MEMBER.MENU.URL=會員菜單連結

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-search</artifactId> <artifactId>chestnut-cms-search</artifactId>

View File

@ -26,7 +26,6 @@ import com.chestnut.common.utils.StringUtils;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.service.ISiteService; import com.chestnut.contentcore.service.ISiteService;
import com.chestnut.search.domain.SearchLog; import com.chestnut.search.domain.SearchLog;
import com.chestnut.search.domain.SearchWord;
import com.chestnut.search.service.ISearchLogService; import com.chestnut.search.service.ISearchLogService;
import com.chestnut.system.security.AdminUserType; import com.chestnut.system.security.AdminUserType;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -46,7 +45,7 @@ public class CMSSearchLogController extends BaseRestController {
@Priv(type = AdminUserType.TYPE) @Priv(type = AdminUserType.TYPE)
@GetMapping @GetMapping
public R<?> getPageList(@RequestParam(value = "query", required = false) String query) { public R<?> getPageList(@RequestParam(required = false) String query) {
PageRequest pr = this.getPageRequest(); PageRequest pr = this.getPageRequest();
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest()); CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());
Page<SearchLog> page = this.searchLogService.lambdaQuery() Page<SearchLog> page = this.searchLogService.lambdaQuery()

View File

@ -28,10 +28,11 @@ import com.chestnut.common.utils.StringUtils;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.service.ISiteService; import com.chestnut.contentcore.service.ISiteService;
import com.chestnut.search.domain.SearchWord; import com.chestnut.search.domain.SearchWord;
import com.chestnut.search.domain.dto.CreateSearchWordRequest;
import com.chestnut.search.service.ISearchWordService; import com.chestnut.search.service.ISearchWordService;
import com.chestnut.system.security.AdminUserType; import com.chestnut.system.security.AdminUserType;
import com.chestnut.system.security.StpAdminUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@Priv(type = AdminUserType.TYPE) @Priv(type = AdminUserType.TYPE)
@ -45,7 +46,7 @@ public class CMSSearchWordStatController extends BaseRestController {
private final ISearchWordService searchWordStatService; private final ISearchWordService searchWordStatService;
@GetMapping @GetMapping
public R<?> getPageList(@RequestParam(value = "query", required = false) String query) { public R<?> getPageList(@RequestParam(required = false) String query) {
PageRequest pr = this.getPageRequest(); PageRequest pr = this.getPageRequest();
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest()); CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());
Page<SearchWord> page = this.searchWordStatService.lambdaQuery() Page<SearchWord> page = this.searchWordStatService.lambdaQuery()
@ -58,11 +59,10 @@ public class CMSSearchWordStatController extends BaseRestController {
@Log(title = "新增搜索词", businessType = BusinessType.INSERT) @Log(title = "新增搜索词", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
public R<?> addWord(@RequestBody SearchWord wordStat) { public R<?> addWord(@RequestBody @Validated CreateSearchWordRequest req) {
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest()); CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());
wordStat.setSource(CmsSearchConstants.generateSearchSource(site.getSiteId())); req.setSource(CmsSearchConstants.generateSearchSource(site.getSiteId()));
wordStat.createBy(StpAdminUtil.getLoginUser().getUsername()); this.searchWordStatService.addWord(req);
this.searchWordStatService.addWord(wordStat);
return R.ok(); return R.ok();
} }
} }

View File

@ -54,6 +54,7 @@ import com.chestnut.xmodel.core.IMetaModelType;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.hibernate.validator.constraints.Length;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.io.IOException; import java.io.IOException;
@ -85,9 +86,9 @@ public class ContentIndexController extends BaseRestController {
} }
@GetMapping("/contents") @GetMapping("/contents")
public R<?> selectDocumentList(@RequestParam(value = "query", required = false) String query, public R<?> selectDocumentList(@RequestParam(value = "query", required = false) @Length(max = 200) String query,
@RequestParam(value = "onlyTitle", required = false ,defaultValue = "false") Boolean onlyTitle, @RequestParam(value = "onlyTitle", required = false ,defaultValue = "false") Boolean onlyTitle,
@RequestParam(value = "contentType", required = false) String contentType) throws ElasticsearchException, IOException { @RequestParam(value = "contentType", required = false) @Length(max = 20) String contentType) throws ElasticsearchException, IOException {
this.checkElasticSearchEnabled(); this.checkElasticSearchEnabled();
PageRequest pr = this.getPageRequest(); PageRequest pr = this.getPageRequest();
CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest()); CmsSite site = this.siteService.getCurrentSite(ServletUtils.getRequest());

View File

@ -19,7 +19,9 @@ import com.chestnut.cms.search.impl.SearchDynamicPageType;
import com.chestnut.common.security.web.BaseRestController; import com.chestnut.common.security.web.BaseRestController;
import com.chestnut.common.utils.ServletUtils; import com.chestnut.common.utils.ServletUtils;
import com.chestnut.contentcore.service.impl.DynamicPageService; import com.chestnut.contentcore.service.impl.DynamicPageService;
import com.chestnut.system.validator.LongId;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
@ -44,11 +46,11 @@ public class CmsSearchController extends BaseRestController {
private final DynamicPageService dynamicPageService; private final DynamicPageService dynamicPageService;
@GetMapping(SearchDynamicPageType.REQUEST_PATH) @GetMapping(SearchDynamicPageType.REQUEST_PATH)
public void searchPage(@RequestParam(value ="q", required = false, defaultValue = "") @Length(max = 50) String query, public void searchPage(@RequestParam(value ="q", required = false, defaultValue = "") @Length(max = 200) String query,
@RequestParam("sid") Long siteId, @RequestParam("sid") @LongId Long siteId,
@RequestParam("pp") String publishPipeCode, @RequestParam("pp") @NotBlank @Length(max = 50) String publishPipeCode,
@RequestParam(value = "ot", required = false ,defaultValue = "false") Boolean onlyTitle, @RequestParam(value = "ot", required = false ,defaultValue = "false") Boolean onlyTitle,
@RequestParam(value = "ct", required = false) String contentType, @RequestParam(value = "ct", required = false) @Length(max = 20) String contentType,
@RequestParam(value = "page", required = false, defaultValue = "1") Integer page, @RequestParam(value = "page", required = false, defaultValue = "1") Integer page,
@RequestParam(required = false, defaultValue = "false") Boolean preview, @RequestParam(required = false, defaultValue = "false") Boolean preview,
HttpServletResponse response) HttpServletResponse response)

View File

@ -40,8 +40,9 @@ import com.chestnut.search.SearchConsts;
import com.chestnut.search.service.ISearchLogService; import com.chestnut.search.service.ISearchLogService;
import com.chestnut.system.validator.LongId; import com.chestnut.system.validator.LongId;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min; import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
@ -51,6 +52,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.util.List; import java.util.List;
@ -65,6 +67,9 @@ import java.util.stream.Collectors;
@RequestMapping("/api/cms/search") @RequestMapping("/api/cms/search")
public class SearchApiController extends BaseRestController { public class SearchApiController extends BaseRestController {
private static final String SORT_SCORE = "1"; // 排序方式相关度
private static final String SORT_PUBLISH_DATE = "2"; // 排序方式发布时间
private final ICatalogService catalogService; private final ICatalogService catalogService;
private final ElasticsearchClient esClient; private final ElasticsearchClient esClient;
@ -75,14 +80,18 @@ public class SearchApiController extends BaseRestController {
@GetMapping("/query") @GetMapping("/query")
public R<?> selectDocumentList( public R<?> selectDocumentList(
@RequestParam(value = "sid") Long siteId, @RequestParam(value = "sid") Long siteId, // 站点ID
@RequestParam(value = "pp") String publishPipeCode, @RequestParam(value = "pp") String publishPipeCode, // 发布通道
@RequestParam(value = "q") @Length(max = 50) String query, @RequestParam(value = "q") @Length(max = 50) String query, // 检索词
@RequestParam(value = "ot", required = false ,defaultValue = "false") Boolean onlyTitle, @RequestParam(value = "ot", required = false ,defaultValue = "false") Boolean onlyTitle, // 是否只查标题
@RequestParam(value = "ct", required = false) String contentType, @RequestParam(value = "ct", required = false) String contentType, // 类型类型
@RequestParam(value = "page", required = false, defaultValue = "1") @Min(1) Integer page, @RequestParam(value = "ts", required = false) String[] tags, // 标签列表
@RequestParam(value = "st", required = false, defaultValue = SORT_SCORE) String sortType, // 排序方式1 = 相关度2 = 发布时间
@RequestParam(value = "bt", required = false) LocalDate beginTime, // 发布时间Begin
@RequestParam(value = "et", required = false) LocalDate endTime, // 发布时间End
@RequestParam(value = "page", required = false, defaultValue = "1") @Min(1) Integer page, // 页码
@RequestParam(value = "size", required = false, defaultValue = "10") @Min(1) Integer pageSize, // 每页数量
@RequestParam(value = "preview", required = false, defaultValue = "false") Boolean preview) throws ElasticsearchException, IOException { @RequestParam(value = "preview", required = false, defaultValue = "false") Boolean preview) throws ElasticsearchException, IOException {
int pageSize = 10;
String indexName = CmsSearchConstants.indexName(siteId.toString()); String indexName = CmsSearchConstants.indexName(siteId.toString());
SearchResponse<ObjectNode> sr = esClient.search(s -> { SearchResponse<ObjectNode> sr = esClient.search(s -> {
s.index(indexName) // 索引 s.index(indexName) // 索引
@ -110,6 +119,31 @@ public class SearchApiController extends BaseRestController {
); );
} }
} }
if (StringUtils.isNotEmpty(tags)) {
b.must(should -> {
for (String tag : tags) {
should.constantScore(cs ->
cs.boost(1F).filter(f ->
f.match(m ->
m.field("tags").query(tag))));
}
return should;
});
}
if (Objects.nonNull(beginTime) || Objects.nonNull(endTime)) {
b.must(must -> must.range(range ->
range.number(num -> {
num.field("publishDate");
if (Objects.nonNull(beginTime)) {
num.gte((double) beginTime.atStartOfDay().toEpochSecond(ZoneOffset.UTC));
}
if (Objects.nonNull(endTime)) {
num.lte((double) endTime.atStartOfDay().toEpochSecond(ZoneOffset.UTC));
}
return num;
})
));
}
return b; return b;
}) })
); );
@ -118,7 +152,9 @@ public class SearchApiController extends BaseRestController {
h.fields("title", f -> f.preTags("<font color='red'>").postTags("</font>")) h.fields("title", f -> f.preTags("<font color='red'>").postTags("</font>"))
.fields("fullText", f -> f.preTags("<font color='red'>").postTags("</font>"))); .fields("fullText", f -> f.preTags("<font color='red'>").postTags("</font>")));
} }
if (SORT_SCORE.equals(sortType)) {
s.sort(sort -> sort.field(f -> f.field("_score").order(SortOrder.Desc))); s.sort(sort -> sort.field(f -> f.field("_score").order(SortOrder.Desc)));
}
s.sort(sort -> sort.field(f -> f.field("publishDate").order(SortOrder.Desc))); // 排序: _score:desc + publishDate:desc s.sort(sort -> sort.field(f -> f.field("publishDate").order(SortOrder.Desc))); // 排序: _score:desc + publishDate:desc
// s.source(source -> source.filter(f -> f.excludes("fullText"))); // 过滤字段 // s.source(source -> source.filter(f -> f.excludes("fullText"))); // 过滤字段
s.from((page - 1) * pageSize).size(pageSize); // 分页0开始 s.from((page - 1) * pageSize).size(pageSize); // 分页0开始
@ -166,13 +202,13 @@ public class SearchApiController extends BaseRestController {
@GetMapping("/tag") @GetMapping("/tag")
public R<?> selectDocumentByTag( public R<?> selectDocumentByTag(
@RequestParam(value = "sid") Long siteId, @RequestParam(value = "sid") @LongId Long siteId,
@RequestParam(value = "cid", required = false, defaultValue = "0") Long catalogId, @RequestParam(value = "cid", required = false, defaultValue = "0") Long catalogId,
@RequestParam(value = "pp") String publishPipeCode, @RequestParam(value = "pp") @NotBlank @Length(max = 50) String publishPipeCode,
@RequestParam(value = "q", required = false) @Length(max = 200) String query, @RequestParam(value = "q", required = false) @NotBlank @Length(max = 200) String query,
@RequestParam(value = "ct", required = false) String contentType, @RequestParam(value = "ct", required = false) @Length(max = 20) String contentType,
@RequestParam(value = "page", required = false, defaultValue = "1") @Min(1) Integer page, @RequestParam(value = "page", required = false, defaultValue = "1") @Min(1) Integer page,
@RequestParam(value = "size", required = false, defaultValue = "10") @Min(1) Integer size, @RequestParam(value = "size", required = false, defaultValue = "10") @Min(1) @Max(100) Integer size,
@RequestParam(value = "preview", required = false, defaultValue = "false") Boolean preview) throws ElasticsearchException, IOException { @RequestParam(value = "preview", required = false, defaultValue = "false") Boolean preview) throws ElasticsearchException, IOException {
String indexName = CmsSearchConstants.indexName(siteId.toString()); String indexName = CmsSearchConstants.indexName(siteId.toString());
SearchResponse<ObjectNode> sr = esClient.search(s -> { SearchResponse<ObjectNode> sr = esClient.search(s -> {
@ -238,9 +274,9 @@ public class SearchApiController extends BaseRestController {
@GetMapping("/suggest") @GetMapping("/suggest")
public R<List<String>> getSuggestWords(@RequestParam("sid") @LongId Long siteId, public R<List<String>> getSuggestWords(@RequestParam("sid") @LongId Long siteId,
@RequestParam(value = "cid", required = false, defaultValue = "0") Long catalogId, @RequestParam(value = "cid", required = false, defaultValue = "0") Long catalogId,
@RequestParam(value = "q") @NotEmpty @Length(max = 50) String query, @RequestParam(value = "q") @NotBlank @Length(max = 200) String query,
@RequestParam(value = "ct", required = false) String contentType, @RequestParam(value = "ct", required = false) @Length(max = 20) String contentType,
@RequestParam(value = "size", required = false) Integer size) throws IOException { @RequestParam(value = "size", required = false) @Min(1) @Max(100) Integer size) throws IOException {
String suggester = "title-suggest"; String suggester = "title-suggest";
String indexName = CmsSearchConstants.indexName(siteId.toString()); String indexName = CmsSearchConstants.indexName(siteId.toString());
SearchResponse<ObjectNode> sr = esClient.search(s -> SearchResponse<ObjectNode> sr = esClient.search(s ->
@ -279,11 +315,11 @@ public class SearchApiController extends BaseRestController {
@GetMapping("/group/catalog") @GetMapping("/group/catalog")
public R<?> groupBy(@RequestParam("sid") @LongId Long siteId, public R<?> groupBy(@RequestParam("sid") @LongId Long siteId,
@RequestParam(value = "q") @Length(max = 50) String query, @RequestParam(value = "q") @NotBlank @Length(max = 200) String query,
@RequestParam(value = "cid", defaultValue = "0") Long catalogId, @RequestParam(value = "cid", defaultValue = "0") Long catalogId,
@RequestParam(value = "level", defaultValue = "0") Integer level, @RequestParam(value = "level", defaultValue = "0") Integer level,
@RequestParam(value = "ot", required = false ,defaultValue = "false") Boolean onlyTitle, @RequestParam(value = "ot", required = false ,defaultValue = "false") Boolean onlyTitle,
@RequestParam(value = "ct", required = false) String contentType) throws ElasticsearchException, IOException { @RequestParam(value = "ct", required = false) @Length(max = 20) String contentType) throws ElasticsearchException, IOException {
CmsCatalog catalog = IdUtils.validate(catalogId) ? catalogService.getCatalog(catalogId) : null; CmsCatalog catalog = IdUtils.validate(catalogId) ? catalogService.getCatalog(catalogId) : null;
String indexName = CmsSearchConstants.indexName(siteId.toString()); String indexName = CmsSearchConstants.indexName(siteId.toString());
SearchResponse<ObjectNode> sr = esClient.search(s -> SearchResponse<ObjectNode> sr = esClient.search(s ->

View File

@ -12,8 +12,8 @@ FREEMARKER.TAG.cms_search_content.mode.TagAnd=標籤與檢索,多個標籤英
FREEMARKER.TAG.cms_search_content.level=數據獲取範圍V1.5.6+ FREEMARKER.TAG.cms_search_content.level=數據獲取範圍V1.5.6+
FREEMARKER.TAG.cms_search_content.level.Current=當前欄目 FREEMARKER.TAG.cms_search_content.level.Current=當前欄目
FREEMARKER.TAG.cms_search_content.level.CurrentAndChild=當前欄目和子欄目 FREEMARKER.TAG.cms_search_content.level.CurrentAndChild=當前欄目和子欄目
FREEMARKER.TAG.cms_search_word.NAME=檢索詞熱詞標籤 FREEMARKER.TAG.cms_search_word.NAME=搜索熱詞標籤
FREEMARKER.TAG.cms_search_word.DESC=檢索詞熱詞標籤 FREEMARKER.TAG.cms_search_word.DESC=搜索熱詞標籤
CONFIG.CMSSearchAnalyzeType=索引分詞方式 CONFIG.CMSSearchAnalyzeType=索引分詞方式
@ -25,9 +25,10 @@ DYNAMIC_PAGE_TYPE.Search.ARG.ct=內容類型
DYNAMIC_PAGE_TYPE.Search.ARG.page=頁碼 DYNAMIC_PAGE_TYPE.Search.ARG.page=頁碼
PROGRESS.INFO.BUILDING_INDEX=正在重建欄目索引:{0} PROGRESS.INFO.BUILDING_INDEX=正在重建欄目索引:{0}
PROGRESS.INFO.BUILD_SUCCEED=重建索引完成
CMS.ES_CONTENT.FULL_TEXT=全文內容 CMS.ES_CONTENT.FULL_TEXT=全文內容
CMS.ES_CONTENT.PUBLISH_DATE_TIMESTAMP=時間戳 CMS.ES_CONTENT.PUBLISH_DATE_TIMESTAMP=時間戳
CMS.ES_CONTENT.CREATE_TIME_TIMESTAMP=建時間戳 CMS.ES_CONTENT.CREATE_TIME_TIMESTAMP=時間戳
CMS.ES_CONTENT.HIT_SCORE=匹配度 CMS.ES_CONTENT.HIT_SCORE=匹配度
CMS.ES_CONTENT.EXTEND_DATA=擴展模型數據 CMS.ES_CONTENT.EXTEND_DATA=擴展模型數據

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-seo</artifactId> <artifactId>chestnut-cms-seo</artifactId>

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-stat</artifactId> <artifactId>chestnut-cms-stat</artifactId>

View File

@ -21,6 +21,6 @@ STAT.MENU.ContentStatByUser=用戶發布統計
# TAG # TAG
FREEMARKER.TAG.cms_stat.NAME=訪問統計標籤 FREEMARKER.TAG.cms_stat.NAME=訪問統計標籤
FREEMARKER.TAG.cms_stat.DESC=用於在模板頁面中插入內置訪問統計腳本代碼 FREEMARKER.TAG.cms_stat.DESC=用於在模板頁面中插入內置訪問統計指令碼或直譯式程式代碼
SCHEDULED_TASK.StatContentCountByStatus=內容發統計任務 SCHEDULED_TASK.StatContentCountByStatus=內容發統計任務

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-vote</artifactId> <artifactId>chestnut-cms-vote</artifactId>

View File

@ -3,6 +3,6 @@ FREEMARKER.TAG.cms_vote.NAME=調查問卷列表標籤
FREEMARKER.TAG.cms_vote.DESC=獲取調查問卷數據列表,內嵌`<#list DataList as vote>${vote.title}</#list>`遍曆數據 FREEMARKER.TAG.cms_vote.DESC=獲取調查問卷數據列表,內嵌`<#list DataList as vote>${vote.title}</#list>`遍曆數據
FREEMARKER.TAG.cms_vote_subject.NAME=調查問卷主題列表標籤 FREEMARKER.TAG.cms_vote_subject.NAME=調查問卷主題列表標籤
FREEMARKER.TAG.cms_vote_subject.DESC=獲取調查問卷主題數據列表,內嵌`<#list DataList as subject>${subject.title}</#list>`遍曆數據 FREEMARKER.TAG.cms_vote_subject.DESC=獲取調查問卷主題數據列表,內嵌`<#list DataList as subject>${subject.title}</#list>`遍曆數據
FREEMARKER.TAG.cms_vote_subject.code=調查問卷編碼 FREEMARKER.TAG.cms_vote_subject.code=問卷調查編碼
FREEMARKER.ERR.VOTE_NOT_FOUND=調查問卷數據不存在code = {0}。 FREEMARKER.ERR.VOTE_NOT_FOUND=調查問卷數據不存在code = {0}。

View File

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>com.chestnut</groupId> <groupId>com.chestnut</groupId>
<artifactId>chestnut-cms</artifactId> <artifactId>chestnut-cms</artifactId>
<version>1.5.7</version> <version>1.5.8</version>
</parent> </parent>
<artifactId>chestnut-cms-word</artifactId> <artifactId>chestnut-cms-word</artifactId>

View File

@ -26,8 +26,8 @@ import com.chestnut.common.utils.StringUtils;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.service.ISiteService; import com.chestnut.contentcore.service.ISiteService;
import com.chestnut.system.security.AdminUserType; import com.chestnut.system.security.AdminUserType;
import com.chestnut.system.security.StpAdminUtil;
import com.chestnut.word.domain.HotWordGroup; import com.chestnut.word.domain.HotWordGroup;
import com.chestnut.word.domain.dto.CreateHotWordGroupRequest;
import com.chestnut.word.permission.WordPriv; import com.chestnut.word.permission.WordPriv;
import com.chestnut.word.service.IHotWordGroupService; import com.chestnut.word.service.IHotWordGroupService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -72,11 +72,7 @@ public class CMSHotWordGroupController extends BaseRestController {
List<HotWordGroup> list = this.hotWordGroupService.lambdaQuery() List<HotWordGroup> list = this.hotWordGroupService.lambdaQuery()
.eq(HotWordGroup::getOwner, currentSite.getSiteId().toString()) .eq(HotWordGroup::getOwner, currentSite.getSiteId().toString())
.list(); .list();
List<Map<String, Object>> options = new ArrayList<>(); return this.bindSelectOptions(list, HotWordGroup::getCode, HotWordGroup::getName);
list.forEach(g -> {
options.add(Map.of("code", g.getCode(), "name", g.getName()));
});
return this.bindDataTable(options);
} }
@Priv(type = AdminUserType.TYPE, value = WordPriv.View) @Priv(type = AdminUserType.TYPE, value = WordPriv.View)
@ -99,10 +95,9 @@ public class CMSHotWordGroupController extends BaseRestController {
@Priv(type = AdminUserType.TYPE, value = WordPriv.View) @Priv(type = AdminUserType.TYPE, value = WordPriv.View)
@PostMapping @PostMapping
public R<?> add(@RequestBody @Validated HotWordGroup group) { public R<?> add(@RequestBody @Validated CreateHotWordGroupRequest req) {
CmsSite site = siteService.getCurrentSite(ServletUtils.getRequest()); CmsSite site = siteService.getCurrentSite(ServletUtils.getRequest());
group.setOwner(site.getSiteId().toString()); req.setOwner(site.getSiteId().toString());
group.createBy(StpAdminUtil.getLoginUser().getUsername()); return R.ok(this.hotWordGroupService.addHotWordGroup(req));
return R.ok(this.hotWordGroupService.addHotWordGroup(group));
} }
} }

View File

@ -23,8 +23,8 @@ import com.chestnut.common.utils.ServletUtils;
import com.chestnut.contentcore.domain.CmsSite; import com.chestnut.contentcore.domain.CmsSite;
import com.chestnut.contentcore.service.ISiteService; import com.chestnut.contentcore.service.ISiteService;
import com.chestnut.system.security.AdminUserType; import com.chestnut.system.security.AdminUserType;
import com.chestnut.system.security.StpAdminUtil;
import com.chestnut.word.domain.TagWordGroup; import com.chestnut.word.domain.TagWordGroup;
import com.chestnut.word.domain.dto.CreateTagWordGroupRequest;
import com.chestnut.word.permission.WordPriv; import com.chestnut.word.permission.WordPriv;
import com.chestnut.word.service.ITagWordGroupService; import com.chestnut.word.service.ITagWordGroupService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -61,10 +61,9 @@ public class CMSTagWordGroupController extends BaseRestController {
@Priv(type = AdminUserType.TYPE, value = WordPriv.View) @Priv(type = AdminUserType.TYPE, value = WordPriv.View)
@PostMapping @PostMapping
public R<?> add(@RequestBody @Validated TagWordGroup group) { public R<?> add(@RequestBody @Validated CreateTagWordGroupRequest req) {
group.createBy(StpAdminUtil.getLoginUser().getUsername());
CmsSite currentSite = siteService.getCurrentSite(ServletUtils.getRequest()); CmsSite currentSite = siteService.getCurrentSite(ServletUtils.getRequest());
group.setOwner(currentSite.getSiteId().toString()); req.setOwner(currentSite.getSiteId().toString());
return R.ok(this.tagWordGroupService.addTagWordGroup(group)); return R.ok(this.tagWordGroupService.addTagWordGroup(req));
} }
} }

Some files were not shown because too many files have changed in this diff Show More