patch reminders

This commit is contained in:
jude 2022-03-22 22:21:47 +00:00
parent 878ea11502
commit afb2fbe4ff
9 changed files with 274 additions and 97 deletions

View File

@ -122,7 +122,12 @@ pub async fn initialize(
warn!("Exiting rocket runtime"); warn!("Exiting rocket runtime");
// distribute kill signal // distribute kill signal
kill_channel.send(()); match kill_channel.send(()) {
Ok(_) => {}
Err(e) => {
error!("Failed to issue kill signal: {:?}", e);
}
}
Ok(()) Ok(())
} }

View File

@ -79,3 +79,41 @@ macro_rules! check_authorization {
} }
} }
} }
macro_rules! update_field {
($pool:expr, $error:ident, $reminder:ident.[$field:ident]) => {
if let Some(value) = &$reminder.$field {
match sqlx::query(concat!(
"UPDATE reminders SET `",
stringify!($field),
"` = ? WHERE uid = ?"
))
.bind(value)
.bind(&$reminder.uid)
.execute($pool)
.await
{
Ok(_) => {}
Err(e) => {
warn!(
concat!(
"Error in `update_field!(",
stringify!($pool),
stringify!($reminder),
stringify!($field),
")': {:?}"
),
e
);
$error.push(format!("Error setting field {}", stringify!($field)));
}
}
}
};
($pool:expr, $error:ident, $reminder:ident.[$field:ident, $($fields:ident),+]) => {
update_field!($pool, $error, $reminder.[$field]);
update_field!($pool, $error, $reminder.[$($fields),+]);
};
}

View File

@ -294,42 +294,35 @@ pub async fn get_reminders(id: u64, ctx: &State<Context>, pool: &State<Pool<MySq
sqlx::query_as_unchecked!( sqlx::query_as_unchecked!(
Reminder, Reminder,
" "SELECT
SELECT reminders.attachment,
reminders.attachment, reminders.attachment_name,
reminders.attachment_name, reminders.avatar,
reminders.avatar, channels.channel,
channels.channel, reminders.content,
reminders.content, reminders.embed_author,
reminders.embed_author, reminders.embed_author_url,
reminders.embed_author_url, reminders.embed_color,
reminders.embed_color, reminders.embed_description,
reminders.embed_description, reminders.embed_footer,
reminders.embed_footer, reminders.embed_footer_url,
reminders.embed_footer_url, reminders.embed_image_url,
reminders.embed_image_url, reminders.embed_thumbnail_url,
reminders.embed_thumbnail_url, reminders.embed_title,
reminders.embed_title, reminders.enabled,
reminders.enabled, reminders.expires,
reminders.expires, reminders.interval_seconds,
reminders.interval_seconds, reminders.interval_months,
reminders.interval_months, reminders.name,
reminders.name, reminders.pin,
reminders.pin, reminders.restartable,
reminders.restartable, reminders.tts,
reminders.tts, reminders.uid,
reminders.uid, reminders.username,
reminders.username, reminders.utc_time
reminders.utc_time FROM reminders
FROM LEFT JOIN channels ON channels.id = reminders.channel_id
reminders WHERE FIND_IN_SET(channels.channel, ?)",
LEFT JOIN
channels
ON
channels.id = reminders.channel_id
WHERE
FIND_IN_SET(channels.channel, ?)
",
channels channels
) )
.fetch_all(pool.inner()) .fetch_all(pool.inner())
@ -356,10 +349,90 @@ pub async fn edit_reminder(
serenity_context: &State<Context>, serenity_context: &State<Context>,
pool: &State<Pool<MySql>>, pool: &State<Pool<MySql>>,
) -> JsonValue { ) -> JsonValue {
if let Some(enabled) = reminder.enabled { let mut error = vec![];
sqlx::query!("UPDATE reminders SET enabled = ? WHERE uid = ?", enabled, reminder.uid)
.execute(pool.inner()) update_field!(pool.inner(), error, reminder.[
.await; 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,
enabled,
expires,
interval_seconds,
interval_months,
name,
pin,
restartable,
tts,
username,
utc_time
]);
if reminder.channel > 0 {
let channel = ChannelId(reminder.channel).to_channel_cached(&serenity_context.inner());
match channel {
Some(channel) => {
let channel_matches_guild = channel.guild().map_or(false, |c| c.guild_id.0 == id);
if !channel_matches_guild {
warn!(
"Error in `edit_reminder`: channel {:?} not found for guild {}",
reminder.channel, id
);
return json!({"error": "Channel not found"});
}
let channel = create_database_channel(
serenity_context.inner(),
ChannelId(reminder.channel),
pool.inner(),
)
.await;
if let Err(e) = channel {
warn!("`create_database_channel` returned an error code: {:?}", e);
return json!({"error": "Failed to configure channel for reminders. Please check the bot permissions"});
}
let channel = channel.unwrap();
match sqlx::query!(
"UPDATE reminders SET channel_id = ? WHERE uid = ?",
channel,
reminder.uid
)
.execute(pool.inner())
.await
{
Ok(_) => {}
Err(e) => {
warn!("Error setting channel: {:?}", e);
error.push("Couldn't set channel".to_string())
}
}
}
None => {
warn!(
"Error in `edit_reminder`: channel {:?} not found for guild {}",
reminder.channel, id
);
return json!({"error": "Channel not found"});
}
}
} }
match sqlx::query_as_unchecked!( match sqlx::query_as_unchecked!(
@ -397,12 +470,12 @@ pub async fn edit_reminder(
.fetch_one(pool.inner()) .fetch_one(pool.inner())
.await .await
{ {
Ok(reminder) => json!(reminder), Ok(reminder) => json!({"reminder": reminder, "errors": error}),
Err(e) => { Err(e) => {
warn!("Error exiting `edit_reminder': {:?}", e); warn!("Error exiting `edit_reminder': {:?}", e);
json!({"error": "Unknown error"}) json!({"reminder": Option::<Reminder>::None, "errors": vec!["Unknown error"]})
} }
} }
} }

View File

@ -22,6 +22,10 @@ fn name_default() -> String {
"Reminder".to_string() "Reminder".to_string()
} }
fn channel_default() -> u64 {
0
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Reminder { pub struct Reminder {
attachment: Option<Vec<u8>>, attachment: Option<Vec<u8>>,
@ -63,6 +67,9 @@ pub struct PatchReminder {
attachment_name: Unset<Option<String>>, attachment_name: Unset<Option<String>>,
#[serde(default)] #[serde(default)]
avatar: Unset<Option<String>>, avatar: Unset<Option<String>>,
#[serde(default = "channel_default")]
#[serde(with = "string")]
channel: u64,
#[serde(default)] #[serde(default)]
content: Unset<String>, content: Unset<String>,
#[serde(default)] #[serde(default)]

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -12,6 +12,10 @@ function colorToInt(r, g, b) {
return (r << 16) + (g << 8) + b; return (r << 16) + (g << 8) + b;
} }
function intToColor(i) {
return `#${i.toString(16)}`;
}
function resize_textareas() { function resize_textareas() {
document.querySelectorAll("textarea.autoresize").forEach((element) => { document.querySelectorAll("textarea.autoresize").forEach((element) => {
element.style.height = ""; element.style.height = "";
@ -134,19 +138,23 @@ async function fetch_reminders(guild_id) {
document.dispatchEvent(remindersLoadedEvent); document.dispatchEvent(remindersLoadedEvent);
} }
}); });
register_interval_hide();
} }
document.addEventListener("remindersLoaded", (event) => { document.addEventListener("remindersLoaded", (event) => {
const guild = document.querySelector(".guildList a.is-active").dataset["guild"]; const guild = document.querySelector(".guildList a.is-active").dataset["guild"];
for (let reminder of event.detail) { for (let reminder of event.detail) {
reminder.node.querySelector("button.hide-box").addEventListener("click", () => { let node = reminder.node;
reminder.node.closest(".reminderContent").classList.toggle("is-collapsed");
node.querySelector("button.hide-box").addEventListener("click", () => {
node.closest(".reminderContent").classList.toggle("is-collapsed");
}); });
const enableBtn = reminder.node.querySelector(".disable-enable"); node.querySelector("div.discord-embed").style.borderLeftColor = intToColor(
reminder.embed_color
);
const enableBtn = node.querySelector(".disable-enable");
enableBtn.addEventListener("click", () => { enableBtn.addEventListener("click", () => {
let enable = enableBtn.dataset.action === "enable"; let enable = enableBtn.dataset.action === "enable";
@ -167,14 +175,68 @@ document.addEventListener("remindersLoaded", (event) => {
}); });
}); });
reminder.node node.querySelector("button.delete-reminder").addEventListener("click", () => {
.querySelector("button.delete-reminder") $deleteReminderBtn.dataset["uid"] = reminder["uid"];
.addEventListener("click", () => { $deleteReminderBtn.closest(".modal").classList.toggle("is-active");
let uid = reminder.node.closest(".reminderContent").dataset.uid; });
$deleteReminderBtn.dataset["uid"] = uid; node.querySelector("button.save-btn").addEventListener("click", (event) => {
$deleteReminderBtn.closest(".modal").classList.toggle("is-active"); let seconds =
}); parseInt(node.querySelector('input[name="interval_seconds"]').value) ||
null;
let months =
parseInt(node.querySelector('input[name="interval_months"]').value) ||
null;
let rgb_color = window.getComputedStyle(
node.querySelector("div.discord-embed")
).borderLeftColor;
let rgb = rgb_color.match(/\d+/g);
let color = colorToInt(parseInt(rgb[0]), parseInt(rgb[1]), parseInt(rgb[2]));
let utc_time = luxon.DateTime.fromISO(
node.querySelector('input[name="time"]').value
).setZone("UTC");
let reminder = {
uid: node.closest(".reminderContent").dataset["uid"],
avatar: node.querySelector("img.discord-avatar").src,
channel: node.querySelector("select.channel-selector").value,
content: node.querySelector('textarea[name="content"]').value,
embed_author_url: node.querySelector("img.embed_author_url").src,
embed_author: node.querySelector('textarea[name="embed_author"]').value,
embed_color: color,
embed_description: node.querySelector(
'textarea[name="embed_description"]'
).value,
embed_footer: node.querySelector('textarea[name="embed_footer"]').value,
embed_footer_url: node.querySelector("img.embed_footer_url").src,
embed_image_url: node.querySelector("img.embed_image_url").src,
embed_thumbnail_url: node.querySelector("img.embed_thumbnail_url").src,
embed_title: node.querySelector('textarea[name="embed_title"]').value,
expires: null,
interval_seconds: seconds,
interval_months: months,
name: node.querySelector('input[name="name"]').value,
pin: node.querySelector('input[name="pin"]').checked,
tts: node.querySelector('input[name="tts"]').checked,
username: node.querySelector('input[name="username"]').value,
utc_time: utc_time.toFormat("yyyy-LL-dd'T'HH:mm:ss"),
};
// send to server
let guild = document.querySelector(".guildList a.is-active").dataset["guild"];
fetch(`/dashboard/api/guild/${guild}/reminders`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(reminder),
})
.then((response) => response.json())
.then((data) => console.log(data));
});
} }
}); });
@ -214,19 +276,6 @@ colorPicker.on("color:change", function (color) {
$colorPickerInput.value = color.hexString; $colorPickerInput.value = color.hexString;
}); });
document.querySelectorAll(".change-color").forEach((element) => {
element.addEventListener("click", (e) => {
e.preventDefault();
$discordFrame = element
.closest("div.reminderContent")
.querySelector("div.discord-embed");
$colorPickerModal.classList.toggle("is-active");
colorPicker.color.rgbString =
window.getComputedStyle($discordFrame).borderLeftColor;
});
});
$colorPickerModal.querySelector("button.is-success").addEventListener("click", () => { $colorPickerModal.querySelector("button.is-success").addEventListener("click", () => {
$discordFrame.style.borderLeftColor = colorPicker.color.rgbString; $discordFrame.style.borderLeftColor = colorPicker.color.rgbString;
@ -464,7 +513,7 @@ let $img;
const $urlModal = document.querySelector("div#addImageModal"); const $urlModal = document.querySelector("div#addImageModal");
const $urlInput = $urlModal.querySelector("input"); const $urlInput = $urlModal.querySelector("input");
$urlModal.querySelector("button.is-success").addEventListener("click", () => { $urlModal.querySelector("button#setImgUrl").addEventListener("click", () => {
$img.src = $urlInput.value; $img.src = $urlInput.value;
$urlInput.value = ""; $urlInput.value = "";
@ -481,26 +530,29 @@ document.querySelectorAll("button.close-modal").forEach((element) => {
}); });
}); });
document.querySelectorAll(".customizable").forEach((element) => { document.addEventListener("remindersLoaded", () => {
element.querySelector("a").addEventListener("click", (e) => { document.querySelectorAll(".customizable").forEach((element) => {
e.preventDefault(); element.querySelector("a").addEventListener("click", (e) => {
e.preventDefault();
$img = element.querySelector("img"); $img = element.querySelector("img");
$urlModal.classList.toggle("is-active"); $urlModal.classList.toggle("is-active");
});
}); });
});
document.querySelectorAll("a.icon-toggle").forEach((element) => { const fileInput = document.querySelectorAll("input[type=file]");
element.addEventListener("click", (e) => {
e.preventDefault();
element.classList.toggle("is-active"); fileInput.forEach((element) => {
element.addEventListener("change", () => {
if (element.files.length > 0) {
const fileName = element.parentElement.querySelector(".file-label");
fileName.textContent = element.files[0].name;
}
});
}); });
});
function register_interval_hide() { const $showInterval = document.querySelectorAll("a.intervalLabel");
let $showInterval = document.querySelectorAll("a.intervalLabel");
$showInterval.forEach((element) => { $showInterval.forEach((element) => {
element.addEventListener("click", () => { element.addEventListener("click", () => {
@ -509,16 +561,18 @@ function register_interval_hide() {
element.nextElementSibling.classList.toggle("is-hidden"); element.nextElementSibling.classList.toggle("is-hidden");
}); });
}); });
}
const fileInput = document.querySelectorAll("input[type=file]"); document.querySelectorAll(".change-color").forEach((element) => {
element.addEventListener("click", (e) => {
e.preventDefault();
fileInput.forEach((element) => { $discordFrame = element
element.addEventListener("change", () => { .closest("div.reminderContent")
if (element.files.length > 0) { .querySelector("div.discord-embed");
const fileName = element.parentElement.querySelector(".file-label"); $colorPickerModal.classList.toggle("is-active");
fileName.textContent = element.files[0].name; colorPicker.color.rgbString =
} window.getComputedStyle($discordFrame).borderLeftColor;
});
}); });
}); });

View File

@ -36,7 +36,7 @@
<div class="navbar-brand"> <div class="navbar-brand">
<a class="navbar-item" href="/"> <a class="navbar-item" href="/">
<figure class="image"> <figure class="image">
<img src="/static/img/logo_flat.jpg" alt="Reminder Bot Logo" class="is-rounded" style="width: auto;"> <img src="/static/img/logo_flat.webp" alt="Reminder Bot Logo" class="is-rounded" style="width: auto;">
</figure> </figure>
</a> </a>

View File

@ -38,7 +38,7 @@
<div class="navbar-brand"> <div class="navbar-brand">
<a class="navbar-item" href="/"> <a class="navbar-item" href="/">
<figure class="image"> <figure class="image">
<img src="/static/img/logo_flat.jpg" alt="Reminder Bot Logo"> <img src="/static/img/logo_flat.webp" alt="Reminder Bot Logo">
</figure> </figure>
</a> </a>
@ -85,7 +85,7 @@
<input class="input" id="urlInput" placeholder="Image URL..."> <input class="input" id="urlInput" placeholder="Image URL...">
</section> </section>
<footer class="modal-card-foot"> <footer class="modal-card-foot">
<button class="button is-success">Save</button> <button class="button is-success" id="setImgUrl">Save</button>
<button class="button close-modal">Cancel</button> <button class="button close-modal">Cancel</button>
</footer> </footer>
</div> </div>
@ -165,7 +165,7 @@
<div class="column is-2 is-sidebar-menu dashboard-sidebar is-hidden-touch" style="display: flex; flex-direction: column;"> <div class="column is-2 is-sidebar-menu dashboard-sidebar is-hidden-touch" style="display: flex; flex-direction: column;">
<a href="/"> <a href="/">
<div class="brand"> <div class="brand">
<img src="/static/img/logo_flat.jpg" alt="Reminder bot logo" <img src="/static/img/logo_flat.webp" alt="Reminder bot logo"
class="dashboard-brand"> class="dashboard-brand">
</div> </div>
</a> </a>
@ -210,7 +210,7 @@
<div class="dashboard-sidebar mobile-sidebar is-hidden-desktop" id="mobileSidebar"> <div class="dashboard-sidebar mobile-sidebar is-hidden-desktop" id="mobileSidebar">
<a href="/"> <a href="/">
<div class="brand"> <div class="brand">
<img src="/static/img/logo_flat.jpg" alt="Reminder bot logo" <img src="/static/img/logo_flat.webp" alt="Reminder bot logo"
class="dashboard-brand"> class="dashboard-brand">
</div> </div>
</a> </a>

View File

@ -211,8 +211,8 @@
Create Reminder Create Reminder
</button> </button>
{% else %} {% else %}
<button class="button is-primary" disabled> <button class="button is-primary save-btn">
Saved! Save
</button> </button>
<button class="button is-warning disable-enable"> <button class="button is-warning disable-enable">
</button> </button>