create routes for body parts and muscles
This commit is contained in:
@@ -6,7 +6,7 @@ use utoipa_axum::{router::OpenApiRouter, routes};
|
|||||||
use utoipa_swagger_ui::SwaggerUi;
|
use utoipa_swagger_ui::SwaggerUi;
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
use v1::auth::AUTH_TAG;
|
use v1::{auth::AUTH_TAG, body_parts::BODY_PARTS_TAG, exercises::EXERCISES_TAG};
|
||||||
|
|
||||||
mod v1;
|
mod v1;
|
||||||
mod structs;
|
mod structs;
|
||||||
@@ -27,6 +27,8 @@ pub(crate) use utoipa::ToSchema;
|
|||||||
#[openapi(
|
#[openapi(
|
||||||
tags(
|
tags(
|
||||||
(name = AUTH_TAG, description = "Authentication API endpoints"),
|
(name = AUTH_TAG, description = "Authentication API endpoints"),
|
||||||
|
(name = EXERCISES_TAG, description = "Exercise API endpoints"),
|
||||||
|
(name = BODY_PARTS_TAG, description = "Body part API endpoints"),
|
||||||
// (name = CUSTOMER_TAG, description = "Customer API endpoints"),
|
// (name = CUSTOMER_TAG, description = "Customer API endpoints"),
|
||||||
// (name = ORDER_TAG, description = "Order API endpoints")
|
// (name = ORDER_TAG, description = "Order API endpoints")
|
||||||
),
|
),
|
||||||
@@ -71,8 +73,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
.routes(routes!(health_check))
|
.routes(routes!(health_check))
|
||||||
.routes(routes!(index))
|
.routes(routes!(index))
|
||||||
.with_state(state.clone())
|
.with_state(state.clone())
|
||||||
.nest("/api/v1/auth", v1::auth::router(state.clone()))
|
.nest("/api/v1", v1::router(state.clone()))
|
||||||
.nest("/api/v1/exercises", v1::exercises::router(state.clone()))
|
|
||||||
.split_for_parts();
|
.split_for_parts();
|
||||||
|
|
||||||
let router = router.merge(SwaggerUi::new("/docs").url("/docs/openapi.json", api));
|
let router = router.merge(SwaggerUi::new("/docs").url("/docs/openapi.json", api));
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub mod login;
|
|||||||
|
|
||||||
pub const AUTH_TAG: &str = "auth";
|
pub const AUTH_TAG: &str = "auth";
|
||||||
|
|
||||||
pub fn router(state: AppState) -> OpenApiRouter {
|
pub(super) fn router(state: AppState) -> OpenApiRouter {
|
||||||
OpenApiRouter::new()
|
OpenApiRouter::new()
|
||||||
.routes(routes!(signup::signup))
|
.routes(routes!(signup::signup))
|
||||||
.routes(routes!(login::login))
|
.routes(routes!(login::login))
|
||||||
|
|||||||
34
src/v1/body_parts/create.rs
Normal file
34
src/v1/body_parts/create.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use extractors::users::UserId;
|
||||||
|
use sqlx::query;
|
||||||
|
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ToSchema)]
|
||||||
|
pub struct CreateBodyPartBody {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(post, path = "/create", responses((status = OK, body = String)), tag = super::BODY_PARTS_TAG)]
|
||||||
|
pub async fn create(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
UserId(user_id): UserId,
|
||||||
|
Json(body): Json<CreateBodyPartBody>,
|
||||||
|
) -> Result<String, AppError> {
|
||||||
|
let is_admin = query!("SELECT is_admin FROM users WHERE id = $1", user_id)
|
||||||
|
.fetch_one(&*state.db)
|
||||||
|
.await?
|
||||||
|
.is_admin;
|
||||||
|
|
||||||
|
if !is_admin {
|
||||||
|
return Err(AppError::Error(Errors::Unauthorized));
|
||||||
|
}
|
||||||
|
|
||||||
|
let out = query!(
|
||||||
|
"INSERT INTO body_parts (name) VALUES ($1) RETURNING id",
|
||||||
|
body.name
|
||||||
|
)
|
||||||
|
.fetch_one(&*state.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(out.id.to_string())
|
||||||
|
}
|
||||||
13
src/v1/body_parts/mod.rs
Normal file
13
src/v1/body_parts/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
use crate::AppState;
|
||||||
|
|
||||||
|
pub(super) use super::*;
|
||||||
|
|
||||||
|
pub mod create;
|
||||||
|
|
||||||
|
pub const BODY_PARTS_TAG: &str = "body_parts";
|
||||||
|
|
||||||
|
pub(super) fn router(state: AppState) -> OpenApiRouter {
|
||||||
|
OpenApiRouter::new()
|
||||||
|
.routes(routes!(create::create))
|
||||||
|
.with_state(state)
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::NaiveDateTime;
|
||||||
use extractors::users::UserId;
|
use extractors::users::UserId;
|
||||||
use sqlx::{query, query_as};
|
use sqlx::query;
|
||||||
use structs::exercise_types::ExerciseType;
|
use structs::exercise_types::ExerciseType;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@@ -12,6 +12,9 @@ pub struct CreateExerciseBody {
|
|||||||
// todo: make this an enum
|
// todo: make this an enum
|
||||||
exercise_type: ExerciseType,
|
exercise_type: ExerciseType,
|
||||||
description: String,
|
description: String,
|
||||||
|
body_parts: Vec<String>,
|
||||||
|
primary_muscles: Vec<String>,
|
||||||
|
secondary_muscles: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, sqlx::Type, PartialEq, sqlx::FromRow)]
|
#[derive(Debug, Deserialize, Serialize, Clone, sqlx::Type, PartialEq, sqlx::FromRow)]
|
||||||
@@ -22,7 +25,7 @@ pub struct Exercise {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
pub author_id: Uuid,
|
pub author_id: Uuid,
|
||||||
pub official: bool,
|
pub official: bool,
|
||||||
pub created_at: DateTime<Utc>,
|
pub created_at: NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[utoipa::path(post, path = "/create", responses((status = OK, body = String)), tag = super::EXERCISES_TAG)]
|
#[utoipa::path(post, path = "/create", responses((status = OK, body = String)), tag = super::EXERCISES_TAG)]
|
||||||
@@ -36,24 +39,19 @@ pub async fn create(
|
|||||||
.await?
|
.await?
|
||||||
.is_admin;
|
.is_admin;
|
||||||
|
|
||||||
if !is_admin {
|
query!(
|
||||||
return Err(AppError::Error(Errors::Unauthorized));
|
|
||||||
}
|
|
||||||
// INSERT INTO users (id, created_at, updated_at, role) VALUES ($1, NOW(), NOW(), ($2::text)::user_role) RETURNING id, created_at, updated_at, role as "role:UserRole"
|
|
||||||
//
|
|
||||||
let insert = query_as!(
|
|
||||||
Exercise,
|
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO exercises (name, exercise_type, description, author_id, official)
|
INSERT INTO exercises (name, exercise_type, official, author_id, description)
|
||||||
VALUES ($1, ($2::text)::exercise_type, $3, $4, $5)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
RETURNING id, name, exercise_type, description, author_id, official, created_at
|
|
||||||
"#,
|
"#,
|
||||||
body.name,
|
body.name,
|
||||||
body.exercise_type.to_string(),
|
body.exercise_type as ExerciseType,
|
||||||
body.description,
|
is_admin,
|
||||||
user,
|
user,
|
||||||
false
|
body.description
|
||||||
);
|
)
|
||||||
|
.fetch_one(&*state.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ pub mod create;
|
|||||||
|
|
||||||
pub const EXERCISES_TAG: &str = "exercises";
|
pub const EXERCISES_TAG: &str = "exercises";
|
||||||
|
|
||||||
pub fn router(state: AppState) -> OpenApiRouter {
|
pub(super) fn router(state: AppState) -> OpenApiRouter {
|
||||||
OpenApiRouter::new()
|
OpenApiRouter::new()
|
||||||
.routes(routes!(create::create))
|
.routes(routes!(create::create))
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
pub(super) use utoipa_axum::router::OpenApiRouter;
|
pub(super) use utoipa_axum::router::OpenApiRouter;
|
||||||
pub(super) use utoipa_axum::routes;
|
pub(super) use utoipa_axum::routes;
|
||||||
|
|
||||||
|
use crate::AppState;
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
pub mod body_parts;
|
||||||
pub mod exercises;
|
pub mod exercises;
|
||||||
|
pub mod muscles;
|
||||||
|
|
||||||
|
pub fn router(state: AppState) -> OpenApiRouter {
|
||||||
|
OpenApiRouter::new()
|
||||||
|
.with_state(state.clone())
|
||||||
|
.nest("/auth", auth::router(state.clone()))
|
||||||
|
.nest("/exercises", exercises::router(state.clone()))
|
||||||
|
.nest("/body_parts", body_parts::router(state.clone()))
|
||||||
|
.nest("/muscles", muscles::router(state.clone()))
|
||||||
|
}
|
||||||
|
|||||||
35
src/v1/muscles/create.rs
Normal file
35
src/v1/muscles/create.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use extractors::users::UserId;
|
||||||
|
use sqlx::query;
|
||||||
|
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ToSchema)]
|
||||||
|
pub struct CreateMuscleBody {
|
||||||
|
name: String,
|
||||||
|
body_parts: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(post, path = "/create", responses((status = OK, body = String)), tag = super::MUSCLES_TAG)]
|
||||||
|
pub async fn create(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
UserId(user_id): UserId,
|
||||||
|
Json(body): Json<CreateMuscleBody>,
|
||||||
|
) -> Result<String, AppError> {
|
||||||
|
let is_admin = query!("SELECT is_admin FROM users WHERE id = $1", user_id)
|
||||||
|
.fetch_one(&*state.db)
|
||||||
|
.await?
|
||||||
|
.is_admin;
|
||||||
|
|
||||||
|
if !is_admin {
|
||||||
|
return Err(AppError::Error(Errors::Unauthorized));
|
||||||
|
}
|
||||||
|
|
||||||
|
let out = query!(
|
||||||
|
"INSERT INTO muscles (name) VALUES ($1) RETURNING id",
|
||||||
|
body.name
|
||||||
|
)
|
||||||
|
.fetch_one(&*state.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(out.id.to_string())
|
||||||
|
}
|
||||||
13
src/v1/muscles/mod.rs
Normal file
13
src/v1/muscles/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
use crate::AppState;
|
||||||
|
|
||||||
|
pub(super) use super::*;
|
||||||
|
|
||||||
|
pub mod create;
|
||||||
|
|
||||||
|
pub const MUSCLES_TAG: &str = "muscles";
|
||||||
|
|
||||||
|
pub(super) fn router(state: AppState) -> OpenApiRouter {
|
||||||
|
OpenApiRouter::new()
|
||||||
|
.routes(routes!(create::create))
|
||||||
|
.with_state(state)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user