use log::warn; use rocket::{ get, http::CookieJar, patch, post, serde::json::{json, Json}, State, }; use serenity::{client::Context, model::id::UserId}; use sqlx::{MySql, Pool}; use crate::web::{ check_subscription, guards::transaction::Transaction, routes::{ dashboard::{ api::user::models::{create_reminder, Reminder}, PatchReminder, MIN_INTERVAL, }, JsonResult, }, Database, }; #[post("/api/user/reminders", data = "")] pub async fn create_user_reminder( reminder: Json, cookies: &CookieJar<'_>, ctx: &State, mut transaction: Transaction<'_>, ) -> JsonResult { let user_id = cookies.get_private("userid").map(|c| c.value().parse::().ok()).flatten().unwrap(); match create_reminder( ctx.inner(), &mut transaction, UserId::new(user_id), reminder.into_inner(), ) .await { Ok(r) => match transaction.commit().await { Ok(_) => Ok(r), Err(e) => { warn!("Couldn't commit transaction: {:?}", e); json_err!("Couldn't commit transaction.") } }, Err(e) => Err(e), } } #[get("/api/user/reminders")] pub async fn get_reminders( cookies: &CookieJar<'_>, ctx: &State, pool: &State>, ) -> JsonResult { let user_id = cookies.get_private("userid").map(|c| c.value().parse::().ok()).flatten().unwrap(); let channel = UserId::new(user_id).create_dm_channel(ctx.inner()).await; match channel { Ok(channel) => sqlx::query_as_unchecked!( Reminder, " SELECT reminders.attachment, reminders.attachment_name, reminders.content, reminders.embed_author, reminders.embed_author_url, reminders.embed_color, reminders.embed_description, reminders.embed_footer, reminders.embed_footer_url, reminders.embed_image_url, reminders.embed_thumbnail_url, reminders.embed_title, IFNULL(reminders.embed_fields, '[]') AS embed_fields, reminders.enabled, reminders.expires, reminders.interval_seconds, reminders.interval_days, reminders.interval_months, reminders.name, reminders.tts, reminders.uid, reminders.utc_time FROM reminders INNER JOIN channels ON channels.id = reminders.channel_id WHERE `status` = 'pending' AND channels.channel = ? ", channel.id.get() ) .fetch_all(pool.inner()) .await .map(|r| Ok(json!(r))) .unwrap_or_else(|e| { warn!("Failed to complete SQL query: {:?}", e); json_err!("Could not load reminders") }), Err(e) => { warn!("Couldn't get DM channel: {:?}", e); json_err!("Could not find a DM channel") } } } #[patch("/api/user/reminders", data = "")] pub async fn edit_reminder( reminder: Json, ctx: &State, mut transaction: Transaction<'_>, pool: &State>, cookies: &CookieJar<'_>, ) -> JsonResult { let user_id_cookie = cookies.get_private("userid").map(|c| c.value().parse::().ok()).flatten(); if user_id_cookie.is_none() { return Err(json!({"error": "User not authorized"})); } let mut error = vec![]; let user_id = user_id_cookie.unwrap(); if reminder.message_ok() { update_field!(transaction.executor(), error, reminder.[ content, embed_author, embed_description, embed_footer, embed_title, embed_fields ]); } else { error.push("Message exceeds limits.".to_string()); } update_field!(transaction.executor(), error, reminder.[ attachment, attachment_name, embed_author_url, embed_color, embed_footer_url, embed_image_url, embed_thumbnail_url, enabled, expires, name, tts, utc_time ]); if reminder.interval_days.flatten().is_some() || reminder.interval_months.flatten().is_some() || reminder.interval_seconds.flatten().is_some() { if check_subscription(&ctx.inner(), user_id).await { let new_interval_length = match reminder.interval_days { Some(interval) => interval.unwrap_or(0), None => sqlx::query!( "SELECT interval_days AS days FROM reminders WHERE uid = ?", reminder.uid ) .fetch_one(transaction.executor()) .await .map_err(|e| { warn!("Error updating reminder interval: {:?}", e); json!({ "reminder": Option::::None, "errors": vec!["Unknown error"] }) })? .days .unwrap_or(0), } * 86400 + match reminder.interval_months { Some(interval) => interval.unwrap_or(0), None => sqlx::query!( "SELECT interval_months AS months FROM reminders WHERE uid = ?", reminder.uid ) .fetch_one(transaction.executor()) .await .map_err(|e| { warn!("Error updating reminder interval: {:?}", e); json!({ "reminder": Option::::None, "errors": vec!["Unknown error"] }) })? .months .unwrap_or(0), } * 2592000 + match reminder.interval_seconds { Some(interval) => interval.unwrap_or(0), None => sqlx::query!( "SELECT interval_seconds AS seconds FROM reminders WHERE uid = ?", reminder.uid ) .fetch_one(transaction.executor()) .await .map_err(|e| { warn!("Error updating reminder interval: {:?}", e); json!({ "reminder": Option::::None, "errors": vec!["Unknown error"] }) })? .seconds .unwrap_or(0), }; if new_interval_length < *MIN_INTERVAL { error.push(String::from("New interval is too short.")); } else { update_field!(transaction.executor(), error, reminder.[ interval_days, interval_months, interval_seconds ]); } } } else { sqlx::query!( " UPDATE reminders SET interval_seconds = NULL, interval_days = NULL, interval_months = NULL WHERE uid = ? ", reminder.uid ) .execute(transaction.executor()) .await .map_err(|e| { warn!("Error updating reminder interval: {:?}", e); json!({ "reminder": Option::::None, "errors": vec!["Unknown error"] }) })?; } if let Err(e) = transaction.commit().await { warn!("Couldn't commit transaction: {:?}", e); return json_err!("Couldn't commit transaction"); } match sqlx::query_as_unchecked!( Reminder, " SELECT reminders.attachment, reminders.attachment_name, reminders.content, reminders.embed_author, reminders.embed_author_url, reminders.embed_color, reminders.embed_description, reminders.embed_footer, reminders.embed_footer_url, reminders.embed_image_url, reminders.embed_thumbnail_url, reminders.embed_title, reminders.embed_fields, reminders.enabled, reminders.expires, reminders.interval_seconds, reminders.interval_days, reminders.interval_months, reminders.name, reminders.tts, reminders.uid, reminders.utc_time FROM reminders LEFT JOIN channels ON channels.id = reminders.channel_id WHERE uid = ? ", reminder.uid ) .fetch_one(pool.inner()) .await { Ok(reminder) => Ok(json!({"reminder": reminder, "errors": error})), Err(e) => { warn!("Error exiting `edit_reminder': {:?}", e); Err(json!({"reminder": Option::::None, "errors": vec!["Unknown error"]})) } } }