use axum::{ response::IntoResponse, extract::{Json, Path}, Extension, }; use axum_extra::extract::CookieJar; use tetratto_shared::unix_epoch_timestamp; use crate::{ get_user_from_token, routes::api::v1::{CreateNote, RenderMarkdown, UpdateNoteContent, UpdateNoteTitle}, State, }; use tetratto_core::model::{ journals::{JournalPrivacyPermission, Note}, oauth, permissions::FinePermission, uploads::CustomEmoji, ApiReturn, Error, }; pub async fn get_request( jar: CookieJar, Path(id): Path, Extension(data): Extension, ) -> impl IntoResponse { let data = &(data.read().await).0; let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReadJournals) { Some(ua) => ua, None => return Json(Error::NotAllowed.into()), }; let note = match data.get_note_by_id(id).await { Ok(x) => x, Err(e) => return Json(e.into()), }; let journal = match data.get_journal_by_id(note.id).await { Ok(x) => x, Err(e) => return Json(e.into()), }; if journal.privacy == JournalPrivacyPermission::Private && user.id != journal.owner && !user.permissions.contains(FinePermission::MANAGE_JOURNALS) { return Json(Error::NotAllowed.into()); } Json(ApiReturn { ok: true, message: "Success".to_string(), payload: Some(note), }) } pub async fn list_request( jar: CookieJar, Path(id): Path, Extension(data): Extension, ) -> impl IntoResponse { let data = &(data.read().await).0; let user = match get_user_from_token!(jar, data, oauth::AppScope::UserReadJournals) { Some(ua) => ua, None => return Json(Error::NotAllowed.into()), }; let journal = match data.get_journal_by_id(id).await { Ok(x) => x, Err(e) => return Json(e.into()), }; if journal.privacy == JournalPrivacyPermission::Private && user.id != journal.owner && !user.permissions.contains(FinePermission::MANAGE_JOURNALS) { return Json(Error::NotAllowed.into()); } match data.get_notes_by_journal(id).await { Ok(x) => Json(ApiReturn { ok: true, message: "Success".to_string(), payload: Some(x), }), Err(e) => Json(e.into()), } } pub async fn create_request( jar: CookieJar, Extension(data): Extension, Json(props): Json, ) -> impl IntoResponse { let data = &(data.read().await).0; let user = match get_user_from_token!(jar, data, oauth::AppScope::UserCreateNotes) { Some(ua) => ua, None => return Json(Error::NotAllowed.into()), }; match data .create_note(Note::new( user.id, props.title, match props.journal.parse() { Ok(x) => x, Err(_) => return Json(Error::Unknown.into()), }, props.content, )) .await { Ok(x) => Json(ApiReturn { ok: true, message: "Note created".to_string(), payload: Some(x.id.to_string()), }), Err(e) => Json(e.into()), } } pub async fn update_title_request( jar: CookieJar, Path(id): Path, Extension(data): Extension, Json(mut props): Json, ) -> impl IntoResponse { let data = &(data.read().await).0; let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageNotes) { Some(ua) => ua, None => return Json(Error::NotAllowed.into()), }; let note = match data.get_note_by_id(id).await { Ok(n) => n, Err(e) => return Json(e.into()), }; props.title = props.title.replace(" ", "_"); // make sure this title isn't already in use if data .get_note_by_journal_title(note.journal, &props.title) .await .is_ok() { return Json(Error::TitleInUse.into()); } // ... match data.update_note_title(id, &user, &props.title).await { Ok(_) => Json(ApiReturn { ok: true, message: "Note updated".to_string(), payload: (), }), Err(e) => Json(e.into()), } } pub async fn update_content_request( jar: CookieJar, Path(id): Path, Extension(data): Extension, Json(props): Json, ) -> impl IntoResponse { let data = &(data.read().await).0; let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageNotes) { Some(ua) => ua, None => return Json(Error::NotAllowed.into()), }; match data.update_note_content(id, &user, &props.content).await { Ok(_) => { if let Err(e) = data .update_note_edited(id, unix_epoch_timestamp() as i64) .await { return Json(e.into()); } Json(ApiReturn { ok: true, message: "Note updated".to_string(), payload: (), }) } Err(e) => Json(e.into()), } } pub async fn delete_request( jar: CookieJar, Path(id): Path, Extension(data): Extension, ) -> impl IntoResponse { let data = &(data.read().await).0; let user = match get_user_from_token!(jar, data, oauth::AppScope::UserManageNotes) { Some(ua) => ua, None => return Json(Error::NotAllowed.into()), }; match data.delete_note(id, &user).await { Ok(_) => Json(ApiReturn { ok: true, message: "Note deleted".to_string(), payload: (), }), Err(e) => Json(e.into()), } } pub async fn render_markdown_request(Json(req): Json) -> impl IntoResponse { tetratto_shared::markdown::render_markdown(&CustomEmoji::replace(&req.content)) .replace("\\@", "@") .replace("%5C@", "@") }