use crate::web::routes::dashboard::{create_reminder_template, ReminderTemplate}; use crate::web::{ check_authorization, guards::transaction::Transaction, routes::{ dashboard::{ create_reminder, CreateReminder, ImportBody, ReminderCsv, ReminderTemplateCsv, TodoCsv, }, JsonResult, }, }; use crate::Database; use base64::{prelude::BASE64_STANDARD, Engine}; use csv::{QuoteStyle, WriterBuilder}; use log::warn; use rocket::{ get, http::CookieJar, put, serde::json::{json, Json}, State, }; use serenity::{ client::Context, model::id::{ChannelId, GuildId, UserId}, }; use sqlx::{MySql, Pool}; #[get("/api/guild//export/reminder_templates")] pub async fn export( id: u64, cookies: &CookieJar<'_>, ctx: &State, pool: &State>, ) -> JsonResult { check_authorization(cookies, ctx.inner(), id).await?; let mut csv_writer = WriterBuilder::new().quote_style(QuoteStyle::Always).from_writer(vec![]); match sqlx::query_as_unchecked!( ReminderTemplateCsv, "SELECT name, attachment, attachment_name, avatar, content, embed_author, embed_author_url, embed_color, embed_description, embed_footer, embed_footer_url, embed_image_url, embed_thumbnail_url, embed_title, embed_fields, interval_seconds, interval_days, interval_months, tts, username FROM reminder_template WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)", id ) .fetch_all(pool.inner()) .await { Ok(templates) => { templates.iter().for_each(|template| { csv_writer.serialize(template).unwrap(); }); match csv_writer.into_inner() { Ok(inner) => match String::from_utf8(inner) { Ok(encoded) => Ok(json!({ "body": encoded })), Err(e) => { warn!("Failed to write UTF-8: {:?}", e); json_err!("Failed to write UTF-8") } }, Err(e) => { warn!("Failed to extract CSV: {:?}", e); json_err!("Failed to extract CSV") } } } Err(e) => { warn!("Could not fetch templates from {}: {:?}", id, e); json_err!("Failed to query templates") } } } #[put("/api/guild//export/reminder_templates", data = "")] pub async fn import( id: u64, cookies: &CookieJar<'_>, body: Json, ctx: &State, mut transaction: Transaction<'_>, ) -> JsonResult { check_authorization(cookies, ctx.inner(), id).await?; match BASE64_STANDARD.decode(&body.body) { Ok(body) => { let mut reader = csv::Reader::from_reader(body.as_slice()); let mut count = 0; for result in reader.deserialize::() { match result { Ok(record) => { let reminder_template = ReminderTemplate { id: 0, guild_id: 0, name: record.name, attachment: record.attachment, attachment_name: record.attachment_name, avatar: record.avatar, content: record.content, embed_author: record.embed_author, embed_author_url: record.embed_author_url, embed_color: record.embed_color, embed_description: record.embed_description, embed_footer: record.embed_footer, embed_footer_url: record.embed_footer_url, embed_image_url: record.embed_image_url, embed_thumbnail_url: record.embed_thumbnail_url, embed_title: record.embed_title, embed_fields: record .embed_fields .map(|s| serde_json::from_str(&s).ok()) .flatten(), interval_seconds: record.interval_seconds, interval_days: record.interval_days, interval_months: record.interval_months, tts: record.tts, username: record.username, }; create_reminder_template( ctx.inner(), &mut transaction, GuildId::new(id), reminder_template, ) .await?; count += 1; } Err(e) => { warn!("Couldn't deserialize CSV row: {:?}", e); return json_err!(format!("Deserialize error: {:?}", e)); } } } match transaction.commit().await { Ok(_) => Ok(json!({ "message": format!("Imported {} reminder templates", count) })), Err(e) => { warn!("Failed to commit transaction: {:?}", e); json_err!("Couldn't commit transaction") } } } Err(_) => { json_err!("Malformed base64") } } }