Skip to content

Commit

Permalink
feat: bootstrap evaluate routes
Browse files Browse the repository at this point in the history
  • Loading branch information
rootCircle committed Oct 21, 2024
1 parent e45a38d commit 7a367b0
Show file tree
Hide file tree
Showing 13 changed files with 336 additions and 20 deletions.
11 changes: 11 additions & 0 deletions cpast_api/DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Development Guide

### Adding a New Route

Here’s how you can add routes:

1. **Create a Route**: Add a new route in the `src/routes` folder.
2. **Update `src/startup.rs`**: Import the new route and include it under the `/api/v1` path in the `src/startup.rs` file.
3. **Document with `utoipa`**: To ensure API documentation is generated, annotate the exposed service function with the `#[utoipa]` attribute. Also, make sure the path is registered in `src/routes/api/v1/mod.rs` so it appears in the API documentation.
4. **Handle Migrations (if necessary)**: If the route involves schema or database changes, create a migration. Use `make migrate-create <migration_info>` to generate a new migration file and then modify it as needed. Run the migration using `make migrate-run`.
5. **Write Tests**: It’s good practice to add tests for your route. Create a new test file in the `tests/api` folder, and refer to existing tests for guidance.
90 changes: 88 additions & 2 deletions cpast_api/src/routes/api/v1/evaluate/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,89 @@
pub(crate) mod with_code;
use actix_web::{http::StatusCode, ResponseError};
use serde::Serialize;
use utoipa::{OpenApi, ToSchema};

pub(crate) mod with_code_and_clex;
pub(crate) mod with_code_and_constraint;
pub(crate) mod with_code_and_platform;
pub(crate) mod with_platform;
pub(crate) mod with_shared_code;
pub(crate) mod with_shared_id;

#[derive(OpenApi)]
#[openapi(paths(
crate::routes::api::v1::evaluate::with_code_and_constraint::post_with_code_and_constraint,
crate::routes::api::v1::evaluate::with_code_and_clex::post_with_code_and_clex,
crate::routes::api::v1::evaluate::with_code_and_platform::post_with_code_and_platform,
crate::routes::api::v1::evaluate::with_shared_id::post_with_shared_id,
crate::routes::api::v1::evaluate::with_platform::post_with_platform,
))]
pub(crate) struct EvaluateCodeApiv1;

#[derive(Serialize, ToSchema)]
struct EvaluateCodeInputDiff {
#[schema(example = "Hello, world!")]
expected_output: String,

#[schema(example = "Hello, worldd!")]
actual_output: String,
}

#[derive(Serialize, ToSchema)]
struct EvaluateCodeResponse {
#[schema(example = false)]
has_output_matched: bool,

#[schema(example = json!(Vec::from([EvaluateCodeInputDiff {
expected_output: "Hello, world!".to_string(),
actual_output: "Hello, worldd!".to_string(),
}])))]
input_diffs: Vec<EvaluateCodeInputDiff>,
}

#[derive(thiserror::Error)]
pub enum EvaluateAPIError {
#[error("{0}")]
InvalidClex(String),

#[error("{0}")]
DirtyLanguageInDatabase(String),

#[error("{0}")]
ShareIdNotFound(String),

#[error("{0}")]
InvalidShareId(String),

#[error(transparent)]
UnexpectedError(#[from] anyhow::Error),
}

impl std::fmt::Debug for EvaluateAPIError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
error_chain_fmt(self, f)
}
}

impl ResponseError for EvaluateAPIError {
fn status_code(&self) -> StatusCode {
match self {
EvaluateAPIError::InvalidClex(_) => StatusCode::BAD_REQUEST,
EvaluateAPIError::InvalidShareId(_) => StatusCode::BAD_REQUEST,
EvaluateAPIError::DirtyLanguageInDatabase(_) => StatusCode::INTERNAL_SERVER_ERROR,
EvaluateAPIError::ShareIdNotFound(_) => StatusCode::NOT_FOUND,
EvaluateAPIError::UnexpectedError(_) => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}

pub fn error_chain_fmt(
e: &impl std::error::Error,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
writeln!(f, "{}\n", e)?;
let mut current = e.source();
while let Some(cause) = current {
writeln!(f, "Caused by:\n\t{}", cause)?;
current = cause.source();
}
Ok(())
}
1 change: 0 additions & 1 deletion cpast_api/src/routes/api/v1/evaluate/with_code.rs

This file was deleted.

42 changes: 42 additions & 0 deletions cpast_api/src/routes/api/v1/evaluate/with_code_and_clex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use actix_web::post;
use actix_web::web::Json;
use actix_web::{web, HttpResponse};
use ccode_runner::lang_runner::runner::LanguageName;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use utoipa::ToSchema;

use super::{EvaluateAPIError, EvaluateCodeResponse};

#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
struct EvaluateCodeWithClexRequest {
#[schema(example = "print('Hello, world!')")]
correct_code: String,

#[schema(example = "python")]
correct_code_language: LanguageName,

#[schema(example = "print('Hello, worldd!')")]
test_code: String,

#[schema(example = "python")]
test_code_language: LanguageName,

#[schema(example = "N[1,50] S[1, @CH_UPPER@]")]
clex: String,
}

#[utoipa::path(
responses(
(status = 200, description = "Share_id", body = EvaluateCodeResponse),
(status = 400, description = "Invalid clex", body = String),
(status = 500, description = "Internal server error", body = String),
)
)]
#[post("/with_code_and_clex")]
pub async fn post_with_code_and_clex(
pool: web::Data<PgPool>,

Check failure on line 38 in cpast_api/src/routes/api/v1/evaluate/with_code_and_clex.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `pool`

Check failure on line 38 in cpast_api/src/routes/api/v1/evaluate/with_code_and_clex.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `pool`

Check failure on line 38 in cpast_api/src/routes/api/v1/evaluate/with_code_and_clex.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `pool`
code_request: Json<EvaluateCodeWithClexRequest>,

Check failure on line 39 in cpast_api/src/routes/api/v1/evaluate/with_code_and_clex.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `code_request`

Check failure on line 39 in cpast_api/src/routes/api/v1/evaluate/with_code_and_clex.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `code_request`

Check failure on line 39 in cpast_api/src/routes/api/v1/evaluate/with_code_and_clex.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `code_request`
) -> Result<HttpResponse, EvaluateAPIError> {
todo!("Implement post_with_code_and_clex");
}
48 changes: 48 additions & 0 deletions cpast_api/src/routes/api/v1/evaluate/with_code_and_constraint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use actix_web::post;
use actix_web::web::Json;
use actix_web::{web, HttpResponse};
use ccode_runner::lang_runner::runner::LanguageName;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use utoipa::ToSchema;

use super::{EvaluateAPIError, EvaluateCodeResponse};

#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
struct EvaluateCodeWithConstraintRequest {
#[schema(example = "print('Hello,', input(), '!')")]
correct_code: String,

#[schema(example = "python")]
correct_code_language: LanguageName,

#[schema(example = "print('Hello, worldd!')")]
test_code: String,

#[schema(example = "python")]
test_code_language: LanguageName,

#[schema(example = "Print hello followed by inputted name")]
problem_description: String,

#[schema(example = "One string input")]
input_format: String,

#[schema(example = "length of name is less than 50")]
constraints: String,
}

#[utoipa::path(
responses(
(status = 200, description = "Share_id", body = EvaluateCodeResponse),
(status = 400, description = "Invalid clex", body = String),
(status = 500, description = "Internal server error", body = String),
)
)]
#[post("/with_code_and_constraint")]
pub async fn post_with_code_and_constraint(
pool: web::Data<PgPool>,

Check failure on line 44 in cpast_api/src/routes/api/v1/evaluate/with_code_and_constraint.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `pool`

Check failure on line 44 in cpast_api/src/routes/api/v1/evaluate/with_code_and_constraint.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `pool`

Check failure on line 44 in cpast_api/src/routes/api/v1/evaluate/with_code_and_constraint.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `pool`
code_request: Json<EvaluateCodeWithConstraintRequest>,

Check failure on line 45 in cpast_api/src/routes/api/v1/evaluate/with_code_and_constraint.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `code_request`

Check failure on line 45 in cpast_api/src/routes/api/v1/evaluate/with_code_and_constraint.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `code_request`

Check failure on line 45 in cpast_api/src/routes/api/v1/evaluate/with_code_and_constraint.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `code_request`
) -> Result<HttpResponse, EvaluateAPIError> {
todo!("Implement post_with_code_and_clex");
}
43 changes: 43 additions & 0 deletions cpast_api/src/routes/api/v1/evaluate/with_code_and_platform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use actix_web::post;
use actix_web::web::Json;
use actix_web::{web, HttpResponse};
use ccode_runner::lang_runner::runner::LanguageName;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use utoipa::ToSchema;

use super::{EvaluateAPIError, EvaluateCodeResponse};

#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
struct EvaluateCodeWithPlatformRequest {
#[schema(example = "print('Hello,', input(), '!')")]
correct_code: String,

#[schema(example = "python")]
correct_code_language: LanguageName,

#[schema(example = "print('Hello, worldd!')")]
test_code: String,

#[schema(example = "python")]
test_code_language: LanguageName,

// TODO: Use custom in house URL type instead of String
#[schema(example = "https://codeforces.com/problemset/problem/4/A")]
problem_url: String,
}

#[utoipa::path(
responses(
(status = 200, description = "Share_id", body = EvaluateCodeResponse),
(status = 400, description = "Invalid clex", body = String),
(status = 500, description = "Internal server error", body = String),
)
)]
#[post("/with_code_and_platform")]
pub async fn post_with_code_and_platform(
pool: web::Data<PgPool>,

Check failure on line 39 in cpast_api/src/routes/api/v1/evaluate/with_code_and_platform.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `pool`

Check failure on line 39 in cpast_api/src/routes/api/v1/evaluate/with_code_and_platform.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `pool`

Check failure on line 39 in cpast_api/src/routes/api/v1/evaluate/with_code_and_platform.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `pool`
code_request: Json<EvaluateCodeWithPlatformRequest>,

Check failure on line 40 in cpast_api/src/routes/api/v1/evaluate/with_code_and_platform.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `code_request`

Check failure on line 40 in cpast_api/src/routes/api/v1/evaluate/with_code_and_platform.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `code_request`

Check failure on line 40 in cpast_api/src/routes/api/v1/evaluate/with_code_and_platform.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `code_request`
) -> Result<HttpResponse, EvaluateAPIError> {
todo!("Implement post_with_code_and_platform");
}
36 changes: 36 additions & 0 deletions cpast_api/src/routes/api/v1/evaluate/with_platform.rs
Original file line number Diff line number Diff line change
@@ -1 +1,37 @@
use actix_web::post;
use actix_web::web::Json;
use actix_web::{web, HttpResponse};
use ccode_runner::lang_runner::runner::LanguageName;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use utoipa::ToSchema;

use super::{EvaluateAPIError, EvaluateCodeResponse};

#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
struct EvaluateCodeWithOnlyPlatformRequest {
#[schema(example = "print('Hello, worldd!')")]
test_code: String,

#[schema(example = "python")]
test_code_language: LanguageName,

// TODO: Use custom in house URL type instead of String
#[schema(example = "https://codeforces.com/problemset/problem/4/A")]
problem_url: String,
}

#[utoipa::path(
responses(
(status = 200, description = "Share_id", body = EvaluateCodeResponse),
(status = 400, description = "Invalid clex", body = String),
(status = 500, description = "Internal server error", body = String),
)
)]
#[post("/with_platform")]
pub async fn post_with_platform(
pool: web::Data<PgPool>,

Check failure on line 33 in cpast_api/src/routes/api/v1/evaluate/with_platform.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `pool`

Check failure on line 33 in cpast_api/src/routes/api/v1/evaluate/with_platform.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `pool`

Check failure on line 33 in cpast_api/src/routes/api/v1/evaluate/with_platform.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `pool`
code_request: Json<EvaluateCodeWithOnlyPlatformRequest>,

Check failure on line 34 in cpast_api/src/routes/api/v1/evaluate/with_platform.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `code_request`

Check failure on line 34 in cpast_api/src/routes/api/v1/evaluate/with_platform.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `code_request`

Check failure on line 34 in cpast_api/src/routes/api/v1/evaluate/with_platform.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `code_request`
) -> Result<HttpResponse, EvaluateAPIError> {
todo!("Implement post_with_code_and_platform");
}
1 change: 0 additions & 1 deletion cpast_api/src/routes/api/v1/evaluate/with_shared_code.rs

This file was deleted.

36 changes: 36 additions & 0 deletions cpast_api/src/routes/api/v1/evaluate/with_shared_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use actix_web::post;
use actix_web::web::Json;
use actix_web::{web, HttpResponse};
use ccode_runner::lang_runner::runner::LanguageName;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use utoipa::ToSchema;

use super::{EvaluateAPIError, EvaluateCodeResponse};

#[derive(Serialize, Deserialize, ToSchema, Clone, Debug)]
struct EvaluateCodeWithOnlySharedIDRequest {
#[schema(example = "print('Hello, worldd!')")]
test_code: String,

#[schema(example = "python")]
test_code_language: LanguageName,

#[schema(example = "1e23fdh-sdf23-23sdf")]
share_id: String,
}

#[utoipa::path(
responses(
(status = 200, description = "Share_id", body = EvaluateCodeResponse),
(status = 400, description = "Invalid clex", body = String),
(status = 500, description = "Internal server error", body = String),
)
)]
#[post("/with_shared_id")]
pub async fn post_with_shared_id(
pool: web::Data<PgPool>,

Check failure on line 32 in cpast_api/src/routes/api/v1/evaluate/with_shared_id.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `pool`

Check failure on line 32 in cpast_api/src/routes/api/v1/evaluate/with_shared_id.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `pool`

Check failure on line 32 in cpast_api/src/routes/api/v1/evaluate/with_shared_id.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `pool`
code_request: Json<EvaluateCodeWithOnlySharedIDRequest>,

Check failure on line 33 in cpast_api/src/routes/api/v1/evaluate/with_shared_id.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused variable: `code_request`

Check failure on line 33 in cpast_api/src/routes/api/v1/evaluate/with_shared_id.rs

View workflow job for this annotation

GitHub Actions / Code coverage

unused variable: `code_request`

Check failure on line 33 in cpast_api/src/routes/api/v1/evaluate/with_shared_id.rs

View workflow job for this annotation

GitHub Actions / Test

unused variable: `code_request`
) -> Result<HttpResponse, EvaluateAPIError> {
todo!("Implement post_with_code_and_platform");
}
9 changes: 6 additions & 3 deletions cpast_api/src/routes/api/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ pub(crate) mod share;
#[derive(OpenApi)]
#[openapi(paths(
crate::routes::api::v1::share::post::post_share_code,
crate::routes::api::v1::share::get::get_share_code
))]
pub(crate) struct EvaluateApiv1;
crate::routes::api::v1::share::get::get_share_code,
),
nest(
(path = "/evaluate", api = crate::routes::api::v1::evaluate::EvaluateCodeApiv1),
))]
pub(crate) struct Apiv1;
8 changes: 4 additions & 4 deletions cpast_api/src/routes/api/v1/share/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use utoipa::ToSchema;
use uuid::{Uuid, Version};

#[derive(Serialize, ToSchema)]
struct CodeDetailResponse {
struct ShareGetResponse {
#[schema(example = "print('Hello, world!')")]
code: String,

Expand All @@ -21,7 +21,7 @@ struct CodeDetailResponse {

#[utoipa::path(
responses(
(status = 200, description = "Code details", body = CodeDetailResponse),
(status = 200, description = "Code details", body = ShareGetResponse),
(status = 400, description = "Invalid input", body = String),
(status = 404, description = "Share ID not found", body = String),
(status = 500, description = "Internal server error", body = String),
Expand Down Expand Up @@ -50,7 +50,7 @@ pub async fn get_share_code(
pub(crate) async fn get_code_from_share_id(
pool: &PgPool,
share_id: &str,
) -> Result<CodeDetailResponse, anyhow::Error> {
) -> Result<ShareGetResponse, anyhow::Error> {
let query = sqlx::query!(
r#"
SELECT code, code_language AS "language", clex
Expand All @@ -65,7 +65,7 @@ pub(crate) async fn get_code_from_share_id(
.await
.context("Failed to fetch code details")?;

Ok(CodeDetailResponse {
Ok(ShareGetResponse {
code: code_details.code,
language: code_details
.language
Expand Down
Loading

0 comments on commit 7a367b0

Please sign in to comment.