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;
|
||||
|
||||
// tags
|
||||
use v1::auth::AUTH_TAG;
|
||||
use v1::{auth::AUTH_TAG, body_parts::BODY_PARTS_TAG, exercises::EXERCISES_TAG};
|
||||
|
||||
mod v1;
|
||||
mod structs;
|
||||
@@ -27,6 +27,8 @@ pub(crate) use utoipa::ToSchema;
|
||||
#[openapi(
|
||||
tags(
|
||||
(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 = ORDER_TAG, description = "Order API endpoints")
|
||||
),
|
||||
@@ -71,8 +73,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
.routes(routes!(health_check))
|
||||
.routes(routes!(index))
|
||||
.with_state(state.clone())
|
||||
.nest("/api/v1/auth", v1::auth::router(state.clone()))
|
||||
.nest("/api/v1/exercises", v1::exercises::router(state.clone()))
|
||||
.nest("/api/v1", v1::router(state.clone()))
|
||||
.split_for_parts();
|
||||
|
||||
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 fn router(state: AppState) -> OpenApiRouter {
|
||||
pub(super) fn router(state: AppState) -> OpenApiRouter {
|
||||
OpenApiRouter::new()
|
||||
.routes(routes!(signup::signup))
|
||||
.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 sqlx::{query, query_as};
|
||||
use sqlx::query;
|
||||
use structs::exercise_types::ExerciseType;
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -12,6 +12,9 @@ pub struct CreateExerciseBody {
|
||||
// todo: make this an enum
|
||||
exercise_type: ExerciseType,
|
||||
description: String,
|
||||
body_parts: Vec<String>,
|
||||
primary_muscles: Vec<String>,
|
||||
secondary_muscles: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, sqlx::Type, PartialEq, sqlx::FromRow)]
|
||||
@@ -22,7 +25,7 @@ pub struct Exercise {
|
||||
pub description: String,
|
||||
pub author_id: Uuid,
|
||||
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)]
|
||||
@@ -36,24 +39,19 @@ pub async fn create(
|
||||
.await?
|
||||
.is_admin;
|
||||
|
||||
if !is_admin {
|
||||
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,
|
||||
query!(
|
||||
r#"
|
||||
INSERT INTO exercises (name, exercise_type, description, author_id, official)
|
||||
VALUES ($1, ($2::text)::exercise_type, $3, $4, $5)
|
||||
RETURNING id, name, exercise_type, description, author_id, official, created_at
|
||||
INSERT INTO exercises (name, exercise_type, official, author_id, description)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
"#,
|
||||
body.name,
|
||||
body.exercise_type.to_string(),
|
||||
body.description,
|
||||
body.exercise_type as ExerciseType,
|
||||
is_admin,
|
||||
user,
|
||||
false
|
||||
);
|
||||
body.description
|
||||
)
|
||||
.fetch_one(&*state.db)
|
||||
.await?;
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ pub mod create;
|
||||
|
||||
pub const EXERCISES_TAG: &str = "exercises";
|
||||
|
||||
pub fn router(state: AppState) -> OpenApiRouter {
|
||||
pub(super) fn router(state: AppState) -> OpenApiRouter {
|
||||
OpenApiRouter::new()
|
||||
.routes(routes!(create::create))
|
||||
.with_state(state)
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
pub(super) use utoipa_axum::router::OpenApiRouter;
|
||||
pub(super) use utoipa_axum::routes;
|
||||
|
||||
use crate::AppState;
|
||||
|
||||
pub mod auth;
|
||||
pub mod body_parts;
|
||||
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