channel selection shows properly. loader

This commit is contained in:
jude 2022-03-19 21:28:11 +00:00
parent d0d2d50966
commit 3e4dd0fa48
6 changed files with 163 additions and 55 deletions

View File

@ -25,7 +25,7 @@ type Database = MySql;
#[derive(Debug)] #[derive(Debug)]
enum Error { enum Error {
SQLx(sqlx::Error), SQLx(sqlx::Error),
serenity(serenity::Error), Serenity(serenity::Error),
} }
#[catch(401)] #[catch(401)]

View File

@ -45,3 +45,37 @@ macro_rules! check_url_opt {
check_url_opt!($($fields),+); check_url_opt!($($fields),+);
}; };
} }
macro_rules! check_authorization {
($cookies:expr, $ctx:expr, $guild:expr) => {
use serenity::model::id::UserId;
let user_id = $cookies.get_private("userid").map(|c| c.value().parse::<u64>().ok()).flatten();
match user_id {
Some(user_id) => {
match GuildId($guild).to_guild_cached($ctx) {
Some(guild) => {
let member = guild.member($ctx, UserId(user_id)).await;
match member {
Err(_) => {
return json!({"error": "User not in guild"})
}
Ok(_) => {}
}
}
None => {
return json!({"error": "Bot not in guild"})
}
}
}
None => {
return json!({"error": "User not authorized"});
}
}
}
}

View File

@ -31,13 +31,15 @@ struct ChannelInfo {
webhook_name: Option<String>, webhook_name: Option<String>,
} }
// todo check the user can access this guild
#[get("/api/guild/<id>/channels")] #[get("/api/guild/<id>/channels")]
pub async fn get_guild_channels( pub async fn get_guild_channels(
id: u64, id: u64,
cookies: &CookieJar<'_>,
ctx: &State<Context>, ctx: &State<Context>,
pool: &State<Pool<MySql>>, pool: &State<Pool<MySql>>,
) -> JsonValue { ) -> JsonValue {
check_authorization!(cookies, ctx.inner(), id);
let channels_res = GuildId(id).channels(ctx.inner()).await; let channels_res = GuildId(id).channels(ctx.inner()).await;
match channels_res { match channels_res {
@ -96,9 +98,10 @@ struct RoleInfo {
name: String, name: String,
} }
// todo check the user can access this guild
#[get("/api/guild/<id>/roles")] #[get("/api/guild/<id>/roles")]
pub async fn get_guild_roles(id: u64, ctx: &State<Context>) -> JsonValue { pub async fn get_guild_roles(id: u64, cookies: &CookieJar<'_>, ctx: &State<Context>) -> JsonValue {
check_authorization!(cookies, ctx.inner(), id);
let roles_res = ctx.cache.guild_roles(id); let roles_res = ctx.cache.guild_roles(id);
match roles_res { match roles_res {
@ -126,14 +129,10 @@ pub async fn create_reminder(
serenity_context: &State<Context>, serenity_context: &State<Context>,
pool: &State<Pool<MySql>>, pool: &State<Pool<MySql>>,
) -> JsonValue { ) -> JsonValue {
// get userid from cookies check_authorization!(cookies, serenity_context.inner(), id);
let user_id = cookies.get_private("userid").map(|c| c.value().parse::<u64>().ok()).flatten();
if user_id.is_none() { let user_id =
return json!({"error": "User not authorized"}); cookies.get_private("userid").map(|c| c.value().parse::<u64>().ok()).flatten().unwrap();
}
let user_id = user_id.unwrap();
// validate channel // validate channel
let channel = ChannelId(reminder.channel).to_channel_cached(&serenity_context.inner()); let channel = ChannelId(reminder.channel).to_channel_cached(&serenity_context.inner());

View File

@ -106,7 +106,7 @@ async fn create_database_channel(
let webhook = channel let webhook = channel
.create_webhook_with_avatar(&ctx, "Reminder", DEFAULT_AVATAR.clone()) .create_webhook_with_avatar(&ctx, "Reminder", DEFAULT_AVATAR.clone())
.await .await
.map_err(|e| Error::serenity(e))?; .map_err(|e| Error::Serenity(e))?;
sqlx::query!( sqlx::query!(
"UPDATE channels SET webhook_id = ?, webhook_token = ? WHERE channel = ?", "UPDATE channels SET webhook_id = ?, webhook_token = ? WHERE channel = ?",
@ -127,7 +127,7 @@ async fn create_database_channel(
let webhook = channel let webhook = channel
.create_webhook_with_avatar(&ctx, "Reminder", DEFAULT_AVATAR.clone()) .create_webhook_with_avatar(&ctx, "Reminder", DEFAULT_AVATAR.clone())
.await .await
.map_err(|e| Error::serenity(e))?; .map_err(|e| Error::Serenity(e))?;
// create database entry // create database entry
sqlx::query!( sqlx::query!(

View File

@ -54,6 +54,19 @@
</div> </div>
</nav> </nav>
<div id="loader" class="is-hidden hero is-fullheight" style="position: fixed; background-color: white; opacity: 0.8; width: 100vw; z-index: 999;">
<div class="hero-body">
<div class="container has-text-centered">
<p class="title" style="font-size: 6rem; color: #8fb677">
<i class="fas fa-cog fa-spin"></i>
</p>
<p class="subtitle">
Bear with...
</p>
</div>
</div>
</div>
<!-- dead image used to check which other images are dead --> <!-- dead image used to check which other images are dead -->
<img style="display: none;" src="" id="dead"> <img style="display: none;" src="" id="dead">
@ -158,7 +171,7 @@
<ul class="menu-list guildList"> <ul class="menu-list guildList">
</ul> </ul>
<div class="aside-footer" style="margin-top: auto;"> <div class="aside-footer" style="position: fixed; bottom: 0;">
<p class="menu-label"> <p class="menu-label">
Settings Settings
</p> </p>
@ -234,24 +247,22 @@
<section id="guild" class="is-hidden"> <section id="guild" class="is-hidden">
{% include "reminder_dashboard/reminder_dashboard" %} {% include "reminder_dashboard/reminder_dashboard" %}
</section> </section>
<section id="guild-error" class="is-hidden hero is-fullheight">
<div class="hero-body">
<div class="">
<p class="title">
We couldn't get this server's data
</p>
<p class="subtitle">
Please check Reminder Bot is in the server, and has correct permissions.
</p>
</div>
</div>
</section>
</div> </div>
<!-- /main content --> <!-- /main content -->
</div> </div>
<footer class="footer">
<div class="content has-text-centered">
<p>
<strong>Reminder Bot</strong>, created by <a href="https://github.com/JellyWX"><strong>JellyWX</strong></a>
<br>
<a href="https://patreon.com/jellywx"><strong>Patreon</strong></a> | <a
href="https://discord.jellywx.com"><strong>Discord</strong></a> | <a
href="https://github.com/JellyWX"><strong>GitHub</strong></a>
<br>
or, <a href="mailto:jude@jellywx.com">Email me</a>
</p>
</div>
</footer>
<template id="embedFieldTemplate"> <template id="embedFieldTemplate">
<div class="embed-field-box"> <div class="embed-field-box">
<label class="is-sr-only" for="embedFieldTitle">Field Title</label> <label class="is-sr-only" for="embedFieldTitle">Field Title</label>
@ -412,7 +423,7 @@
let newFrame = $template.content.cloneNode(true); let newFrame = $template.content.cloneNode(true);
// populate channels // populate channels
newFrame.querySelector('select.channel-selector'); set_channels(newFrame.querySelector('select.channel-selector'))
// populate majority of items // populate majority of items
for (let prop in reminder) { for (let prop in reminder) {
@ -475,6 +486,7 @@
let colorPicker = new iro.ColorPicker('#colorpicker'); let colorPicker = new iro.ColorPicker('#colorpicker');
let $discordFrame; let $discordFrame;
const $loader = document.querySelector('#loader');
const $colorPickerModal = document.querySelector('div#pickColorModal'); const $colorPickerModal = document.querySelector('div#pickColorModal');
const $colorPickerInput = $colorPickerModal.querySelector('input'); const $colorPickerInput = $colorPickerModal.querySelector('input');
@ -482,6 +494,8 @@
const browserTimezone = luxon.DateTime.now().zone.name; const browserTimezone = luxon.DateTime.now().zone.name;
let botTimezone = 'UTC'; let botTimezone = 'UTC';
let channels;
document.getElementById('set-bot-timezone').addEventListener('click', () => { document.getElementById('set-bot-timezone').addEventListener('click', () => {
timezone = botTimezone; timezone = botTimezone;
update_times(); update_times();
@ -557,6 +571,8 @@
}) })
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
$loader.classList.remove('is-hidden');
document.querySelectorAll('.navbar-burger').forEach(el => { document.querySelectorAll('.navbar-burger').forEach(el => {
el.addEventListener('click', () => { el.addEventListener('click', () => {
const target = el.dataset.target; const target = el.dataset.target;
@ -616,39 +632,26 @@
$anchor.dataset['guild'] = guild.id; $anchor.dataset['guild'] = guild.id;
$anchor.dataset['name'] = guild.name; $anchor.dataset['name'] = guild.name;
$anchor.addEventListener('click', (e) => { $anchor.addEventListener('click', async (e) => {
e.preventDefault(); e.preventDefault();
$loader.classList.remove('is-hidden');
switch_pane($anchor.dataset['pane']); switch_pane($anchor.dataset['pane']);
reset_guild_pane(); reset_guild_pane();
fetch_roles($anchor.dataset['guild']); fetch_roles($anchor.dataset['guild']);
fetch(`/dashboard/api/guild/${$anchor.dataset['guild']}/channels`) await fetch(`/dashboard/api/guild/${$anchor.dataset['guild']}/channels`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.error) { if (data.error) {
show_error(data.error); show_error(data.error);
} else { } else {
document.querySelectorAll('select.channel-selector').forEach((el) => { channels = data;
for (let channel of data) {
let newOption = document.createElement('option');
newOption.value = channel.id; document.querySelectorAll('select.channel-selector').forEach(set_channels);
newOption.textContent = channel.name;
if (channel.webhook_avatar !== null) {
newOption.dataset['webhookAvatar'] = channel.webhook_avatar;
}
if (channel.webhook_name !== null) {
newOption.dataset['webhookName'] = channel.webhook_name;
}
el.appendChild(newOption);
}
update_select(el);
});
} }
}); });
@ -664,6 +667,8 @@
}); });
$anchor.classList.add('is-active'); $anchor.classList.add('is-active');
resize_textareas(); resize_textareas();
$loader.classList.add('is-hidden');
}); });
element.append($clone); element.append($clone);
@ -671,8 +676,29 @@
} }
} }
}); });
$loader.classList.add('is-hidden');
}); });
function set_channels(element) {
for (let channel of channels) {
let newOption = document.createElement('option');
newOption.value = channel.id;
newOption.textContent = channel.name;
if (channel.webhook_avatar !== null) {
newOption.dataset['webhookAvatar'] = channel.webhook_avatar;
}
if (channel.webhook_name !== null) {
newOption.dataset['webhookName'] = channel.webhook_name;
}
element.appendChild(newOption);
}
update_select(element);
}
let $createReminder = document.querySelector('#reminderCreator'); let $createReminder = document.querySelector('#reminderCreator');
$createReminder.querySelector('button#createReminder').addEventListener('click', () => { $createReminder.querySelector('button#createReminder').addEventListener('click', () => {
@ -711,8 +737,6 @@
utc_time: utc_time.toFormat("yyyy-LL-dd'T'HH:mm:ss") utc_time: utc_time.toFormat("yyyy-LL-dd'T'HH:mm:ss")
} }
console.log(reminder);
// send to server // send to server
let guild = document.querySelector('.guildList a.is-active').dataset['guild']; let guild = document.querySelector('.guildList a.is-active').dataset['guild'];

View File

@ -1,13 +1,64 @@
{% extends "base" %} {% extends "base" %}
{% set title = "Commands" %} {% block init %}
{% set page_title = "Commands" %} {% set title = "Support" %}
{% set page_title = "Reminder Bot" %}
{% set page_subtitle = "Command Support" %}
{% set page_emoji = "fa-life-ring" %}
{% set show_invite = true %}
{% endblock %}
{% block content %} {% block content %}
<section class="section"> <section class="hero is-small">
<div class="container"> <div class="hero-body">
<h2 class="title">Information Commands</h2> <div class="container has-text-centered">
<p class="title">First things first...</p>
<p class="content">
Use the link below to add the bot.
</p>
</div>
</div>
<div class="hero-foot has-text-centered">
<a class="button is-size-6 is-rounded is-success" href="https://invite.reminder-bot.com">
<p class="is-size-6">
Add Now <span class="icon"><i class="fas fa-chevron-right"></i></span>
</p>
</a>
</div>
</section>
<section class="hero">
<div class="hero-body">
<div class="container has-text-centered">
<p class="title">Choose Your Timezone</p>
<p class="content">
Select your timezone with <code>/timezone</code>, to ensure times are correct.
</p>
</div>
</div>
</section>
<section class="hero">
<div class="hero-body">
<div class="container has-text-centered">
<p class="title">Create a Reminder</p>
<p class="content">
Create reminders with <code>/remind</code>!
</p>
</div>
</div>
</section>
<section class="hero">
<div class="hero-body">
<div class="container has-text-centered">
<p class="title">Delete a Reminder</p>
<p class="content">
Made a mistake? Delete reminders with <code>/del</code>.
</p>
</div>
</div> </div>
</section> </section>