Move postman and web inside src
This commit is contained in:
1 parent
075fde71df
commit
4a80d42f86
152 files changed
+833
-779
No files matched your search
Generated
+572
-324
File diff suppressed because it is too large.
Load diff
+8
-7
@@ -10,7 +10,7 @@ description = "Reminder Bot for Discord, now in Rust"
|
||||
poise = "0.6.1"
|
||||
dotenv = "0.15"
|
||||
tokio = { version = "1", features = ["process", "full"] }
|
||||
reqwest = "0.11"
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
lazy-regex = "3.1"
|
||||
regex = "1.10"
|
||||
log = "0.4"
|
||||
@@ -29,12 +29,13 @@ sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "macros", "mysql",
|
||||
base64 = "0.21"
|
||||
secrecy = "0.8.0"
|
||||
futures = "0.3.30"
|
||||
|
||||
[dependencies.postman]
|
||||
path = "postman"
|
||||
|
||||
[dependencies.reminder_web]
|
||||
path = "web"
|
||||
prometheus = "0.13.3"
|
||||
rocket = { version = "0.5.0", features = ["tls", "secrets", "json"] }
|
||||
rocket_dyn_templates = { version = "0.1.0", features = ["tera"] }
|
||||
serenity = { version = "0.12", default-features = false, features = ["builder", "cache", "client", "gateway", "http", "model", "utils", "rustls_backend"] }
|
||||
oauth2 = "4"
|
||||
csv = "1.2"
|
||||
axum = "0.7"
|
||||
|
||||
[dependencies.extract_derive]
|
||||
path = "extract_derive"
|
||||
|
||||
+11
-11
@@ -1,28 +1,28 @@
|
||||
[default]
|
||||
address = "0.0.0.0"
|
||||
port = 18920
|
||||
template_dir = "web/templates"
|
||||
template_dir = "templates"
|
||||
limits = { json = "10MiB" }
|
||||
|
||||
[debug]
|
||||
secret_key = "tR8krio5FXTnnyIZNiJDXPondz0kI1v6X6BXZcBGIRY="
|
||||
|
||||
[debug.tls]
|
||||
certs = "web/private/rsa_sha256_cert.pem"
|
||||
key = "web/private/rsa_sha256_key.pem"
|
||||
certs = "private/rsa_sha256_cert.pem"
|
||||
key = "private/rsa_sha256_key.pem"
|
||||
|
||||
[debug.rsa_sha256.tls]
|
||||
certs = "web/private/rsa_sha256_cert.pem"
|
||||
key = "web/private/rsa_sha256_key.pem"
|
||||
certs = "private/rsa_sha256_cert.pem"
|
||||
key = "private/rsa_sha256_key.pem"
|
||||
|
||||
[debug.ecdsa_nistp256_sha256.tls]
|
||||
certs = "web/private/ecdsa_nistp256_sha256_cert.pem"
|
||||
key = "web/private/ecdsa_nistp256_sha256_key_pkcs8.pem"
|
||||
certs = "private/ecdsa_nistp256_sha256_cert.pem"
|
||||
key = "private/ecdsa_nistp256_sha256_key_pkcs8.pem"
|
||||
|
||||
[debug.ecdsa_nistp384_sha384.tls]
|
||||
certs = "web/private/ecdsa_nistp384_sha384_cert.pem"
|
||||
key = "web/private/ecdsa_nistp384_sha384_key_pkcs8.pem"
|
||||
certs = "private/ecdsa_nistp384_sha384_cert.pem"
|
||||
key = "private/ecdsa_nistp384_sha384_key_pkcs8.pem"
|
||||
|
||||
[debug.ed25519.tls]
|
||||
certs = "web/private/ed25519_cert.pem"
|
||||
key = "eb/private/ed25519_key.pem"
|
||||
certs = "private/ed25519_cert.pem"
|
||||
key = "private/ed25519_key.pem"
|
||||
+26
-26
@@ -1,41 +1,41 @@
|
||||
server {
|
||||
server_name www.reminder-bot.com;
|
||||
server_name www.reminder-bot.com;
|
||||
|
||||
return 301 $scheme://reminder-bot.com$request_uri;
|
||||
return 301 $scheme://reminder-bot.com$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name reminder-bot.com;
|
||||
listen 80;
|
||||
server_name reminder-bot.com;
|
||||
|
||||
return 301 https://reminder-bot.com$request_uri;
|
||||
return 301 https://reminder-bot.com$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name reminder-bot.com;
|
||||
listen 443 ssl;
|
||||
server_name reminder-bot.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/reminder-bot.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/reminder-bot.com/privkey.pem;
|
||||
ssl_certificate /etc/letsencrypt/live/reminder-bot.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/reminder-bot.com/privkey.pem;
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log;
|
||||
|
||||
proxy_buffer_size 128k;
|
||||
proxy_buffers 4 256k;
|
||||
proxy_busy_buffers_size 256k;
|
||||
proxy_buffer_size 128k;
|
||||
proxy_buffers 4 256k;
|
||||
proxy_busy_buffers_size 256k;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:18920;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
location / {
|
||||
proxy_pass http://localhost:18920;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /static {
|
||||
alias /var/www/reminder-rs/static;
|
||||
expires 30d;
|
||||
}
|
||||
location /static {
|
||||
alias /var/www/reminder-rs/static;
|
||||
expires 30d;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
[package]
|
||||
name = "postman"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["process", "full"] }
|
||||
regex = "1.9"
|
||||
log = "0.4"
|
||||
chrono = "0.4"
|
||||
chrono-tz = { version = "0.8", features = ["serde"] }
|
||||
lazy_static = "1.4"
|
||||
num-integer = "0.1"
|
||||
serde = "1.0"
|
||||
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono", "json"]}
|
||||
serenity = { version = "0.12", default-features = false, features = ["builder", "cache", "client", "gateway", "http", "model", "utils", "rustls_backend"] }
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,4 +1,4 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use chrono::DateTime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
@@ -24,10 +24,10 @@ impl Recordable for Options {
|
||||
let parsed = natural_parser(&until, &timezone.to_string()).await;
|
||||
|
||||
if let Some(timestamp) = parsed {
|
||||
match NaiveDateTime::from_timestamp_opt(timestamp, 0) {
|
||||
match DateTime::from_timestamp(timestamp, 0) {
|
||||
Some(dt) => {
|
||||
channel.paused = true;
|
||||
channel.paused_until = Some(dt);
|
||||
channel.paused_until = Some(dt.naive_utc());
|
||||
|
||||
channel.commit_changes(&ctx.data().database).await;
|
||||
|
||||
|
||||
+11
-3
@@ -12,12 +12,15 @@ mod event_handlers;
|
||||
#[cfg(not(test))]
|
||||
mod hooks;
|
||||
mod interval_parser;
|
||||
mod metrics;
|
||||
#[cfg(not(test))]
|
||||
mod models;
|
||||
mod postman;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
mod time_parser;
|
||||
mod utils;
|
||||
mod web;
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@@ -28,7 +31,7 @@ use std::{
|
||||
};
|
||||
|
||||
use chrono_tz::Tz;
|
||||
use log::{error, warn};
|
||||
use log::warn;
|
||||
use poise::serenity_prelude::{
|
||||
model::{
|
||||
gateway::GatewayIntents,
|
||||
@@ -39,6 +42,7 @@ use poise::serenity_prelude::{
|
||||
use sqlx::{MySql, Pool};
|
||||
use tokio::sync::{broadcast, broadcast::Sender, RwLock};
|
||||
|
||||
use crate::metrics::init_metrics;
|
||||
#[cfg(test)]
|
||||
use crate::test::TestContext;
|
||||
#[cfg(not(test))]
|
||||
@@ -206,6 +210,10 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Start metrics
|
||||
init_metrics();
|
||||
tokio::spawn(async { metrics::serve().await });
|
||||
|
||||
let database =
|
||||
Pool::connect(&env::var("DATABASE_URL").expect("No database URL provided")).await.unwrap();
|
||||
|
||||
@@ -249,7 +257,7 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
|
||||
match postman::initialize(kill_recv, ctx1, &pool1).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!("postman exiting: {}", e);
|
||||
panic!("postman exiting: {}", e);
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -259,7 +267,7 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
|
||||
|
||||
if !run_settings.contains("web") {
|
||||
tokio::spawn(async move {
|
||||
reminder_web::initialize(kill_tx, ctx2, pool2).await.unwrap();
|
||||
web::initialize(kill_tx, ctx2, pool2).await.unwrap();
|
||||
});
|
||||
} else {
|
||||
warn!("Not running web");
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
use axum::{routing::get, Router};
|
||||
use lazy_static::lazy_static;
|
||||
use log::warn;
|
||||
use prometheus::{IntCounterVec, Opts, Registry};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref REGISTRY: Registry = Registry::new();
|
||||
pub static ref REQUEST_COUNTER: IntCounterVec =
|
||||
IntCounterVec::new(Opts::new("requests", "Requests"), &["method", "status", "route"])
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn init_metrics() {
|
||||
REGISTRY.register(Box::new(REQUEST_COUNTER.clone())).unwrap();
|
||||
}
|
||||
|
||||
pub async fn serve() {
|
||||
let app = Router::new().route("/metrics", get(metrics));
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("localhost:31756").await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
||||
async fn metrics() -> String {
|
||||
let encoder = prometheus::TextEncoder::new();
|
||||
let res_custom = encoder.encode_to_string(®ISTRY.gather());
|
||||
|
||||
match res_custom {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
warn!("Error encoding metrics: {:?}", e);
|
||||
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use chrono::{Duration, NaiveDateTime, Utc};
|
||||
use chrono::{DateTime, NaiveDateTime, TimeDelta, Utc};
|
||||
use chrono_tz::Tz;
|
||||
use poise::serenity_prelude::{
|
||||
model::id::{ChannelId, GuildId, UserId},
|
||||
@@ -73,7 +73,7 @@ impl ReminderBuilder {
|
||||
|
||||
match queried_time.utc_time {
|
||||
Some(utc_time) => {
|
||||
if utc_time < (Utc::now() - Duration::seconds(60)).naive_local() {
|
||||
if utc_time < (Utc::now() - TimeDelta::try_minutes(1).unwrap()).naive_local() {
|
||||
Err(ReminderError::PastTime)
|
||||
} else {
|
||||
sqlx::query!(
|
||||
@@ -165,7 +165,7 @@ impl<'a> MultiReminderBuilder<'a> {
|
||||
}
|
||||
|
||||
pub fn time<T: Into<i64>>(mut self, time: T) -> Self {
|
||||
if let Some(utc_time) = NaiveDateTime::from_timestamp_opt(time.into(), 0) {
|
||||
if let Some(utc_time) = DateTime::from_timestamp(time.into(), 0).map(|d| d.naive_utc()) {
|
||||
self.utc_time = utc_time;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,8 @@ impl<'a> MultiReminderBuilder<'a> {
|
||||
}
|
||||
|
||||
pub fn expires<T: Into<i64>>(mut self, time: Option<T>) -> Self {
|
||||
self.expires = time.map(|t| NaiveDateTime::from_timestamp_opt(t.into(), 0)).flatten();
|
||||
self.expires =
|
||||
time.map(|t| DateTime::from_timestamp(t.into(), 0)).flatten().map(|d| d.naive_utc());
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Reminder {
|
||||
pub id: u32,
|
||||
pub uid: String,
|
||||
|
||||
@@ -4,6 +4,7 @@ use sqlx::MySqlPool;
|
||||
pub struct Timer {
|
||||
pub name: String,
|
||||
pub start_time: DateTime<Utc>,
|
||||
#[allow(dead_code)]
|
||||
pub owner: u64,
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::consts::LOCAL_TIMEZONE;
|
||||
|
||||
pub struct UserData {
|
||||
pub id: u32,
|
||||
#[allow(dead_code)]
|
||||
pub user: u64,
|
||||
pub dm_channel: u32,
|
||||
pub timezone: String,
|
||||
@@ -22,7 +23,7 @@ impl UserData {
|
||||
|
||||
match sqlx::query!(
|
||||
"
|
||||
SELECT IFNULL(timezone, 'UTC') AS timezone FROM users WHERE user = ?
|
||||
SELECT IFNULL(timezone, 'UTC') AS timezone FROM users WHERE user = ?
|
||||
",
|
||||
user_id
|
||||
)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
use axum::{routing::get, Router};
|
||||
use lazy_static;
|
||||
use log::warn;
|
||||
use prometheus::{register_int_counter, IntCounter, Registry};
|
||||
|
||||
lazy_static! {
|
||||
static ref REGISTRY: Registry = Registry::new();
|
||||
pub static ref REMINDERS_SENT: IntCounter =
|
||||
register_int_counter!("reminders_sent", "Number of reminders sent").unwrap();
|
||||
pub static ref REMINDERS_FAILED: IntCounter =
|
||||
register_int_counter!("reminders_failed", "Number of reminders failed").unwrap();
|
||||
}
|
||||
|
||||
pub fn init_metrics() {
|
||||
REGISTRY.register(Box::new(REMINDERS_SENT.clone())).unwrap();
|
||||
REGISTRY.register(Box::new(REMINDERS_FAILED.clone())).unwrap();
|
||||
}
|
||||
|
||||
pub async fn serve() {
|
||||
let app = Router::new().route("/metrics", get(metrics));
|
||||
|
||||
let metrics_port = std::env("PROMETHEUS_PORT").unwrap();
|
||||
let listener =
|
||||
tokio::net::TcpListener::bind(format!("localhost:{}", metrics_port)).await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
||||
async fn metrics() -> String {
|
||||
let encoder = prometheus::TextEncoder::new();
|
||||
let res_custom = encoder.encode_to_string(®ISTRY.gather());
|
||||
|
||||
match res_custom {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
warn!("Error encoding metrics: {:?}", e);
|
||||
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ mod sender;
|
||||
use std::env;
|
||||
|
||||
use log::{info, warn};
|
||||
use serenity::client::Context;
|
||||
use poise::serenity_prelude::client::Context;
|
||||
use sqlx::{Executor, MySql};
|
||||
use tokio::{
|
||||
sync::broadcast::Receiver,
|
||||
@@ -1,13 +1,11 @@
|
||||
use std::env;
|
||||
|
||||
use chrono::{DateTime, Days, Duration, Months};
|
||||
use chrono::{DateTime, Days, Months, TimeDelta};
|
||||
use chrono_tz::Tz;
|
||||
use lazy_static::lazy_static;
|
||||
use log::{error, info, warn};
|
||||
use num_integer::Integer;
|
||||
use regex::{Captures, Regex};
|
||||
use serde::Deserialize;
|
||||
use serenity::{
|
||||
use poise::serenity_prelude::{
|
||||
all::{CreateAttachment, CreateEmbedFooter},
|
||||
builder::{CreateEmbed, CreateEmbedAuthor, CreateMessage, ExecuteWebhook},
|
||||
http::{CacheHttp, Http, HttpError},
|
||||
@@ -18,6 +16,8 @@ use serenity::{
|
||||
},
|
||||
Error, Result,
|
||||
};
|
||||
use regex::{Captures, Regex};
|
||||
use serde::Deserialize;
|
||||
use sqlx::{
|
||||
types::{
|
||||
chrono::{NaiveDateTime, Utc},
|
||||
@@ -66,15 +66,15 @@ pub fn substitute(string: &str) -> String {
|
||||
let format = caps.name("format").map(|m| m.as_str());
|
||||
|
||||
if let (Some(final_time), Some(format)) = (final_time, format) {
|
||||
match NaiveDateTime::from_timestamp_opt(final_time, 0) {
|
||||
match DateTime::from_timestamp(final_time, 0) {
|
||||
Some(dt) => {
|
||||
let now = Utc::now().naive_utc();
|
||||
let now = Utc::now();
|
||||
|
||||
let difference = {
|
||||
if now < dt {
|
||||
dt - Utc::now().naive_utc()
|
||||
dt - Utc::now()
|
||||
} else {
|
||||
Utc::now().naive_utc() - dt
|
||||
Utc::now() - dt
|
||||
}
|
||||
};
|
||||
|
||||
@@ -397,7 +397,13 @@ impl Reminder {
|
||||
}
|
||||
|
||||
if let Some(interval) = self.interval_seconds {
|
||||
updated_reminder_time += Duration::seconds(interval as i64);
|
||||
updated_reminder_time += TimeDelta::try_seconds(interval as i64)
|
||||
.unwrap_or_else(|| {
|
||||
warn!("{}: Could not add {} seconds to a reminder", self.id, interval);
|
||||
fail_count += 1;
|
||||
|
||||
TimeDelta::zero()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rocket::serde::json::json;
|
||||
use rocket::{catch, serde::json::json};
|
||||
use rocket_dyn_templates::Template;
|
||||
|
||||
use crate::JsonValue;
|
||||
use crate::web::JsonValue;
|
||||
|
||||
#[catch(403)]
|
||||
pub(crate) async fn forbidden() -> Template {
|
||||
@@ -20,14 +20,14 @@ pub const DAY: usize = 24 * HOUR;
|
||||
|
||||
pub const CHARACTERS: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
||||
|
||||
use std::{collections::HashSet, env, iter::FromIterator};
|
||||
use std::{collections::HashSet, env};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use serenity::builder::CreateAttachment;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref DEFAULT_AVATAR: CreateAttachment = CreateAttachment::bytes(
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/../assets/webhook.jpg")) as &[u8],
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/webhook.jpg")) as &[u8],
|
||||
"webhook.jpg",
|
||||
);
|
||||
pub static ref SUBSCRIPTION_ROLES: HashSet<u64> = HashSet::from_iter(
|
||||
File renamed without changes.
@@ -20,6 +20,7 @@ impl Transaction<'_> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum TransactionError {
|
||||
Error(sqlx::Error),
|
||||
Missing,
|
||||
File renamed without changes.
@@ -0,0 +1,27 @@
|
||||
use rocket::{
|
||||
fairing::{Fairing, Info, Kind},
|
||||
Request, Response,
|
||||
};
|
||||
|
||||
use crate::metrics::REQUEST_COUNTER;
|
||||
|
||||
pub struct MetricProducer;
|
||||
|
||||
#[rocket::async_trait]
|
||||
impl Fairing for MetricProducer {
|
||||
fn info(&self) -> Info {
|
||||
Info { name: "Metrics fairing", kind: Kind::Response }
|
||||
}
|
||||
|
||||
async fn on_response<'r>(&self, req: &'r Request<'_>, resp: &mut Response<'r>) {
|
||||
if let Some(route) = req.route() {
|
||||
REQUEST_COUNTER
|
||||
.with_label_values(&[
|
||||
req.method().as_str(),
|
||||
&resp.status().code.to_string(),
|
||||
&route.uri.to_string(),
|
||||
])
|
||||
.inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
mod consts;
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
@@ -11,24 +8,27 @@ mod routes;
|
||||
|
||||
use std::{env, path::Path};
|
||||
|
||||
use log::{error, info, warn};
|
||||
use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, TokenUrl};
|
||||
use rocket::{
|
||||
fs::FileServer,
|
||||
http::CookieJar,
|
||||
serde::json::{json, Value as JsonValue},
|
||||
tokio::sync::broadcast::Sender,
|
||||
};
|
||||
use rocket_dyn_templates::Template;
|
||||
use serenity::{
|
||||
use poise::serenity_prelude::{
|
||||
client::Context,
|
||||
http::CacheHttp,
|
||||
model::id::{GuildId, UserId},
|
||||
};
|
||||
use rocket::{
|
||||
catchers,
|
||||
fs::FileServer,
|
||||
http::CookieJar,
|
||||
routes,
|
||||
serde::json::{json, Value as JsonValue},
|
||||
tokio::sync::broadcast::Sender,
|
||||
};
|
||||
use rocket_dyn_templates::Template;
|
||||
use sqlx::{MySql, Pool};
|
||||
|
||||
use crate::{
|
||||
use crate::web::{
|
||||
consts::{CNC_GUILD, DISCORD_OAUTH_AUTHORIZE, DISCORD_OAUTH_TOKEN, SUBSCRIPTION_ROLES},
|
||||
metrics::{init_metrics, MetricProducer},
|
||||
metrics::MetricProducer,
|
||||
};
|
||||
|
||||
type Database = MySql;
|
||||
@@ -68,9 +68,7 @@ pub async fn initialize(
|
||||
let reqwest_client = reqwest::Client::new();
|
||||
|
||||
let static_path =
|
||||
if Path::new("web/static").exists() { "web/static" } else { "/lib/reminder-rs/static" };
|
||||
|
||||
init_metrics();
|
||||
if Path::new("static").exists() { "static" } else { "/lib/reminder-rs/static" };
|
||||
|
||||
rocket::build()
|
||||
.attach(MetricProducer)
|
||||
@@ -96,7 +94,6 @@ pub async fn initialize(
|
||||
routes![
|
||||
routes::cookies,
|
||||
routes::index,
|
||||
routes::metrics::metrics,
|
||||
routes::privacy,
|
||||
routes::report::report_error,
|
||||
routes::return_to_same_site,
|
||||
@@ -154,7 +151,6 @@ pub async fn initialize(
|
||||
routes::dashboard::export::import_todos,
|
||||
],
|
||||
)
|
||||
.mount("/admin", routes![routes::admin::admin_dashboard_home, routes::admin::bot_data])
|
||||
.launch()
|
||||
.await?;
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
use rocket::{http::CookieJar, serde::json::json, State};
|
||||
use rocket::{get, http::CookieJar, serde::json::json, State};
|
||||
use serde::Serialize;
|
||||
use serenity::{
|
||||
client::Context,
|
||||
@@ -8,7 +8,7 @@ use serenity::{
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{check_authorization, routes::JsonResult};
|
||||
use crate::web::{check_authorization, routes::JsonResult};
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ChannelInfo {
|
||||
+2
-2
@@ -7,7 +7,7 @@ use std::env;
|
||||
|
||||
pub use channels::*;
|
||||
pub use reminders::*;
|
||||
use rocket::{http::CookieJar, serde::json::json, State};
|
||||
use rocket::{get, http::CookieJar, serde::json::json, State};
|
||||
pub use roles::*;
|
||||
use serenity::{
|
||||
client::Context,
|
||||
@@ -15,7 +15,7 @@ use serenity::{
|
||||
};
|
||||
pub use templates::*;
|
||||
|
||||
use crate::{check_authorization, routes::JsonResult};
|
||||
use crate::web::{check_authorization, routes::JsonResult};
|
||||
|
||||
#[get("/api/guild/<id>")]
|
||||
pub async fn get_guild_info(id: u64, cookies: &CookieJar<'_>, ctx: &State<Context>) -> JsonResult {
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
use log::warn;
|
||||
use rocket::{
|
||||
get,
|
||||
http::CookieJar,
|
||||
patch, post,
|
||||
serde::json::{json, Json},
|
||||
State,
|
||||
};
|
||||
@@ -9,7 +12,7 @@ use serenity::{
|
||||
};
|
||||
use sqlx::{MySql, Pool};
|
||||
|
||||
use crate::{
|
||||
use crate::web::{
|
||||
check_authorization, check_guild_subscription, check_subscription,
|
||||
consts::MIN_INTERVAL,
|
||||
guards::transaction::Transaction,
|
||||
+3
-2
@@ -1,8 +1,9 @@
|
||||
use rocket::{http::CookieJar, serde::json::json, State};
|
||||
use log::warn;
|
||||
use rocket::{get, http::CookieJar, serde::json::json, State};
|
||||
use serde::Serialize;
|
||||
use serenity::client::Context;
|
||||
|
||||
use crate::{check_authorization, routes::JsonResult};
|
||||
use crate::web::{check_authorization, routes::JsonResult};
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct RoleInfo {
|
||||
+4
-1
@@ -1,12 +1,15 @@
|
||||
use log::warn;
|
||||
use rocket::{
|
||||
delete, get,
|
||||
http::CookieJar,
|
||||
post,
|
||||
serde::json::{json, Json},
|
||||
State,
|
||||
};
|
||||
use serenity::client::Context;
|
||||
use sqlx::{MySql, Pool};
|
||||
|
||||
use crate::{
|
||||
use crate::web::{
|
||||
check_authorization,
|
||||
consts::{
|
||||
MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH, MAX_EMBED_DESCRIPTION_LENGTH,
|
||||
@@ -1,14 +1,16 @@
|
||||
pub mod guild;
|
||||
pub mod user;
|
||||
|
||||
use log::warn;
|
||||
use rocket::{
|
||||
delete,
|
||||
http::CookieJar,
|
||||
serde::json::{json, Json},
|
||||
State,
|
||||
};
|
||||
use sqlx::{MySql, Pool};
|
||||
|
||||
use crate::routes::{dashboard::DeleteReminder, JsonResult};
|
||||
use crate::web::routes::{dashboard::DeleteReminder, JsonResult};
|
||||
|
||||
#[delete("/api/reminders", data = "<reminder>")]
|
||||
pub async fn delete_reminder(
|
||||
+3
-1
@@ -1,5 +1,7 @@
|
||||
use log::warn;
|
||||
use reqwest::Client;
|
||||
use rocket::{
|
||||
get,
|
||||
http::CookieJar,
|
||||
serde::json::{json, Value as JsonValue},
|
||||
State,
|
||||
@@ -7,7 +9,7 @@ use rocket::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::model::{id::GuildId, permissions::Permissions};
|
||||
|
||||
use crate::consts::DISCORD_API;
|
||||
use crate::web::consts::DISCORD_API;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GuildInfo {
|
||||
@@ -8,7 +8,9 @@ use chrono_tz::Tz;
|
||||
pub use guilds::*;
|
||||
pub use reminders::*;
|
||||
use rocket::{
|
||||
get,
|
||||
http::CookieJar,
|
||||
patch,
|
||||
serde::json::{json, Json, Value as JsonValue},
|
||||
State,
|
||||
};
|
||||
+4
-63
@@ -1,11 +1,12 @@
|
||||
use chrono::{naive::NaiveDateTime, Utc};
|
||||
use futures::TryFutureExt;
|
||||
use log::warn;
|
||||
use rocket::serde::json::json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::{client::Context, futures, model::id::UserId};
|
||||
use serenity::{client::Context, model::id::UserId};
|
||||
use sqlx::types::Json;
|
||||
|
||||
use crate::{
|
||||
use crate::web::{
|
||||
check_subscription,
|
||||
consts::{
|
||||
DAY, MAX_CONTENT_LENGTH, MAX_EMBED_AUTHOR_LENGTH, MAX_EMBED_DESCRIPTION_LENGTH,
|
||||
@@ -15,10 +16,7 @@ use crate::{
|
||||
},
|
||||
guards::transaction::Transaction,
|
||||
routes::{
|
||||
dashboard::{
|
||||
create_database_channel, deserialize_optional_field, generate_uid, interval_default,
|
||||
name_default, Attachment, EmbedField, Unset,
|
||||
},
|
||||
dashboard::{create_database_channel, generate_uid, name_default, Attachment, EmbedField},
|
||||
JsonResult,
|
||||
},
|
||||
Error,
|
||||
@@ -231,60 +229,3 @@ pub async fn create_reminder(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct PatchReminder {
|
||||
pub uid: String,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub attachment: Unset<Option<Attachment>>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub attachment_name: Unset<Option<String>>,
|
||||
#[serde(default)]
|
||||
pub content: Unset<String>,
|
||||
#[serde(default)]
|
||||
pub embed_author: Unset<String>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub embed_author_url: Unset<Option<String>>,
|
||||
#[serde(default)]
|
||||
pub embed_color: Unset<u32>,
|
||||
#[serde(default)]
|
||||
pub embed_description: Unset<String>,
|
||||
#[serde(default)]
|
||||
pub embed_footer: Unset<String>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub embed_footer_url: Unset<Option<String>>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub embed_image_url: Unset<Option<String>>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub embed_thumbnail_url: Unset<Option<String>>,
|
||||
#[serde(default)]
|
||||
pub embed_title: Unset<String>,
|
||||
#[serde(default)]
|
||||
pub embed_fields: Unset<Json<Vec<EmbedField>>>,
|
||||
#[serde(default)]
|
||||
pub enabled: Unset<bool>,
|
||||
#[serde(default)]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub expires: Unset<Option<NaiveDateTime>>,
|
||||
#[serde(default = "interval_default")]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub interval_seconds: Unset<Option<u32>>,
|
||||
#[serde(default = "interval_default")]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub interval_days: Unset<Option<u32>>,
|
||||
#[serde(default = "interval_default")]
|
||||
#[serde(deserialize_with = "deserialize_optional_field")]
|
||||
pub interval_months: Unset<Option<u32>>,
|
||||
#[serde(default)]
|
||||
pub name: Unset<String>,
|
||||
#[serde(default)]
|
||||
pub tts: Unset<bool>,
|
||||
#[serde(default)]
|
||||
pub utc_time: Unset<NaiveDateTime>,
|
||||
}
|
||||
+4
-1
@@ -1,12 +1,15 @@
|
||||
use log::warn;
|
||||
use rocket::{
|
||||
get,
|
||||
http::CookieJar,
|
||||
patch, post,
|
||||
serde::json::{json, Json},
|
||||
State,
|
||||
};
|
||||
use serenity::{client::Context, model::id::UserId};
|
||||
use sqlx::{MySql, Pool};
|
||||
|
||||
use crate::{
|
||||
use crate::web::{
|
||||
check_subscription,
|
||||
guards::transaction::Transaction,
|
||||
routes::{
|
||||
@@ -1,7 +1,11 @@
|
||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||
use csv::{QuoteStyle, WriterBuilder};
|
||||
use log::warn;
|
||||
use rocket::{
|
||||
get,
|
||||
http::CookieJar,
|
||||
serde::json::{json, serde_json, Json},
|
||||
put,
|
||||
serde::json::{json, Json},
|
||||
State,
|
||||
};
|
||||
use serenity::{
|
||||
@@ -10,7 +14,7 @@ use serenity::{
|
||||
};
|
||||
use sqlx::{MySql, Pool};
|
||||
|
||||
use crate::{
|
||||
use crate::web::{
|
||||
check_authorization,
|
||||
guards::transaction::Transaction,
|
||||
routes::{
|
||||
@@ -134,7 +138,7 @@ pub(crate) async fn import_reminders(
|
||||
let user_id =
|
||||
cookies.get_private("userid").map(|c| c.value().parse::<u64>().ok()).flatten().unwrap();
|
||||
|
||||
match base64::decode(&body.body) {
|
||||
match BASE64_STANDARD.decode(&body.body) {
|
||||
Ok(body) => {
|
||||
let mut reader = csv::Reader::from_reader(body.as_slice());
|
||||
let mut count = 0;
|
||||
@@ -292,7 +296,7 @@ pub async fn import_todos(
|
||||
let channels_res = GuildId::new(id).channels(&ctx.inner()).await;
|
||||
|
||||
match channels_res {
|
||||
Ok(channels) => match base64::decode(&body.body) {
|
||||
Ok(channels) => match BASE64_STANDARD.decode(&body.body) {
|
||||
Ok(body) => {
|
||||
let mut reader = csv::Reader::from_reader(body.as_slice());
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
use std::path::Path;
|
||||
|
||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||
use chrono::{naive::NaiveDateTime, Utc};
|
||||
use log::warn;
|
||||
use rand::{rngs::OsRng, seq::IteratorRandom};
|
||||
use rocket::{fs::NamedFile, http::CookieJar, response::Redirect, serde::json::json};
|
||||
use rocket::{
|
||||
fs::NamedFile, get, http::CookieJar, response::Redirect, serde::json::json, Responder,
|
||||
};
|
||||
use rocket_dyn_templates::Template;
|
||||
use secrecy::ExposeSecret;
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
@@ -14,7 +18,7 @@ use serenity::{
|
||||
};
|
||||
use sqlx::types::Json;
|
||||
|
||||
use crate::{
|
||||
use crate::web::{
|
||||
catchers::internal_server_error,
|
||||
check_guild_subscription, check_subscription,
|
||||
consts::{
|
||||
@@ -63,7 +67,7 @@ impl<'de> Deserialize<'de> for Attachment {
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let string = String::deserialize(deserializer)?;
|
||||
Ok(Attachment(base64::decode(string).map_err(de::Error::custom)?))
|
||||
Ok(Attachment(BASE64_STANDARD.decode(string).map_err(de::Error::custom)?))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +76,7 @@ impl Serialize for Attachment {
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_str(&base64::encode(&self.0))
|
||||
serializer.collect_str(&BASE64_STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,7 +599,7 @@ async fn create_database_channel(
|
||||
ctx: impl CacheHttp,
|
||||
channel: ChannelId,
|
||||
transaction: &mut Transaction<'_>,
|
||||
) -> Result<u32, crate::Error> {
|
||||
) -> Result<u32, Error> {
|
||||
let row = sqlx::query!(
|
||||
"SELECT webhook_token, webhook_id FROM channels WHERE channel = ?",
|
||||
channel.get()
|
||||
@@ -5,13 +5,14 @@ use oauth2::{
|
||||
};
|
||||
use reqwest::Client;
|
||||
use rocket::{
|
||||
get,
|
||||
http::{private::cookie::Expiration, Cookie, CookieJar, SameSite},
|
||||
response::{Flash, Redirect},
|
||||
uri, State,
|
||||
};
|
||||
use serenity::model::user::User;
|
||||
|
||||
use crate::{consts::DISCORD_API, routes};
|
||||
use crate::web::{consts::DISCORD_API, routes};
|
||||
|
||||
#[get("/discord")]
|
||||
pub async fn discord_login(
|
||||
@@ -1,12 +1,10 @@
|
||||
pub mod admin;
|
||||
pub mod dashboard;
|
||||
pub mod login;
|
||||
pub mod metrics;
|
||||
pub mod report;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rocket::{request::FlashMessage, serde::json::Value as JsonValue};
|
||||
use rocket::{get, request::FlashMessage, serde::json::Value as JsonValue};
|
||||
use rocket_dyn_templates::Template;
|
||||
|
||||
pub type JsonResult = Result<JsonValue, JsonValue>;
|
||||
@@ -1,12 +1,14 @@
|
||||
use log::error;
|
||||
use rocket::{
|
||||
http::CookieJar,
|
||||
post,
|
||||
serde::{
|
||||
json::{json, Json},
|
||||
Deserialize,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::routes::JsonResult;
|
||||
use crate::web::routes::JsonResult;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ClientError {
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Symlink
+1
@@ -0,0 +1 @@
|
||||
/home/jude/reminder-bot/reminder-dashboard/dist/index.html
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 152 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user