use axum::{ extract::{Path, State}, http::StatusCode, Json, }; use axum_extra::routing::Resource; use serde::{Deserialize, Serialize}; use sqlx::PgPool; use time::OffsetDateTime; use uuid::Uuid; use crate::{auth::AccessClaims, state::AppState}; use super::error::Error; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Task { pub id: Uuid, pub user_id: Option, pub title: String, pub description: Option, pub remote: bool, pub location: Option, pub start_at: Option, pub end_at: Option, pub created_at: OffsetDateTime, pub updated_at: OffsetDateTime, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CreateTaskSchema { pub user_id: Uuid, pub title: String, pub description: Option, pub remote: bool, pub location: Option, pub start_at: Option, pub end_at: Option, } pub fn router() -> Resource { Resource::named("tasks") .create(create) .show(show) .destroy(destroy) } pub async fn create( State(pool): State, _: AccessClaims, Json(CreateTaskSchema { user_id, title, description, remote, location, start_at, end_at, }): Json, ) -> Result<(StatusCode, Json), Error> { let task = sqlx::query_as!(Task, "INSERT INTO task (user_id, title, description, remote, location, start_at, end_at) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *", user_id, title, description, remote, location, start_at, end_at, ) .fetch_one(&pool) .await?; Ok((StatusCode::CREATED, Json(task))) } pub async fn show( State(pool): State, Path(uuid): Path, _: AccessClaims, ) -> Result, Error> { sqlx::query_as!(Task, "SELECT * FROM task WHERE id = $1 LIMIT 1", uuid) .fetch_optional(&pool) .await? .ok_or_else(|| Error::TaskNotFound) .map(Json) } pub async fn destroy( State(pool): State, Path(uuid): Path, AccessClaims { sub, .. }: AccessClaims, ) -> Result, Error> { sqlx::query_as!( Task, "SELECT * FROM task WHERE id = $1 AND user_id = $2 LIMIT 1", uuid, sub ) .fetch_optional(&pool) .await? .ok_or_else(|| Error::TaskNotFound) .map(Json) }