diff --git a/client/src/client.rs b/client/src/client.rs index 5031f4d..0e587c1 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -11,8 +11,9 @@ use std::{ time::Duration, }; -use clusterizer_api::client::ApiClient; +use clusterizer_api::{client::ApiClient, result::ApiError}; use clusterizer_common::{ + errors::SubmitResultError, records::{ Platform, PlatformFilter, Project, ProjectFilter, ProjectVersion, ProjectVersionFilter, Task, @@ -223,7 +224,10 @@ impl ClusterizerClient { exit_code: output.status.code(), }; - self.client.submit_result(task_id, &request).await?; + match self.client.submit_result(task_id, &request).await { + Err(ApiError::Specific(SubmitResultError::AssignmentExpired)) => {} + result => result?, + }; Ok(Return::SubmitResult) } diff --git a/common/src/errors/submit_result_error.rs b/common/src/errors/submit_result_error.rs index 8e6992c..b8ec6eb 100644 --- a/common/src/errors/submit_result_error.rs +++ b/common/src/errors/submit_result_error.rs @@ -7,4 +7,8 @@ pub enum SubmitResultError { InvalidTask, #[error("already exists")] AlreadyExists, + #[error("assignment canceled")] + AssignmentCanceled, + #[error("assignment expired")] + AssignmentExpired, } diff --git a/common/src/types/assignment_state.rs b/common/src/types/assignment_state.rs index 9cbe8ec..d5336bd 100644 --- a/common/src/types/assignment_state.rs +++ b/common/src/types/assignment_state.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Clone, Hash, Debug, Serialize, Deserialize)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[cfg_attr( feature = "sqlx", diff --git a/server/.sqlx/query-1260e6fd3c1f30f651d1f86bf86af3351a6629a942b732ccf6740b2e683eedae.json b/server/.sqlx/query-1260e6fd3c1f30f651d1f86bf86af3351a6629a942b732ccf6740b2e683eedae.json new file mode 100644 index 0000000..4e370e3 --- /dev/null +++ b/server/.sqlx/query-1260e6fd3c1f30f651d1f86bf86af3351a6629a942b732ccf6740b2e683eedae.json @@ -0,0 +1,68 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n *\n FROM\n assignments\n WHERE\n task_id = $1\n AND user_id = $2\n FOR UPDATE\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 2, + "name": "deadline_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 3, + "name": "task_id", + "type_info": "Int8" + }, + { + "ordinal": 4, + "name": "user_id", + "type_info": "Int8" + }, + { + "ordinal": 5, + "name": "state", + "type_info": { + "Custom": { + "name": "assignment_state", + "kind": { + "Enum": [ + "init", + "canceled", + "expired", + "submitted", + "valid", + "invalid", + "inconclusive" + ] + } + } + } + } + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false + ] + }, + "hash": "1260e6fd3c1f30f651d1f86bf86af3351a6629a942b732ccf6740b2e683eedae" +} diff --git a/server/.sqlx/query-fb96b317421697e972b3098b2ecc82113138a82a0f1c4c08dbb7f827e5150b97.json b/server/.sqlx/query-fb96b317421697e972b3098b2ecc82113138a82a0f1c4c08dbb7f827e5150b97.json deleted file mode 100644 index ac51bb7..0000000 --- a/server/.sqlx/query-fb96b317421697e972b3098b2ecc82113138a82a0f1c4c08dbb7f827e5150b97.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n id \"id: Id\"\n FROM\n assignments\n WHERE\n task_id = $1\n AND user_id = $2\n AND state != 'canceled'\n FOR UPDATE\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id: Id", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - }, - "nullable": [ - false - ] - }, - "hash": "fb96b317421697e972b3098b2ecc82113138a82a0f1c4c08dbb7f827e5150b97" -} diff --git a/server/src/routes/submit_result.rs b/server/src/routes/submit_result.rs index ebb1ef5..c628f90 100644 --- a/server/src/routes/submit_result.rs +++ b/server/src/routes/submit_result.rs @@ -11,7 +11,7 @@ use clusterizer_common::{ use crate::{ auth::Auth, - result::{AppResult, ResultExt}, + result::{AppError, AppResult, ResultExt}, state::AppState, util, }; @@ -24,16 +24,16 @@ pub async fn submit_result( ) -> AppResult<(), SubmitResultError> { let mut tx = state.pool.begin().await?; - let assignment_id = sqlx::query_scalar_unchecked!( + let assignment = sqlx::query_as_unchecked!( + Assignment, r#" SELECT - id "id: Id" + * FROM assignments WHERE task_id = $1 AND user_id = $2 - AND state != 'canceled' FOR UPDATE "#, task_id, @@ -43,6 +43,14 @@ pub async fn submit_result( .await .map_not_found(SubmitResultError::InvalidTask)?; + if assignment.state == AssignmentState::Canceled { + Err(AppError::Specific(SubmitResultError::AssignmentCanceled))?; + } + + if assignment.state == AssignmentState::Expired { + Err(AppError::Specific(SubmitResultError::AssignmentExpired))?; + } + sqlx::query_unchecked!( r#" INSERT INTO results ( @@ -57,7 +65,7 @@ pub async fn submit_result( $4 ) "#, - assignment_id, + assignment.id, request.stdout, request.stderr, request.exit_code, @@ -66,7 +74,7 @@ pub async fn submit_result( .await .map_unique_violation(SubmitResultError::AlreadyExists)?; - util::set_assignment_state(&[assignment_id], AssignmentState::Submitted) + util::set_assignment_state(&[assignment.id], AssignmentState::Submitted) .execute(&mut *tx) .await?;