From 290b2a5a209778f54fba7943d7d1ef988c059f8c Mon Sep 17 00:00:00 2001 From: Vladislav Kopnin Date: Sun, 27 Sep 2026 22:38:48 +0300 Subject: [PATCH] Refactor: split content order API; near-default detekt thresholds --- config/detekt/detekt.yml | 26 +++--- .../ru/ysu/lms/web/api/ApiClientContent.kt | 75 ------------------ .../ysu/lms/web/api/ApiClientContentOrder.kt | 79 +++++++++++++++++++ 3 files changed, 94 insertions(+), 86 deletions(-) create mode 100644 web/src/main/kotlin/ru/ysu/lms/web/api/ApiClientContentOrder.kt diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index d2f3c78..b5482b5 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -9,31 +9,35 @@ config: warningsAsErrors: false complexity: - # Пороги выставлены под реальный масштаб классов проекта. Дробление крупных - # агрегатов (web ApiClient, AdminController, ContentService) — отдельная задача; - # когда оно будет выполнено, пороги можно вернуть к значениям по умолчанию. + # Крупные агрегаты уже раздроблены (web ApiClient — по доменам, AdminController — + # на AdminSupport + 5 контроллеров, импорт материалов — в ContentImporter). + # Оставшиеся послабления точечные и перечислены ниже; после дробления ContentService + # и выноса хелперов из методов groupDetail/labDetail/editLab их можно снять. LongMethod: + # groupDetail (82), labDetail (73), editLab (86) в админ-контроллерах. threshold: 90 LongParameterList: + # MVC-обработчики форм принимают набор @RequestParam — для них это нормально. functionThreshold: 8 constructorThreshold: 8 ignoreDefaultParameters: true - # MVC-обработчики форм принимают набор @RequestParam — для них параметров «много» нормально. ignoreAnnotated: - 'PostMapping' - 'GetMapping' TooManyFunctions: - thresholdInFiles: 80 - thresholdInClasses: 80 - thresholdInInterfaces: 40 - thresholdInObjects: 40 - thresholdInEnums: 40 + # ContentService (26) — следующий кандидат на разделение. + thresholdInFiles: 27 + thresholdInClasses: 27 + thresholdInInterfaces: 20 + thresholdInObjects: 20 + thresholdInEnums: 20 LargeClass: - threshold: 1400 + threshold: 600 ComplexCondition: threshold: 4 CyclomaticComplexMethod: - threshold: 20 + # editLab (16) в AdminLabController. + threshold: 17 style: MagicNumber: diff --git a/web/src/main/kotlin/ru/ysu/lms/web/api/ApiClientContent.kt b/web/src/main/kotlin/ru/ysu/lms/web/api/ApiClientContent.kt index feaf3d3..6900b20 100644 --- a/web/src/main/kotlin/ru/ysu/lms/web/api/ApiClientContent.kt +++ b/web/src/main/kotlin/ru/ysu/lms/web/api/ApiClientContent.kt @@ -33,31 +33,6 @@ fun ApiClient.contentArticle( .body(ContentArticleDto::class.java) } -fun ApiClient.setContentPublished( - token: String, - kind: String, - id: String, - published: Boolean, -) { - val path = - when (kind) { - "chapters" -> "/api/v1/content/chapters/{id}/published" - "sections" -> "/api/v1/content/sections/{id}/published" - "articles" -> "/api/v1/content/articles/{id}/published" - else -> throw IllegalArgumentException("Неизвестный тип материала: $kind") - } - call { - client - .put() - .uri(path, id) - .header(HttpHeaders.AUTHORIZATION, bearer(token)) - .contentType(MediaType.APPLICATION_JSON) - .body(mapOf("published" to published)) - .retrieve() - .toBodilessEntity() - } -} - fun ApiClient.contentTreeList(token: String?): List { val type = object : ParameterizedTypeReference>() {} return call { @@ -68,56 +43,6 @@ fun ApiClient.contentTreeList(token: String?): List { } } -fun ApiClient.reorderContent( - token: String, - tree: ContentReorderDto, -) { - call { - client - .post() - .uri("/api/v1/content/reorder") - .header(HttpHeaders.AUTHORIZATION, bearer(token)) - .contentType(MediaType.APPLICATION_JSON) - .body(tree) - .retrieve() - .toBodilessEntity() - } -} - -fun ApiClient.reorderSections( - token: String, - chapterId: String, - body: SectionsReorderDto, -) { - call { - client - .post() - .uri("/api/v1/content/chapters/{id}/sections/reorder", chapterId) - .header(HttpHeaders.AUTHORIZATION, bearer(token)) - .contentType(MediaType.APPLICATION_JSON) - .body(body) - .retrieve() - .toBodilessEntity() - } -} - -fun ApiClient.reorderArticles( - token: String, - sectionId: String, - body: ArticlesReorderDto, -) { - call { - client - .post() - .uri("/api/v1/content/sections/{id}/articles/reorder", sectionId) - .header(HttpHeaders.AUTHORIZATION, bearer(token)) - .contentType(MediaType.APPLICATION_JSON) - .body(body) - .retrieve() - .toBodilessEntity() - } -} - fun ApiClient.importContent( token: String, filename: String, diff --git a/web/src/main/kotlin/ru/ysu/lms/web/api/ApiClientContentOrder.kt b/web/src/main/kotlin/ru/ysu/lms/web/api/ApiClientContentOrder.kt new file mode 100644 index 0000000..667dfad --- /dev/null +++ b/web/src/main/kotlin/ru/ysu/lms/web/api/ApiClientContentOrder.kt @@ -0,0 +1,79 @@ +package ru.ysu.lms.web.api + +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType + +fun ApiClient.setContentPublished( + token: String, + kind: String, + id: String, + published: Boolean, +) { + val path = + when (kind) { + "chapters" -> "/api/v1/content/chapters/{id}/published" + "sections" -> "/api/v1/content/sections/{id}/published" + "articles" -> "/api/v1/content/articles/{id}/published" + else -> throw IllegalArgumentException("Неизвестный тип материала: $kind") + } + call { + client + .put() + .uri(path, id) + .header(HttpHeaders.AUTHORIZATION, bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .body(mapOf("published" to published)) + .retrieve() + .toBodilessEntity() + } +} + +fun ApiClient.reorderContent( + token: String, + tree: ContentReorderDto, +) { + call { + client + .post() + .uri("/api/v1/content/reorder") + .header(HttpHeaders.AUTHORIZATION, bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .body(tree) + .retrieve() + .toBodilessEntity() + } +} + +fun ApiClient.reorderSections( + token: String, + chapterId: String, + body: SectionsReorderDto, +) { + call { + client + .post() + .uri("/api/v1/content/chapters/{id}/sections/reorder", chapterId) + .header(HttpHeaders.AUTHORIZATION, bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .body(body) + .retrieve() + .toBodilessEntity() + } +} + +fun ApiClient.reorderArticles( + token: String, + sectionId: String, + body: ArticlesReorderDto, +) { + call { + client + .post() + .uri("/api/v1/content/sections/{id}/articles/reorder", sectionId) + .header(HttpHeaders.AUTHORIZATION, bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .body(body) + .retrieve() + .toBodilessEntity() + } +}