|
|
@@ -1,159 +1,145 @@
|
|
|
package com.fs.feishu.service;
|
|
|
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
-import com.fs.course.domain.FsCourseLink;
|
|
|
-import com.fs.course.mapper.FsCourseLinkMapper;
|
|
|
-import com.fs.feishu.config.FeiShuConfig;
|
|
|
-import com.fs.feishu.model.FeishuFileDTO;
|
|
|
-import com.fs.feishu.model.FeishuLinkParam;
|
|
|
+import com.fs.common.core.redis.RedisCache;
|
|
|
import com.fs.common.exception.CustomException;
|
|
|
import com.fs.course.config.CourseConfig;
|
|
|
+import com.fs.course.domain.FsCourseLink;
|
|
|
import com.fs.course.domain.FsUserCourseVideo;
|
|
|
+import com.fs.course.mapper.FsCourseLinkMapper;
|
|
|
import com.fs.course.mapper.FsUserCourseVideoMapper;
|
|
|
+import com.fs.feishu.model.FeishuLinkParam;
|
|
|
import com.fs.system.service.ISysConfigService;
|
|
|
import com.lark.oapi.Client;
|
|
|
-import com.lark.oapi.service.docx.v1.model.*;
|
|
|
-import com.lark.oapi.service.drive.v1.model.DeleteFileReq;
|
|
|
-import com.lark.oapi.service.drive.v1.model.DeleteFileResp;
|
|
|
-import com.lark.oapi.service.drive.v1.model.ListFileReq;
|
|
|
-import com.lark.oapi.service.drive.v1.model.ListFileResp;
|
|
|
-import com.lark.oapi.service.drive.v2.model.PatchPermissionPublicReq;
|
|
|
-import com.lark.oapi.service.drive.v2.model.PermissionPublic;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import javax.annotation.PostConstruct;
|
|
|
-import java.io.UnsupportedEncodingException;
|
|
|
-import java.net.URLEncoder;
|
|
|
-import java.util.*;
|
|
|
-
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 飞书业务编排层:
|
|
|
+ * 负责课程链接和注册链接的完整业务流程,包括缓存、URL 构建、调用底层 API 服务等。
|
|
|
+ */
|
|
|
@Component
|
|
|
@Slf4j
|
|
|
public class FeiShuService {
|
|
|
|
|
|
- @Autowired
|
|
|
- private FeiShuConfig feishuConfig;
|
|
|
@Autowired
|
|
|
private ISysConfigService configService;
|
|
|
@Autowired
|
|
|
private FsUserCourseVideoMapper videoMapper;
|
|
|
-
|
|
|
@Autowired
|
|
|
private FsCourseLinkMapper courseLinkMapper;
|
|
|
-
|
|
|
- private Client client;
|
|
|
-
|
|
|
- @PostConstruct
|
|
|
- public void init() {
|
|
|
- this.client = Client.newBuilder(feishuConfig.getAppId(), feishuConfig.getAppSecret()).logReqAtDebug(true).build();
|
|
|
- }
|
|
|
+ @Autowired
|
|
|
+ private RedisCache redisCache;
|
|
|
+ @Autowired
|
|
|
+ private FeishuClientPool clientPool;
|
|
|
+ @Autowired
|
|
|
+ private FeishuDocApiService docApiService;
|
|
|
|
|
|
/**
|
|
|
- * 001 生成飞书初始链接
|
|
|
+ * 001 生成飞书初始链接(注册授权链接)
|
|
|
+ * 每次 shortCode 唯一
|
|
|
*/
|
|
|
- public String getFeishuRegisterLink(Long videoId, Long companyId, Long courseId,Long companyUserId,String shortCode) {
|
|
|
- // 读取配置判断是否启用飞书新跳转
|
|
|
- String json = configService.selectConfigByKey("course.config");
|
|
|
- if (StringUtils.isBlank(json)) {
|
|
|
- throw new CustomException("飞书看课配置为空");
|
|
|
- }
|
|
|
- CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
|
|
|
- Boolean enableFeishuNewLink = config.getEnableFeishuNewLink();
|
|
|
- if (!Boolean.TRUE.equals(enableFeishuNewLink)) {
|
|
|
+ public String getFeishuRegisterLink(Long videoId, Long companyId, Long courseId,
|
|
|
+ Long companyUserId, String shortLink) {
|
|
|
+ // 检查功能开关
|
|
|
+ CourseConfig config = getCourseConfig();
|
|
|
+ if (!Boolean.TRUE.equals(config.getEnableFeishuNewLink())) {
|
|
|
throw new CustomException("未开启飞书看课");
|
|
|
}
|
|
|
|
|
|
- // 构建参数
|
|
|
- FeishuLinkParam param = new FeishuLinkParam();
|
|
|
- param.setCompanyId(companyId);
|
|
|
- param.setCompanyUserId(companyUserId);
|
|
|
- param.setCourseId(courseId);
|
|
|
- param.setVideoId(videoId);
|
|
|
-
|
|
|
- FsUserCourseVideo userCourseVideo = videoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
|
|
|
+ FsUserCourseVideo userCourseVideo = videoMapper.selectFsUserCourseVideoByVideoId(videoId);
|
|
|
if (userCourseVideo == null) {
|
|
|
- throw new CustomException("视频不存在: " + param.getVideoId());
|
|
|
+ throw new CustomException("视频不存在: " + videoId);
|
|
|
}
|
|
|
|
|
|
- try {
|
|
|
- // 创建云文档
|
|
|
- String documentId = createDocument(userCourseVideo.getTitle() + "-注册");
|
|
|
-
|
|
|
- // 拼接授权url
|
|
|
- String authUrl = buildAuthLink(param.getCompanyId(), param.getCompanyUserId(),
|
|
|
- param.getCourseId(), param.getVideoId(),shortCode);
|
|
|
-
|
|
|
- // 创建关注公众号 text + link block
|
|
|
- createTextLinkBlock(documentId, authUrl);
|
|
|
- // 更新文档权限
|
|
|
- changeDocumentPermissions(documentId);
|
|
|
-
|
|
|
- // 返回飞书看课链接
|
|
|
- return "https://www.feishu.cn/docx/" + documentId;
|
|
|
- } catch (Exception e) {
|
|
|
- throw new CustomException("创建飞书注册链接失败: " + e.getMessage(), e);
|
|
|
+ int maxRetries = clientPool.getAvailableCount();
|
|
|
+ for (int i = 0; i < maxRetries; i++) {
|
|
|
+ Client client = clientPool.getClient();
|
|
|
+ try {
|
|
|
+ String documentId = docApiService.createDocument(client, userCourseVideo.getTitle() + "-注册");
|
|
|
+ String authUrl = buildAuthLink(companyId, companyUserId, courseId, videoId, shortLink);
|
|
|
+ docApiService.createTextLinkBlock(client, documentId, authUrl);
|
|
|
+ docApiService.changeDocumentPermissions(client, documentId);
|
|
|
+ return "https://www.feishu.cn/docx/" + documentId;
|
|
|
+ } catch (CustomException e) {
|
|
|
+ // 如果是账号禁用异常,继续尝试下一个账号
|
|
|
+ if (e.getMessage().contains("不可用") || e.getMessage().contains("已被自动禁用")) {
|
|
|
+ log.warn("账号不可用,尝试下一个");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new CustomException("创建飞书注册链接失败: " + e.getMessage(), e);
|
|
|
+ }
|
|
|
}
|
|
|
+ throw new CustomException("所有飞书账号均不可用,请联系管理员");
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
- * 002生成飞书课程链接
|
|
|
+ * 002 生成飞书课程链接
|
|
|
+ * 相同参数可能重复,使用 Redis 缓存避免重复创建文档
|
|
|
*/
|
|
|
public String getFeishuCourseNewLink(FeishuLinkParam param) {
|
|
|
if (param == null || param.getCompanyUserId() == null || param.getCompanyId() == null) {
|
|
|
throw new CustomException("参数不能为空");
|
|
|
}
|
|
|
|
|
|
+ String cacheKey = String.format("feishu:course_link:%d:%d:%d:%d:%d:%s",
|
|
|
+ param.getCompanyId(), param.getCompanyUserId(),
|
|
|
+ param.getCourseId(), param.getVideoId(),
|
|
|
+ param.getUserId(), param.getLink());
|
|
|
+
|
|
|
+ // 缓存命中直接返回
|
|
|
+ String cached = redisCache.getCacheObject(cacheKey);
|
|
|
+ if (StringUtils.isNotBlank(cached)) {
|
|
|
+ return cached;
|
|
|
+ }
|
|
|
+
|
|
|
FsUserCourseVideo userCourseVideo = videoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
|
|
|
if (userCourseVideo == null) {
|
|
|
throw new CustomException("视频不存在: " + param.getVideoId());
|
|
|
}
|
|
|
- try {
|
|
|
- // 创建云文档
|
|
|
- String documentId = createDocument(userCourseVideo.getTitle());
|
|
|
-
|
|
|
- // 拼接新看课url
|
|
|
- String url = buildCourseNewLink(param.getCompanyId(), param.getCompanyUserId(), param.getCourseId(), param.getVideoId(),param.getUserId(),param.getLink());
|
|
|
|
|
|
- // 创建iframe块
|
|
|
- createIframeBlock(documentId, url);
|
|
|
-
|
|
|
- // 更新文档权限
|
|
|
- changeDocumentPermissions(documentId);
|
|
|
-
|
|
|
- // 返回飞书看课链接
|
|
|
- return "https://www.feishu.cn/docx/" + documentId;
|
|
|
- } catch (Exception e) {
|
|
|
- throw new CustomException("创建飞书课程链接失败: " + e.getMessage(), e);
|
|
|
+ int maxRetries = clientPool.getAvailableCount();
|
|
|
+ for (int i = 0; i < maxRetries; i++) {
|
|
|
+ Client client = clientPool.getClient();
|
|
|
+ try {
|
|
|
+ String documentId = docApiService.createDocument(client, userCourseVideo.getTitle());
|
|
|
+ String url = buildCourseNewLink(param.getCompanyId(), param.getCompanyUserId(),
|
|
|
+ param.getCourseId(), param.getVideoId(), param.getUserId(), param.getLink());
|
|
|
+ docApiService.createIframeBlock(client, documentId, url);
|
|
|
+ docApiService.changeDocumentPermissions(client, documentId);
|
|
|
+
|
|
|
+ String resultUrl = "https://www.feishu.cn/docx/" + documentId;
|
|
|
+ redisCache.setCacheObject(cacheKey, resultUrl, 24, TimeUnit.HOURS);
|
|
|
+ return resultUrl;
|
|
|
+ } catch (CustomException e) {
|
|
|
+ if (e.getMessage().contains("不可用") || e.getMessage().contains("已被自动禁用")) {
|
|
|
+ log.warn("账号不可用,尝试下一个");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new CustomException("创建飞书课程链接失败: " + e.getMessage(), e);
|
|
|
+ }
|
|
|
}
|
|
|
+ throw new CustomException("所有飞书账号均不可用,请联系管理员");
|
|
|
}
|
|
|
|
|
|
+ // ==================== URL 构建(纯业务逻辑,无外部调用) ====================
|
|
|
|
|
|
- /**
|
|
|
- * 创建云文档
|
|
|
- */
|
|
|
- private String createDocument(String title) throws Exception {
|
|
|
- CreateDocumentReq req = CreateDocumentReq.newBuilder()
|
|
|
- .createDocumentReqBody(CreateDocumentReqBody.newBuilder().title(title).build())
|
|
|
- .build();
|
|
|
- CreateDocumentResp resp = client.docx().v1().document().create(req);
|
|
|
-
|
|
|
- CreateDocumentRespBody data = resp.getData();
|
|
|
- return data.getDocument().getDocumentId();
|
|
|
- }
|
|
|
+ private String buildCourseNewLink(Long companyId, Long companyUserId, Long courseId,
|
|
|
+ Long videoId, Long userId, String link) {
|
|
|
+ CourseConfig config = getCourseConfig();
|
|
|
|
|
|
-
|
|
|
- /**
|
|
|
- * 拼接看课url(课程参数JSON方式,适配飞书iframe,双重URL编码)
|
|
|
- */
|
|
|
- private String buildCourseNewLink(Long companyId, Long companyUserId, Long courseId, Long videoId,Long userId,String link) {
|
|
|
- String json = configService.selectConfigByKey("course.config");
|
|
|
- CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
|
|
|
-
|
|
|
- // 构造课程参数 JSON
|
|
|
Map<String, Object> courseParam = new LinkedHashMap<>();
|
|
|
courseParam.put("companyUserId", companyUserId);
|
|
|
courseParam.put("videoId", videoId);
|
|
|
@@ -161,48 +147,40 @@ public class FeiShuService {
|
|
|
courseParam.put("courseId", courseId);
|
|
|
courseParam.put("link", link);
|
|
|
|
|
|
- //查询课程短链表拼接参数
|
|
|
FsCourseLink fsCourseLink = courseLinkMapper.selectFsCourseLinkByLink(link);
|
|
|
- if (fsCourseLink==null){
|
|
|
+ if (fsCourseLink == null) {
|
|
|
throw new CustomException("课程链接已过期");
|
|
|
}
|
|
|
courseParam.put("corpId", fsCourseLink.getCorpId());
|
|
|
courseParam.put("linkType", fsCourseLink.getLinkType());
|
|
|
courseParam.put("qwExternalId", fsCourseLink.getQwExternalId());
|
|
|
courseParam.put("qwUserId", fsCourseLink.getQwUserId());
|
|
|
- String courseJson = JSONUtil.toJsonStr(courseParam);
|
|
|
+
|
|
|
try {
|
|
|
- // 第一次编码:对JSON进行URL编码
|
|
|
- String encodedJson = URLEncoder.encode(courseJson, "UTF-8");
|
|
|
- // 拼接完整URL(userId与course参数同级)
|
|
|
- String baseUrl = config.getFeishuCourseDomain();
|
|
|
- String fullUrl = baseUrl + "/feishuCourse/pages_course/video?course=" + encodedJson + "&userId=" +userId;
|
|
|
- // 第二次编码:对整个URL进行URL编码(适配飞书iframe创建要求)
|
|
|
+ String encodedJson = URLEncoder.encode(JSONUtil.toJsonStr(courseParam), "UTF-8");
|
|
|
+ String fullUrl = config.getFeishuCourseDomain() +
|
|
|
+ "/feishuCourse/pages_course/video?course=" + encodedJson + "&userId=" + userId;
|
|
|
return URLEncoder.encode(fullUrl, "UTF-8");
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
throw new CustomException("看课URL拼接失败", e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 拼接授权url(课程参数JSON方式,适配飞书iframe,双重URL编码)
|
|
|
- */
|
|
|
- private String buildAuthLink(Long companyId, Long companyUserId, Long courseId, Long videoId,String shortCode) {
|
|
|
- String json = configService.selectConfigByKey("course.config");
|
|
|
- CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
|
|
|
+ private String buildAuthLink(Long companyId, Long companyUserId, Long courseId,
|
|
|
+ Long videoId, String shortLink) {
|
|
|
+ CourseConfig config = getCourseConfig();
|
|
|
|
|
|
Map<String, Object> authParam = new LinkedHashMap<>();
|
|
|
authParam.put("companyUserId", companyUserId);
|
|
|
authParam.put("videoId", videoId);
|
|
|
authParam.put("companyId", companyId);
|
|
|
authParam.put("courseId", courseId);
|
|
|
- authParam.put("link", shortCode);
|
|
|
- String authJson = JSONUtil.toJsonStr(authParam);
|
|
|
+ authParam.put("link", shortLink);
|
|
|
|
|
|
try {
|
|
|
- String encodedJson = URLEncoder.encode(authJson, "UTF-8");
|
|
|
- String baseUrl =config.getFeishuAuthDomain();
|
|
|
- String fullUrl = baseUrl + "/feishuCourse/pages/wxauth?course=" + encodedJson;
|
|
|
+ String encodedJson = URLEncoder.encode(JSONUtil.toJsonStr(authParam), "UTF-8");
|
|
|
+ String fullUrl = config.getFeishuAuthDomain() +
|
|
|
+ "/feishuCourse/pages/wxauth?course=" + encodedJson;
|
|
|
return URLEncoder.encode(fullUrl, "UTF-8");
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
throw new CustomException("授权URL拼接失败", e);
|
|
|
@@ -210,200 +188,13 @@ public class FeiShuService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 创建iframe块
|
|
|
- */
|
|
|
- private void createIframeBlock(String documentId, String url) throws Exception {
|
|
|
- CreateDocumentBlockChildrenReq req = CreateDocumentBlockChildrenReq.newBuilder()
|
|
|
- .documentId(documentId)
|
|
|
- .blockId(documentId)
|
|
|
- .documentRevisionId(-1)
|
|
|
- .createDocumentBlockChildrenReqBody(CreateDocumentBlockChildrenReqBody.newBuilder()
|
|
|
- .children(new Block[] {
|
|
|
- Block.newBuilder()
|
|
|
- .blockType(26)
|
|
|
- .iframe(Iframe.newBuilder()
|
|
|
- .component(IframeComponent.newBuilder()
|
|
|
- .iframeType(1)
|
|
|
- .url(url).build()
|
|
|
- ).build()
|
|
|
- )
|
|
|
- .build()
|
|
|
- })
|
|
|
- .index(0)
|
|
|
- .build())
|
|
|
- .build();
|
|
|
-
|
|
|
- // 发起请求
|
|
|
- client.docx().v1().documentBlockChildren().create(req);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 创建 text + link block
|
|
|
+ * 读取课程配置并检查非空
|
|
|
*/
|
|
|
- private void createTextLinkBlock(String documentId, String url) throws Exception {
|
|
|
-
|
|
|
- CreateDocumentBlockChildrenReq req = CreateDocumentBlockChildrenReq.newBuilder()
|
|
|
- .documentId(documentId)
|
|
|
- .blockId(documentId)
|
|
|
- .documentRevisionId(-1)
|
|
|
- .createDocumentBlockChildrenReqBody(
|
|
|
- CreateDocumentBlockChildrenReqBody.newBuilder()
|
|
|
- .index(0)
|
|
|
- .children(new Block[] {
|
|
|
- Block.newBuilder()
|
|
|
- .blockType(2)
|
|
|
- .text(Text.newBuilder()
|
|
|
- .elements(new TextElement[] {
|
|
|
- TextElement.newBuilder()
|
|
|
- .textRun(TextRun.newBuilder()
|
|
|
- .content("观看课程")
|
|
|
- .textElementStyle(TextElementStyle.newBuilder()
|
|
|
- .link(Link.newBuilder()
|
|
|
- .url(url)
|
|
|
- .build())
|
|
|
- .build())
|
|
|
- .build())
|
|
|
- .build()
|
|
|
- })
|
|
|
- .build())
|
|
|
- .build()
|
|
|
- })
|
|
|
- .build())
|
|
|
- .build();
|
|
|
-
|
|
|
- client.docx().v1().documentBlockChildren().create(req);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取飞书云文档列表
|
|
|
- */
|
|
|
- public List<FeishuFileDTO> listFiles(int pageSize) throws Exception {
|
|
|
-
|
|
|
- ListFileReq req = ListFileReq.newBuilder()
|
|
|
- .pageSize(pageSize)
|
|
|
- .orderBy("EditedTime")
|
|
|
- .direction("DESC")
|
|
|
- .build();
|
|
|
-
|
|
|
- ListFileResp resp = client.drive().v1().file().list(req);
|
|
|
-
|
|
|
- if (!resp.success()) {
|
|
|
- throw new RuntimeException(
|
|
|
- "Feishu error code:" + resp.getCode()
|
|
|
- + ", msg:" + resp.getMsg()
|
|
|
- + ", reqId:" + resp.getRequestId()
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- List<FeishuFileDTO> result = new ArrayList<>();
|
|
|
-
|
|
|
- if (resp.getData() != null && resp.getData().getFiles() != null) {
|
|
|
- com.lark.oapi.service.drive.v1.model.File[] files = resp.getData().getFiles();
|
|
|
- Arrays.stream(files).forEach(file -> {
|
|
|
- FeishuFileDTO dto = new FeishuFileDTO();
|
|
|
- dto.setName(file.getName());
|
|
|
- dto.setToken(file.getToken());
|
|
|
- dto.setType(file.getType());
|
|
|
- dto.setUrl(file.getUrl());
|
|
|
- dto.setOwnerId(file.getOwnerId());
|
|
|
- dto.setParentToken(file.getParentToken());
|
|
|
- dto.setCreatedTime(file.getCreatedTime());
|
|
|
- dto.setModifiedTime(file.getModifiedTime());
|
|
|
-
|
|
|
- result.add(dto);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 修改文档权限
|
|
|
- */
|
|
|
- private void changeDocumentPermissions(String documentId) throws Exception {
|
|
|
- PatchPermissionPublicReq req = PatchPermissionPublicReq.newBuilder()
|
|
|
- .token(documentId)
|
|
|
- .type("docx")
|
|
|
- .permissionPublic(PermissionPublic.newBuilder()
|
|
|
- .externalAccessEntity("open")
|
|
|
- .securityEntity("anyone_can_view")
|
|
|
- .commentEntity("anyone_can_edit")
|
|
|
- .shareEntity("anyone")
|
|
|
- .manageCollaboratorEntity("collaborator_full_access")
|
|
|
- .linkShareEntity("anyone_readable")
|
|
|
- .copyEntity("only_full_access")
|
|
|
- .build())
|
|
|
- .build();
|
|
|
-
|
|
|
- // 发起请求
|
|
|
- client.drive().v2().permissionPublic().patch(req);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 根据 token 删除飞书文档
|
|
|
- *
|
|
|
- * @param fileToken 文档token
|
|
|
- * @param type 文档类型(docx / sheet / bitable / file 等)
|
|
|
- */
|
|
|
- public boolean deleteFile(String fileToken, String type) throws Exception {
|
|
|
-
|
|
|
- DeleteFileReq req = DeleteFileReq.newBuilder()
|
|
|
- .fileToken(fileToken)
|
|
|
- .type(type)
|
|
|
- .build();
|
|
|
-
|
|
|
- DeleteFileResp resp = client.drive().v1().file().delete(req);
|
|
|
-
|
|
|
- if (!resp.success()) {
|
|
|
- throw new RuntimeException(
|
|
|
- "Feishu delete failed, code=" + resp.getCode()
|
|
|
- + ", msg=" + resp.getMsg()
|
|
|
- + ", reqId=" + resp.getRequestId()
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 删除今天之前创建的飞书云文档
|
|
|
- * 1. 查询云文档列表
|
|
|
- * 2. 遍历比较创建时间(飞书返回秒级时间戳)
|
|
|
- * 3. 创建时间在今天 00:00:00 之前的执行删除
|
|
|
- */
|
|
|
- public void deleteFilesBeforeToday() throws Exception {
|
|
|
- // 今天 00:00:00 的时间戳(秒)
|
|
|
- Calendar today = Calendar.getInstance();
|
|
|
- today.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
- today.set(Calendar.MINUTE, 0);
|
|
|
- today.set(Calendar.SECOND, 0);
|
|
|
- today.set(Calendar.MILLISECOND, 0);
|
|
|
- long todayStartSec = today.getTimeInMillis() / 1000;
|
|
|
-
|
|
|
- List<FeishuFileDTO> files = listFiles(200);
|
|
|
- int total = files.size();
|
|
|
- int deleted = 0;
|
|
|
- for (FeishuFileDTO file : files) {
|
|
|
- try {
|
|
|
- // 飞书返回的 createdTime 为秒级时间戳
|
|
|
- long createdTime = Long.parseLong(file.getCreatedTime());
|
|
|
- if (createdTime < todayStartSec) {
|
|
|
- String type = file.getType();
|
|
|
- // wiki 类型无法直接删除,跳过
|
|
|
- if ("wiki".equalsIgnoreCase(type)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- boolean ok = deleteFile(file.getToken(), type);
|
|
|
- if (ok) {
|
|
|
- deleted++;
|
|
|
- log.info("已删除: {} | type={} | createdTime={}", file.getName(), type, file.getCreatedTime());
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("删除失败: {} | token={} | err={}", file.getName(), file.getToken(), e.getMessage());
|
|
|
- }
|
|
|
+ private CourseConfig getCourseConfig() {
|
|
|
+ String json = configService.selectConfigByKey("course.config");
|
|
|
+ if (StringUtils.isBlank(json)) {
|
|
|
+ throw new CustomException("飞书看课配置为空");
|
|
|
}
|
|
|
- log.info("飞书云文档清理完成 | 列表总数={} | 删除成功={}", total, deleted);
|
|
|
+ return JSONUtil.toBean(json, CourseConfig.class);
|
|
|
}
|
|
|
-
|
|
|
}
|