update dependencies
This commit is contained in:
@ -7,7 +7,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "master", features = ["tls", "secrets", "json"] }
|
||||
rocket_dyn_templates = { git = "https://github.com/SergioBenitez/Rocket", branch = "master", features = ["tera"] }
|
||||
serenity = { git = "https://github.com/serenity-rs/serenity", branch = "next", default-features = false, features = ["builder", "cache", "client", "gateway", "http", "model", "utils", "rustls_backend"] }
|
||||
serenity = { version = "0.11.1", default-features = false, features = ["builder", "cache", "client", "gateway", "http", "model", "utils", "rustls_backend"] }
|
||||
oauth2 = "4"
|
||||
log = "0.4"
|
||||
reqwest = "0.11"
|
||||
|
@ -1,7 +1,6 @@
|
||||
pub const DISCORD_OAUTH_TOKEN: &'static str = "https://discord.com/api/oauth2/token";
|
||||
pub const DISCORD_OAUTH_AUTHORIZE: &'static str = "https://discord.com/api/oauth2/authorize";
|
||||
pub const DISCORD_API: &'static str = "https://discord.com/api";
|
||||
pub const DISCORD_CDN: &'static str = "https://cdn.discordapp.com/avatars";
|
||||
|
||||
pub const MAX_CONTENT_LENGTH: usize = 2000;
|
||||
pub const MAX_EMBED_DESCRIPTION_LENGTH: usize = 4096;
|
||||
|
@ -137,6 +137,7 @@ pub async fn initialize(
|
||||
routes::dashboard::user::get_user_info,
|
||||
routes::dashboard::user::update_user_info,
|
||||
routes::dashboard::user::get_user_guilds,
|
||||
routes::dashboard::guild::get_guild_patreon,
|
||||
routes::dashboard::guild::get_guild_channels,
|
||||
routes::dashboard::guild::get_guild_roles,
|
||||
routes::dashboard::guild::get_reminder_templates,
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::env;
|
||||
|
||||
use base64;
|
||||
use chrono::Utc;
|
||||
use rocket::{
|
||||
@ -10,7 +12,7 @@ use serenity::{
|
||||
client::Context,
|
||||
model::{
|
||||
channel::GuildChannel,
|
||||
id::{ChannelId, GuildId},
|
||||
id::{ChannelId, GuildId, RoleId},
|
||||
},
|
||||
};
|
||||
use sqlx::{MySql, Pool};
|
||||
@ -18,10 +20,10 @@ use sqlx::{MySql, Pool};
|
||||
use crate::{
|
||||
check_guild_subscription, check_subscription,
|
||||
consts::{
|
||||
DAY, DISCORD_CDN, MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH,
|
||||
MAX_EMBED_DESCRIPTION_LENGTH, MAX_EMBED_FIELDS, MAX_EMBED_FIELD_TITLE_LENGTH,
|
||||
MAX_EMBED_FIELD_VALUE_LENGTH, MAX_EMBED_FOOTER_LENGTH, MAX_EMBED_TITLE_LENGTH,
|
||||
MAX_URL_LENGTH, MAX_USERNAME_LENGTH, MIN_INTERVAL,
|
||||
DAY, MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH, MAX_EMBED_DESCRIPTION_LENGTH,
|
||||
MAX_EMBED_FIELDS, MAX_EMBED_FIELD_TITLE_LENGTH, MAX_EMBED_FIELD_VALUE_LENGTH,
|
||||
MAX_EMBED_FOOTER_LENGTH, MAX_EMBED_TITLE_LENGTH, MAX_URL_LENGTH, MAX_USERNAME_LENGTH,
|
||||
MIN_INTERVAL,
|
||||
},
|
||||
routes::dashboard::{
|
||||
create_database_channel, generate_uid, name_default, template_name_default, DeleteReminder,
|
||||
@ -37,19 +39,45 @@ struct ChannelInfo {
|
||||
webhook_name: Option<String>,
|
||||
}
|
||||
|
||||
#[get("/api/guild/<id>/channels")]
|
||||
pub async fn get_guild_channels(
|
||||
#[get("/api/guild/<id>/patreon")]
|
||||
pub async fn get_guild_patreon(
|
||||
id: u64,
|
||||
cookies: &CookieJar<'_>,
|
||||
ctx: &State<Context>,
|
||||
pool: &State<Pool<MySql>>,
|
||||
) -> JsonValue {
|
||||
check_authorization!(cookies, ctx.inner(), id);
|
||||
|
||||
match GuildId(id).to_guild_cached(ctx.inner()) {
|
||||
Some(guild) => {
|
||||
let mut channel_info = vec![];
|
||||
let member_res = GuildId(env::var("PATREON_GUILD_ID").unwrap().parse().unwrap())
|
||||
.member(&ctx.inner(), guild.owner_id)
|
||||
.await;
|
||||
|
||||
let patreon = member_res.map_or(false, |member| {
|
||||
member
|
||||
.roles
|
||||
.contains(&RoleId(env::var("PATREON_ROLE_ID").unwrap().parse().unwrap()))
|
||||
});
|
||||
|
||||
json!({ "patreon": patreon })
|
||||
}
|
||||
|
||||
None => {
|
||||
json!({"error": "Bot not in guild"})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/api/guild/<id>/channels")]
|
||||
pub async fn get_guild_channels(
|
||||
id: u64,
|
||||
cookies: &CookieJar<'_>,
|
||||
ctx: &State<Context>,
|
||||
) -> JsonValue {
|
||||
check_authorization!(cookies, ctx.inner(), id);
|
||||
|
||||
match GuildId(id).to_guild_cached(ctx.inner()) {
|
||||
Some(guild) => {
|
||||
let mut channels = guild
|
||||
.channels
|
||||
.iter()
|
||||
@ -59,17 +87,15 @@ pub async fn get_guild_channels(
|
||||
|
||||
channels.sort_by(|(_, c1), (_, c2)| c1.position.cmp(&c2.position));
|
||||
|
||||
// todo change to map
|
||||
for (channel_id, channel) in channels {
|
||||
let mut ch = ChannelInfo {
|
||||
let channel_info = channels
|
||||
.iter()
|
||||
.map(|(channel_id, channel)| ChannelInfo {
|
||||
name: channel.name.to_string(),
|
||||
id: channel_id.to_string(),
|
||||
webhook_avatar: None,
|
||||
webhook_name: None,
|
||||
};
|
||||
|
||||
channel_info.push(ch);
|
||||
}
|
||||
})
|
||||
.collect::<Vec<ChannelInfo>>();
|
||||
|
||||
json!(channel_info)
|
||||
}
|
||||
|
@ -563,3 +563,16 @@ textarea, input {
|
||||
.button.is-outlined.is-success {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.is-locked {
|
||||
pointer-events: none;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.is-locked .foreground {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.is-locked .field:last-of-type {
|
||||
display: none;
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ let channels = [];
|
||||
let roles = [];
|
||||
let templates = {};
|
||||
|
||||
let globalPatreon = false;
|
||||
|
||||
function guildId() {
|
||||
return document.querySelector(".guildList a.is-active").dataset["guild"];
|
||||
}
|
||||
@ -221,6 +223,10 @@ async function serialize_reminder(node, mode) {
|
||||
if (node.querySelector('input[name="attachment"]').files.length > 0) {
|
||||
let file = node.querySelector('input[name="attachment"]').files[0];
|
||||
|
||||
if (file.size >= 8 * 1024 * 1024) {
|
||||
return { error: "File too large." };
|
||||
}
|
||||
|
||||
attachment = await new Promise((resolve) => {
|
||||
let fileReader = new FileReader();
|
||||
fileReader.onload = (e) => resolve(fileReader.result);
|
||||
@ -240,6 +246,34 @@ async function serialize_reminder(node, mode) {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
const content = node.querySelector('textarea[name="content"]').value;
|
||||
const embed_author_url = has_source(node.querySelector("img.embed_author_url").src);
|
||||
const embed_author = node.querySelector('textarea[name="embed_author"]').value;
|
||||
const embed_description = node.querySelector(
|
||||
'textarea[name="embed_description"]'
|
||||
).value;
|
||||
const embed_footer = node.querySelector('textarea[name="embed_footer"]').value;
|
||||
const embed_footer_url = has_source(node.querySelector("img.embed_footer_url").src);
|
||||
const embed_image_url = has_source(node.querySelector("img.embed_image_url").src);
|
||||
const embed_thumbnail_url = has_source(
|
||||
node.querySelector("img.embed_thumbnail_url").src
|
||||
);
|
||||
const embed_title = node.querySelector('textarea[name="embed_title"]').value;
|
||||
|
||||
if (
|
||||
attachment === null &&
|
||||
content.length == 0 &&
|
||||
embed_author_url === null &&
|
||||
embed_author.length == 0 &&
|
||||
embed_description.length == 0 &&
|
||||
embed_footer.length == 0 &&
|
||||
embed_footer_url === null &&
|
||||
embed_image_url === null &&
|
||||
embed_thumbnail_url === null
|
||||
) {
|
||||
return { error: "Reminder needs content." };
|
||||
}
|
||||
|
||||
return {
|
||||
// if we're creating a reminder, ignore this field
|
||||
uid: uid,
|
||||
@ -250,18 +284,16 @@ async function serialize_reminder(node, mode) {
|
||||
attachment_name: attachment_name,
|
||||
avatar: has_source(node.querySelector("img.discord-avatar").src),
|
||||
channel: node.querySelector("select.channel-selector").value,
|
||||
content: node.querySelector('textarea[name="content"]').value,
|
||||
embed_author_url: has_source(node.querySelector("img.embed_author_url").src),
|
||||
embed_author: node.querySelector('textarea[name="embed_author"]').value,
|
||||
content: content,
|
||||
embed_author_url: embed_author_url,
|
||||
embed_author: embed_author,
|
||||
embed_color: color,
|
||||
embed_description: node.querySelector('textarea[name="embed_description"]').value,
|
||||
embed_footer: node.querySelector('textarea[name="embed_footer"]').value,
|
||||
embed_footer_url: has_source(node.querySelector("img.embed_footer_url").src),
|
||||
embed_image_url: has_source(node.querySelector("img.embed_image_url").src),
|
||||
embed_thumbnail_url: has_source(
|
||||
node.querySelector("img.embed_thumbnail_url").src
|
||||
),
|
||||
embed_title: node.querySelector('textarea[name="embed_title"]').value,
|
||||
embed_description: embed_description,
|
||||
embed_footer: embed_footer,
|
||||
embed_footer_url: embed_footer_url,
|
||||
embed_image_url: embed_image_url,
|
||||
embed_thumbnail_url: embed_thumbnail_url,
|
||||
embed_title: embed_title,
|
||||
embed_fields: fields,
|
||||
expires: expiration_time,
|
||||
interval_seconds: mode !== "template" ? interval.seconds : null,
|
||||
@ -325,7 +357,7 @@ function deserialize_reminder(reminder, frame, mode) {
|
||||
}).setZone(timezone);
|
||||
timeInput.value = localTime.toFormat("yyyy-LL-dd'T'HH:mm:ss");
|
||||
|
||||
if (reminder['expires']) {
|
||||
if (reminder["expires"]) {
|
||||
let expiresInput = frame.querySelector('input[name="time"]');
|
||||
let expiresTime = luxon.DateTime.fromISO(reminder["expires"], {
|
||||
zone: "UTC",
|
||||
@ -522,6 +554,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
} else {
|
||||
if (data.timezone !== null) botTimezone = data.timezone;
|
||||
|
||||
globalPatreon = data.patreon;
|
||||
|
||||
update_times();
|
||||
}
|
||||
});
|
||||
@ -722,19 +756,20 @@ $deleteTemplateBtn.addEventListener("click", (ev) => {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({id: parseInt($templateSelect.value)}),
|
||||
body: JSON.stringify({ id: parseInt($templateSelect.value) }),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (data.error) {
|
||||
show_error(data.error)
|
||||
show_error(data.error);
|
||||
} else {
|
||||
$templateSelect.querySelector(`option[value="${$templateSelect.value}"]`).remove();
|
||||
$templateSelect
|
||||
.querySelector(`option[value="${$templateSelect.value}"]`)
|
||||
.remove();
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
document.querySelectorAll("textarea.autoresize").forEach((element) => {
|
||||
element.addEventListener("input", () => {
|
||||
element.style.height = "";
|
||||
@ -785,16 +820,6 @@ document.addEventListener("remindersLoaded", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const $showInterval = document.querySelectorAll("a.intervalLabel");
|
||||
|
||||
$showInterval.forEach((element) => {
|
||||
element.addEventListener("click", () => {
|
||||
element.querySelector("i").classList.toggle("fa-chevron-right");
|
||||
element.querySelector("i").classList.toggle("fa-chevron-down");
|
||||
element.nextElementSibling.classList.toggle("is-hidden");
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll(".change-color").forEach((element) => {
|
||||
element.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
|
@ -158,43 +158,45 @@
|
||||
</div>
|
||||
|
||||
<div class="collapses">
|
||||
<div class="field">
|
||||
<a class="intervalLabel"><label class="label">Interval <i class="fas fa-chevron-down"></i></label></a>
|
||||
<div class="control intervalSelector" style="min-width: 400px;" >
|
||||
<div class="input interval-group">
|
||||
<div class="interval-group-left">
|
||||
<label>
|
||||
<span class="is-sr-only">Interval months</span>
|
||||
<input class="w2" type="text" pattern="\d*" name="interval_months" maxlength="2" placeholder=""> <span class="half-rem"></span> months, <span class="half-rem"></span>
|
||||
</label>
|
||||
<label>
|
||||
<span class="is-sr-only">Interval days</span>
|
||||
<input class="w3" type="text" pattern="\d*" name="interval_days" maxlength="4" placeholder=""> <span class="half-rem"></span> days, <span class="half-rem"></span>
|
||||
</label>
|
||||
<label>
|
||||
<span class="is-sr-only">Interval hours</span>
|
||||
<input class="w2" type="text" pattern="\d*" name="interval_hours" maxlength="2" placeholder="HH">:
|
||||
</label>
|
||||
<label>
|
||||
<span class="is-sr-only">Interval minutes</span>
|
||||
<input class="w2" type="text" pattern="\d*" name="interval_minutes" maxlength="2" placeholder="MM">:
|
||||
</label>
|
||||
<label>
|
||||
<span class="is-sr-only">Interval seconds</span>
|
||||
<input class="w2" type="text" pattern="\d*" name="interval_seconds" maxlength="2" placeholder="SS">
|
||||
</label>
|
||||
<div class="is-locked">
|
||||
<div class="field">
|
||||
<label class="label">Interval <a class="foreground" href="/help/interval"><i class="fas fa-question-circle"></i></a></label>
|
||||
<div class="control intervalSelector" style="min-width: 400px;" >
|
||||
<div class="input interval-group">
|
||||
<div class="interval-group-left">
|
||||
<label>
|
||||
<span class="is-sr-only">Interval months</span>
|
||||
<input class="w2" type="text" pattern="\d*" name="interval_months" maxlength="2" placeholder=""> <span class="half-rem"></span> months, <span class="half-rem"></span>
|
||||
</label>
|
||||
<label>
|
||||
<span class="is-sr-only">Interval days</span>
|
||||
<input class="w3" type="text" pattern="\d*" name="interval_days" maxlength="4" placeholder=""> <span class="half-rem"></span> days, <span class="half-rem"></span>
|
||||
</label>
|
||||
<label>
|
||||
<span class="is-sr-only">Interval hours</span>
|
||||
<input class="w2" type="text" pattern="\d*" name="interval_hours" maxlength="2" placeholder="HH">:
|
||||
</label>
|
||||
<label>
|
||||
<span class="is-sr-only">Interval minutes</span>
|
||||
<input class="w2" type="text" pattern="\d*" name="interval_minutes" maxlength="2" placeholder="MM">:
|
||||
</label>
|
||||
<label>
|
||||
<span class="is-sr-only">Interval seconds</span>
|
||||
<input class="w2" type="text" pattern="\d*" name="interval_seconds" maxlength="2" placeholder="SS">
|
||||
</label>
|
||||
</div>
|
||||
<button class="clear"><span class="is-sr-only">Clear interval</span><span class="icon"><i class="fas fa-trash"></i></span></button>
|
||||
</div>
|
||||
<button class="clear"><span class="is-sr-only">Clear interval</span><span class="icon"><i class="fas fa-trash"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<label class="label">
|
||||
Expiration
|
||||
<input class="input" type="datetime-local" step="1" name="expiration">
|
||||
</label>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<label class="label">
|
||||
Expiration
|
||||
<input class="input" type="datetime-local" step="1" name="expiration">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -226,27 +228,29 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="pad-left"></span>
|
||||
{% if creating %}
|
||||
<button class="button is-success" id="createReminder">
|
||||
<span>Create Reminder</span> <span class="icon"><i class="fas fa-sparkles"></i></span>
|
||||
</button>
|
||||
<button class="button is-success is-outlined" id="createTemplate">
|
||||
<span>Create Template</span> <span class="icon"><i class="fas fa-file-spreadsheet"></i></span>
|
||||
</button>
|
||||
<button class="button is-outlined show-modal is-pulled-right" data-modal="chooseTemplateModal">
|
||||
Load Template
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="button is-success save-btn">
|
||||
<span>Save</span> <span class="icon"><i class="fas fa-save"></i></span>
|
||||
</button>
|
||||
<button class="button is-warning disable-enable">
|
||||
</button>
|
||||
<button class="button is-danger delete-reminder">
|
||||
Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
<div>
|
||||
<span class="pad-left"></span>
|
||||
{% if creating %}
|
||||
<button class="button is-success" id="createReminder">
|
||||
<span>Create Reminder</span> <span class="icon"><i class="fas fa-sparkles"></i></span>
|
||||
</button>
|
||||
<button class="button is-success is-outlined" id="createTemplate">
|
||||
<span>Create Template</span> <span class="icon"><i class="fas fa-file-spreadsheet"></i></span>
|
||||
</button>
|
||||
<button class="button is-outlined show-modal is-pulled-right" data-modal="chooseTemplateModal">
|
||||
Load Template
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="button is-success save-btn">
|
||||
<span>Save</span> <span class="icon"><i class="fas fa-save"></i></span>
|
||||
</button>
|
||||
<button class="button is-warning disable-enable">
|
||||
</button>
|
||||
<button class="button is-danger delete-reminder">
|
||||
Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user