From 5396869eeb7172190d935818f46a766753577e66 Mon Sep 17 00:00:00 2001 From: Guan <46285865+guansss@users.noreply.github.com> Date: Fri, 1 Mar 2024 16:24:13 +0800 Subject: [PATCH 01/12] ci: submit ts client to maa-copilot-client-ts --- .github/workflows/openapi.yml | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index f1d7ec25..65062182 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -98,4 +98,33 @@ jobs: uses: actions/upload-artifact@v4 with: name: ts-client - path: ./build/clients/ts-fetch-client/* \ No newline at end of file + path: ./build/clients/ts-fetch-client/* + + - name: Checkout maa-copilot-client-ts + uses: actions/checkout@v4 + with: + path: maa-copilot-client-ts + + - name: Copy ts client into maa-copilot-client-ts + run: | + cp -f build/clients/ts-fetch-client/* maa-copilot-client-ts/ + + - name: Create PR to maa-copilot-client-ts + id: cpr + uses: peter-evans/create-pull-request@v6 + with: + path: maa-copilot-client-ts + author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> + commit-message: 'release: ${{ steps.version.outputs.version }}' + title: 'release: ${{ steps.version.outputs.version }}' + body: https://github.com/MaaAssistantArknights/MaaBackendCenter/actions/runs/${{ github.run_id }} + branch: ts-client + delete-branch: true + + - name: Tag previous commit with version + if: ${{ steps.cpr.outputs.pull-request-number }} + run: | + cd maa-copilot-client-ts + git checkout ts-client + git tag ${{ steps.version.outputs.version }} + git push --tags From f074d147eb5d25752d4f3e1790beff6167079242 Mon Sep 17 00:00:00 2001 From: Guan <46285865+guansss@users.noreply.github.com> Date: Fri, 1 Mar 2024 16:28:36 +0800 Subject: [PATCH 02/12] ci: fix checkout repo --- .github/workflows/openapi.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index 65062182..463dce78 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -103,6 +103,7 @@ jobs: - name: Checkout maa-copilot-client-ts uses: actions/checkout@v4 with: + repository: MaaAssistantArknights/maa-copilot-client-ts path: maa-copilot-client-ts - name: Copy ts client into maa-copilot-client-ts From 04e546e8fb9eb4e32813682c7795bc1411350008 Mon Sep 17 00:00:00 2001 From: Guan <46285865+guansss@users.noreply.github.com> Date: Fri, 1 Mar 2024 18:37:28 +0800 Subject: [PATCH 03/12] chore: make ts client support ES6 --- client-config/ts-fetch.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client-config/ts-fetch.json b/client-config/ts-fetch.json index 4cb2f87a..a8558081 100644 --- a/client-config/ts-fetch.json +++ b/client-config/ts-fetch.json @@ -1,5 +1,6 @@ { "npmName": "maa-copilot-client", "npmVersion": "1.0.0", - "modelPropertyNaming": "camelCase" -} \ No newline at end of file + "modelPropertyNaming": "camelCase", + "supportsES6": true +} From 883f67c5484e6bc8bda1ef5e6f38d4231aaa790b Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 2 Mar 2024 16:55:36 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E4=BD=BF=E7=94=A8@BindParam=E4=BB=A5?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E9=80=82=E9=85=8D=E9=A9=BC=E5=B3=B0=E5=92=8C?= =?UTF-8?q?SnakeCase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/controller/CopilotController.kt | 13 ------ .../request/copilot/CopilotQueriesRequest.kt | 40 +++---------------- 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt b/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt index f50cfc5e..6e0b88e4 100644 --- a/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt @@ -74,19 +74,6 @@ class CopilotController( fun queriesCopilot( @ParameterObject parsed: @Valid CopilotQueriesRequest ): MaaResult { - // FIXME 请求对下划线的处理存在问题,需要更正 - if (parsed.copilotIds == null) { - parsed.copilotIds = parsed.copilot_ids - } - if (parsed.levelKeyword == null) { - parsed.levelKeyword = parsed.level_keyword - } - if (parsed.orderBy == null) { - parsed.orderBy = parsed.order_by - } - if (parsed.uploaderId == null) { - parsed.uploaderId = parsed.uploader_id - } // 三秒防抖,缓解前端重复请求问题 response.setHeader(HttpHeaders.CACHE_CONTROL, "private, max-age=3, must-revalidate") return success(copilotService.queriesCopilot(helper.userId, parsed)) diff --git a/src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt index 2258e79d..4c6b3d5e 100644 --- a/src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt +++ b/src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt @@ -1,6 +1,7 @@ package plus.maa.backend.controller.request.copilot import jakarta.validation.constraints.Max +import org.springframework.web.bind.annotation.BindParam /** * @author LoMu @@ -9,42 +10,13 @@ import jakarta.validation.constraints.Max data class CopilotQueriesRequest( val page: Int = 0, val limit: @Max(value = 50, message = "单页大小不得超过50") Int = 10, - var levelKeyword: String? = null, - val level_keyword: String? = null, + @BindParam("level_keyword") var levelKeyword: String? = null, val operator: String? = null, val content: String? = null, val document: String? = null, - var uploaderId: String? = null, - val uploader_id: String? = null, + @BindParam("uploader_id") var uploaderId: String? = null, val desc: Boolean = true, - var orderBy: String? = null, - val order_by: String? = null, + @BindParam("order_by") var orderBy: String? = null, val language: String? = null, - var copilotIds: List? = null, - val copilot_ids: List? = null -) { - -// /* -// * 这里为了正确接收前端的下划线风格,手动写了三个 setter 用于起别名 -// * 因为 Get 请求传入的参数不是 JSON,所以没办法使用 Jackson 的注解直接实现别名 -// * 添加 @JsonAlias 和 @JsonIgnore 注解只是为了保障 Swagger 的文档正确显示 -// * (吐槽一下,同样是Get请求,怎么CommentsQueries是驼峰命名,到了CopilotQueries就成了下划线命名) -// */ -// @JsonIgnore -// @Suppress("unused") -// fun setLevel_keyword(levelKeyword: String?) { -// this.levelKeyword = levelKeyword -// } -// -// @JsonIgnore -// @Suppress("unused") -// fun setUploader_id(uploaderId: String?) { -// this.uploaderId = uploaderId -// } -// -// @JsonIgnore -// @Suppress("unused") -// fun setCopilot_ids(copilotIds: List?) { -// this.copilotIds = copilotIds -// } -} + @BindParam("copilot_ids") var copilotIds: List? = null, +) From 5c5bba6976d89360b6b2486b238d321bb50a30c1 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Sat, 2 Mar 2024 22:27:23 +0800 Subject: [PATCH 05/12] ci: copy client source codes recursively --- .github/workflows/openapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index 463dce78..bde493b7 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -108,7 +108,7 @@ jobs: - name: Copy ts client into maa-copilot-client-ts run: | - cp -f build/clients/ts-fetch-client/* maa-copilot-client-ts/ + cp -rf build/clients/ts-fetch-client/* maa-copilot-client-ts/ - name: Create PR to maa-copilot-client-ts id: cpr From cc610e166b6279e932e92ee83a69c3910f4a1bfe Mon Sep 17 00:00:00 2001 From: Guan <46285865+guansss@users.noreply.github.com> Date: Sun, 3 Mar 2024 14:57:51 +0800 Subject: [PATCH 06/12] ci: use PAT for pushing commits to maa-copilot-client-ts --- .github/workflows/openapi.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index bde493b7..c8368f53 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -121,11 +121,13 @@ jobs: body: https://github.com/MaaAssistantArknights/MaaBackendCenter/actions/runs/${{ github.run_id }} branch: ts-client delete-branch: true + token: ${{ secrets.TS_CLIENT_PAT }} - name: Tag previous commit with version if: ${{ steps.cpr.outputs.pull-request-number }} run: | cd maa-copilot-client-ts + git remote set-url origin https://${{ secrets.TS_CLIENT_PAT }}@github.com/MaaAssistantArknights/maa-copilot-client-ts.git git checkout ts-client git tag ${{ steps.version.outputs.version }} git push --tags From 6ca8d378f0e4d855b9ce98841c0114e2f847ace0 Mon Sep 17 00:00:00 2001 From: Guan <46285865+guansss@users.noreply.github.com> Date: Sun, 3 Mar 2024 15:40:49 +0800 Subject: [PATCH 07/12] ci: fix PAT conflicting with default GITHUB_TOKEN --- .github/workflows/openapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index c8368f53..f189bd1e 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -105,6 +105,7 @@ jobs: with: repository: MaaAssistantArknights/maa-copilot-client-ts path: maa-copilot-client-ts + token: ${{ secrets.TS_CLIENT_PAT }} - name: Copy ts client into maa-copilot-client-ts run: | @@ -127,7 +128,6 @@ jobs: if: ${{ steps.cpr.outputs.pull-request-number }} run: | cd maa-copilot-client-ts - git remote set-url origin https://${{ secrets.TS_CLIENT_PAT }}@github.com/MaaAssistantArknights/maa-copilot-client-ts.git git checkout ts-client git tag ${{ steps.version.outputs.version }} git push --tags From acd2a76b5d64a207d7c07cb9c7036e7615886fc8 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Mon, 4 Mar 2024 00:38:01 +0800 Subject: [PATCH 08/12] refactor: remove some not-null assertion --- .../maa/backend/common/aop/JsonSchemaAop.kt | 6 +++--- .../backend/controller/CopilotController.kt | 4 ++-- .../maa/backend/service/ArkGameDataService.kt | 14 ++++---------- .../maa/backend/service/ArkLevelService.kt | 19 +++++++++---------- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/common/aop/JsonSchemaAop.kt b/src/main/kotlin/plus/maa/backend/common/aop/JsonSchemaAop.kt index 8782a51c..66fce403 100644 --- a/src/main/kotlin/plus/maa/backend/common/aop/JsonSchemaAop.kt +++ b/src/main/kotlin/plus/maa/backend/common/aop/JsonSchemaAop.kt @@ -21,7 +21,7 @@ import plus.maa.backend.controller.request.copilot.CopilotRatingReq import plus.maa.backend.controller.response.MaaResultException import java.io.IOException -private val log = KotlinLogging.logger { } +private val log = KotlinLogging.logger { } /** * @author LoMu @@ -61,12 +61,12 @@ class JsonSchemaAop( } } } - if (content == null) return + if (schemaJson == null || content == null) return //获取json schema json路径并验证 try { - ClassPathResource(schemaJson!!).inputStream.use { inputStream -> + ClassPathResource(schemaJson).inputStream.use { inputStream -> val json = JSONObject(content) val jsonObject = JSONObject(JSONTokener(inputStream)) val schema = SchemaLoader.load(jsonObject) diff --git a/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt b/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt index 6e0b88e4..b56c5322 100644 --- a/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt @@ -51,8 +51,8 @@ class CopilotController( @ApiResponse(description = "删除作业结果") @RequireJwt @PostMapping("/delete") - fun deleteCopilot(@RequestBody request: CopilotCUDRequest?): MaaResult { - copilotService.delete(helper.requireUserId(), request!!) + fun deleteCopilot(@RequestBody request: CopilotCUDRequest): MaaResult { + copilotService.delete(helper.requireUserId(), request) return success() } diff --git a/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt b/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt index 2130d676..1de9285b 100644 --- a/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt +++ b/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt @@ -198,17 +198,11 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { } val node = mapper.reader().readTree(body.string()) val characters = mapper.convertValue(node, object : TypeReference>() {}) - characters.forEach { (id, c) -> c.id = id } arkCharacterMap.clear() - characters.values.forEach { c -> - if (c.id.isNullOrBlank()) { - return@forEach - } - val ids = c.id!!.split("_") - if (ids.size != 3) { - // 不是干员 - return@forEach - } + characters.forEach { (id, c) -> + val ids = id.split("_") + if (ids.size != 3) return@forEach + c.id = id arkCharacterMap[ids[2]] = c } log.info { "[DATA]获取character数据成功, 共${arkCharacterMap.size}条" } diff --git a/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt b/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt index fbec4887..48294434 100644 --- a/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt +++ b/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt @@ -32,7 +32,7 @@ import java.time.ZoneId import java.util.* import java.util.concurrent.atomic.AtomicInteger -private val log = KotlinLogging.logger { } +private val log = KotlinLogging.logger { } /** * @author dragove @@ -164,7 +164,8 @@ class ArkLevelService( */ fun updateActivitiesOpenStatus() { log.info { "[ACTIVITIES-OPEN-STATUS]准备更新活动地图开放状态" } - val stages = githubRepo.getContents(githubToken, "resource").firstOrNull { content: GithubContent -> content.isFile && "stages.json" == content.name } + val stages = githubRepo.getContents(githubToken, "resource") + .firstOrNull { content: GithubContent -> content.isFile && "stages.json" == content.name } if (stages == null) { log.info { "[ACTIVITIES-OPEN-STATUS]活动地图开放状态数据不存在" } @@ -186,14 +187,12 @@ class ArkLevelService( okHttpClient .newCall(Request.Builder().url(stages.downloadUrl).build()) .execute().use { response -> - if (!response.isSuccessful || response.body == null) { + val body = response.body?.byteStream() + if (!response.isSuccessful || body == null) { log.error { "[ACTIVITIES-OPEN-STATUS]活动地图开放状态下载失败" } return } - val body = response.body!!.byteStream() - val stagesList: List = - mapper.readValue(body, object : TypeReference>() { - }) + val stagesList = mapper.readValue(body, object : TypeReference>() {}) val keyInfos = stagesList .map { it.stageId } // 提取地图系列的唯一标识 @@ -210,7 +209,7 @@ class ArkLevelService( val nowTime = LocalDateTime.now() while (arkLevelPage.hasContent()) { - arkLevelPage.forEach{ arkLevel: ArkLevel -> + arkLevelPage.forEach { arkLevel: ArkLevel -> // 只考虑地图系列的唯一标识 if (keyInfos.contains(ArkLevelUtil.getKeyInfoById(arkLevel.stageId))) { arkLevel.isOpen = true @@ -335,7 +334,7 @@ class ArkLevelService( private val fail: AtomicInteger = AtomicInteger(0), private val pass: AtomicInteger = AtomicInteger(0), val total: Int = 0, - private val finishCallback: ((DownloadTask) -> Unit)? = null + private val finishCallback: ((DownloadTask) -> Unit) ) { fun success() { success.incrementAndGet() @@ -365,7 +364,7 @@ class ArkLevelService( if (success.get() + fail.get() + pass.get() != total) { return } - finishCallback!!.invoke(this) + finishCallback.invoke(this) log.info { "[LEVEL]地图数据下载完成, 成功:${success.get()}, 失败:${fail.get()}, 跳过:${pass.get()} 总用时${duration}s" } } } From bf5e7c4906571f9c458bcf38a0d31b34807d9536 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Sat, 9 Mar 2024 00:51:19 +0800 Subject: [PATCH 09/12] refactor: CommentsAreaService --- .../maa/backend/common/utils/KtExtensions.kt | 4 + .../utils/converter/CommentConverter.kt | 29 -- .../request/comments/CommentsAddDTO.kt | 15 +- .../response/comments/CommentsAreaInfo.kt | 6 + .../backend/service/CommentsAreaService.kt | 364 +++++++----------- .../plus/maa/backend/service/EmailService.kt | 32 +- .../service/model/CommentNotification.kt | 13 - .../maa/backend/service/model/RatingType.kt | 4 + 8 files changed, 176 insertions(+), 291 deletions(-) create mode 100644 src/main/kotlin/plus/maa/backend/common/utils/KtExtensions.kt delete mode 100644 src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt delete mode 100644 src/main/kotlin/plus/maa/backend/service/model/CommentNotification.kt diff --git a/src/main/kotlin/plus/maa/backend/common/utils/KtExtensions.kt b/src/main/kotlin/plus/maa/backend/common/utils/KtExtensions.kt new file mode 100644 index 00000000..9753e3e7 --- /dev/null +++ b/src/main/kotlin/plus/maa/backend/common/utils/KtExtensions.kt @@ -0,0 +1,4 @@ +package plus.maa.backend.common.utils + + +inline fun T?.requireNotNull(lazyMessage: () -> Any): T = requireNotNull(this, lazyMessage) \ No newline at end of file diff --git a/src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt deleted file mode 100644 index 7cd7710c..00000000 --- a/src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt +++ /dev/null @@ -1,29 +0,0 @@ -package plus.maa.backend.common.utils.converter - -import org.mapstruct.Mapper -import org.mapstruct.Mapping -import plus.maa.backend.controller.response.comments.CommentsInfo -import plus.maa.backend.controller.response.comments.SubCommentsInfo -import plus.maa.backend.repository.entity.CommentsArea -import plus.maa.backend.repository.entity.MaaUser - -/** - * @author LoMu - * Date 2023-02-21 18:16 - */ -@Mapper(componentModel = "spring") -interface CommentConverter { - @Mapping(target = "like", source = "commentsArea.likeCount") - @Mapping(target = "dislike", source = "commentsArea.dislikeCount") - @Mapping(target = "uploader", source = "maaUser.userName") - @Mapping(target = "commentId", source = "commentsArea.id") - fun toCommentsInfo(commentsArea: CommentsArea, maaUser: MaaUser, subCommentsInfos: List): CommentsInfo - - - @Mapping(target = "like", source = "commentsArea.likeCount") - @Mapping(target = "dislike", source = "commentsArea.dislikeCount") - @Mapping(target = "uploader", source = "maaUser.userName") - @Mapping(target = "commentId", source = "commentsArea.id") - @Mapping(target = "deleted", source = "commentsArea.delete") - fun toSubCommentsInfo(commentsArea: CommentsArea, maaUser: MaaUser): SubCommentsInfo -} diff --git a/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt index 2a9012c0..e853e18f 100644 --- a/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt +++ b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt @@ -8,13 +8,22 @@ import org.hibernate.validator.constraints.Length * Date 2023-02-17 14:58 */ data class CommentsAddDTO( - // 评论内容 + /** + * 评论内容 + */ @field:Length(min = 1, max = 150, message = "评论内容不可超过150字,请删减") @field:NotBlank(message = "请填写评论内容") val message: String, - // 评论的作业id + /** + * 评论所在作业的 id + */ val copilotId: Long, - // 子评论来源评论id(回复评论) + /** + * 被回复评论的 id + */ val fromCommentId: String? = null, + /** + * 是否接收通知 + */ val notification: Boolean = true ) diff --git a/src/main/kotlin/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt index 7532a8e1..6e107488 100644 --- a/src/main/kotlin/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt +++ b/src/main/kotlin/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt @@ -6,7 +6,13 @@ package plus.maa.backend.controller.response.comments */ data class CommentsAreaInfo ( val hasNext: Boolean, + /** + * Total number of pages + */ val page: Int, + /** + * Total number of elements + */ val total: Long, val data: List ) diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 3bea2ac8..8b75568c 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -1,28 +1,28 @@ package plus.maa.backend.service -import org.apache.commons.lang3.StringUtils import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Pageable import org.springframework.data.domain.Sort +import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service -import org.springframework.util.Assert -import plus.maa.backend.common.utils.converter.CommentConverter -import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.common.utils.requireNotNull import plus.maa.backend.controller.request.comments.CommentsAddDTO import plus.maa.backend.controller.request.comments.CommentsQueriesDTO import plus.maa.backend.controller.request.comments.CommentsRatingDTO import plus.maa.backend.controller.request.comments.CommentsToppingDTO import plus.maa.backend.controller.response.comments.CommentsAreaInfo -import plus.maa.backend.repository.* +import plus.maa.backend.controller.response.comments.CommentsInfo +import plus.maa.backend.controller.response.comments.SubCommentsInfo +import plus.maa.backend.repository.CommentsAreaRepository +import plus.maa.backend.repository.CopilotRepository +import plus.maa.backend.repository.RatingRepository +import plus.maa.backend.repository.UserRepository import plus.maa.backend.repository.entity.CommentsArea import plus.maa.backend.repository.entity.Copilot import plus.maa.backend.repository.entity.MaaUser import plus.maa.backend.repository.entity.Rating -import plus.maa.backend.service.model.CommentNotification import plus.maa.backend.service.model.RatingType import java.time.LocalDateTime -import java.time.format.DateTimeFormatter -import java.util.* /** * @author LoMu @@ -35,11 +35,7 @@ class CommentsAreaService( private val copilotRepository: CopilotRepository, private val userRepository: UserRepository, private val emailService: EmailService, - private val maaCopilotProperties: MaaCopilotProperties, - private val commentConverter: CommentConverter, ) { - - /** * 评论 * 每个评论都有一个uuid加持 @@ -49,113 +45,58 @@ class CommentsAreaService( */ fun addComments(userId: String, commentsAddDTO: CommentsAddDTO) { val copilotId = commentsAddDTO.copilotId - val message = commentsAddDTO.message - val copilotOptional = copilotRepository.findByCopilotId(copilotId) - Assert.isTrue(StringUtils.isNotBlank(message), "评论不可为空") - Assert.isTrue(copilotOptional != null, "作业表不存在") - - - var fromCommentsId: String? = null - var mainCommentsId: String? = null - - var commentsArea: CommentsArea? = null - var isCopilotAuthor: Boolean? = null - - - //代表这是一条回复评论 - if (!commentsAddDTO.fromCommentId.isNullOrBlank()) { - val commentsAreaOptional = commentsAreaRepository.findById(commentsAddDTO.fromCommentId) - Assert.isTrue(commentsAreaOptional.isPresent, "回复的评论不存在") - commentsArea = commentsAreaOptional.get() - Assert.isTrue(!commentsArea.delete, "回复的评论不存在") - - mainCommentsId = if (StringUtils - .isNoneBlank(commentsArea.mainCommentId) - ) commentsArea.mainCommentId else commentsArea.id - - fromCommentsId = if (StringUtils - .isNoneBlank(commentsArea.id) - ) commentsArea.id else null - - if (Objects.isNull(commentsArea.notification) || commentsArea.notification) { - isCopilotAuthor = false - } - } else { - isCopilotAuthor = true - } - - //判断是否需要通知 - if (Objects.nonNull(isCopilotAuthor) && maaCopilotProperties.mail.notification) { - val copilot = copilotOptional!! - - //通知作业作者或是评论作者 - val replyUserId = if (isCopilotAuthor!!) copilot.uploaderId else commentsArea!!.uploaderId - - - val maaUserMap = userRepository.findByUsersId(listOf(userId, replyUserId!!)) - - //防止通知自己 - if (replyUserId != userId) { - val time = LocalDateTime.now() - val timeStr = time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) - + val copilot = copilotRepository.findByCopilotId(copilotId).requireNotNull { "作业不存在" } - val authorName = maaUserMap.getOrDefault(replyUserId, MaaUser.UNKNOWN).userName - val reName = maaUserMap.getOrDefault(userId, MaaUser.UNKNOWN).userName + val parentCommentId = commentsAddDTO.fromCommentId?.ifBlank { null } + // 指定了回复对象但该对象不存在时抛出异常 + val parentComment = parentCommentId?.let { id -> requireCommentsAreaById(id) { "回复的评论不存在" } } - val title = if (isCopilotAuthor) copilot.doc?.title else commentsArea!!.message - - val commentNotification = CommentNotification(authorName, reName, timeStr, title, message) + notifyRelatedUser(userId, commentsAddDTO.message, copilot, parentComment) + val comment = CommentsArea( + copilotId = copilotId, + uploaderId = userId, + fromCommentId = parentComment?.id, + mainCommentId = parentComment?.run { mainCommentId ?: id }, + message = commentsAddDTO.message, + notification = commentsAddDTO.notification + ) + commentsAreaRepository.insert(comment) + } - val maaUser = maaUserMap[replyUserId] - if (Objects.nonNull(maaUser)) { - emailService.sendCommentNotification(maaUser!!.email, commentNotification) - } - } - } + private fun notifyRelatedUser(replierId: String, message: String, copilot: Copilot, parentComment: CommentsArea?) { + if (parentComment?.notification == false) return + val receiverId = parentComment?.uploaderId ?: copilot.uploaderId + if (receiverId == null || receiverId == replierId) return + val userMap = userRepository.findAllById(listOf(receiverId, replierId)).associateBy(MaaUser::userId) + val receiver = userMap[receiverId] ?: return + val replier = userMap.getOrDefault(replierId, MaaUser.UNKNOWN) - //创建评论表 - commentsAreaRepository.insert( - CommentsArea( - copilotId = copilotId, - uploaderId = userId, - fromCommentId = fromCommentsId, - mainCommentId = mainCommentsId, - message = message, - notification = commentsAddDTO.notification - ) - ) + val targetMsg = parentComment?.message ?: copilot.doc?.title ?: "" + emailService.sendCommentNotification(receiver.email, receiver.userName, targetMsg, replier.userName, message) } - fun deleteComments(userId: String, commentsId: String) { - val commentsArea = findCommentsById(commentsId) - //允许作者删除评论 - copilotRepository.findByCopilotId(commentsArea.copilotId)?.let { copilot: Copilot -> - Assert.isTrue( - userId == copilot.uploaderId || userId == commentsArea.uploaderId, - "您无法删除不属于您的评论" - ) - } + val commentsArea = requireCommentsAreaById(commentsId) + // 允许作者删除评论 + val copilot = copilotRepository.findByCopilotId(commentsArea.copilotId) + require(userId == copilot?.uploaderId || userId == commentsArea.uploaderId) { "您无法删除不属于您的评论" } + val now = LocalDateTime.now() commentsArea.delete = true commentsArea.deleteTime = now - - //删除所有回复 - if (StringUtils.isBlank(commentsArea.mainCommentId)) { - val commentsAreaList = commentsAreaRepository.findByMainCommentId(commentsArea.id!!) - commentsAreaList.forEach { ca: CommentsArea -> + val comments = mutableListOf(commentsArea) + // 删除所有回复 + if (commentsArea.mainCommentId.isNullOrBlank()) { + comments += commentsAreaRepository.findByMainCommentId(commentsId).onEach { ca -> ca.deleteTime = now ca.delete = true } - commentsAreaRepository.saveAll(commentsAreaList) } - commentsAreaRepository.save(commentsArea) + commentsAreaRepository.saveAll(comments) } - /** * 为评论进行点赞 * @@ -163,64 +104,38 @@ class CommentsAreaService( * @param commentsRatingDTO CommentsRatingDTO */ fun rates(userId: String, commentsRatingDTO: CommentsRatingDTO) { - val rating = commentsRatingDTO.rating + val commentId = commentsRatingDTO.commentId + val commentsArea = requireCommentsAreaById(commentId) + + val rating = ratingRepository.findByTypeAndKeyAndUserId( + Rating.KeyType.COMMENT, + commentId, + userId + ) ?: Rating( + null, + Rating.KeyType.COMMENT, + commentId, + userId, + RatingType.NONE, + LocalDateTime.now() + ) - val commentsArea = findCommentsById(commentsRatingDTO.commentId) + val prevType = rating.rating + val nextType = RatingType.fromRatingType(commentsRatingDTO.rating) + // 如果评分未发生变化则返回 + if (nextType == prevType) return - val likeCountChange: Long - val dislikeCountChange: Long + rating.rating = nextType + rating.rateTime = LocalDateTime.now() + ratingRepository.save(rating) - val ratingOptional = - ratingRepository.findByTypeAndKeyAndUserId( - Rating.KeyType.COMMENT, - commentsArea.id!!, userId - ) - // 判断该用户是否存在评分 - if (ratingOptional != null) { - // 如果评分发生变化则更新 - if (ratingOptional.rating != RatingType.fromRatingType(rating)) { - val oldRatingType = ratingOptional.rating - ratingOptional.rating = RatingType.fromRatingType(rating) - ratingOptional.rateTime = LocalDateTime.now() - val newRatingType = ratingRepository.save(ratingOptional).rating - // 更新评分后更新评论的点赞数 - likeCountChange = - (if (newRatingType == RatingType.LIKE) 1 else (if (oldRatingType != RatingType.LIKE) 0 else -1)).toLong() - dislikeCountChange = - (if (newRatingType == RatingType.DISLIKE) 1 else (if (oldRatingType != RatingType.DISLIKE) 0 else -1)).toLong() - } else { - // 如果评分未发生变化则结束 - return - } - } else { - // 不存在评分则创建 - val newRating = Rating( - null, - Rating.KeyType.COMMENT, - commentsArea.id!!, - userId, - RatingType.fromRatingType(rating), - LocalDateTime.now() - ) - - ratingRepository.insert(newRating) - likeCountChange = (if (newRating.rating == RatingType.LIKE) 1 else 0).toLong() - dislikeCountChange = (if (newRating.rating == RatingType.DISLIKE) 1 else 0).toLong() - } + // 更新评分后更新评论的点赞数 + val likeCountChange = nextType.countLike() - prevType.countLike() + val dislikeCountChange = nextType.countDislike() - prevType.countDislike() // 点赞数不需要在高并发下特别精准,大概就行,但是也得避免特别离谱的数字 - var likeCount = commentsArea.likeCount + likeCountChange - if (likeCount < 0) { - likeCount = 0 - } - - var dislikeCount = commentsArea.dislikeCount + dislikeCountChange - if (dislikeCount < 0) { - dislikeCount = 0 - } - - commentsArea.likeCount = likeCount - commentsArea.dislikeCount = dislikeCount + commentsArea.likeCount = (commentsArea.likeCount + likeCountChange).coerceAtLeast(0) + commentsArea.dislikeCount = (commentsArea.dislikeCount + dislikeCountChange).coerceAtLeast(0) commentsAreaRepository.save(commentsArea) } @@ -232,17 +147,13 @@ class CommentsAreaService( * @param commentsToppingDTO CommentsToppingDTO */ fun topping(userId: String, commentsToppingDTO: CommentsToppingDTO) { - val commentsArea = findCommentsById(commentsToppingDTO.commentId) - Assert.isTrue(!commentsArea.delete, "评论不存在") + val commentsArea = requireCommentsAreaById(commentsToppingDTO.commentId) // 只允许作者置顶评论 - copilotRepository.findByCopilotId(commentsArea.copilotId)?.let { copilot: Copilot -> - Assert.isTrue( - userId == copilot.uploaderId, - "只有作者才能置顶评论" - ) - commentsArea.topping = commentsToppingDTO.topping - commentsAreaRepository.save(commentsArea) - } + val copilot = copilotRepository.findByCopilotId(commentsArea.copilotId) + require(userId == copilot?.uploaderId) { "只有作者才能置顶评论" } + + commentsArea.topping = commentsToppingDTO.topping + commentsAreaRepository.save(commentsArea) } /** @@ -253,7 +164,6 @@ class CommentsAreaService( */ fun queriesCommentsArea(request: CommentsQueriesDTO): CommentsAreaInfo { val toppingOrder = Sort.Order.desc("topping") - val sortOrder = Sort.Order( if (request.desc) Sort.Direction.DESC else Sort.Direction.ASC, when (request.orderBy) { @@ -262,16 +172,12 @@ class CommentsAreaService( else -> request.orderBy ?: "likeCount" } ) - - val page = if (request.page > 0) request.page else 1 + val page = (request.page - 1).coerceAtLeast(0) val limit = if (request.limit > 0) request.limit else 10 + val pageable: Pageable = PageRequest.of(page, limit, Sort.by(toppingOrder, sortOrder)) - - val pageable: Pageable = PageRequest.of(page - 1, limit, Sort.by(toppingOrder, sortOrder)) - - - //主评论 - val mainCommentsList = if (!request.justSeeId.isNullOrBlank()) { + // 主评论 + val mainCommentsPage = if (!request.justSeeId.isNullOrBlank()) { commentsAreaRepository.findByCopilotIdAndUploaderIdAndDeleteAndMainCommentIdExists( request.copilotId, request.justSeeId, @@ -288,79 +194,69 @@ class CommentsAreaService( ) } - val count = mainCommentsList.totalElements - - val pageNumber = mainCommentsList.totalPages - - // 判断是否存在下一页 - val hasNext = count - page.toLong() * limit > 0 - - + val mainCommentIds = mainCommentsPage.map(CommentsArea::id).filterNotNull() //获取子评论 - val subCommentsList = commentsAreaRepository.findByMainCommentIdIn( - mainCommentsList - .map { obj: CommentsArea -> requireNotNull(obj.id) } - .toList() - ) - - //将已删除评论内容替换为空 - subCommentsList.forEach { comment: CommentsArea -> - if (comment.delete) { - comment.message = "" - } + val subCommentsList = commentsAreaRepository.findByMainCommentIdIn(mainCommentIds).onEach { + //将已删除评论内容替换为空 + if (it.delete) it.message = "" } - - //所有评论 - val allComments: MutableList = ArrayList(mainCommentsList.toList()) - allComments.addAll(subCommentsList) - //获取所有评论用户 - val userIds = allComments.map { obj: CommentsArea -> obj.uploaderId }.distinct().toList() - val maaUserMap = userRepository.findByUsersId(userIds) - + val allUserIds = (mainCommentsPage + subCommentsList).map(CommentsArea::uploaderId).distinct() + val users = userRepository.findAllById(allUserIds).associateBy(MaaUser::userId) + val subCommentGroups = subCommentsList.groupBy(CommentsArea::mainCommentId) //转换主评论数据并填充用户名 - val commentsInfos = mainCommentsList.map { mainComment: CommentsArea -> - val subCommentsInfoList = subCommentsList - .filter { comment: CommentsArea -> mainComment.id == comment.mainCommentId } //转换子评论数据并填充用户名 - .map { subComment: CommentsArea -> - commentConverter.toSubCommentsInfo( - subComment, //填充评论用户名 - maaUserMap.getOrDefault( - subComment.uploaderId, - MaaUser.UNKNOWN - ) - ) - }.toList() - val commentsInfo = commentConverter.toCommentsInfo( - mainComment, - maaUserMap.getOrDefault( - mainComment.uploaderId, - MaaUser.UNKNOWN - ), - subCommentsInfoList - ) - commentsInfo - }.toList() - - return CommentsAreaInfo(hasNext, pageNumber, count, commentsInfos) - } - + val commentsInfos = mainCommentsPage.toList().map { mainComment -> + val subCommentsInfos = (subCommentGroups[mainComment.id] ?: emptyList()).map { c -> + buildSubCommentsInfo(c, users[c.uploaderId] ?: MaaUser.UNKNOWN) + } + buildMainCommentsInfo(mainComment, users[mainComment.uploaderId] ?: MaaUser.UNKNOWN, subCommentsInfos) + } - private fun findCommentsById(commentsId: String): CommentsArea { - val commentsArea = commentsAreaRepository.findById(commentsId) - Assert.isTrue(commentsArea.isPresent, "评论不存在") - return commentsArea.get() + return CommentsAreaInfo( + hasNext = mainCommentsPage.hasNext(), + page = mainCommentsPage.totalPages, + total = mainCommentsPage.totalElements, + data = commentsInfos + ) } + /** + * 转换子评论数据并填充用户名 + */ + private fun buildSubCommentsInfo(c: CommentsArea, user: MaaUser) = SubCommentsInfo( + commentId = c.id!!, + uploader = user.userName, + uploaderId = c.uploaderId, + message = c.message, + uploadTime = c.uploadTime, + like = c.likeCount, + dislike = c.dislikeCount, + fromCommentId = c.fromCommentId!!, + mainCommentId = c.mainCommentId!!, + deleted = c.delete + ) + + private fun buildMainCommentsInfo(c: CommentsArea, user: MaaUser, subList: List) = CommentsInfo( + commentId = c.id!!, + uploader = user.userName, + uploaderId = c.uploaderId, + message = c.message, + uploadTime = c.uploadTime, + like = c.likeCount, + dislike = c.dislikeCount, + topping = c.topping, + subCommentsInfos = subList + ) fun notificationStatus(userId: String, id: String, status: Boolean) { - val commentsAreaOptional = commentsAreaRepository.findById(id) - Assert.isTrue(commentsAreaOptional.isPresent, "评论不存在") - val commentsArea = commentsAreaOptional.get() - Assert.isTrue(userId == commentsArea.uploaderId, "您没有权限修改") + val commentsArea = requireCommentsAreaById(id) + require(userId == commentsArea.uploaderId) { "您没有权限修改" } commentsArea.notification = status commentsAreaRepository.save(commentsArea) } + + private fun requireCommentsAreaById(commentsId: String, lazyMessage: () -> Any = { "评论不存在" }): CommentsArea = + commentsAreaRepository.findByIdOrNull(commentsId)?.takeIf { !it.delete }.requireNotNull(lazyMessage) } diff --git a/src/main/kotlin/plus/maa/backend/service/EmailService.kt b/src/main/kotlin/plus/maa/backend/service/EmailService.kt index fbd52f8b..00b35988 100644 --- a/src/main/kotlin/plus/maa/backend/service/EmailService.kt +++ b/src/main/kotlin/plus/maa/backend/service/EmailService.kt @@ -12,7 +12,8 @@ import plus.maa.backend.common.utils.FreeMarkerUtils import plus.maa.backend.config.external.MaaCopilotProperties import plus.maa.backend.controller.response.MaaResultException import plus.maa.backend.repository.RedisCache -import plus.maa.backend.service.model.CommentNotification +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter import java.util.* /** @@ -38,6 +39,7 @@ class EmailService( .setPass(mail.pass) .setSslEnable(mail.ssl) .setStarttlsEnable(mail.starttls) + private val timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") /** * 发送验证码 @@ -87,24 +89,30 @@ class EmailService( } } - fun sendCommentNotification(email: String, commentNotification: CommentNotification) = emailTaskExecutor.execute { + fun sendCommentNotification( + receiverEmail: String, + receiverName: String, + targetMessage: String, + replierName: String, + message: String, + timeStr: String = LocalDateTime.now().format(timeFormatter) + ) = emailTaskExecutor.execute { + if (!maaCopilotProperties.mail.notification) return@execute val limit = 25 - val title = (commentNotification.title ?: "").let { - if (it.length > limit) it.substring(0, limit - 4) + "...." else it - } + val title = targetMessage.run { if (length > limit) take(limit - 4) + "...." else this } + + val subject = "收到新回复 来自用户@${replierName} Re: $title" - val subject = "收到新回复 来自用户@${commentNotification.reName} Re: $title" val dataModel = mapOf( "content" to "mail-comment-notification.ftlh", - "authorName" to commentNotification.authorName, + "authorName" to receiverName, "frontendLink" to maaCopilotProperties.info.frontendDomain, - "reName" to commentNotification.reName, - "date" to commentNotification.date, + "reName" to replierName, + "date" to timeStr, "title" to title, - "reMessage" to commentNotification.reMessage, + "reMessage" to message, ) val content = FreeMarkerUtils.parseData("mail-includeHtml.ftlh", dataModel) - - MailUtil.send(mailAccount, listOf(email), subject, content, true) + MailUtil.send(mailAccount, listOf(receiverEmail), subject, content, true) } } diff --git a/src/main/kotlin/plus/maa/backend/service/model/CommentNotification.kt b/src/main/kotlin/plus/maa/backend/service/model/CommentNotification.kt deleted file mode 100644 index 29553803..00000000 --- a/src/main/kotlin/plus/maa/backend/service/model/CommentNotification.kt +++ /dev/null @@ -1,13 +0,0 @@ -package plus.maa.backend.service.model - -/** - * @author LoMu - * Date 2023-05-18 1:18 - */ -data class CommentNotification( - val authorName: String, - val reName: String, - val date: String, - val title: String?, - val reMessage: String -) diff --git a/src/main/kotlin/plus/maa/backend/service/model/RatingType.kt b/src/main/kotlin/plus/maa/backend/service/model/RatingType.kt index e63b19be..65855719 100644 --- a/src/main/kotlin/plus/maa/backend/service/model/RatingType.kt +++ b/src/main/kotlin/plus/maa/backend/service/model/RatingType.kt @@ -9,6 +9,10 @@ enum class RatingType(val display: Int) { DISLIKE(2), NONE(0); + fun countLike() = if (this == LIKE) 1L else 0L + + fun countDislike() = if (this == DISLIKE) 1L else 0L + companion object { /** * 将rating转换为 0 = NONE 1 = LIKE 2 = DISLIKE From 0b5a59e5f07765b3a8c8a65a0581646136252e2f Mon Sep 17 00:00:00 2001 From: dragove Date: Sat, 9 Mar 2024 20:01:48 +0800 Subject: [PATCH 10/12] =?UTF-8?q?feat:=20=E4=BD=9C=E4=B8=9A=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E3=80=81=E5=88=97=E8=A1=A8=E6=B7=BB=E5=8A=A0=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E4=B8=8A=E4=BC=A0=E8=80=85id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/controller/response/copilot/CopilotInfo.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/plus/maa/backend/controller/response/copilot/CopilotInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/copilot/CopilotInfo.kt index 7bebf995..fd7dd302 100644 --- a/src/main/kotlin/plus/maa/backend/controller/response/copilot/CopilotInfo.kt +++ b/src/main/kotlin/plus/maa/backend/controller/response/copilot/CopilotInfo.kt @@ -7,6 +7,7 @@ data class CopilotInfo ( val id: Long, val uploadTime: LocalDateTime, + val uploaderId: String, val uploader: String, //用于前端显示的格式化后的干员信息 [干员名]::[技能] From a71cbeb0757b3f552d8127c2fb0163155e993f99 Mon Sep 17 00:00:00 2001 From: Guan <46285865+guansss@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:34:05 +0800 Subject: [PATCH 11/12] ci: directly push changes to maa-copilot-client-ts --- .github/workflows/openapi.yml | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index f189bd1e..d72cb81c 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -107,27 +107,18 @@ jobs: path: maa-copilot-client-ts token: ${{ secrets.TS_CLIENT_PAT }} - - name: Copy ts client into maa-copilot-client-ts + - name: Update maa-copilot-client-ts and push to remote run: | cp -rf build/clients/ts-fetch-client/* maa-copilot-client-ts/ + cd maa-copilot-client-ts - - name: Create PR to maa-copilot-client-ts - id: cpr - uses: peter-evans/create-pull-request@v6 - with: - path: maa-copilot-client-ts - author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> - commit-message: 'release: ${{ steps.version.outputs.version }}' - title: 'release: ${{ steps.version.outputs.version }}' - body: https://github.com/MaaAssistantArknights/MaaBackendCenter/actions/runs/${{ github.run_id }} - branch: ts-client - delete-branch: true - token: ${{ secrets.TS_CLIENT_PAT }} + git diff --quiet && exit 0 - - name: Tag previous commit with version - if: ${{ steps.cpr.outputs.pull-request-number }} - run: | - cd maa-copilot-client-ts - git checkout ts-client + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add . + git commit -m "release: ${{ steps.version.outputs.version }}"\ + -m "Generated from https://github.com/MaaAssistantArknights/MaaBackendCenter/actions/runs/${{ github.run_id }}" git tag ${{ steps.version.outputs.version }} + git push git push --tags From 72ca97fab581c4895e15e66ee719e945b739c9e7 Mon Sep 17 00:00:00 2001 From: dragove Date: Thu, 14 Mar 2024 13:02:30 +0800 Subject: [PATCH 12/12] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=83=AD?= =?UTF-8?q?=E5=BA=A6=E6=9B=B4=E6=96=B0=E4=BB=BB=E5=8A=A1=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt b/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt index 4c42818a..b4e18939 100644 --- a/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt @@ -97,7 +97,7 @@ class CopilotScoreRefreshTask( // 判断关卡是否开放 val level = arkLevelService.findByLevelIdFuzzy(copilot.stageName!!) // 关卡已关闭,且作业在关闭前上传 - if (level!!.closeTime != null + if (level?.closeTime != null && copilot.firstUploadTime != null && false == level.isOpen && copilot.firstUploadTime!!.isBefore(level.closeTime)