From 63a84f4a77a53490a910bfe7de91471ee4fc7d7c Mon Sep 17 00:00:00 2001 From: Kirill Gevorkyan <26010098+kgevorkyan@users.noreply.github.com> Date: Tue, 6 Sep 2022 17:03:13 +0300 Subject: [PATCH 01/16] WIP ### What's done: * WIP --- .../backend/service/LnkContestProjectService.kt | 13 +++++++++++++ .../save/backend/service/TestExecutionService.kt | 9 +++++++-- .../kotlin/com/saveourtool/save/entities/Project.kt | 2 +- .../saveourtool/save/utils/ExecutionScoreUtils.kt | 6 +++++- .../frontend/components/basic/ExecutionLabels.kt | 12 ++++++++---- .../frontend/components/views/OrganizationView.kt | 2 +- 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/LnkContestProjectService.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/LnkContestProjectService.kt index 079549f630..e292238d08 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/LnkContestProjectService.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/LnkContestProjectService.kt @@ -15,6 +15,7 @@ import org.springframework.transaction.annotation.Transactional class LnkContestProjectService( private val lnkContestProjectRepository: LnkContestProjectRepository, private val lnkContestExecutionService: LnkContestExecutionService, + private val projectService: ProjectService, ) { /** * @param contestName name of a [Contest] @@ -95,9 +96,21 @@ class LnkContestProjectService( lnkContestProject.bestExecution = newExecution lnkContestProject.bestScore = newExecution.score lnkContestProjectRepository.save(lnkContestProject) + + updateProjectContestRating(project) } } + private fun updateProjectContestRating(project: Project) { + val projectContestRating = lnkContestProjectRepository.findByProject(project).mapNotNull { + it.bestScore + }.sum() + + projectService.updateProject(project.apply { + this.contestRating = projectContestRating + }) + } + companion object { @Suppress("GENERIC_VARIABLE_WRONG_DECLARATION") private val logger = getLogger() diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/TestExecutionService.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/TestExecutionService.kt index 973153da6d..416bfe560f 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/TestExecutionService.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/TestExecutionService.kt @@ -16,8 +16,8 @@ import com.saveourtool.save.test.TestDto import com.saveourtool.save.utils.ScoreType import com.saveourtool.save.utils.calculateScore import com.saveourtool.save.utils.debug -import com.saveourtool.save.utils.error import com.saveourtool.save.utils.getLogger +import com.saveourtool.save.utils.isValid import org.apache.commons.io.FilenameUtils import org.slf4j.Logger @@ -242,7 +242,12 @@ class TestExecutionService(private val testExecutionRepository: TestExecutionRep expectedChecks += counters.expectedChecks unexpectedChecks += counters.unexpectedChecks - score = toDto().calculateScore(scoreType = ScoreType.F_MEASURE) + val executionScore = toDto().calculateScore(scoreType = ScoreType.F_MEASURE) + + if (!executionScore.isValid()) { + log.error("Execution score for execution id $id is invalid: $executionScore") + } + score = executionScore } executionRepository.save(execution) } diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/Project.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/Project.kt index 92b22fc6cf..6e979480b8 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/Project.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/Project.kt @@ -43,7 +43,7 @@ data class Project( columnDefinition = "", ) var organization: Organization, - var contestRating: Long = 0, + var contestRating: Double = 0.0, ) { /** * id of project diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/utils/ExecutionScoreUtils.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/utils/ExecutionScoreUtils.kt index b70cd02024..f6bf47e1b2 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/utils/ExecutionScoreUtils.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/utils/ExecutionScoreUtils.kt @@ -51,7 +51,7 @@ private fun ExecutionDto.calculateScoreForContestMode(scoreType: ScoreType): Dou } private fun ExecutionDto.calculateFmeasure(): Double { - val denominator = getPrecisionRate() + getRecallRate() + val denominator = (getPrecisionRate() + getRecallRate()) return if (denominator == 0) { 0.0 } else { @@ -59,6 +59,10 @@ private fun ExecutionDto.calculateFmeasure(): Double { } } +fun Double.isValid() = this.toInt().isValid() + +fun Int.isValid() = this in 0..100 + /** * @param numerator * @param denominator diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt index f75288434e..30ac0ffb74 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt @@ -15,6 +15,7 @@ import com.saveourtool.save.frontend.externals.fontawesome.fontAwesomeIcon import com.saveourtool.save.utils.calculateRate import com.saveourtool.save.utils.getPrecisionRate import com.saveourtool.save.utils.getRecallRate +import com.saveourtool.save.utils.isValid import csstype.ClassName import csstype.Width @@ -32,6 +33,7 @@ import react.dom.html.ReactHTML.i import react.dom.html.ReactHTML.img import kotlinx.js.jso +import react.dom.html.ReactHTML.pre /** * Class contains all execution statistics values for rending @@ -101,8 +103,9 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { ?: "0" this.precisionRate = executionDto ?.let { - if (isAllApplicable(it.matchedChecks, it.unexpectedChecks)) { - "${it.getPrecisionRate()}" + val precisionRate = it.getPrecisionRate() + if (isAllApplicable(it.matchedChecks, it.unexpectedChecks) && precisionRate.isValid()) { + "$precisionRate" } else { "N/A" } @@ -110,8 +113,9 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { ?: "0" this.recallRate = executionDto ?.let { - if (isAllApplicable(it.matchedChecks, it.unmatchedChecks)) { - "${it.getRecallRate()}" + val recallRate = it.getRecallRate() + if (isAllApplicable(it.matchedChecks, it.unmatchedChecks) && recallRate.isValid()) { + "$recallRate" } else { "N/A" } diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/OrganizationView.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/OrganizationView.kt index d74d9f0d33..81c75c72ac 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/OrganizationView.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/OrganizationView.kt @@ -601,7 +601,7 @@ class OrganizationView : AbstractView( topProject?.let { scoreCard { name = it.name - contestScore = it.contestRating.toDouble() + contestScore = it.contestRating url = "#/${props.organizationName}/${it.name}" } } From d4f99d99959fda37a057d1553aaab71d8bf29667 Mon Sep 17 00:00:00 2001 From: Kirill Gevorkyan <26010098+kgevorkyan@users.noreply.github.com> Date: Tue, 6 Sep 2022 18:04:44 +0300 Subject: [PATCH 02/16] WIP ### What's done: * WIP --- .../controllers/OrganizationController.kt | 48 +++++++++++++++++++ .../backend/controllers/ProjectController.kt | 14 ++---- .../save/backend/service/ProjectService.kt | 13 +++++ 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt index aca4122b2e..fb984e1f07 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt @@ -5,8 +5,10 @@ import com.saveourtool.save.backend.configs.ApiSwaggerSupport import com.saveourtool.save.backend.configs.RequiresAuthorizationSourceHeader import com.saveourtool.save.backend.security.OrganizationPermissionEvaluator import com.saveourtool.save.backend.service.GitService +import com.saveourtool.save.backend.service.LnkContestProjectService import com.saveourtool.save.backend.service.LnkUserOrganizationService import com.saveourtool.save.backend.service.OrganizationService +import com.saveourtool.save.backend.service.ProjectService import com.saveourtool.save.backend.service.TestSuitesService import com.saveourtool.save.backend.service.TestSuitesSourceService import com.saveourtool.save.backend.storage.TestSuitesSourceSnapshotStorage @@ -62,6 +64,7 @@ internal class OrganizationController( private val testSuitesSourceService: TestSuitesSourceService, private val testSuitesService: TestSuitesService, private val testSuitesSourceSnapshotStorage: TestSuitesSourceSnapshotStorage, + private val projectService: ProjectService ) { @GetMapping("/all") @PreAuthorize("permitAll()") @@ -419,6 +422,51 @@ internal class OrganizationController( ResponseEntity.ok("Git credentials and corresponding data successfully deleted") } + @DeleteMapping("/{organizationName}/get-organization-contest-rank") + @RequiresAuthorizationSourceHeader + @PreAuthorize("isAuthenticated()") + fun getOrganizationContestRank( + @PathVariable organizationName: String, + @RequestParam url: String, + authentication: Authentication, + ): Mono = Mono.just(organizationName) + .flatMap { + organizationService.findByName(it).toMono() + } + .switchIfEmptyToNotFound { + "Could not find an organization with name $organizationName." + } + .filter { + organizationPermissionEvaluator.hasPermission(authentication, it, Permission.DELETE) + } + .switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { + "Not enough permission for managing organization git credentials." + } + .map { organization -> + // Find and remove all corresponding data to the current git repository from DB and file system storage + val git = gitService.getByOrganizationAndUrl(organization, url) + val testSuitesSources = testSuitesSourceService.findByGit(git) + // List of test suites for removing data from storage at next step + val testSuitesList = testSuitesSources.mapNotNull { testSuitesSource -> + val testSuites = testSuitesService.getBySource(testSuitesSource) + testSuitesService.deleteTestSuiteDto(testSuites.map { it.toDto() }) + testSuitesSourceService.delete(testSuitesSource) + // Since storage data is common for all test suites from one test suite source, it's enough to take any one of them + testSuites.firstOrNull() + } + gitService.delete(organization, url) + testSuitesList + } + .flatMap { testSuitesList -> + Flux.fromIterable(testSuitesList).map { testSuite -> + cleanupStorageData(testSuite) + }.collectList() + } + .map { + ResponseEntity.ok("Git credentials and corresponding data successfully deleted") + } + + private fun cleanupStorageData(testSuite: TestSuite) { testSuitesSourceSnapshotStorage.findKey( testSuite.source.organization.name, diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/ProjectController.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/ProjectController.kt index 4726c89648..bf7624809a 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/ProjectController.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/ProjectController.kt @@ -68,8 +68,8 @@ class ProjectController( @PreAuthorize("permitAll()") @Operation( method = "GET", - summary = "Get all avaliable projects.", - description = "Get all projects, avaliable for current user.", + summary = "Get all available projects.", + description = "Get all projects, available for current user.", ) @ApiResponse(responseCode = "200", description = "Projects successfully fetched.") fun getProjects( @@ -84,7 +84,7 @@ class ProjectController( @Operation( method = "GET", summary = "Get non-deleted projects.", - description = "Get non-deleted projects, avaliable for current user.", + description = "Get non-deleted projects, available for current user.", ) @ApiResponse(responseCode = "200", description = "Successfully fetched non-deleted projects.") fun getNotDeletedProjects( @@ -157,13 +157,7 @@ class ProjectController( fun getNonDeletedProjectsByOrganizationName( @RequestParam organizationName: String, authentication: Authentication?, - ): Flux = projectService.findByOrganizationName(organizationName) - .filter { - it.status != ProjectStatus.DELETED - } - .filter { - projectPermissionEvaluator.hasPermission(authentication, it, Permission.READ) - } + ): Flux = projectService.getNotDeletedProjectsByOrganizationName(organizationName, authentication) @PostMapping("/save") @RequiresAuthorizationSourceHeader diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectService.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectService.kt index 8f061b9443..27a4f554d0 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectService.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectService.kt @@ -94,6 +94,19 @@ class ProjectService( return projects } + fun getNotDeletedProjectsByOrganizationName( + organizationName: String, + authentication: Authentication?, + ): Flux { + return findByOrganizationName(organizationName) + .filter { + it.status != ProjectStatus.DELETED + } + .filter { + projectPermissionEvaluator.hasPermission(authentication, it, Permission.READ) + } + } + /** * @param authentication [Authentication] of the user who wants to access the project * @param projectName name of the project From eed3c553b525088b1cb5e50286222e17d5e132c3 Mon Sep 17 00:00:00 2001 From: Kirill Gevorkyan <26010098+kgevorkyan@users.noreply.github.com> Date: Wed, 7 Sep 2022 16:09:22 +0300 Subject: [PATCH 03/16] WIP ### What's done: * WIP --- .../controllers/OrganizationController.kt | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt index fb984e1f07..213dafb4e3 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt @@ -429,7 +429,7 @@ internal class OrganizationController( @PathVariable organizationName: String, @RequestParam url: String, authentication: Authentication, - ): Mono = Mono.just(organizationName) + ): Mono = Mono.just(organizationName) .flatMap { organizationService.findByName(it).toMono() } @@ -442,28 +442,11 @@ internal class OrganizationController( .switchIfEmptyToResponseException(HttpStatus.FORBIDDEN) { "Not enough permission for managing organization git credentials." } - .map { organization -> - // Find and remove all corresponding data to the current git repository from DB and file system storage - val git = gitService.getByOrganizationAndUrl(organization, url) - val testSuitesSources = testSuitesSourceService.findByGit(git) - // List of test suites for removing data from storage at next step - val testSuitesList = testSuitesSources.mapNotNull { testSuitesSource -> - val testSuites = testSuitesService.getBySource(testSuitesSource) - testSuitesService.deleteTestSuiteDto(testSuites.map { it.toDto() }) - testSuitesSourceService.delete(testSuitesSource) - // Since storage data is common for all test suites from one test suite source, it's enough to take any one of them - testSuites.firstOrNull() - } - gitService.delete(organization, url) - testSuitesList - } - .flatMap { testSuitesList -> - Flux.fromIterable(testSuitesList).map { testSuite -> - cleanupStorageData(testSuite) - }.collectList() + .flatMap { + projectService.getNotDeletedProjectsByOrganizationName(organizationName, authentication).collectList() } - .map { - ResponseEntity.ok("Git credentials and corresponding data successfully deleted") + .map { projectsList -> + projectsList.map { it.contestRating }.sum() } From b75f31676b89ad959aba499ecf7268ea27e3af49 Mon Sep 17 00:00:00 2001 From: Kirill Gevorkyan <26010098+kgevorkyan@users.noreply.github.com> Date: Wed, 7 Sep 2022 16:14:14 +0300 Subject: [PATCH 04/16] WIP ### What's done: * WIP --- .../controllers/OrganizationController.kt | 14 ++++++++----- .../save/backend/service/ProjectService.kt | 21 +++++++++++-------- .../save/utils/ExecutionScoreUtils.kt | 14 +++++++++---- .../components/basic/ExecutionLabels.kt | 5 ++--- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt index 213dafb4e3..04c492450b 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt @@ -5,7 +5,6 @@ import com.saveourtool.save.backend.configs.ApiSwaggerSupport import com.saveourtool.save.backend.configs.RequiresAuthorizationSourceHeader import com.saveourtool.save.backend.security.OrganizationPermissionEvaluator import com.saveourtool.save.backend.service.GitService -import com.saveourtool.save.backend.service.LnkContestProjectService import com.saveourtool.save.backend.service.LnkUserOrganizationService import com.saveourtool.save.backend.service.OrganizationService import com.saveourtool.save.backend.service.ProjectService @@ -422,10 +421,16 @@ internal class OrganizationController( ResponseEntity.ok("Git credentials and corresponding data successfully deleted") } - @DeleteMapping("/{organizationName}/get-organization-contest-rank") + /** + * @param organizationName + * @param url + * @param authentication + * @return contest rating for organization + */ + @DeleteMapping("/{organizationName}/get-organization-contest-rating") @RequiresAuthorizationSourceHeader @PreAuthorize("isAuthenticated()") - fun getOrganizationContestRank( + fun getOrganizationContestRating( @PathVariable organizationName: String, @RequestParam url: String, authentication: Authentication, @@ -446,10 +451,9 @@ internal class OrganizationController( projectService.getNotDeletedProjectsByOrganizationName(organizationName, authentication).collectList() } .map { projectsList -> - projectsList.map { it.contestRating }.sum() + projectsList.sumOf { it.contestRating } } - private fun cleanupStorageData(testSuite: TestSuite) { testSuitesSourceSnapshotStorage.findKey( testSuite.source.organization.name, diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectService.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectService.kt index 27a4f554d0..9492d0c72d 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectService.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/ProjectService.kt @@ -94,18 +94,21 @@ class ProjectService( return projects } + /** + * @param organizationName + * @param authentication + * @return list of not deleted projects + */ fun getNotDeletedProjectsByOrganizationName( organizationName: String, authentication: Authentication?, - ): Flux { - return findByOrganizationName(organizationName) - .filter { - it.status != ProjectStatus.DELETED - } - .filter { - projectPermissionEvaluator.hasPermission(authentication, it, Permission.READ) - } - } + ): Flux = findByOrganizationName(organizationName) + .filter { + it.status != ProjectStatus.DELETED + } + .filter { + projectPermissionEvaluator.hasPermission(authentication, it, Permission.READ) + } /** * @param authentication [Authentication] of the user who wants to access the project diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/utils/ExecutionScoreUtils.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/utils/ExecutionScoreUtils.kt index f6bf47e1b2..dd92a579c0 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/utils/ExecutionScoreUtils.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/utils/ExecutionScoreUtils.kt @@ -45,6 +45,16 @@ fun ExecutionDto.calculateScore(scoreType: ScoreType): Double = when (type) { else -> 0.0 } +/** + * @return true if value is in range (0, 100); false otherwise + */ +fun Double.isValid() = this.toInt().isValid() + +/** + * @return true if value is in range (0, 100); false otherwise + */ +fun Int.isValid() = this in 0..100 + private fun ExecutionDto.calculateScoreForContestMode(scoreType: ScoreType): Double = when (scoreType) { ScoreType.F_MEASURE -> calculateFmeasure() else -> TODO("Invalid score type for contest mode!") @@ -59,10 +69,6 @@ private fun ExecutionDto.calculateFmeasure(): Double { } } -fun Double.isValid() = this.toInt().isValid() - -fun Int.isValid() = this in 0..100 - /** * @param numerator * @param denominator diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt index 30ac0ffb74..f88f67c542 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt @@ -33,7 +33,6 @@ import react.dom.html.ReactHTML.i import react.dom.html.ReactHTML.img import kotlinx.js.jso -import react.dom.html.ReactHTML.pre /** * Class contains all execution statistics values for rending @@ -105,7 +104,7 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { ?.let { val precisionRate = it.getPrecisionRate() if (isAllApplicable(it.matchedChecks, it.unexpectedChecks) && precisionRate.isValid()) { - "$precisionRate" + precisionRate } else { "N/A" } @@ -115,7 +114,7 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { ?.let { val recallRate = it.getRecallRate() if (isAllApplicable(it.matchedChecks, it.unmatchedChecks) && recallRate.isValid()) { - "$recallRate" + recallRate } else { "N/A" } From de34a3f4e2c5377e83e546fb18fbef4ac2c99357 Mon Sep 17 00:00:00 2001 From: Kirill Gevorkyan <26010098+kgevorkyan@users.noreply.github.com> Date: Wed, 7 Sep 2022 16:23:07 +0300 Subject: [PATCH 05/16] WIP ### What's done: * WIP --- .../backend/controllers/OrganizationController.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt index 87b582d297..6e651cee01 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt @@ -431,16 +431,25 @@ internal class OrganizationController( /** * @param organizationName - * @param url * @param authentication * @return contest rating for organization */ - @DeleteMapping("/{organizationName}/get-organization-contest-rating") + @GetMapping("/{organizationName}/get-organization-contest-rating") @RequiresAuthorizationSourceHeader @PreAuthorize("isAuthenticated()") + @Operation( + method = "Get", + summary = "Get organization contest rating.", + description = "Get organization contest rating.", + ) + @Parameters( + Parameter(name = "organizationName", `in` = ParameterIn.PATH, description = "name of an organization", required = true), + ) + @ApiResponse(responseCode = "200", description = "Successfully get an organization contest rating.") + @ApiResponse(responseCode = "403", description = "Not enough permission for get organization contest rating.") + @ApiResponse(responseCode = "404", description = "Could not find an organization with such name.") fun getOrganizationContestRating( @PathVariable organizationName: String, - @RequestParam url: String, authentication: Authentication, ): Mono = Mono.just(organizationName) .flatMap { From 6bc417cf327675efa65ff74f7289671eee7771e2 Mon Sep 17 00:00:00 2001 From: Kirill Gevorkyan <26010098+kgevorkyan@users.noreply.github.com> Date: Wed, 7 Sep 2022 16:32:30 +0300 Subject: [PATCH 06/16] WIP ### What's done: * WIP --- .../save/frontend/components/basic/ExecutionLabels.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt index d83ee08fe0..613b4a0b4b 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt @@ -14,6 +14,7 @@ import com.saveourtool.save.frontend.externals.fontawesome.fontAwesomeIcon import com.saveourtool.save.utils.calculateRate import com.saveourtool.save.utils.getPrecisionRate import com.saveourtool.save.utils.getRecallRate +import com.saveourtool.save.utils.isValid import csstype.ClassName import csstype.Width @@ -101,7 +102,7 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { this.precisionRate = executionDto ?.let { val precisionRate = it.getPrecisionRate() - if (isAllApplicable(it.matchedChecks, it.unexpectedChecks) && precisionRate.isValid()) { + if (precisionRate.isValid()) { precisionRate } else { "N/A" @@ -111,7 +112,7 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { this.recallRate = executionDto ?.let { val recallRate = it.getRecallRate() - if (isAllApplicable(it.matchedChecks, it.unmatchedChecks) && recallRate.isValid()) { + if (recallRate.isValid()) { recallRate } else { "N/A" @@ -119,8 +120,6 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { } ?: "0" } - - private fun isAllApplicable(vararg values: Long): Boolean = values.all { !CountWarnings.isNotApplicable(it.toInt()) } } /** From edf6030cd08fe2369a8f3bdb7e211bb28f22df00 Mon Sep 17 00:00:00 2001 From: Kirill Gevorkyan <26010098+kgevorkyan@users.noreply.github.com> Date: Wed, 7 Sep 2022 16:47:47 +0300 Subject: [PATCH 07/16] Fix ### What's done: * Fix --- .../save/frontend/components/basic/ExecutionLabels.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt index 613b4a0b4b..c21f783fc6 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ExecutionLabels.kt @@ -103,7 +103,8 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { ?.let { val precisionRate = it.getPrecisionRate() if (precisionRate.isValid()) { - precisionRate + @Suppress("STRING_TEMPLATE_QUOTES") + "$precisionRate" } else { "N/A" } @@ -113,7 +114,8 @@ internal class ExecutionStatisticsValues(executionDto: ExecutionDto?) { ?.let { val recallRate = it.getRecallRate() if (recallRate.isValid()) { - recallRate + @Suppress("STRING_TEMPLATE_QUOTES") + "$recallRate" } else { "N/A" } From 9393b55f88e2ea98311cd0efc6743cd5ad7fe3ed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 7 Sep 2022 13:54:22 +0000 Subject: [PATCH 08/16] Update backend-api-docs.json --- save-backend/backend-api-docs.json | 86 ++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/save-backend/backend-api-docs.json b/save-backend/backend-api-docs.json index 05b098c3da..b74fcf44ec 100644 --- a/save-backend/backend-api-docs.json +++ b/save-backend/backend-api-docs.json @@ -3553,8 +3553,8 @@ "tags": [ "projects" ], - "summary": "Get all avaliable projects.", - "description": "Get all projects, avaliable for current user.", + "summary": "Get all available projects.", + "description": "Get all projects, available for current user.", "operationId": "getProjects", "parameters": [ { @@ -4307,6 +4307,84 @@ ] } }, + "/api/v1/organizations/{organizationName}/get-organization-contest-rating": { + "get": { + "tags": [ + "organizations" + ], + "summary": "Get organization contest rating.", + "description": "Get organization contest rating.", + "operationId": "getOrganizationContestRating", + "parameters": [ + { + "name": "organizationName", + "in": "path", + "description": "name of an organization", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "X-Authorization-Source", + "in": "header", + "required": true, + "example": "basic" + } + ], + "responses": { + "200": { + "description": "Successfully get an organization contest rating.", + "content": { + "*/*": { + "schema": { + "type": "number", + "format": "double" + } + } + } + }, + "404": { + "description": "Could not find an organization with such name.", + "content": { + "*/*": { + "schema": { + "type": "number", + "format": "double" + } + } + } + }, + "403": { + "description": "Not enough permission for get organization contest rating.", + "content": { + "*/*": { + "schema": { + "type": "number", + "format": "double" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "*/*": { + "schema": { + "type": "number", + "format": "double" + } + } + } + } + }, + "security": [ + { + "basic": [] + } + ] + } + }, "/api/v1/organizations/{organizationName}/avatar": { "get": { "tags": [ @@ -7046,8 +7124,8 @@ "$ref": "#/components/schemas/Organization" }, "contestRating": { - "type": "integer", - "format": "int64" + "type": "number", + "format": "double" }, "id": { "type": "integer", From 6a037def40f7121fcb632575a59f72f834301d9e Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Thu, 8 Sep 2022 11:45:17 +0300 Subject: [PATCH 09/16] Display organizations' global rating on ContestGlobalRatingView * Change returned type from controller from Organization to OrganizationDto * Display rating on frontend --- .../controllers/OrganizationController.kt | 21 +++++++++++++------ .../backend/service/OrganizationService.kt | 9 ++++++++ .../save/entities/OrganizationDto.kt | 14 +++++++------ .../views/contests/ContestGlobalRatingView.kt | 12 +++++------ 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt index 6e651cee01..d830e6095c 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt @@ -85,8 +85,20 @@ internal class OrganizationController( description = "Get non-deleted organizations.", ) @ApiResponse(responseCode = "200", description = "Successfully fetched non-deleted projects.") - fun getNotDeletedOrganizations(@RequestBody(required = false) organizationFilters: OrganizationFilters?) = - organizationService.getNotDeletedOrganizations(organizationFilters).toFlux() + fun getNotDeletedOrganizations( + @RequestBody(required = false) organizationFilters: OrganizationFilters?, + authentication: Authentication, + ): Flux = + organizationService.getNotDeletedOrganizations(organizationFilters) + .toFlux() + .flatMap { organization -> + organizationService.getGlobalRating(organization.name, authentication).map { + organization to it + } + } + .map { (organization, rating) -> + organization.toDto().copy(globalRating = rating) + } @GetMapping("/{organizationName}") @PreAuthorize("permitAll()") @@ -465,10 +477,7 @@ internal class OrganizationController( "Not enough permission for managing organization git credentials." } .flatMap { - projectService.getNotDeletedProjectsByOrganizationName(organizationName, authentication).collectList() - } - .map { projectsList -> - projectsList.sumOf { it.contestRating } + organizationService.getGlobalRating(organizationName, authentication) } private fun cleanupStorageData(testSuite: TestSuite) { diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/OrganizationService.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/OrganizationService.kt index ae717ebb59..ed73f1f3ab 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/OrganizationService.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/OrganizationService.kt @@ -5,6 +5,7 @@ import com.saveourtool.save.domain.OrganizationSaveStatus import com.saveourtool.save.entities.Organization import com.saveourtool.save.entities.OrganizationStatus import com.saveourtool.save.filters.OrganizationFilters +import org.springframework.security.core.Authentication import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -15,6 +16,7 @@ import org.springframework.transaction.annotation.Transactional */ @Service class OrganizationService( + private val projectService: ProjectService, private val organizationRepository: OrganizationRepository, ) { /** @@ -115,4 +117,11 @@ class OrganizationService( * @return all organizations that were registered in SAVE */ fun findAll(): List = organizationRepository.findAll() + + fun getGlobalRating(organizationName: String, authentication: Authentication) = + projectService.getNotDeletedProjectsByOrganizationName(organizationName, authentication) + .collectList() + .map { projectsList -> + projectsList.sumOf { it.contestRating } + } } diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/OrganizationDto.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/OrganizationDto.kt index 7f9ed5f903..2ef8c91644 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/OrganizationDto.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/OrganizationDto.kt @@ -25,6 +25,7 @@ data class OrganizationDto( val description: String = "", val canCreateContests: Boolean = false, val userRoles: Map = emptyMap(), + val globalRating: Double? = null, ) : Validatable { /** * Validation of organization name @@ -47,12 +48,13 @@ data class OrganizationDto( * Value that represents an empty [OrganizationDto] */ val empty = OrganizationDto( - "", - null, - null, - "", - false, - emptyMap(), + name = "", + dateCreated = null, + avatar = null, + description = "", + canCreateContests = false, + userRoles = emptyMap(), + globalRating = null, ) } } diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt index 7ee20e9092..3f3199a814 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt @@ -5,7 +5,7 @@ package com.saveourtool.save.frontend.components.views.contests import com.saveourtool.save.domain.Role -import com.saveourtool.save.entities.Organization +import com.saveourtool.save.entities.OrganizationDto import com.saveourtool.save.entities.Project import com.saveourtool.save.filters.OrganizationFilters import com.saveourtool.save.filters.ProjectFilters @@ -63,7 +63,7 @@ external interface ContestGlobalRatingViewState : State, HasSelectedMenu + var organizations: Array /** * All projects @@ -91,7 +91,7 @@ class ContestGlobalRatingView : AbstractView { + columns = columns { column(id = "index", header = "Position") { Fragment.create { td { @@ -121,10 +121,10 @@ class ContestGlobalRatingView : AbstractView Fragment.create { td { - +"4560" + +"${cellProps.value.globalRating}" } } } @@ -236,7 +236,7 @@ class ContestGlobalRatingView : AbstractView = post( + val organizationsFromBackend: List = post( url = "$apiUrl/organizations/not-deleted", headers = jsonHeaders, body = Json.encodeToString(filterValue), From 564ef700b66b88700ad1715218ae33f751c24bbc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 8 Sep 2022 08:52:24 +0000 Subject: [PATCH 10/16] Update backend-api-docs.json --- save-backend/backend-api-docs.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/save-backend/backend-api-docs.json b/save-backend/backend-api-docs.json index b74fcf44ec..e47074d2e5 100644 --- a/save-backend/backend-api-docs.json +++ b/save-backend/backend-api-docs.json @@ -1779,7 +1779,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Organization" + "$ref": "#/components/schemas/OrganizationDto" } } } @@ -1792,7 +1792,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/Organization" + "$ref": "#/components/schemas/OrganizationDto" } } } @@ -7170,6 +7170,10 @@ "VIEWER" ] } + }, + "globalRating": { + "type": "number", + "format": "double" } } }, From e6fe347c5588174921bb7152a80eaf577e1b0004 Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Thu, 8 Sep 2022 11:56:44 +0300 Subject: [PATCH 11/16] Display organizations' and projects' global rating on ContestGlobalRatingView and UserRating --- .../views/contests/ContestGlobalRatingView.kt | 4 ++-- .../components/views/contests/UserRating.kt | 16 +++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt index 3f3199a814..b169c10559 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt @@ -185,10 +185,10 @@ class ContestGlobalRatingView : AbstractView Fragment.create { td { - +"1370" + +"${cellProps.value.contestRating}" } } } diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/UserRating.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/UserRating.kt index 294ee05f5b..9540fb7866 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/UserRating.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/UserRating.kt @@ -6,7 +6,7 @@ package com.saveourtool.save.frontend.components.views.contests -import com.saveourtool.save.entities.Organization +import com.saveourtool.save.entities.OrganizationDto import com.saveourtool.save.entities.Project import com.saveourtool.save.frontend.TabMenuBar import com.saveourtool.save.frontend.externals.fontawesome.faArrowRight @@ -39,7 +39,7 @@ enum class UserRatingTab { companion object : TabMenuBar { // The string is the postfix of a [regexForUrlClassification] for parsing the url - private val postfixInRegex = values().map { it.name.lowercase() }.joinToString("|") + private val postfixInRegex = values().joinToString("|") { it.name.lowercase() } override val nameOfTheHeadUrlSection = "" override val defaultTab: UserRatingTab = UserRatingTab.ORGS override val regexForUrlClassification = Regex("/${FrontendRoutes.CONTESTS_GLOBAL_RATING.path}/($postfixInRegex)") @@ -76,18 +76,17 @@ private fun ChildrenBuilder.renderingProjectChampionsTable(projects: Set) { +private fun ChildrenBuilder.renderingOrganizationChampionsTable(organizations: Set) { organizations.forEachIndexed { i, organization -> div { className = ClassName("row text-muted pb-3 mb-3 border-bottom border-gray mx-2") @@ -115,11 +114,10 @@ private fun ChildrenBuilder.renderingOrganizationChampionsTable(organizations: S } } - // FixMe: add rating after kirill's changes div { className = ClassName("col-lg-4") p { - +"4560" + +"${organization.globalRating}" } } } @@ -133,9 +131,9 @@ private fun ChildrenBuilder.renderingOrganizationChampionsTable(organizations: S private fun userRating() = VFC { val (selectedTab, setSelectedTab) = useState(UserRatingTab.ORGS) - val (organizations, setOrganizations) = useState>(emptySet()) + val (organizations, setOrganizations) = useState>(emptySet()) useRequest { - val organizationsFromBackend: List = post( + val organizationsFromBackend: List = post( url = "$apiUrl/organizations/not-deleted", headers = jsonHeaders, body = undefined, From 2b3024e0492d3a52d8cec20a325966253ee2ce1b Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Thu, 8 Sep 2022 11:59:44 +0300 Subject: [PATCH 12/16] Code style --- .../save/backend/service/OrganizationService.kt | 15 ++++++++++----- .../saveourtool/save/entities/OrganizationDto.kt | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/OrganizationService.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/OrganizationService.kt index ed73f1f3ab..042c2f06f7 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/OrganizationService.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/service/OrganizationService.kt @@ -118,10 +118,15 @@ class OrganizationService( */ fun findAll(): List = organizationRepository.findAll() + /** + * @param organizationName + * @param authentication + * @return global rating of organization by name [organizationName] based on ratings of all projects under this organization + */ fun getGlobalRating(organizationName: String, authentication: Authentication) = - projectService.getNotDeletedProjectsByOrganizationName(organizationName, authentication) - .collectList() - .map { projectsList -> - projectsList.sumOf { it.contestRating } - } + projectService.getNotDeletedProjectsByOrganizationName(organizationName, authentication) + .collectList() + .map { projectsList -> + projectsList.sumOf { it.contestRating } + } } diff --git a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/OrganizationDto.kt b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/OrganizationDto.kt index 2ef8c91644..0f330eaf39 100644 --- a/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/OrganizationDto.kt +++ b/save-cloud-common/src/commonMain/kotlin/com/saveourtool/save/entities/OrganizationDto.kt @@ -15,6 +15,7 @@ import kotlinx.serialization.Serializable * @property description * @property canCreateContests * @property userRoles map where keys are usernames and values are their [Role]s + * @property globalRating */ @Serializable data class OrganizationDto( From b1d59b9e662056df7c31769f7f6a260b5ffb5699 Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Thu, 8 Sep 2022 12:05:00 +0300 Subject: [PATCH 13/16] Fix beans in test --- .../save/backend/service/LnkContestProjectServiceTest.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/save-backend/src/test/kotlin/com/saveourtool/save/backend/service/LnkContestProjectServiceTest.kt b/save-backend/src/test/kotlin/com/saveourtool/save/backend/service/LnkContestProjectServiceTest.kt index 5af7e05d94..df6599332e 100644 --- a/save-backend/src/test/kotlin/com/saveourtool/save/backend/service/LnkContestProjectServiceTest.kt +++ b/save-backend/src/test/kotlin/com/saveourtool/save/backend/service/LnkContestProjectServiceTest.kt @@ -10,6 +10,7 @@ import org.junit.jupiter.api.extension.ExtendWith import org.mockito.kotlin.* import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.boot.test.mock.mockito.MockBeans import org.springframework.context.annotation.Import import org.springframework.test.context.junit.jupiter.SpringExtension import java.util.Optional @@ -17,6 +18,9 @@ import kotlin.math.abs @ExtendWith(SpringExtension::class) @Import(LnkContestProjectService::class) +@MockBeans( + MockBean(ProjectService::class), +) @Suppress("UnsafeCallOnNullableType") class LnkContestProjectServiceTest { @Autowired private lateinit var lnkContestProjectService: LnkContestProjectService From a6a3ff224b7a6b3ab46ca60605d208047e05eb17 Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Thu, 8 Sep 2022 12:45:37 +0300 Subject: [PATCH 14/16] Display scores rounded to 2 digits --- .../saveourtool/save/frontend/components/basic/ScoreCard.kt | 3 ++- .../components/views/contests/ContestGlobalRatingView.kt | 4 ++-- .../save/frontend/components/views/contests/UserRating.kt | 4 ++-- .../main/kotlin/com/saveourtool/save/frontend/utils/Utils.kt | 5 +++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ScoreCard.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ScoreCard.kt index 49b82e955f..2d9cec27fe 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ScoreCard.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/basic/ScoreCard.kt @@ -2,6 +2,7 @@ package com.saveourtool.save.frontend.components.basic +import com.saveourtool.save.frontend.utils.toFixed import csstype.* import react.FC import react.Props @@ -80,7 +81,7 @@ private fun scoreCard() = FC { props -> alignItems = AlignItems.center alignSelf = AlignSelf.start } - +"${props.contestScore}" + +"${props.contestScore.toFixed(2)}" } } div { diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt index b169c10559..781341d044 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/ContestGlobalRatingView.kt @@ -124,7 +124,7 @@ class ContestGlobalRatingView : AbstractView Fragment.create { td { - +"${cellProps.value.globalRating}" + +"${cellProps.value.globalRating?.toFixed(2)}" } } } @@ -188,7 +188,7 @@ class ContestGlobalRatingView : AbstractView Fragment.create { td { - +"${cellProps.value.contestRating}" + +"${cellProps.value.contestRating.toFixed(2)}" } } } diff --git a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/UserRating.kt b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/UserRating.kt index 9540fb7866..8a33dd8543 100644 --- a/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/UserRating.kt +++ b/save-frontend/src/main/kotlin/com/saveourtool/save/frontend/components/views/contests/UserRating.kt @@ -79,7 +79,7 @@ private fun ChildrenBuilder.renderingProjectChampionsTable(projects: Set maxLength + +/** + * @param digits number of digits to round to + */ +internal fun Double.toFixed(digits: Int) = asDynamic().toFixed(digits) From d5d08cdc630cfb4a45d924aa2de901cfdc854cd8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 8 Sep 2022 10:36:10 +0000 Subject: [PATCH 15/16] Update backend-api-docs.json --- save-backend/backend-api-docs.json | 78 ------------------------------ 1 file changed, 78 deletions(-) diff --git a/save-backend/backend-api-docs.json b/save-backend/backend-api-docs.json index 293223afa7..f6e728ef6a 100644 --- a/save-backend/backend-api-docs.json +++ b/save-backend/backend-api-docs.json @@ -4419,84 +4419,6 @@ ] } }, - "/api/v1/organizations/{organizationName}/get-organization-contest-rating": { - "get": { - "tags": [ - "organizations" - ], - "summary": "Get organization contest rating.", - "description": "Get organization contest rating.", - "operationId": "getOrganizationContestRating", - "parameters": [ - { - "name": "organizationName", - "in": "path", - "description": "name of an organization", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "X-Authorization-Source", - "in": "header", - "required": true, - "example": "basic" - } - ], - "responses": { - "200": { - "description": "Successfully get an organization contest rating.", - "content": { - "*/*": { - "schema": { - "type": "number", - "format": "double" - } - } - } - }, - "404": { - "description": "Could not find an organization with such name.", - "content": { - "*/*": { - "schema": { - "type": "number", - "format": "double" - } - } - } - }, - "403": { - "description": "Not enough permission for get organization contest rating.", - "content": { - "*/*": { - "schema": { - "type": "number", - "format": "double" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "*/*": { - "schema": { - "type": "number", - "format": "double" - } - } - } - } - }, - "security": [ - { - "basic": [] - } - ] - } - }, "/api/v1/organizations/{organizationName}/avatar": { "get": { "tags": [ From 7d3c83d35dfc8c51ac945c7de7f6c401ce21f074 Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Thu, 8 Sep 2022 14:46:35 +0300 Subject: [PATCH 16/16] Fix typo --- save-backend/backend-api-docs.json | 2 +- .../save/backend/controllers/OrganizationController.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/save-backend/backend-api-docs.json b/save-backend/backend-api-docs.json index f6e728ef6a..d85a340a40 100644 --- a/save-backend/backend-api-docs.json +++ b/save-backend/backend-api-docs.json @@ -1758,7 +1758,7 @@ }, "responses": { "200": { - "description": "Successfully fetched non-deleted projects.", + "description": "Successfully fetched non-deleted organizations.", "content": { "*/*": { "schema": { diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt index 06047ff228..12d08bdc99 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/controllers/OrganizationController.kt @@ -84,7 +84,7 @@ internal class OrganizationController( summary = "Get non-deleted organizations.", description = "Get non-deleted organizations.", ) - @ApiResponse(responseCode = "200", description = "Successfully fetched non-deleted projects.") + @ApiResponse(responseCode = "200", description = "Successfully fetched non-deleted organizations.") fun getNotDeletedOrganizations( @RequestBody(required = false) organizationFilters: OrganizationFilters?, authentication: Authentication,