use axum::{extract::Path, http::StatusCode, response::Redirect, Form}; use axum_login::AuthSession; use crate::{ handler::internal_error, models::{ documents::{self, NewDocument}, users::User, }, permissions::{self, query::Permission}, prelude::*, }; pub async fn documents_page( State(ctx): State, auth_session: AuthSession, ) -> Result { if let Some(user) = auth_session.user { render_documents_page(ctx, user).await } else { Ok(Redirect::to("/login").into_response()) } } async fn render_documents_page(ctx: Context, user: User) -> Result { let mut db = ctx.db_pool.get().map_err(internal_error)?; let documents = permissions::query::accessible_documents(&mut db, &user.id).map_err(internal_error)?; let projects = permissions::query::accessible_projects(&mut db, &user.id).map_err(internal_error)?; let values = context! { user => user, documents => documents, projects => projects, }; Ok(ctx.render_resp("documents/list_documents.html", values)) } pub async fn create_document_page( State(ctx): State, auth_session: AuthSession, ) -> Result { let user = match auth_session.user { Some(user) => user, None => return Ok(Redirect::to("/login").into_response()), }; let mut db = ctx.db_pool.get().map_err(internal_error)?; let projects = permissions::query::accessible_projects(&mut db, &user.id).map_err(internal_error)?; let values = context! { user => user, projects => projects, }; Ok(ctx.render_resp("documents/create_document.html", values)) } #[derive(Debug, Deserialize)] pub struct CreateDocumentSubmission { pub project_id: Uuid, pub title: String, } pub async fn create_document_submit( State(ctx): State, auth_session: AuthSession, form: Form, ) -> Result { let user = match auth_session.user { Some(user) => user, None => return Ok(Redirect::to("/login").into_response()), }; let mut db = ctx.db_pool.get().map_err(internal_error)?; let project_allowed = permissions::query::check_user_project( &mut db, &user.id, &form.project_id.to_string(), Permission::Write, ) .map_err(internal_error)?; if !project_allowed { return Err((StatusCode::FORBIDDEN, "permission denied".to_owned())); } let new_document = NewDocument::new( &user.id, &form.project_id.to_string(), form.title.to_owned(), "".to_owned(), ); let document = documents::query::create(&mut db, new_document).map_err(internal_error)?; info!(?document, "document created"); Ok(Redirect::to("/documents").into_response()) } pub async fn edit_document_page( State(ctx): State, auth_session: AuthSession, Path((id,)): Path<(Uuid,)>, ) -> Result { let user = match auth_session.user { Some(user) => user, None => return Ok(Redirect::to("/login").into_response()), }; let mut db = ctx.db_pool.get().map_err(internal_error)?; let document_allowed = permissions::query::check_user_document( &mut db, &user.id, &id.to_string(), Permission::Write, ) .map_err(internal_error)?; if !document_allowed { return Err((StatusCode::FORBIDDEN, "permission denied".to_owned())); } let document = documents::query::by_id(&mut db, &id.to_string()).map_err(internal_error)?; let projects = permissions::query::accessible_projects(&mut db, &user.id).map_err(internal_error)?; let values = context! { user => user, document => document, projects => projects, }; Ok(ctx.render_resp("documents/edit_document.html", values)) } #[derive(Debug, Deserialize)] pub struct EditDocumentSubmission { pub title: String, pub content: String, } pub async fn edit_document_submit( State(ctx): State, auth_session: AuthSession, Path((document_id,)): Path<(Uuid,)>, form: Form, ) -> Result { let user = match auth_session.user { Some(user) => user, None => return Ok(Redirect::to("/login").into_response()), }; let mut db = ctx.db_pool.get().map_err(internal_error)?; let document_allowed = permissions::query::check_user_document( &mut db, &user.id, &document_id.to_string(), Permission::Write, ) .map_err(internal_error)?; if !document_allowed { return Err((StatusCode::FORBIDDEN, "permission denied".to_owned())); } documents::query::update( &mut db, &document_id.to_string(), form.title.to_owned(), form.content.to_owned(), ) .map_err(internal_error)?; Ok(Redirect::to("/documents").into_response()) }