Skip to content

Commit

Permalink
ContestView results improvements (#1081)
Browse files Browse the repository at this point in the history
* ContestView results improvements

### What's done:
 * Renamed `PARTICIPANTS` ContestView tab to `SUMMARY`
 * Renamed `RESULTS` ContestView tab to `SUBMISSIONS`
 * Improved `SUBMISSIONS` tab
 * Added `ContestExecutionView`
 * Added several endpoints on backend for new tab and view

 (#1035)

Co-authored-by: Peter Trifanov <[email protected]>
  • Loading branch information
sanyavertolet and petertrr authored Aug 22, 2022
1 parent 97ec216 commit 90412be
Show file tree
Hide file tree
Showing 22 changed files with 1,108 additions and 212 deletions.
266 changes: 265 additions & 1 deletion save-backend/backend-api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -5389,6 +5389,246 @@
]
}
},
"/api/v1/contests/{contestName}/my-results": {
"get": {
"tags": [
"contests"
],
"summary": "Get your best results in contest.",
"description": "Get list of best results of your projects in a given contest.",
"operationId": "getBestResultsInUserProjects",
"parameters": [
{
"name": "contestName",
"in": "path",
"description": "name of a contest",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "X-Authorization-Source",
"in": "header",
"required": true,
"example": "basic"
}
],
"responses": {
"200": {
"description": "Successfully fetched your best results.",
"content": {
"*/*": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ContestResult"
}
}
}
}
},
"404": {
"description": "Either given project or given contest was not found.",
"content": {
"*/*": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ContestResult"
}
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"*/*": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ContestResult"
}
}
}
}
}
},
"security": [
{
"basic": []
}
]
}
},
"/api/v1/contests/{contestName}/executions/{organizationName}/{projectName}": {
"get": {
"tags": [
"contests"
],
"summary": "Get project executions in contest.",
"description": "Get list of execution of a project with given name in contest with given name.",
"operationId": "getContestExecutionsForProject",
"parameters": [
{
"name": "contestName",
"in": "path",
"description": "name of an organization",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "organizationName",
"in": "path",
"description": "name of an organization",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "projectName",
"in": "path",
"description": "name of a project",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"404": {
"description": "Either contest is not found or project is not found or execution is not found.",
"content": {
"*/*": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ExecutionDto"
}
}
}
}
},
"200": {
"description": "Successfully fetched latest project execution in contest.",
"content": {
"*/*": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ExecutionDto"
}
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"*/*": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ExecutionDto"
}
}
}
}
}
},
"security": [
{
"basic": []
}
]
}
},
"/api/v1/contests/{contestName}/executions/{organizationName}/{projectName}/latest": {
"get": {
"tags": [
"contests"
],
"summary": "Get latest project execution in contest.",
"description": "Get latest execution of a project with given name in contest with given name.",
"operationId": "getLatestExecutionOfProjectInContest",
"parameters": [
{
"name": "organizationName",
"in": "path",
"description": "name of an organization",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "projectName",
"in": "path",
"description": "name of a project",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "contestName",
"in": "path",
"description": "name of an organization",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "X-Authorization-Source",
"in": "header",
"required": true,
"example": "basic"
}
],
"responses": {
"404": {
"description": "Either contest is not found or project is not found or execution is not found.",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ExecutionDto"
}
}
}
},
"200": {
"description": "Successfully fetched latest project execution in contest.",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ExecutionDto"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ExecutionDto"
}
}
}
}
},
"security": [
{
"basic": []
}
]
}
},
"/api/v1/contests/{contestName}/enroll": {
"get": {
"tags": [
Expand Down Expand Up @@ -7219,6 +7459,7 @@
"type": {
"type": "string",
"enum": [
"CONTEST",
"GIT",
"STANDARD"
]
Expand Down Expand Up @@ -7396,6 +7637,7 @@
"type": {
"type": "string",
"enum": [
"CONTEST",
"GIT",
"STANDARD"
]
Expand Down Expand Up @@ -7452,8 +7694,11 @@
"ContestResult": {
"required": [
"contestName",
"hasFailedTest",
"organizationName",
"projectName"
"projectName",
"sdk",
"submissionStatus"
],
"type": "object",
"properties": {
Expand All @@ -7469,6 +7714,25 @@
"score": {
"type": "number",
"format": "double"
},
"submissionTime": {
"type": "string",
"format": "date-time"
},
"submissionStatus": {
"type": "string",
"enum": [
"ERROR",
"FINISHED",
"PENDING",
"RUNNING"
]
},
"sdk": {
"type": "string"
},
"hasFailedTest": {
"type": "boolean"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.saveourtool.save.execution.ExecutionDto
import com.saveourtool.save.execution.ExecutionUpdateDto
import com.saveourtool.save.permission.Permission
import com.saveourtool.save.utils.orNotFound
import com.saveourtool.save.utils.switchIfEmptyToNotFound
import com.saveourtool.save.v1

import org.slf4j.LoggerFactory
Expand All @@ -29,6 +30,7 @@ import reactor.core.publisher.Flux
import reactor.core.publisher.GroupedFlux
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.switchIfEmpty
import reactor.kotlin.core.publisher.toMono

import java.util.concurrent.atomic.AtomicBoolean

Expand Down Expand Up @@ -97,15 +99,22 @@ class ExecutionController(private val executionService: ExecutionService,
* @param authentication
* @param organizationName
* @return list of execution dtos
* @throws NoSuchElementException
*/
@GetMapping(path = ["/api/$v1/executionDtoList"])
fun getExecutionByProject(@RequestParam name: String, @RequestParam organizationName: String, authentication: Authentication): Mono<List<ExecutionDto>> {
val organization = organizationService.findByName(organizationName) ?: throw NoSuchElementException("Organization with name [$organizationName] was not found.")
return projectService.findWithPermissionByNameAndOrganization(authentication, name, organization.name, Permission.READ).map {
executionService.getExecutionDtoByNameAndOrganization(name, organization).reversed()
fun getExecutionByProject(
@RequestParam name: String,
@RequestParam organizationName: String,
authentication: Authentication,
): Mono<List<ExecutionDto>> = organizationService.findByName(organizationName)
.toMono()
.switchIfEmptyToNotFound {
"Organization with name [$organizationName] was not found."
}
.flatMap { organization ->
projectService.findWithPermissionByNameAndOrganization(authentication, name, organization.name, Permission.READ).map {
executionService.getExecutionDtoByNameAndOrganization(name, organization).reversed()
}
}
}

/**
* Get latest (by start time an) execution by project name and organization
Expand Down
Loading

0 comments on commit 90412be

Please sign in to comment.