225 lines
5.4 KiB
Rust
225 lines
5.4 KiB
Rust
use log::warn;
|
|
use rocket::{
|
|
delete, get,
|
|
http::CookieJar,
|
|
patch, post,
|
|
serde::json::{json, Json},
|
|
State,
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
use serenity::{
|
|
all::{ChannelId, GuildId},
|
|
prelude::Context,
|
|
};
|
|
|
|
use crate::web::{
|
|
check_authorization,
|
|
guards::transaction::Transaction,
|
|
routes::{dashboard::check_channel_matches_guild, JsonResult},
|
|
string_opt,
|
|
};
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct CreateTodo {
|
|
#[serde(with = "string_opt")]
|
|
channel_id: Option<u64>,
|
|
value: String,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct GetTodo {
|
|
id: u32,
|
|
#[serde(with = "string_opt")]
|
|
channel_id: Option<u64>,
|
|
value: String,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct UpdateTodo {
|
|
value: String,
|
|
}
|
|
|
|
#[post("/api/guild/<id>/todos", data = "<todo>")]
|
|
pub async fn create_todo(
|
|
id: u64,
|
|
todo: Json<CreateTodo>,
|
|
cookies: &CookieJar<'_>,
|
|
ctx: &State<Context>,
|
|
mut transaction: Transaction<'_>,
|
|
) -> JsonResult {
|
|
check_authorization(cookies, ctx.inner(), id).await?;
|
|
|
|
let guild_id = GuildId::new(id);
|
|
if todo.value.len() > 2000 {
|
|
return json_err!("Value too long");
|
|
}
|
|
|
|
match todo.channel_id {
|
|
Some(channel_id) => {
|
|
if !check_channel_matches_guild(ctx, ChannelId::new(channel_id), guild_id) {
|
|
warn!("Channel {} not found for guild {}", channel_id, guild_id);
|
|
|
|
return json_err!("Channel not found");
|
|
}
|
|
|
|
sqlx::query!(
|
|
"
|
|
INSERT INTO todos (guild_id, channel_id, value)
|
|
VALUES (
|
|
(SELECT id FROM guilds WHERE guild = ?),
|
|
(SELECT id FROM channels WHERE channel = ?),
|
|
?
|
|
)
|
|
",
|
|
id,
|
|
channel_id,
|
|
todo.value
|
|
)
|
|
.execute(transaction.executor())
|
|
.await
|
|
.map_err(|e| {
|
|
warn!("Error creating todo: {:?}", e);
|
|
json!({"errors": vec!["Unknown error"]})
|
|
})?;
|
|
}
|
|
|
|
None => {
|
|
sqlx::query!(
|
|
"
|
|
INSERT INTO todos (guild_id, channel_id, value)
|
|
VALUES (
|
|
(SELECT id FROM guilds WHERE guild = ?),
|
|
NULL,
|
|
?
|
|
)
|
|
",
|
|
id,
|
|
todo.value
|
|
)
|
|
.execute(transaction.executor())
|
|
.await
|
|
.map_err(|e| {
|
|
warn!("Error creating todo: {:?}", e);
|
|
json!({"errors": vec!["Unknown error"]})
|
|
})?;
|
|
}
|
|
}
|
|
|
|
if let Err(e) = transaction.commit().await {
|
|
warn!("Couldn't commit transaction: {:?}", e);
|
|
return json_err!("Couldn't commit transaction.");
|
|
}
|
|
|
|
Ok(json!({}))
|
|
}
|
|
|
|
#[get("/api/guild/<id>/todos")]
|
|
pub async fn get_todo(
|
|
id: u64,
|
|
cookies: &CookieJar<'_>,
|
|
ctx: &State<Context>,
|
|
mut transaction: Transaction<'_>,
|
|
) -> JsonResult {
|
|
check_authorization(cookies, ctx.inner(), id).await?;
|
|
|
|
let todos = sqlx::query_as!(
|
|
GetTodo,
|
|
"
|
|
SELECT
|
|
todos.id,
|
|
channels.channel AS channel_id,
|
|
value
|
|
FROM todos
|
|
INNER JOIN guilds
|
|
ON guilds.id = todos.guild_id
|
|
LEFT JOIN channels
|
|
ON channels.id = todos.channel_id
|
|
WHERE guilds.guild = ?
|
|
",
|
|
id
|
|
)
|
|
.fetch_all(transaction.executor())
|
|
.await
|
|
.map_err(|e| {
|
|
warn!("Error fetching todos: {:?}", e);
|
|
json!({ "errors": vec!["Unknown error"] })
|
|
})?;
|
|
|
|
Ok(json!(todos))
|
|
}
|
|
|
|
#[patch("/api/guild/<guild_id>/todos/<todo_id>", data = "<todo>")]
|
|
pub async fn update_todo(
|
|
guild_id: u64,
|
|
todo_id: u64,
|
|
todo: Json<UpdateTodo>,
|
|
cookies: &CookieJar<'_>,
|
|
ctx: &State<Context>,
|
|
mut transaction: Transaction<'_>,
|
|
) -> JsonResult {
|
|
check_authorization(cookies, ctx.inner(), guild_id).await?;
|
|
|
|
if todo.value.len() > 2000 {
|
|
return json_err!("Value too long");
|
|
}
|
|
|
|
sqlx::query!(
|
|
"
|
|
UPDATE todos
|
|
SET value = ?
|
|
WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)
|
|
AND id = ?
|
|
",
|
|
todo.value,
|
|
guild_id,
|
|
todo_id,
|
|
)
|
|
.execute(transaction.executor())
|
|
.await
|
|
.map_err(|e| {
|
|
warn!("Error updating todo: {:?}", e);
|
|
json!({"errors": vec!["Unknown error"]})
|
|
})?;
|
|
|
|
if let Err(e) = transaction.commit().await {
|
|
warn!("Couldn't commit transaction: {:?}", e);
|
|
return json_err!("Couldn't commit transaction.");
|
|
}
|
|
|
|
Ok(json!({}))
|
|
}
|
|
|
|
#[delete("/api/guild/<guild_id>/todos/<todo_id>")]
|
|
pub async fn delete_todo(
|
|
guild_id: u64,
|
|
todo_id: u64,
|
|
cookies: &CookieJar<'_>,
|
|
ctx: &State<Context>,
|
|
mut transaction: Transaction<'_>,
|
|
) -> JsonResult {
|
|
check_authorization(cookies, ctx.inner(), guild_id).await?;
|
|
|
|
sqlx::query!(
|
|
"
|
|
DELETE FROM todos
|
|
WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)
|
|
AND id = ?
|
|
",
|
|
guild_id,
|
|
todo_id,
|
|
)
|
|
.execute(transaction.executor())
|
|
.await
|
|
.map_err(|e| {
|
|
warn!("Error deleting todo: {:?}", e);
|
|
json!({"errors": vec!["Unknown error"]})
|
|
})?;
|
|
|
|
if let Err(e) = transaction.commit().await {
|
|
warn!("Couldn't commit transaction: {:?}", e);
|
|
return json_err!("Couldn't commit transaction.");
|
|
}
|
|
|
|
Ok(json!({}))
|
|
}
|