mirror of
https://gitee.com/liweiyi/ChestnutCMS.git
synced 2025-12-06 16:38:24 +08:00
版本更新:V1.5.3
This commit is contained in:
parent
df1edc879f
commit
0274696789
@ -1,4 +1,4 @@
|
||||
# ChestnutCMS v1.5.2
|
||||
# ChestnutCMS v1.5.3
|
||||
|
||||
### 系统简介
|
||||
|
||||
@ -6,7 +6,7 @@ ChestnutCMS是前后端分离的企业级内容管理系统。项目基于[RuoYi
|
||||
|
||||
### 系统预览
|
||||
|
||||
后台预览地址:<http://admin.1000mz.com>
|
||||
后台预览地址:<https://admin.1000mz.com>
|
||||
|
||||
账号:demo / a123456
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@ -5,7 +5,7 @@ chestnut:
|
||||
# 代号
|
||||
alias: ChestnutCMS
|
||||
# 版本
|
||||
version: 1.5.2
|
||||
version: 1.5.3
|
||||
# 版权年份
|
||||
copyrightYear: 2022-2024
|
||||
system:
|
||||
|
||||
@ -5,7 +5,7 @@ chestnut:
|
||||
# 代号
|
||||
alias: ChestnutCMS
|
||||
# 版本
|
||||
version: 1.5.2
|
||||
version: 1.5.3
|
||||
# 版权年份
|
||||
copyrightYear: 2022-2024
|
||||
system:
|
||||
|
||||
@ -5,7 +5,7 @@ chestnut:
|
||||
# 代号
|
||||
alias: ChestnutCMS
|
||||
# 版本
|
||||
version: 1.5.2
|
||||
version: 1.5.3
|
||||
# 版权年份
|
||||
copyrightYear: 2022-2024
|
||||
system:
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
ALTER TABLE cms_ad_click_log ADD COLUMN `ad_name` varchar(255);
|
||||
ALTER TABLE cms_ad_click_log MODIFY COLUMN `ip` varchar(40);
|
||||
ALTER TABLE cms_ad_click_log MODIFY COLUMN `address` varchar(100);
|
||||
ALTER TABLE cms_ad_click_log MODIFY COLUMN `browser` varchar(50);
|
||||
ALTER TABLE cms_ad_click_log MODIFY COLUMN `os` varchar(50);
|
||||
ALTER TABLE cms_ad_click_log MODIFY COLUMN `device_type` varchar(50);
|
||||
ALTER TABLE cms_ad_click_log MODIFY COLUMN `locale` varchar(20);
|
||||
|
||||
ALTER TABLE cms_ad_view_log ADD COLUMN `ad_name` varchar(255);
|
||||
ALTER TABLE cms_ad_view_log MODIFY COLUMN `ip` varchar(40);
|
||||
ALTER TABLE cms_ad_view_log MODIFY COLUMN `address` varchar(100);
|
||||
ALTER TABLE cms_ad_view_log MODIFY COLUMN `browser` varchar(50);
|
||||
ALTER TABLE cms_ad_view_log MODIFY COLUMN `os` varchar(50);
|
||||
ALTER TABLE cms_ad_view_log MODIFY COLUMN `device_type` varchar(50);
|
||||
ALTER TABLE cms_ad_view_log MODIFY COLUMN `locale` varchar(20);
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-advertisement</artifactId>
|
||||
|
||||
@ -37,6 +37,5 @@ public class AdSpacePageWidget extends AbstractPageWidget {
|
||||
// 删除广告版位相关的广告
|
||||
this.advertisementService.remove(new LambdaQueryWrapper<CmsAdvertisement>()
|
||||
.eq(CmsAdvertisement::getAdSpaceId, this.getPageWidgetEntity().getPageWidgetId()));
|
||||
// TODO 删除广告统计数据
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(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.advertisement;
|
||||
|
||||
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.service.IAdvertisementService;
|
||||
import com.chestnut.common.async.AsyncTaskManager;
|
||||
import com.chestnut.contentcore.core.IResourceStat;
|
||||
import com.chestnut.contentcore.core.InternalURL;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 自定义区块资源引用统计
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Component(IResourceStat.BEAN_PREFIX + AdvResourceStat.TYPE)
|
||||
public class AdvResourceStat implements IResourceStat {
|
||||
|
||||
public static final String TYPE = "Adv";
|
||||
|
||||
private final IAdvertisementService advertisementService;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void statQuotedResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 1000;
|
||||
long lastId = 0L;
|
||||
int count = 0;
|
||||
long total = advertisementService.lambdaQuery().select(List.of(CmsAdvertisement::getAdvertisementId))
|
||||
.eq(CmsAdvertisement::getSiteId, siteId).count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsAdvertisement> q = new LambdaQueryWrapper<CmsAdvertisement>()
|
||||
.select(List.of(CmsAdvertisement::getResourcePath))
|
||||
.eq(CmsAdvertisement::getSiteId, siteId)
|
||||
.gt(CmsAdvertisement::getAdvertisementId, lastId)
|
||||
.orderByAsc(CmsAdvertisement::getAdvertisementId);
|
||||
Page<CmsAdvertisement> page = advertisementService.page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsAdvertisement advertisement : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计广告资源引用:" + count + " / " + total + "]");
|
||||
lastId = advertisement.getAdvertisementId();
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(advertisement.getResourcePath());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,7 @@ package com.chestnut.advertisement.controller.front;
|
||||
import com.chestnut.advertisement.stat.AdClickStatEventHandler;
|
||||
import com.chestnut.advertisement.stat.AdViewStatEventHandler;
|
||||
import com.chestnut.common.security.web.BaseRestController;
|
||||
import com.chestnut.common.utils.IdUtils;
|
||||
import com.chestnut.common.utils.JacksonUtils;
|
||||
import com.chestnut.common.utils.ServletUtils;
|
||||
import com.chestnut.stat.core.StatEvent;
|
||||
@ -61,6 +62,10 @@ public class AdApiController extends BaseRestController {
|
||||
|
||||
@GetMapping("/click")
|
||||
public void adClick(@RequestParam("sid") Long siteId, @RequestParam("aid") Long advertisementId) {
|
||||
if (!IdUtils.validate(siteId) || !IdUtils.validate(advertisementId)) {
|
||||
log.warn("Invalid sid/aid: sid = {}, aid = {}", siteId, advertisementId);
|
||||
return;
|
||||
}
|
||||
StatEvent evt = new StatEvent();
|
||||
evt.setType(AdClickStatEventHandler.TYPE);
|
||||
ObjectNode objectNode = JacksonUtils.objectNode();
|
||||
@ -74,6 +79,10 @@ public class AdApiController extends BaseRestController {
|
||||
|
||||
@GetMapping("/view")
|
||||
public void adView(@RequestParam("sid") Long siteId, @RequestParam("aid") Long advertisementId) {
|
||||
if (!IdUtils.validate(siteId) || !IdUtils.validate(advertisementId)) {
|
||||
log.warn("Invalid sid/aid: sid = {}, aid = {}", siteId, advertisementId);
|
||||
return;
|
||||
}
|
||||
StatEvent evt = new StatEvent();
|
||||
evt.setType(AdViewStatEventHandler.TYPE);
|
||||
ObjectNode objectNode = JacksonUtils.objectNode();
|
||||
|
||||
@ -52,7 +52,6 @@ public class CmsAdClickLog implements Serializable {
|
||||
/**
|
||||
* 广告名称
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String adName;
|
||||
|
||||
/**
|
||||
|
||||
@ -52,7 +52,6 @@ public class CmsAdViewLog implements Serializable {
|
||||
/**
|
||||
* 广告名称
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String adName;
|
||||
|
||||
/**
|
||||
|
||||
@ -16,25 +16,33 @@
|
||||
package com.chestnut.advertisement.stat;
|
||||
|
||||
import com.chestnut.advertisement.domain.CmsAdClickLog;
|
||||
import com.chestnut.advertisement.service.IAdvertisementService;
|
||||
import com.chestnut.advertisement.service.IAdvertisementStatService;
|
||||
import com.chestnut.common.utils.IdUtils;
|
||||
import com.chestnut.stat.core.IStatEventHandler;
|
||||
import com.chestnut.stat.core.StatEvent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 广告点击事件
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component(IStatEventHandler.BEAN_PREFIX + AdClickStatEventHandler.TYPE)
|
||||
public class AdClickStatEventHandler implements IStatEventHandler {
|
||||
|
||||
public static final String TYPE = "adclick";
|
||||
|
||||
private final IAdvertisementService adService;
|
||||
|
||||
private final IAdvertisementStatService advertisementStatService;
|
||||
|
||||
@Override
|
||||
@ -44,15 +52,23 @@ public class AdClickStatEventHandler implements IStatEventHandler {
|
||||
|
||||
@Override
|
||||
public void handle(StatEvent event) {
|
||||
CmsAdClickLog log = parseLog(event);
|
||||
String aid = event.getData().get("aid").asText();
|
||||
Map<String, String> map = this.adService.getAdvertisementMap();
|
||||
String adName = map.get(aid);
|
||||
if (Objects.isNull(adName)) {
|
||||
log.warn("Invalid aid: {}", aid);
|
||||
return;
|
||||
}
|
||||
CmsAdClickLog log = parseLog(Long.parseLong(aid), adName, event);
|
||||
advertisementStatService.adClick(log);
|
||||
}
|
||||
|
||||
private CmsAdClickLog parseLog(StatEvent event) {
|
||||
private CmsAdClickLog parseLog(long advertiseId, String adName, StatEvent event) {
|
||||
CmsAdClickLog log = new CmsAdClickLog();
|
||||
log.setLogId(IdUtils.getSnowflakeId());
|
||||
log.setSiteId(event.getData().get("sid").asLong());
|
||||
log.setAdId(event.getData().get("aid").asLong());
|
||||
log.setAdId(advertiseId);
|
||||
log.setAdName(adName);
|
||||
|
||||
log.setHost(event.getRequestData().getHost());
|
||||
log.setIp(event.getRequestData().getIp());
|
||||
|
||||
@ -16,25 +16,33 @@
|
||||
package com.chestnut.advertisement.stat;
|
||||
|
||||
import com.chestnut.advertisement.domain.CmsAdViewLog;
|
||||
import com.chestnut.advertisement.service.IAdvertisementService;
|
||||
import com.chestnut.advertisement.service.IAdvertisementStatService;
|
||||
import com.chestnut.common.utils.IdUtils;
|
||||
import com.chestnut.stat.core.IStatEventHandler;
|
||||
import com.chestnut.stat.core.StatEvent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 广告展现事件
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component(IStatEventHandler.BEAN_PREFIX + AdViewStatEventHandler.TYPE)
|
||||
public class AdViewStatEventHandler implements IStatEventHandler {
|
||||
|
||||
public static final String TYPE = "adview";
|
||||
|
||||
private final IAdvertisementService adService;
|
||||
|
||||
private final IAdvertisementStatService advertisementStatService;
|
||||
|
||||
@Override
|
||||
@ -44,15 +52,23 @@ public class AdViewStatEventHandler implements IStatEventHandler {
|
||||
|
||||
@Override
|
||||
public void handle(StatEvent event) {
|
||||
CmsAdViewLog log = parseLog(event);
|
||||
String aid = event.getData().get("aid").asText();
|
||||
Map<String, String> map = this.adService.getAdvertisementMap();
|
||||
String adName = map.get(aid);
|
||||
if (Objects.isNull(adName)) {
|
||||
log.warn("Invalid aid: {}", aid);
|
||||
return;
|
||||
}
|
||||
CmsAdViewLog log = parseLog(Long.parseLong(aid), adName, event);
|
||||
advertisementStatService.adView(log);
|
||||
}
|
||||
|
||||
private CmsAdViewLog parseLog(StatEvent event) {
|
||||
private CmsAdViewLog parseLog(long advertiseId, String adName, StatEvent event) {
|
||||
CmsAdViewLog log = new CmsAdViewLog();
|
||||
log.setLogId(IdUtils.getSnowflakeId());
|
||||
log.setSiteId(event.getData().get("sid").asLong());
|
||||
log.setAdId(event.getData().get("aid").asLong());
|
||||
log.setAdId(advertiseId);
|
||||
log.setAdName(adName);
|
||||
|
||||
log.setHost(event.getRequestData().getHost());
|
||||
log.setIp(event.getRequestData().getIp());
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-article</artifactId>
|
||||
|
||||
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(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.article;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.chestnut.article.domain.CmsArticleDetail;
|
||||
import com.chestnut.article.format.ArticleBodyFormat_RichText;
|
||||
import com.chestnut.article.service.IArticleService;
|
||||
import com.chestnut.common.async.AsyncTaskManager;
|
||||
import com.chestnut.contentcore.core.IResourceStat;
|
||||
import com.chestnut.contentcore.core.InternalURL;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/**
|
||||
* 文章正文资源引用统计
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component(IResourceStat.BEAN_PREFIX + ArticleRichTextResourceStat.TYPE)
|
||||
public class ArticleRichTextResourceStat implements IResourceStat {
|
||||
|
||||
public static final String TYPE = "ArticleRichText";
|
||||
|
||||
private final IArticleService articleService;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void statQuotedResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 100;
|
||||
long lastId = 0L;
|
||||
int count = 0;
|
||||
long total = articleService.dao().lambdaQuery().select(List.of(CmsArticleDetail::getContentId))
|
||||
.eq(CmsArticleDetail::getSiteId, siteId)
|
||||
.eq(CmsArticleDetail::getFormat, ArticleBodyFormat_RichText.ID)
|
||||
.count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsArticleDetail> q = new LambdaQueryWrapper<CmsArticleDetail>()
|
||||
.select(List.of(CmsArticleDetail::getContentHtml))
|
||||
.eq(CmsArticleDetail::getSiteId, siteId)
|
||||
.eq(CmsArticleDetail::getFormat, ArticleBodyFormat_RichText.ID)
|
||||
.gt(CmsArticleDetail::getContentId, lastId)
|
||||
.orderByAsc(CmsArticleDetail::getContentId);
|
||||
Page<CmsArticleDetail> page = articleService.dao().page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsArticleDetail articleDetail : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计富文本文章正文资源引用:" + count + " / " + total + "]");
|
||||
lastId = articleDetail.getContentId();
|
||||
// 解析文章正文
|
||||
Matcher matcher = InternalUrlUtils.InternalUrlTagPattern.matcher(articleDetail.getContentHtml());
|
||||
while (matcher.find()) {
|
||||
String iurl = matcher.group(1);
|
||||
try {
|
||||
InternalURL internalUrl = InternalUrlUtils.parseInternalUrl(iurl);
|
||||
if (Objects.nonNull(internalUrl)) {
|
||||
quotedResources.compute(internalUrl.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("InternalUrl parse failed: " + iurl, e);
|
||||
}
|
||||
}
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,7 @@ import lombok.Setter;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 文章内容API接口VO
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-block</artifactId>
|
||||
|
||||
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(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.block;
|
||||
|
||||
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.utils.JacksonUtils;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.core.IResourceStat;
|
||||
import com.chestnut.contentcore.core.InternalURL;
|
||||
import com.chestnut.contentcore.domain.CmsPageWidget;
|
||||
import com.chestnut.contentcore.service.IPageWidgetService;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 自定义区块资源引用统计
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Component(IResourceStat.BEAN_PREFIX + BlockResourceStat.TYPE)
|
||||
public class BlockResourceStat implements IResourceStat {
|
||||
|
||||
public static final String TYPE = "Block";
|
||||
|
||||
private final IPageWidgetService pageWidgetService;
|
||||
|
||||
private final ManualPageWidgetType manualPageWidgetType;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void statQuotedResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 1000;
|
||||
long lastId = 0L;
|
||||
int count = 0;
|
||||
long total = pageWidgetService.lambdaQuery().select(List.of(CmsPageWidget::getContent))
|
||||
.eq(CmsPageWidget::getSiteId, siteId).eq(CmsPageWidget::getType, manualPageWidgetType.getId()).count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsPageWidget> q = new LambdaQueryWrapper<CmsPageWidget>()
|
||||
.select(List.of(CmsPageWidget::getContent))
|
||||
.eq(CmsPageWidget::getSiteId, siteId)
|
||||
.eq(CmsPageWidget::getType, manualPageWidgetType.getId())
|
||||
.gt(CmsPageWidget::getPageWidgetId, lastId)
|
||||
.orderByAsc(CmsPageWidget::getPageWidgetId);
|
||||
Page<CmsPageWidget> page = pageWidgetService.page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsPageWidget pageWidget : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计自定义区块资源引用:" + count + " / " + total + "]");
|
||||
lastId = pageWidget.getPageWidgetId();
|
||||
if (StringUtils.isNotEmpty(pageWidget.getContent())) {
|
||||
List<ManualPageWidgetType.RowData> rowData = JacksonUtils.fromList(pageWidget.getContent(), ManualPageWidgetType.RowData.class);
|
||||
if (Objects.nonNull(rowData)) {
|
||||
rowData.forEach(row -> {
|
||||
row.getItems().forEach(item -> {
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(item.getLogo());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,7 @@ public class ManualPageWidgetType implements IPageWidgetType {
|
||||
list = List.of();
|
||||
}
|
||||
list.forEach(rd -> rd.getItems().forEach(item -> {
|
||||
item.setLogoSrc(InternalUrlUtils.getActualPreviewUrl(item.logo));
|
||||
item.setLogoSrc(InternalUrlUtils.getActualUrl(item.logo, publishPipeCode, isPreview));
|
||||
item.setLink(item.getUrl());
|
||||
}));
|
||||
return list;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-comment</artifactId>
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
package com.chestnut.cms.comment;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 评论模块静态变量
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-contentcore</artifactId>
|
||||
|
||||
@ -146,8 +146,8 @@ public class CoreController extends BaseRestController {
|
||||
templateType.initTemplateData(siteId, templateContext);
|
||||
templateContext.getVariables().put(TemplateUtils.TemplateVariable_Request, params);
|
||||
// TODO 兼容历史版本,下个大版本移除IncludeRequest模板变量
|
||||
templateContext.getVariables().put("IncludeRequest", params);
|
||||
templateContext.getVariables().put("ClientType", ServletUtils.getDeviceType());
|
||||
templateContext.getVariables().put(TemplateUtils.TemplateVariable_IncludeRequest, params);
|
||||
templateContext.getVariables().put(TemplateUtils.TemplateVariable_ClientType, ServletUtils.getDeviceType());
|
||||
// staticize
|
||||
HttpServletResponse response = ServletUtils.getResponse();
|
||||
response.setCharacterEncoding(Charset.defaultCharset().displayName());
|
||||
|
||||
@ -55,13 +55,19 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -388,30 +394,31 @@ public class SiteController extends BaseRestController {
|
||||
}
|
||||
|
||||
@Priv(type = AdminUserType.TYPE, value = "Site:Edit:${#siteId}")
|
||||
@PostMapping("/theme_download")
|
||||
public void export(@RequestParam Long siteId, HttpServletResponse response) throws IOException {
|
||||
@GetMapping("/downloadTheme/{siteId}")
|
||||
public ResponseEntity<StreamingResponseBody> downloadTheme(@PathVariable @LongId Long siteId) {
|
||||
CmsSite site = this.siteService.getSite(siteId);
|
||||
File file = new File(SiteUtils.getSiteResourceRoot(site) + SiteThemeService.ThemeZipPath);
|
||||
if (!file.exists()) {
|
||||
response.getWriter().write("站点主题文件不存在");
|
||||
return;
|
||||
}
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
|
||||
response.setHeader("Content-disposition", "attachment;filename="
|
||||
+ StringUtils.substringAfterLast(SiteThemeService.ThemeZipPath, "/"));
|
||||
response.addHeader("Content-Length", "" + file.length());
|
||||
try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
|
||||
byte[] buff = new byte[1024];
|
||||
OutputStream os = response.getOutputStream();
|
||||
int i;
|
||||
while ((i = bis.read(buff)) != -1) {
|
||||
os.write(buff, 0, i);
|
||||
os.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||
response.getWriter().write("Export site theme file failed: " + e.getMessage());
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getName() + "\"")
|
||||
.contentLength(file.length())
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(outputStream -> {
|
||||
long timeout = 600_000;
|
||||
Instant startTime = Instant.now();
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
byte[] data = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = is.read(data)) != -1) {
|
||||
outputStream.write(data, 0, bytesRead);
|
||||
outputStream.flush();
|
||||
if (Duration.between(startTime, Instant.now()).toMillis() > timeout) {
|
||||
throw new RuntimeException("Timed out");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -25,12 +25,12 @@ import com.chestnut.contentcore.domain.CmsCatalog;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.vo.ContentApiVO;
|
||||
import com.chestnut.contentcore.domain.vo.ContentDynamicDataVO;
|
||||
import com.chestnut.contentcore.domain.vo.ContentVO;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentStatus;
|
||||
import com.chestnut.contentcore.service.ICatalogService;
|
||||
import com.chestnut.contentcore.service.IContentService;
|
||||
import com.chestnut.contentcore.service.impl.ContentDynamicDataService;
|
||||
import com.chestnut.contentcore.template.tag.CmsContentTag;
|
||||
import com.chestnut.contentcore.util.CatalogUtils;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -91,21 +91,22 @@ public class ContentApiController extends BaseRestController {
|
||||
@RequestParam(value = "pp") String publishPipeCode,
|
||||
@RequestParam(value = "preview", required = false, defaultValue = "false") Boolean preview
|
||||
) {
|
||||
if (!"Root".equalsIgnoreCase(level) && !IdUtils.validate(catalogId)) {
|
||||
if (!CmsContentTag.LevelTagAttr.isRoot(level) && !IdUtils.validate(catalogId)) {
|
||||
return R.fail("The parameter cid is required where lv is `Root`.");
|
||||
}
|
||||
LambdaQueryWrapper<CmsContent> q = new LambdaQueryWrapper<>();
|
||||
q.eq(CmsContent::getSiteId, siteId).eq(CmsContent::getStatus, ContentStatus.PUBLISHED);
|
||||
if (!"Root".equalsIgnoreCase(level)) {
|
||||
|
||||
if (!CmsContentTag.LevelTagAttr.isRoot(level)) {
|
||||
CmsCatalog catalog = this.catalogService.getCatalog(catalogId);
|
||||
if (Objects.isNull(catalog)) {
|
||||
return R.fail("Catalog not found: " + catalogId);
|
||||
}
|
||||
if ("Current".equalsIgnoreCase(level)) {
|
||||
if (CmsContentTag.LevelTagAttr.isCurrent(level)) {
|
||||
q.eq(CmsContent::getCatalogId, catalog.getCatalogId());
|
||||
} else if ("Child".equalsIgnoreCase(level)) {
|
||||
} else if (CmsContentTag.LevelTagAttr.isChild(level)) {
|
||||
q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors() + CatalogUtils.ANCESTORS_SPLITER);
|
||||
} else if ("CurrentAndChild".equalsIgnoreCase(level)) {
|
||||
} else if (CmsContentTag.LevelTagAttr.isCurrentAndChild(level)) {
|
||||
q.likeRight(CmsContent::getCatalogAncestors, catalog.getAncestors());
|
||||
}
|
||||
}
|
||||
@ -121,8 +122,10 @@ public class ContentApiController extends BaseRestController {
|
||||
q.apply(bit > 0, "attributes&{0}<>{1}", attrTotal, bit);
|
||||
}
|
||||
}
|
||||
if ("Recent".equalsIgnoreCase(sortType)) {
|
||||
if (CmsContentTag.SortTagAttr.isRecent(sortType)) {
|
||||
q.orderByDesc(CmsContent::getPublishDate);
|
||||
} else if (CmsContentTag.SortTagAttr.isViews(sortType)) {
|
||||
q.orderByDesc(CmsContent::getViewCount);
|
||||
} else {
|
||||
q.orderByDesc(Arrays.asList(CmsContent::getTopFlag, CmsContent::getSortFlag));
|
||||
}
|
||||
@ -143,12 +146,4 @@ public class ContentApiController extends BaseRestController {
|
||||
});
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO 按浏览量排序获取数据
|
||||
*/
|
||||
public R<ContentVO> getHotContentList() {
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import com.chestnut.contentcore.exception.ContentCoreErrorCode;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentOpType;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentStatus;
|
||||
import com.chestnut.contentcore.listener.event.*;
|
||||
import com.chestnut.contentcore.perms.CatalogPermissionType;
|
||||
import com.chestnut.contentcore.properties.PublishedContentEditProperty;
|
||||
import com.chestnut.contentcore.service.ICatalogService;
|
||||
import com.chestnut.contentcore.service.IContentService;
|
||||
@ -37,6 +38,7 @@ import com.chestnut.contentcore.util.ContentCoreUtils;
|
||||
import com.chestnut.contentcore.util.ContentLogUtils;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import com.chestnut.system.fixed.dict.YesOrNo;
|
||||
import com.chestnut.system.permission.PermissionUtils;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
@ -270,7 +272,9 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
this.getContentEntity().getTitle())) {
|
||||
throw ContentCoreErrorCode.TITLE_REPLEAT.exception();
|
||||
}
|
||||
// TODO 校验权限,需要同时拥有目标栏目的新建权限和源栏目的复制权限
|
||||
// 校验权限
|
||||
PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(toCatalog.getCatalogId()), this.getOperator());
|
||||
|
||||
CmsContent newContent = new CmsContent();
|
||||
BeanUtils.copyProperties(this.getContentEntity(), newContent, "contentId", "template", "staticPath", "topFlag",
|
||||
"topDate", "isLock", "lockUser");
|
||||
@ -310,7 +314,9 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
this.getContentEntity().getTitle())) {
|
||||
throw ContentCoreErrorCode.TITLE_REPLEAT.exception();
|
||||
}
|
||||
// TODO 校验权限,需要同时拥有目标栏目的新建权限和源栏目的转移权限
|
||||
// 校验权限
|
||||
PermissionUtils.checkPermission(CatalogPermissionType.CatalogPrivItem.AddContent.getPermissionKey(toCatalog.getCatalogId()), this.getOperator());
|
||||
|
||||
CmsCatalog fromCatalog = this.getCatalogService().getCatalog(content.getCatalogId());
|
||||
// 重置内容信息
|
||||
content.setSiteId(toCatalog.getSiteId());
|
||||
|
||||
@ -25,8 +25,15 @@ import java.util.Map;
|
||||
*/
|
||||
public interface IResourceStat {
|
||||
|
||||
String BEAN_PREFIX = "ResourceStat_";
|
||||
|
||||
/**
|
||||
* 查找资源引用次数
|
||||
* 引用分类
|
||||
*/
|
||||
Map<Long, Integer> findQuotedResource();
|
||||
String getType();
|
||||
|
||||
/**
|
||||
* 统计资源引用次数
|
||||
*/
|
||||
void statQuotedResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException;
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
package com.chestnut.contentcore.core;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 站点主题导入/导出上下文
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.core.impl;
|
||||
|
||||
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.utils.ArrayUtils;
|
||||
import com.chestnut.contentcore.core.IResourceStat;
|
||||
import com.chestnut.contentcore.core.InternalURL;
|
||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
||||
@ -27,18 +31,22 @@ import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 资源引用统计
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Component(IResourceStat.BEAN_PREFIX + ContentCoreResourceStat.TYPE)
|
||||
public class ContentCoreResourceStat implements IResourceStat {
|
||||
|
||||
public static final String TYPE = "ContentCore";
|
||||
|
||||
private final ISiteService siteService;
|
||||
|
||||
private final ICatalogService catalogService;
|
||||
@ -46,60 +54,93 @@ public class ContentCoreResourceStat implements IResourceStat {
|
||||
private final IContentService contentService;
|
||||
|
||||
@Override
|
||||
public Map<Long, Integer> findQuotedResource() {
|
||||
Map<Long, Integer> quotedResources = new HashMap<>();
|
||||
this.siteLogo().forEach(rid -> {
|
||||
quotedResources.compute(rid, (k, v) -> {
|
||||
return Objects.isNull(v) ? 1 : v++;
|
||||
});
|
||||
});
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
this.catalogLogo();
|
||||
this.contentLogo();
|
||||
return quotedResources;
|
||||
@Override
|
||||
public void statQuotedResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
this.siteLogo(siteId, quotedResources);
|
||||
this.catalogLogo(siteId, quotedResources);
|
||||
this.contentLogo(siteId, quotedResources);
|
||||
}
|
||||
|
||||
/**
|
||||
* 内容logo引用
|
||||
*/
|
||||
private Set<Long> contentLogo() {
|
||||
Set<Long> resourceIds = new HashSet<>();
|
||||
this.contentService.dao().lambdaQuery().select(List.of(CmsContent::getImages)).list().forEach(content -> {
|
||||
if (Objects.nonNull(content.getImages())) {
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(content.getLogo());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
resourceIds.add(internalURL.getId());
|
||||
}
|
||||
private void contentLogo(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 1000;
|
||||
long lastContentId = 0L;
|
||||
int count = 0;
|
||||
long total = contentService.dao().lambdaQuery().select(List.of(CmsContent::getImages))
|
||||
.eq(CmsContent::getSiteId, siteId).isNotNull(CmsContent::getImages).count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsContent> q = new LambdaQueryWrapper<CmsContent>()
|
||||
.select(List.of(CmsContent::getImages))
|
||||
.eq(CmsContent::getSiteId, siteId)
|
||||
.isNotNull(CmsContent::getImages)
|
||||
.gt(CmsContent::getContentId, lastContentId)
|
||||
.orderByAsc(CmsContent::getContentId);
|
||||
Page<CmsContent> page = contentService.dao().page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsContent content : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计内容LOGO资源引用:" + count + " / " + total + "]");
|
||||
lastContentId = content.getContentId();
|
||||
ArrayUtils.mapNotNull(content.getImages(), InternalUrlUtils::parseInternalUrl)
|
||||
.forEach(internalURL -> {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
});
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
});
|
||||
return resourceIds;
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 栏目logo引用
|
||||
*/
|
||||
private Set<Long> catalogLogo() {
|
||||
Set<Long> resourceIds = new HashSet<>();
|
||||
this.catalogService.lambdaQuery().select(List.of(CmsCatalog::getLogo)).list().forEach(catalog -> {
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(catalog.getLogo());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
resourceIds.add(internalURL.getId());
|
||||
private void catalogLogo(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 1000;
|
||||
long lastCatalogId = 0L;
|
||||
int count = 0;
|
||||
long total = catalogService.lambdaQuery().select(List.of(CmsCatalog::getLogo))
|
||||
.eq(CmsCatalog::getSiteId, siteId).isNotNull(CmsCatalog::getLogo).count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsCatalog> q = new LambdaQueryWrapper<CmsCatalog>()
|
||||
.select(List.of(CmsCatalog::getLogo))
|
||||
.eq(CmsCatalog::getSiteId, siteId)
|
||||
.isNotNull(CmsCatalog::getLogo)
|
||||
.gt(CmsCatalog::getCatalogId, lastCatalogId)
|
||||
.orderByAsc(CmsCatalog::getCatalogId);
|
||||
Page<CmsCatalog> page = catalogService.page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsCatalog catalog : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计栏目LOGO资源引用:" + count + " / " + total + "]");
|
||||
lastCatalogId = catalog.getCatalogId();
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(catalog.getLogo());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
});
|
||||
return resourceIds;
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 站点logo引用
|
||||
*/
|
||||
private Set<Long> siteLogo() {
|
||||
Set<Long> resourceIds = new HashSet<>();
|
||||
this.siteService.lambdaQuery().select(List.of(CmsSite::getLogo)).list().forEach(site -> {
|
||||
if (InternalUrlUtils.isInternalUrl(site.getLogo())) {
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(site.getLogo());
|
||||
resourceIds.add(internalURL.getId());
|
||||
}
|
||||
});
|
||||
return resourceIds;
|
||||
private void siteLogo(Long siteId, Map<Long, Long> quotedResources) {
|
||||
CmsSite site = this.siteService.getById(siteId);
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(site.getLogo());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(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.core.impl;
|
||||
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.core.IPublishPipeProp;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 发布通道属性:通用错误页面地址
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Component(IPublishPipeProp.BEAN_PREFIX + PublishPipeProp_ErrPageLink.KEY)
|
||||
public class PublishPipeProp_ErrPageLink implements IPublishPipeProp {
|
||||
|
||||
public static final String KEY = "errPageLink";
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "通用错误页面链接";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PublishPipePropUseType> getUseTypes() {
|
||||
return List.of(PublishPipePropUseType.Site);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultValue() {
|
||||
return StringUtils.SLASH;
|
||||
}
|
||||
|
||||
public static String getValue(String publishPipeCode, Map<String, Map<String, Object>> publishPipeProps) {
|
||||
if (Objects.nonNull(publishPipeProps)) {
|
||||
return MapUtils.getString(publishPipeProps.get(publishPipeCode), KEY, StringUtils.SLASH);
|
||||
}
|
||||
return StringUtils.SLASH;
|
||||
}
|
||||
}
|
||||
@ -269,9 +269,7 @@ public class ContentServiceImpl implements IContentService {
|
||||
CmsContent cmsContent = this.dao().getById(contentId);
|
||||
Assert.notNull(cmsContent, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("contentId", contentId));
|
||||
|
||||
Long[] catalogIds = dto.getCatalogIds().stream().filter(id -> !Objects.equals(id, cmsContent.getCatalogId()))
|
||||
.toArray(Long[]::new);
|
||||
for (Long catalogId : catalogIds) {
|
||||
for (Long catalogId : dto.getCatalogIds()) {
|
||||
CmsCatalog catalog = this.catalogService.getCatalog(catalogId);
|
||||
if (catalog == null) {
|
||||
continue; // 目标栏目错误直接跳过
|
||||
|
||||
@ -18,6 +18,7 @@ package com.chestnut.contentcore.service.impl;
|
||||
import com.chestnut.common.staticize.StaticizeService;
|
||||
import com.chestnut.common.staticize.core.TemplateContext;
|
||||
import com.chestnut.contentcore.core.IDynamicPageType;
|
||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_ErrPageLink;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.service.IPublishPipeService;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
@ -61,8 +62,7 @@ public class DynamicPageService {
|
||||
}
|
||||
|
||||
public void generateDynamicPage(String dynamicPageType, Long siteId, String publishPipeCode, Boolean preview,
|
||||
Map<String, String> parameters, HttpServletResponse response)
|
||||
throws IOException {
|
||||
Map<String, String> parameters, HttpServletResponse response) throws IOException {
|
||||
response.setCharacterEncoding(Charset.defaultCharset().displayName());
|
||||
response.setContentType("text/html; charset=" + Charset.defaultCharset().displayName());
|
||||
|
||||
@ -71,11 +71,12 @@ public class DynamicPageService {
|
||||
this.catchException("/", response, new RuntimeException("Site not found: " + siteId));
|
||||
return;
|
||||
}
|
||||
String errPageLink = PublishPipeProp_ErrPageLink.getValue(publishPipeCode, site.getPublishPipeProps());
|
||||
IDynamicPageType dpt = this.getDynamicPageType(dynamicPageType);
|
||||
String template = this.publishPipeService.getPublishPipePropValue(dpt.getPublishPipeKey(), publishPipeCode, site.getPublishPipeProps());
|
||||
File templateFile = this.templateService.findTemplateFile(site, template, publishPipeCode);
|
||||
if (Objects.isNull(templateFile) || !templateFile.exists()) {
|
||||
this.catchException(SiteUtils.getSiteLink(site, publishPipeCode, preview), response, new RuntimeException("Template not found: " + template));
|
||||
this.catchException(errPageLink, response, new RuntimeException("Template not found: " + template));
|
||||
return;
|
||||
}
|
||||
long s = System.currentTimeMillis();
|
||||
@ -95,7 +96,7 @@ public class DynamicPageService {
|
||||
this.staticizeService.process(templateContext, response.getWriter());
|
||||
log.debug("动态模板解析,耗时:{} ms", System.currentTimeMillis() - s);
|
||||
} catch (Exception e) {
|
||||
this.catchException(SiteUtils.getSiteLink(site, publishPipeCode, preview), response, e);
|
||||
this.catchException(errPageLink, response, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +104,7 @@ public class DynamicPageService {
|
||||
if (log.isDebugEnabled()) {
|
||||
e.printStackTrace(response.getWriter());
|
||||
} else {
|
||||
response.sendRedirect(redirectLink); // TODO 通过发布通道属性配置错误页面
|
||||
response.sendRedirect(redirectLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,8 +175,6 @@ public class FileServiceImpl implements IFileService {
|
||||
|
||||
@Override
|
||||
public void addFile(CmsSite site, FileAddDTO dto) throws IOException {
|
||||
this.checkFileType(dto.getFileName());
|
||||
|
||||
String dir = dto.getDir();
|
||||
dir = FileExUtils.normalizePath(dir);
|
||||
if (dir.startsWith("/")) {
|
||||
|
||||
@ -60,6 +60,8 @@ public class ResourceServiceImpl extends ServiceImpl<CmsResourceMapper, CmsResou
|
||||
|
||||
private final Map<String, IFileStorageType> fileStorageTypes;
|
||||
|
||||
private final List<IResourceStat> resourceStats;
|
||||
|
||||
private final ISiteService siteService;
|
||||
|
||||
@Override
|
||||
@ -353,28 +355,13 @@ public class ResourceServiceImpl extends ServiceImpl<CmsResourceMapper, CmsResou
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private final List<IResourceStat> resourceStats;
|
||||
|
||||
/**
|
||||
* TODO 统计资源引用
|
||||
* 统计资源引用
|
||||
*/
|
||||
public void statResourceUsage() {
|
||||
Map<Long, Integer> resourceIds = new HashMap<>();
|
||||
this.resourceStats.forEach(rs -> {
|
||||
Map<Long, Integer> quotedResource = rs.findQuotedResource();
|
||||
});
|
||||
// 站点Logo,栏目Logo,内容Logo
|
||||
|
||||
// 页面部件区块Logo
|
||||
|
||||
// 页面部件广告图
|
||||
|
||||
// 文章内容
|
||||
|
||||
// 图集内容
|
||||
|
||||
// 音频内容
|
||||
|
||||
// 视频内容
|
||||
public void statResourceUsage(Long siteId) throws InterruptedException {
|
||||
Map<Long, Long> quotedResources = new HashMap<>();
|
||||
for (IResourceStat resourceStat : this.resourceStats) {
|
||||
resourceStat.statQuotedResource(siteId, quotedResources);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,7 +76,6 @@ public class SiteThemeService {
|
||||
private final List<ICoreDataHandler> contentCoreHandlers;
|
||||
|
||||
public AsyncTask importSiteTheme(CmsSite site, final File zipFile, LoginUser operator) {
|
||||
// TODO 校验数据,必须无栏目、内容、页面部件等数据的站点才能导入
|
||||
AsyncTask asyncTask = new AsyncTask() {
|
||||
|
||||
@Override
|
||||
|
||||
@ -182,7 +182,7 @@ public class CmsContentTag extends AbstractListTag {
|
||||
return DESC;
|
||||
}
|
||||
|
||||
enum LevelTagAttr {
|
||||
public enum LevelTagAttr {
|
||||
Root(ATTR_OPTION_LEVEL_ROOT),
|
||||
Current(ATTR_OPTION_LEVEL_CURRENT),
|
||||
Child(ATTR_OPTION_LEVEL_CHILD),
|
||||
|
||||
@ -137,7 +137,7 @@ public class CmsIncludeTag extends AbstractTag {
|
||||
Map<String, String> mergeParams = mergeRequestVariable(env, paramsMap);
|
||||
env.setVariable(TemplateUtils.TemplateVariable_Request, wrap(env, mergeParams));
|
||||
// TODO 兼容历史版本,1.6.0移除IncludeRequest模板变量
|
||||
env.setVariable("IncludeRequest", wrap(env, mergeParams));
|
||||
env.setVariable(TemplateUtils.TemplateVariable_IncludeRequest, wrap(env, mergeParams));
|
||||
env.include(includeTemplate);
|
||||
} else if (virtual) {
|
||||
// 动态模板
|
||||
@ -198,7 +198,7 @@ public class CmsIncludeTag extends AbstractTag {
|
||||
Map<String, String> mergeParams = mergeRequestVariable(env, params);
|
||||
env.setVariable(TemplateUtils.TemplateVariable_Request, wrap(env, mergeParams));
|
||||
// TODO 兼容历史版本,1.6.0版本移除IncludeRequest模板变量
|
||||
env.setVariable("IncludeRequest", wrap(env, mergeParams));
|
||||
env.setVariable(TemplateUtils.TemplateVariable_IncludeRequest, wrap(env, mergeParams));
|
||||
env.include(includeTemplate);
|
||||
return writer.getBuffer().toString();
|
||||
} finally {
|
||||
|
||||
@ -44,8 +44,9 @@ public class TemplateUtils {
|
||||
public final static String TemplateVariable_Request = "Request";
|
||||
|
||||
/**
|
||||
* 模板变量:<@cms_include>标签file属性请求参数
|
||||
* 模板变量:<@cms_include>标签file属性请求参数,下个大版本移除
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public final static String TemplateVariable_IncludeRequest = "IncludeRequest";
|
||||
|
||||
/**
|
||||
@ -113,6 +114,11 @@ public class TemplateUtils {
|
||||
*/
|
||||
public final static String TemplateVariable_OBJ_Link = "link";
|
||||
|
||||
/**
|
||||
* 模板变量:客户端类型,适用动态模板访问
|
||||
*/
|
||||
public final static String TemplateVariable_ClientType = "ClientType";
|
||||
|
||||
public static Long evalSiteId(Environment env) throws TemplateModelException {
|
||||
return FreeMarkerUtils.evalLongVariable(env, "Site.siteId");
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-customform</artifactId>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-dynamic</artifactId>
|
||||
|
||||
@ -18,7 +18,6 @@ package com.chestnut.cms.dynamic.controller.front;
|
||||
import com.chestnut.cms.dynamic.service.IDynamicPageService;
|
||||
import com.chestnut.common.security.web.BaseRestController;
|
||||
import com.chestnut.common.utils.ServletUtils;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -26,7 +25,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -44,8 +42,6 @@ import java.util.Map;
|
||||
@RequestMapping("/dynamic/page")
|
||||
public class DynamicPageFrontController extends BaseRestController {
|
||||
|
||||
private final ISiteService siteService;
|
||||
|
||||
private final IDynamicPageService dynamicPageService;
|
||||
|
||||
@GetMapping
|
||||
|
||||
@ -38,7 +38,6 @@ public class DynamicListener {
|
||||
CmsSite site = event.getSite();
|
||||
int pageSize = 500;
|
||||
try {
|
||||
// 删除友链数据
|
||||
long total = this.dynamicPageService
|
||||
.count(new LambdaQueryWrapper<CmsDynamicPage>().eq(CmsDynamicPage::getSiteId, site.getSiteId()));
|
||||
for (long i = 0; i * pageSize < total; i++) {
|
||||
|
||||
@ -29,6 +29,7 @@ import com.chestnut.common.staticize.core.TemplateContext;
|
||||
import com.chestnut.common.utils.Assert;
|
||||
import com.chestnut.common.utils.IdUtils;
|
||||
import com.chestnut.common.utils.SpringUtils;
|
||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_ErrPageLink;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import com.chestnut.contentcore.service.ITemplateService;
|
||||
@ -182,17 +183,16 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
||||
this.catchException("/", response, new RuntimeException("Site not found: " + siteId));
|
||||
return;
|
||||
}
|
||||
String errPageLink = PublishPipeProp_ErrPageLink.getValue(publishPipeCode, site.getPublishPipeProps());
|
||||
CmsDynamicPage dynamicPage = dynamicPageHelper.getDynamicPageByPath(siteId, requestURI);
|
||||
String template = dynamicPage.getTemplates().get(publishPipeCode);
|
||||
File templateFile = this.templateService.findTemplateFile(site, template, publishPipeCode);
|
||||
if (Objects.isNull(templateFile) || !templateFile.exists()) {
|
||||
this.catchException(SiteUtils.getSiteLink(site, publishPipeCode, preview), response, new RuntimeException("Template not found: " + template));
|
||||
if (Objects.isNull(templateFile)) {
|
||||
this.catchException(errPageLink, response, new RuntimeException("Template not found: " + template));
|
||||
return;
|
||||
}
|
||||
long s = System.currentTimeMillis();
|
||||
try {
|
||||
// TODO 校验输入参数
|
||||
|
||||
// 生成静态页面
|
||||
// 模板ID = 通道:站点目录:模板文件名
|
||||
String templateKey = SiteUtils.getTemplateKey(site, publishPipeCode, template);
|
||||
@ -203,18 +203,17 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
||||
templateContext.getVariables().put(TemplateUtils.TemplateVariable_Request, parameters);
|
||||
// 动态页面自定义数据
|
||||
if (Objects.nonNull(dynamicPage.getInitDataTypes())) {
|
||||
dynamicPage.getInitDataTypes().forEach(initDataType -> {
|
||||
for (String initDataType : dynamicPage.getInitDataTypes()) {
|
||||
IDynamicPageInitData initData = dynamicPageHelper.getDynamicPageInitData(initDataType);
|
||||
if (Objects.nonNull(initData)) {
|
||||
initData.initTemplateData(templateContext, parameters);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// staticize
|
||||
this.staticizeService.process(templateContext, response.getWriter());
|
||||
log.debug("动态模板解析,耗时:{} ms", System.currentTimeMillis() - s);
|
||||
} catch (Exception e) {
|
||||
this.catchException(SiteUtils.getSiteLink(site, publishPipeCode, preview), response, e);
|
||||
this.catchException(errPageLink, response, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,7 +221,7 @@ public class DynamicPageServiceImpl extends ServiceImpl<CmsDynamicPageMapper, Cm
|
||||
if (log.isDebugEnabled()) {
|
||||
e.printStackTrace(response.getWriter());
|
||||
} else {
|
||||
response.sendRedirect(redirectLink); // TODO 通过发布通道属性配置错误页面
|
||||
response.sendRedirect(redirectLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-exmodel</artifactId>
|
||||
|
||||
@ -83,9 +83,6 @@ public class ExModelService {
|
||||
fv = f.getDefaultValue();
|
||||
}
|
||||
XModelFieldDataDTO dto = XModelFieldDataDTO.newInstance(f, fv);
|
||||
IMetaControlType controlType = controlTypeMap.get(IMetaControlType.BEAN_PREFIX + f.getControlType());
|
||||
Object objectV = controlType.stringAsValue(Objects.isNull(dto.getValue()) ? "" : dto.getValue().toString());
|
||||
dto.setValue(objectV);
|
||||
list.add(dto);
|
||||
});
|
||||
return list;
|
||||
|
||||
@ -21,11 +21,9 @@ import com.chestnut.common.staticize.exception.InvalidTagAttrValueException;
|
||||
import com.chestnut.common.staticize.tag.AbstractTag;
|
||||
import com.chestnut.common.staticize.tag.TagAttr;
|
||||
import com.chestnut.common.staticize.tag.TagAttrOption;
|
||||
import com.chestnut.common.utils.ConvertUtils;
|
||||
import com.chestnut.common.utils.IdUtils;
|
||||
import com.chestnut.exmodel.CmsExtendMetaModelType;
|
||||
import com.chestnut.xmodel.core.IMetaControlType;
|
||||
import com.chestnut.xmodel.core.MetaModel;
|
||||
import com.chestnut.xmodel.service.IModelDataService;
|
||||
import com.chestnut.xmodel.service.IModelService;
|
||||
import freemarker.core.Environment;
|
||||
@ -85,17 +83,6 @@ public class CmsXModelDataTag extends AbstractTag {
|
||||
CmsExtendMetaModelType.FIELD_DATA_TYPE.getCode(), dataType,
|
||||
CmsExtendMetaModelType.FIELD_DATA_ID.getCode(), dataId
|
||||
));
|
||||
MetaModel model = this.modelService.getMetaModel(modelId);
|
||||
modelData.entrySet().forEach(entry -> {
|
||||
model.getFields().stream().filter(field -> field.getCode().equals(entry.getKey()))
|
||||
.findFirst().ifPresent(field -> {
|
||||
IMetaControlType controlType = controlTypeMap.get(IMetaControlType.BEAN_PREFIX + field.getControlType());
|
||||
if (controlType != null) {
|
||||
Object v = controlType.stringAsValue(ConvertUtils.toStr(entry.getValue()));
|
||||
entry.setValue(v);
|
||||
}
|
||||
});
|
||||
});
|
||||
return Map.of(StaticizeConstants.TemplateVariable_Data, this.wrap(env, modelData));
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,6 @@ package com.chestnut.cms.exmodel;
|
||||
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.xmodel.core.BaseModelData;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.time.LocalDateTime;
|
||||
@ -26,7 +25,7 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 生成元数据模型类通用方法
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-image</artifactId>
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(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.cms.image;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.chestnut.cms.image.domain.CmsImage;
|
||||
import com.chestnut.cms.image.service.IImageService;
|
||||
import com.chestnut.common.async.AsyncTaskManager;
|
||||
import com.chestnut.contentcore.core.IResourceStat;
|
||||
import com.chestnut.contentcore.core.InternalURL;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 图集内容资源引用统计
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Component(IResourceStat.BEAN_PREFIX + ImageContentResourceStat.TYPE)
|
||||
public class ImageContentResourceStat implements IResourceStat {
|
||||
|
||||
public static final String TYPE = "ImageContent";
|
||||
|
||||
private final IImageService imageService;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void statQuotedResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 1000;
|
||||
long lastId = 0L;
|
||||
int count = 0;
|
||||
long total = imageService.dao().lambdaQuery().select(List.of()).eq(CmsImage::getSiteId, siteId).count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsImage> q = new LambdaQueryWrapper<CmsImage>()
|
||||
.select(List.of(CmsImage::getPath))
|
||||
.eq(CmsImage::getSiteId, siteId)
|
||||
.gt(CmsImage::getImageId, lastId)
|
||||
.orderByAsc(CmsImage::getImageId);
|
||||
Page<CmsImage> page = imageService.dao().page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsImage image : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计图集内容资源引用:" + count + " / " + total + "]");
|
||||
lastId = image.getImageId();
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(image.getPath());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-link</artifactId>
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(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.link;
|
||||
|
||||
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.contentcore.core.IResourceStat;
|
||||
import com.chestnut.contentcore.core.InternalURL;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import com.chestnut.link.domain.CmsLink;
|
||||
import com.chestnut.link.service.ILinkService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 图集内容资源引用统计
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Component(IResourceStat.BEAN_PREFIX + FriendLinkResourceStat.TYPE)
|
||||
public class FriendLinkResourceStat implements IResourceStat {
|
||||
|
||||
public static final String TYPE = "FriendLink";
|
||||
|
||||
private final ILinkService linkService;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void statQuotedResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 1000;
|
||||
long lastId = 0L;
|
||||
int count = 0;
|
||||
long total = linkService.lambdaQuery().select(List.of()).eq(CmsLink::getSiteId, siteId).count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsLink> q = new LambdaQueryWrapper<CmsLink>()
|
||||
.select(List.of(CmsLink::getLogo))
|
||||
.eq(CmsLink::getSiteId, siteId)
|
||||
.gt(CmsLink::getLinkId, lastId)
|
||||
.orderByAsc(CmsLink::getLinkId);
|
||||
Page<CmsLink> page = linkService.page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsLink friendLink : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计友情链接资源引用:" + count + " / " + total + "]");
|
||||
lastId = friendLink.getLinkId();
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(friendLink.getLogo());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-media</artifactId>
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(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.media;
|
||||
|
||||
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.contentcore.core.IResourceStat;
|
||||
import com.chestnut.contentcore.core.InternalURL;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import com.chestnut.media.dao.CmsAudioDAO;
|
||||
import com.chestnut.media.dao.CmsVideoDAO;
|
||||
import com.chestnut.media.domain.CmsAudio;
|
||||
import com.chestnut.media.domain.CmsVideo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 音视频内容资源引用统计
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Component(IResourceStat.BEAN_PREFIX + MediaResourceStat.TYPE)
|
||||
public class MediaResourceStat implements IResourceStat {
|
||||
|
||||
public static final String TYPE = "Media";
|
||||
|
||||
private final CmsVideoDAO videoDao;
|
||||
|
||||
private final CmsAudioDAO audioDAO;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void statQuotedResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
statAudioResource(siteId, quotedResources);
|
||||
statVideoResource(siteId, quotedResources);
|
||||
}
|
||||
|
||||
private void statAudioResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 1000;
|
||||
long lastId = 0L;
|
||||
int count = 0;
|
||||
long total = audioDAO.lambdaQuery().eq(CmsAudio::getSiteId, siteId).count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsAudio> q = new LambdaQueryWrapper<CmsAudio>()
|
||||
.select(List.of(CmsAudio::getPath))
|
||||
.eq(CmsAudio::getSiteId, siteId)
|
||||
.gt(CmsAudio::getAudioId, lastId)
|
||||
.orderByAsc(CmsAudio::getAudioId);
|
||||
Page<CmsAudio> page = audioDAO.page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsAudio audio : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计音频资源引用:" + count + " / " + total + "]");
|
||||
lastId = audio.getAudioId();
|
||||
// 音频
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(audio.getPath());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void statVideoResource(Long siteId, Map<Long, Long> quotedResources) throws InterruptedException {
|
||||
int pageSize = 1000;
|
||||
long lastId = 0L;
|
||||
int count = 0;
|
||||
long total = videoDao.lambdaQuery().eq(CmsVideo::getSiteId, siteId).count();
|
||||
while (true) {
|
||||
LambdaQueryWrapper<CmsVideo> q = new LambdaQueryWrapper<CmsVideo>()
|
||||
.select(List.of(CmsVideo::getPath, CmsVideo::getCover))
|
||||
.eq(CmsVideo::getSiteId, siteId)
|
||||
.gt(CmsVideo::getVideoId, lastId)
|
||||
.orderByAsc(CmsVideo::getVideoId);
|
||||
Page<CmsVideo> page = videoDao.page(new Page<>(0, pageSize, false), q);
|
||||
for (CmsVideo video : page.getRecords()) {
|
||||
AsyncTaskManager.setTaskProgressInfo((int) (count * 100 / total),
|
||||
"正在统计视频资源引用:" + count + " / " + total + "]");
|
||||
lastId = video.getVideoId();
|
||||
// 视频封面
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(video.getCover());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
// 视频
|
||||
if (!VideoContent.TYPE_SHARE.equals(video.getType())) {
|
||||
internalURL = InternalUrlUtils.parseInternalUrl(video.getPath());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
quotedResources.compute(internalURL.getId(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);
|
||||
}
|
||||
}
|
||||
AsyncTaskManager.checkInterrupt();
|
||||
count++;
|
||||
}
|
||||
if (page.getRecords().size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-member</artifactId>
|
||||
|
||||
@ -21,7 +21,7 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 会员内容发布信息VO
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -23,7 +23,7 @@ import freemarker.core.Environment;
|
||||
import freemarker.template.TemplateModelException;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* CMS会员工具类
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
@ -35,7 +35,7 @@ public class CmsMemberUtils {
|
||||
Long siteId = TemplateUtils.evalSiteId(env);
|
||||
TemplateContext context = FreeMarkerUtils.getTemplateContext(env);
|
||||
if (context.isPreview()) {
|
||||
url = FreeMarkerUtils.evalStringVariable(env, "ApiPrefix")
|
||||
url = FreeMarkerUtils.evalStringVariable(env, TemplateUtils.TemplateVariable_ApiPrefix)
|
||||
+ "account/" + memberId + "?sid=" + siteId + "&pp=" + context.getPublishPipeCode() + "&preview=true";
|
||||
} else {
|
||||
url = FreeMarkerUtils.evalStringVariable(env, "Prefix") + "account/" + memberId;
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-search</artifactId>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-seo</artifactId>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-stat</artifactId>
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(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.cms.stat.domain.vo;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ContentStatusTotal {
|
||||
|
||||
private String status;
|
||||
|
||||
private Integer total;
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-vote</artifactId>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-word</artifactId>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-common</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -19,19 +19,18 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.PropertyPlaceholderHelper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 国际化字符串占位符处理器
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
public class I18nPlaceholderHelper {
|
||||
private static final Log logger = LogFactory.getLog(PropertyPlaceholderHelper.class);
|
||||
private static final Log logger = LogFactory.getLog(I18nPlaceholderHelper.class);
|
||||
private static final Map<String, String> wellKnownSimplePrefixes = new HashMap<>(4);
|
||||
private final String placeholderPrefix;
|
||||
private final String placeholderSuffix;
|
||||
|
||||
@ -112,4 +112,11 @@ public class ArrayUtils {
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <T, R> List<R> mapNotNull(List<T> list, Function<T, R> mapper) {
|
||||
if (Objects.isNull(list)) {
|
||||
return List.of();
|
||||
}
|
||||
return list.stream().map(mapper).filter(Objects::nonNull).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,4 +66,8 @@ public class ObjectUtils {
|
||||
public static <T, R> R ifNullOrElse(T obj, Supplier<R> nullSupplier, Function<T, R> nonNullFunc) {
|
||||
return Objects.isNull(obj) ? nullSupplier.get() : nonNullFunc.apply(obj);
|
||||
}
|
||||
|
||||
public static <T> String nonNullOrElseAsString(T obj, Function<T, String> nonNullFunc) {
|
||||
return Objects.isNull(obj) ? StringUtils.EMPTY : nonNullFunc.apply(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-common</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-common</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-common</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-common</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-common</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-common</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-common</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -16,5 +16,10 @@
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-member</artifactId>
|
||||
</dependency>
|
||||
<!-- 词汇模块 -->
|
||||
<dependency>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-word</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -40,6 +40,7 @@ import com.chestnut.common.utils.ServletUtils;
|
||||
import com.chestnut.member.domain.vo.MemberCache;
|
||||
import com.chestnut.member.service.IMemberExpConfigService;
|
||||
import com.chestnut.member.service.IMemberStatDataService;
|
||||
import com.chestnut.word.service.ISensitiveWordService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.redisson.api.RLock;
|
||||
@ -72,6 +73,8 @@ public class CommentApiServiceImpl implements ICommentApiService, ApplicationCon
|
||||
|
||||
private final IMemberExpConfigService memberExpConfigService;
|
||||
|
||||
private final ISensitiveWordService sensitiveWordService;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
@ -144,7 +147,9 @@ public class CommentApiServiceImpl implements ICommentApiService, ApplicationCon
|
||||
comment.setSourceType(dto.getSourceType());
|
||||
comment.setSourceId(dto.getSourceId());
|
||||
comment.setUid(dto.getOperator().getUserId());
|
||||
comment.setContent(dto.getContent()); // TODO 敏感词过滤
|
||||
// 敏感词过滤
|
||||
String content = sensitiveWordService.replaceSensitiveWords(dto.getContent(), null);
|
||||
comment.setContent(content);
|
||||
comment.setCommentTime(LocalDateTime.now());
|
||||
comment.setAuditStatus(CommentAuditStatus.TO_AUDIT);
|
||||
comment.setLikeCount(0);
|
||||
@ -160,7 +165,7 @@ public class CommentApiServiceImpl implements ICommentApiService, ApplicationCon
|
||||
if (!comment.getSourceType().equals(parent.getSourceType())
|
||||
|| !comment.getSourceId().equals(parent.getSourceId())
|
||||
|| parent.getParentId() != 0) {
|
||||
throw new RuntimeException("评论数据源异常!");
|
||||
throw new RuntimeException("Reply comment not found: " + dto.getCommentId());
|
||||
}
|
||||
comment.setReplyUid(dto.getReplyUid());
|
||||
comment.setParentId(dto.getCommentId());
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 会员配置
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
package com.chestnut.member.core;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 会员注册方式
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -19,7 +19,7 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 收藏DTO
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -21,7 +21,7 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 点赞DTO
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -18,10 +18,9 @@ package com.chestnut.member.domain.dto;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 会员信息修改DTO
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -20,7 +20,7 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 会员头像上传DTO
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
|
||||
@ -20,13 +20,18 @@ import com.chestnut.member.fixed.config.MemberResourcePrefix;
|
||||
import com.chestnut.system.fixed.config.BackendContext;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
* 会员工具类
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
public class MemberUtils {
|
||||
|
||||
/**
|
||||
* 获取会员资源文件访问前缀
|
||||
*
|
||||
* @param isPreview 是否预览模式
|
||||
*/
|
||||
public static String getMemberResourcePrefix(boolean isPreview) {
|
||||
if (isPreview) {
|
||||
return BackendContext.getValue() + MemberConfig.getResourcePrefix();
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -18,7 +18,6 @@ package com.chestnut.xmodel.service.impl;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.chestnut.common.db.util.SqlBuilder;
|
||||
import com.chestnut.common.utils.Assert;
|
||||
import com.chestnut.common.utils.JacksonUtils;
|
||||
import com.chestnut.common.utils.ObjectUtils;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.xmodel.core.*;
|
||||
@ -31,7 +30,10 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -213,11 +215,15 @@ public class ModelDataServiceImpl implements IModelDataService {
|
||||
Map<String, Object> dataMap = new HashMap<>();
|
||||
// 固定字段
|
||||
mmt.getFixedFields().forEach(f -> {
|
||||
dataMap.put(f.getCode(), map.get(f.getFieldName()));
|
||||
Object v = map.get(f.getFieldName());
|
||||
dataMap.put(f.getCode(), v);
|
||||
});
|
||||
// 自定义字段
|
||||
model.getFields().forEach(f -> {
|
||||
dataMap.put(f.getCode(), map.get(f.getFieldName()));
|
||||
Object v = map.get(f.getFieldName());
|
||||
IMetaControlType controlType = getControlType(f.getControlType());
|
||||
Object objectV = controlType.stringAsValue(ObjectUtils.nonNullOrElseAsString(v, Object::toString));
|
||||
dataMap.put(f.getCode(), objectV);
|
||||
});
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-monitor</artifactId>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ package com.chestnut.stat.core;
|
||||
*/
|
||||
public interface IStatEventHandler {
|
||||
|
||||
static final String BEAN_PREFIX = "StatEventHandler_";
|
||||
String BEAN_PREFIX = "StatEventHandler_";
|
||||
|
||||
/**
|
||||
* 事件类型,唯一标识
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
# 校验消息
|
||||
VALIDATOR.SYSTEM.INVALID_DICT_VALUE=字典【{0}】数据非法:{1}
|
||||
VALIDATOR.SYSTEM.USER_GENDER=用户性别输入错误:{1}
|
||||
VALIDATOR.SYSTEM.USER_GENDER=用户性别输入错误:{0}
|
||||
VALIDATOR.SYSTEM.INVALID_LONG_ID=长整形ID参数值错误:{0}
|
||||
VALIDATOR.SYSTEM.SCRIPT_TEXT=Groovy脚本不能为空
|
||||
|
||||
#错误消息
|
||||
ERRCODE.SYS.UNAME_PWD_REQUIRED=账号/密码不能为空
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
VALIDATOR.SYSTEM.INVALID_DICT_VALUE=Invalid dict value "{1}" for [{0}]
|
||||
VALIDATOR.SYSTEM.USER_GENDER=Invalid user gender value: {1}
|
||||
VALIDATOR.SYSTEM.USER_GENDER=Invalid user gender value: {0}
|
||||
VALIDATOR.SYSTEM.INVALID_LONG_ID=Invalid long id value: {0}
|
||||
VALIDATOR.SYSTEM.SCRIPT_TEXT=Groovy script cannot be empty.
|
||||
|
||||
#错误消息
|
||||
ERRCODE.SYS.UNAME_PWD_REQUIRED=Account/Password cannot be empty.
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
# 校驗消息
|
||||
VALIDATOR.SYSTEM.INVALID_DICT_VALUE=字典【{0}】數據非法:{1}
|
||||
VALIDATOR.SYSTEM.USER_GENDER=用戶性別輸入錯誤:{1}
|
||||
VALIDATOR.SYSTEM.USER_GENDER=用戶性別輸入錯誤:{0}
|
||||
VALIDATOR.SYSTEM.INVALID_LONG_ID=長整形ID參數值錯誤:{0}
|
||||
VALIDATOR.SYSTEM.SCRIPT_TEXT=Groovy腳本不能為空
|
||||
|
||||
#錯誤消息
|
||||
ERRCODE.SYS.UNAME_PWD_REQUIRED=賬號/密碼不能為空
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut-modules</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ public interface ISensitiveWordService extends IService<SensitiveWord> {
|
||||
* 替换敏感词
|
||||
*
|
||||
* @param text
|
||||
* @param replaceStr
|
||||
* @param replacement
|
||||
* @return
|
||||
*/
|
||||
String replaceSensitiveWords(String text, String replacement);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user