Compare commits

..
Author SHA1 Message Date
jude 9a6b65f3a3 Don't delete guild data when guild becomes unavailable 2024-09-17 23:47:27 +01:00
jude b6ff149d51 Fix macro list/delete 2024-09-14 12:07:09 +01:00
jude 748e33566b Fix patreon not sharing between guild members 2024-08-19 21:50:14 +01:00
jude d7e90614c8 Bump ver 2024-07-07 16:35:32 +01:00
jude b5dbfe336d Don't set activity in ready event 2024-07-07 16:31:23 +01:00
jude 218be2f0b1 Bump ver 2024-06-18 19:32:47 +01:00
jude d7515f3611 Don't require View Channel permission 2024-06-18 19:28:53 +01:00
jude 6ae1096d79 Bump ver 2024-06-12 17:44:55 +01:00
jude 1f0d7adae3 Correct service file 2024-06-12 17:21:42 +01:00
jude fc96ae526f Default permission checks to true 2024-06-10 18:30:55 +01:00
jude 8881ef0f85 Fix DM reminders trying to load guild data 2024-06-06 16:56:19 +01:00
jude 5e82a687f9 Increase watchdog 2024-06-04 22:34:58 +01:00
jude de4ecf8dd6 QoL
* Made todo added responses ephemeral if /settings ephemeral is on
* Enabled systemd watchdog
* Move metrics to rocket
2024-06-04 18:40:49 +01:00
jude 064efd4386 Bump version 2024-06-04 16:48:26 +01:00
jude 65b8ba3b47 Redirect old dashboard routes to new routes 2024-06-04 16:42:42 +01:00
jude 9d452ed8cb Fix role selector 2024-05-10 17:37:27 +01:00
jude 441419b92b Bump ver 2024-05-04 13:00:30 +01:00
jude aecf2c15be Store times as local time not UTC 2024-05-04 10:24:20 +01:00
jude 79da56c794 Bump ver 2024-05-03 16:26:52 +01:00
jude ef10902c1e Fix todo list deletion not working properly 2024-05-03 16:21:27 +01:00
jude c277f85c2a Bump dependencies 2024-05-03 16:07:34 +01:00
jude 035653c7fa Bump ver 2024-04-29 08:57:47 +01:00
jude 6358bc3deb Partially revert timezone change 2024-04-29 08:49:01 +01:00
jude 9f5066f982 Bump ver 2024-04-29 08:46:36 +01:00
jude 1d06999e41 Fix bugs with time picker
* Load UTC time correctly at page load
* Don't translate to/from timezone when using the browser date/time
  input
2024-04-16 12:44:19 +01:00
jude 1cf707140c Bump version 2024-04-16 12:22:02 +01:00
jude e38c63f5ba Don't show empty channels 2024-04-16 11:42:19 +01:00
jude d52b8b26f2 Upgrade dependencies 2024-04-16 11:19:21 +01:00
jude bb2128a7ed Tweaks
* Don't show @everyone in the role picker
* Show some text on the image picker talking about Discord CDN
* Correct == in todos
2024-04-11 15:40:50 +01:00
jude 5e99a6f9de Add create todo under each channel
Sort channels for consistency
2024-04-11 15:32:34 +01:00
jude 5406e6b8ec Show all channels and filter todos accordingly 2024-04-11 15:26:24 +01:00
jude 4ee0bc4e37 Bump ver 2024-04-11 12:43:22 +01:00
jude b99bb7dcbf Fix todo sorting 2024-04-11 12:39:02 +01:00
jude 98f925dc84 Bump version 2024-04-10 18:54:30 +01:00
jude 24e316b12f Add delete/patch todos 2024-04-10 18:42:29 +01:00
jude 4063334953 More work on todo list 2024-04-09 21:21:46 +01:00
jude e128b9848f More work on todo list support 2024-04-07 20:20:16 +01:00
jude 9989ab3b35 Start work on todo list support for dashboard 2024-04-06 14:27:58 +01:00
jude b951db3f55 Bump version 2024-03-31 13:30:30 +01:00
jude 884a47bf36 Always show remaining time in top bar 2024-03-31 12:54:48 +01:00
jude b0f932445c Add server emoji picker 2024-03-31 12:49:52 +01:00
jude 2861cdda0b Bump version 2024-03-29 16:28:09 +00:00
jude 7ba8fcd6b7 Add note to the server data page that states the bot might be restarting 2024-03-29 16:24:24 +00:00
jude 850f0fad57 Bump version 2024-03-29 16:22:13 +00:00
jude a770a17ee7 Don't invalidate reminders when saving 2024-03-29 16:15:01 +00:00
jude d15a66d9d9 Bump version 2024-03-28 19:36:23 +00:00
jude 30f011fcd5 Don't send attachments over API 2024-03-28 19:34:30 +00:00
jude 15dbed2f0f Bump version 2024-03-27 17:28:35 +00:00
jude 18cac0345b Allow removing attachments
Show HTTP errors
2024-03-27 17:19:19 +00:00
jude 334b1bc084 Bump version 2024-03-26 17:46:56 +00:00
jude ba3c76c25f Fix import/export showing "Malformed base64" 2024-03-26 17:43:35 +00:00
jude 67b6f30c62 Add IDs to metrics 2024-03-25 16:41:49 +00:00
jude 8ae311190f Fix panic????????? 2024-03-25 06:07:30 +00:00
jude 016164affb Remove unused javascript/css 2024-03-24 21:00:27 +00:00
jude 2c0aeef700 Fix build. Bump version 2024-03-24 20:55:07 +00:00
jude ecd75d6f55 Add metrics 2024-03-24 20:38:19 +00:00
jude 4a80d42f86 Move postman and web inside src 2024-03-24 20:23:16 +00:00
jude 075fde71df Bump version 2024-03-11 18:17:22 +00:00
jude 55136aecdc Set default embed color correctly 2024-03-11 18:14:27 +00:00
jude 63fc2cdcbc Block editing username and avatar on DMs 2024-03-10 19:43:57 +00:00
jude 3190738fc5 Extend user reminder API endpoints 2024-03-09 16:17:55 +00:00
jude 8f4810b532 Convert to/from timezone 2024-03-08 16:36:24 +00:00
jude a5e6c41fa5 Bump ver
Update build file
2024-03-05 20:55:20 +00:00
jude 5f0aa0f834 Add routes for getting/posting user reminders 2024-03-05 20:36:38 +00:00
jude dbe8e8e358 Add mentioning for channels 2024-03-04 20:36:37 +00:00
jude 85a114e55c Start adding stuff for user reminders 2024-03-03 21:58:48 +00:00
jude 329492b244 Add mention support
Allow vertical resizing of inputs
2024-03-03 21:44:35 +00:00
jude 66135ecd08 Show time until on collapsed reminders 2024-03-03 20:38:17 +00:00
jude 382c2a5a1e Stick options 2024-03-03 19:43:02 +00:00
jude b91245a3f7 Build dashboard with bot 2024-03-03 13:21:06 +00:00
jude 6f0bdf9852 Support sending reminders to threads 2024-03-03 13:04:50 +00:00
jude dcee9e0d2a Begin to work on thread support 2024-03-03 11:58:22 +00:00
jude 8e6e1a18b7 Bump ver 2024-03-01 18:04:34 +00:00
jude 72af0532fa Fix timezones 2024-03-01 17:54:05 +00:00
jude e83b643d86 Show error for files that are too large 2024-03-01 16:56:31 +00:00
jude 0e0ab053f3 Fix time inputs 2024-03-01 16:54:56 +00:00
jude 8c2296b9c8 Bump versions 2024-02-28 21:37:10 +00:00
jude 1c6103142f Fix color picker not working 2024-02-28 21:30:53 +00:00
jude 328127c55e Fix images not setting properly 2024-02-28 21:30:49 +00:00
jude b0e37b56c0 Bump version 2024-02-26 10:42:46 +00:00
jude 45f5b6261a Convert times to/from UTC 2024-02-26 10:26:07 +00:00
jude 5f6326179c Move styles into Vite
Make sidebar work better
2024-02-25 09:50:10 +00:00
jude 6254f91841 Bump version 2024-02-25 09:18:04 +00:00
jude 60b90a61d4 Adjust permission check
Correct response code for oauth redirect
2024-02-25 09:09:00 +00:00
jude 90f05758d0 Bypass self permission check for DMs 2024-02-24 22:27:29 +00:00
jude 74b7b5d711 Remove glob patterns from static file includes 2024-02-24 17:56:27 +00:00
jude 90550dc2c7 Add loader 2024-02-24 17:47:00 +00:00
jude 79e6498245 Add overlay when data fetching 2024-02-24 17:31:39 +00:00
jude a8ef3d03f9 Add dashboard to build 2024-02-24 16:12:34 +00:00
jude 53e13844f9 Add unit tests 2024-02-24 15:02:34 +00:00
jude dd7e681285 Update rust 2024-02-22 18:35:37 +00:00
jude 6c20bf2a0f Bump version 2024-02-22 17:47:40 +00:00
jude 15aa9ccffd Update help text 2024-02-22 17:42:29 +00:00
jude 525471bcad Correct help text 2024-02-22 17:35:50 +00:00
jude 86d53b63b6 Bump deps 2024-02-20 17:09:50 +00:00
jude d8f266852a Add remaining commands 2024-02-18 14:32:58 +00:00
jude 76a286076b Link all top-level commands with macro recording/replaying logic 2024-02-18 13:24:37 +00:00
jude 5e39e16060 Add option types for top-level commands 2024-02-18 11:04:43 +00:00
jude c1305cfb36 Extract trait 2024-02-17 20:25:14 +00:00
jude 4823754955 Move all commands to their own files 2024-02-17 18:55:16 +00:00
jude eb92eacb90 Rearranged some commands
Working on a macro to automatically add option wrappers
2024-02-17 14:09:01 +00:00
jude d0833b7bca Add macro for extracting arguments 2024-02-16 20:09:32 +00:00
jude b81c3c80c1 Record some parameters for /remind 2024-02-15 17:28:43 +00:00
jude 2f6d035efe Rename table references 2024-02-14 19:44:53 +00:00
jude 96012ce43c Add migration script 2024-02-14 19:35:23 +00:00
jude fa7ec8731b Fix hook 2024-02-09 17:03:04 +00:00
jude def43bfa78 Refactor macros 2024-02-06 20:08:59 +00:00
jude e4e9af2bb4 Wip commit 2024-01-07 17:10:22 +00:00
jude cce0de7c75 wip bump versions 2023-12-22 19:12:42 +00:00
jude e7803b98e8 Merge pull request 'jude/react-dashboard' (#3) from jude/react-dashboard into current
Reviewed-on: #3
2023-12-22 16:58:30 +00:00
jude 7aae246388 Remove submodule 2023-12-22 16:58:30 +00:00
jude a2d442bc54 Reset intervals correctly 2023-12-22 16:58:30 +00:00
jude 59982df827 Correct merge errors 2023-12-22 16:58:30 +00:00
jude 7a6372ed02 Update styles for notification flash 2023-12-22 16:58:30 +00:00
jude 14a54471f7 Build dashboard 2023-12-22 16:58:30 +00:00
jude 5d3b77f1cd Add metrics
Change dashboards to load an index.html file compiled otherwise
2023-12-22 16:58:30 +00:00
jude 1d64c8bb79 Remove stat table 2023-12-22 16:58:03 +00:00
jude 8ba0f02b98 Bump version 2023-11-12 10:00:46 +00:00
jude d36438c6ce Bump package lock. Add attachment serializer 2023-11-12 09:39:45 +00:00
jude e0c60e2ce3 Decode attachments correctly when patching a reminder 2023-11-11 15:05:35 +00:00
jude e7160215b0 Defer offset response 2023-11-11 13:36:40 +00:00
jude 6eaa6f0f28 Bump version 2023-10-19 20:32:01 +01:00
jude 9db0fa2513 Fix attachment decoding 2023-10-19 20:10:40 +01:00
jude ca13fd4fa7 Restructure code 2023-10-08 18:24:04 +01:00
jude 55acc8fd16 Bump ver 2023-10-08 12:39:31 +01:00
jude 145711fa5d Add version strings to files 2023-10-08 12:21:38 +01:00
jude 5524215786 Bump ver 2023-10-07 16:10:01 +01:00
jude e8bd05893f Transmit guild name with patreon information 2023-10-07 16:08:25 +01:00
jude e3d3418f99 Change routing. Remove a macro 2023-10-05 18:54:53 +01:00
jude 2681280a39 Fix interval parsing for different cases 2023-10-01 09:42:58 +01:00
jude 00579428a1 Bump version 2023-09-25 18:20:22 +01:00
jude b8ef999710 Reload reminders after import 2023-09-25 18:17:19 +01:00
jude e8f84e281a Bump version 2023-09-24 14:53:16 +01:00
jude 8ddff698e5 Show messages when imports succeed. 2023-09-24 14:14:21 +01:00
jude 541633270c Fix margin on bottom of collapsed reminders 2023-09-24 13:58:24 +01:00
jude 25286da5e0 Use transactions for certain routes 2023-09-24 13:57:27 +01:00
jude 4bad1324b9 Restructure
Move some code out to other files. Add transaction guard
2023-09-24 13:11:53 +01:00
jude bd1462a00c Reposition "options"
Fix import/export
2023-09-23 23:38:16 +01:00
jude 56ffc43616 Store intervals in templates 2023-09-23 22:47:21 +01:00
jude 52cf642455 Send edit button to beta dashboard 2023-09-23 20:32:57 +01:00
jude 0bf578357a Bump version 2023-09-23 18:31:51 +01:00
jude 6e9eccb62e Update dependencies 2023-09-23 18:29:25 +01:00
jude 6ea28284ce Bump ver 2023-09-23 18:24:39 +01:00
jude a6525f3052 Move button row down. Correct image sizes on some browsers 2023-09-23 18:14:01 +01:00
jude 348639270d Move button row down 2023-09-23 18:05:26 +01:00
jude 37177c2431 Update styles for mobile 2023-09-23 18:04:41 +01:00
jude 8587bed703 Bump ver 2023-08-19 17:10:45 +01:00
jude 6c9af1ae8e Correct styles on mobile burger 2023-08-19 17:09:46 +01:00
jude 7695b7a476 Fix delete command 2023-08-19 14:35:07 +01:00
jude 651da7b28e Improve some styles. Add an offline mode 2023-08-19 14:20:48 +01:00
jude eb086146bf Bump version 2023-08-16 17:05:18 +01:00
jude 4ebd705e5e Add clearer indication of interval patreon requirements 2023-08-16 17:03:38 +01:00
366 changed files with 84087 additions and 6956 deletions

No files matched your search

+26 -3
View File
@@ -1,7 +1,30 @@
/target target
.env .env
/venv /venv
.cargo .cargo
/.idea .idea
web/static/index.html
web/static/assets
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules/ node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
Generated
+1697 -1122
View File
File diff suppressed because it is too large. Load diff
+31 -18
View File
@@ -1,22 +1,21 @@
[package] [package]
name = "reminder-rs" name = "reminder-rs"
version = "1.6.36" version = "1.7.27"
authors = ["Jude Southworth <judesouthworth@pm.me>"] authors = ["Jude Southworth <judesouthworth@pm.me>"]
edition = "2021" edition = "2021"
license = "AGPL-3.0 only" license = "AGPL-3.0 only"
description = "Reminder Bot for Discord, now in Rust" description = "Reminder Bot for Discord, now in Rust"
[dependencies] [dependencies]
poise = "0.5.5" poise = "0.6.1"
dotenv = "0.15" dotenv = "0.15"
tokio = { version = "1", features = ["process", "full"] } tokio = { version = "1", features = ["process", "full"] }
reqwest = "0.11" reqwest = { version = "0.12", features = ["json"] }
lazy-regex = "2.3.0" regex = "1.10"
regex = "1.6"
log = "0.4" log = "0.4"
env_logger = "0.10" env_logger = "0.11"
chrono = "0.4" chrono = "0.4"
chrono-tz = { version = "0.8", features = ["serde"] } chrono-tz = { version = "0.9", features = ["serde"] }
lazy_static = "1.4" lazy_static = "1.4"
num-integer = "0.1" num-integer = "0.1"
serde = "1.0" serde = "1.0"
@@ -25,14 +24,23 @@ serde_repr = "0.1"
rmp-serde = "1.1" rmp-serde = "1.1"
rand = "0.8" rand = "0.8"
levenshtein = "1.0" levenshtein = "1.0"
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono", "migrate"]} sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono", "migrate"] }
base64 = "0.21.0" base64 = "0.22"
secrecy = "0.8.0"
futures = "0.3.30"
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"
sd-notify = "0.4.1"
[dependencies.postman] [dependencies.extract_derive]
path = "postman" path = "extract_derive"
[dependencies.reminder_web] [dependencies.recordable_derive]
path = "web" path = "recordable_derive"
[package.metadata.deb] [package.metadata.deb]
depends = "$auto, python3-dateparser (>= 1.0.0)" depends = "$auto, python3-dateparser (>= 1.0.0)"
@@ -40,13 +48,18 @@ suggests = "mysql-server-8.0, nginx"
maintainer-scripts = "debian" maintainer-scripts = "debian"
assets = [ assets = [
["target/release/reminder-rs", "usr/bin/reminder-rs", "755"], ["target/release/reminder-rs", "usr/bin/reminder-rs", "755"],
["static/css/*", "lib/reminder-rs/static/css", "644"],
["static/favicon/*", "lib/reminder-rs/static/favicon", "644"],
["static/img/*", "lib/reminder-rs/static/img", "644"],
["static/js/*", "lib/reminder-rs/static/js", "644"],
["static/webfonts/*", "lib/reminder-rs/static/webfonts", "644"],
["static/site.webmanifest", "lib/reminder-rs/static/site.webmanifest", "644"],
["templates/**/*", "lib/reminder-rs/templates", "644"],
["reminder-dashboard/dist/static/assets/*", "lib/reminder-rs/static/assets", "644"],
["reminder-dashboard/dist/index.html", "lib/reminder-rs/static/index.html", "644"],
["conf/default.env", "etc/reminder-rs/config.env", "600"], ["conf/default.env", "etc/reminder-rs/config.env", "600"],
["conf/Rocket.toml", "etc/reminder-rs/Rocket.toml", "600"], ["conf/Rocket.toml", "etc/reminder-rs/Rocket.toml", "600"],
["$OUT_DIR/web/static/**/*", "lib/reminder-rs/static", "644"], # ["nginx/reminder-rs", "etc/nginx/sites-available/reminder-rs", "755"]
["web/templates/**/*", "lib/reminder-rs/templates", "644"],
["healthcheck", "lib/reminder-rs/healthcheck", "755"],
["cron.d/reminder_health", "etc/cron.d/reminder_health", "644"],
# ["nginx/reminder-rs", "etc/nginx/sites-available/reminder-rs", "755"]
] ]
conf-files = [ conf-files = [
"/etc/reminder-rs/config.env", "/etc/reminder-rs/config.env",
+1 -1
View File
@@ -4,6 +4,6 @@ ENV RUSTUP_HOME=/usr/local/rustup \
CARGO_HOME=/usr/local/cargo \ CARGO_HOME=/usr/local/cargo \
PATH=/usr/local/cargo/bin:$PATH PATH=/usr/local/cargo/bin:$PATH
RUN apt update && DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt install -y gcc gcc-multilib cmake pkg-config libssl-dev curl mysql-client-8.0 RUN apt update && DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt install -y gcc gcc-multilib cmake pkg-config libssl-dev curl mysql-client-8.0 npm
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal --default-toolchain nightly
RUN cargo install cargo-deb RUN cargo install cargo-deb
+11 -11
View File
@@ -1,28 +1,28 @@
[default] [default]
address = "0.0.0.0" address = "0.0.0.0"
port = 18920 port = 18920
template_dir = "web/templates" template_dir = "templates"
limits = { json = "10MiB" } limits = { json = "10MiB" }
[debug] [debug]
secret_key = "tR8krio5FXTnnyIZNiJDXPondz0kI1v6X6BXZcBGIRY=" secret_key = "tR8krio5FXTnnyIZNiJDXPondz0kI1v6X6BXZcBGIRY="
[debug.tls] [debug.tls]
certs = "web/private/rsa_sha256_cert.pem" certs = "private/rsa_sha256_cert.pem"
key = "web/private/rsa_sha256_key.pem" key = "private/rsa_sha256_key.pem"
[debug.rsa_sha256.tls] [debug.rsa_sha256.tls]
certs = "web/private/rsa_sha256_cert.pem" certs = "private/rsa_sha256_cert.pem"
key = "web/private/rsa_sha256_key.pem" key = "private/rsa_sha256_key.pem"
[debug.ecdsa_nistp256_sha256.tls] [debug.ecdsa_nistp256_sha256.tls]
certs = "web/private/ecdsa_nistp256_sha256_cert.pem" certs = "private/ecdsa_nistp256_sha256_cert.pem"
key = "web/private/ecdsa_nistp256_sha256_key_pkcs8.pem" key = "private/ecdsa_nistp256_sha256_key_pkcs8.pem"
[debug.ecdsa_nistp384_sha384.tls] [debug.ecdsa_nistp384_sha384.tls]
certs = "web/private/ecdsa_nistp384_sha384_cert.pem" certs = "private/ecdsa_nistp384_sha384_cert.pem"
key = "web/private/ecdsa_nistp384_sha384_key_pkcs8.pem" key = "private/ecdsa_nistp384_sha384_key_pkcs8.pem"
[debug.ed25519.tls] [debug.ed25519.tls]
certs = "web/private/ed25519_cert.pem" certs = "private/ed25519_cert.pem"
key = "eb/private/ed25519_key.pem" key = "private/ed25519_key.pem"
+8 -94
View File
@@ -1,99 +1,13 @@
#[cfg(not(debug_assertions))] use std::{path::Path, process::Command};
use std::{
env, fs,
fs::{create_dir_all, DirEntry, File},
io,
io::Write,
path::Path,
process::Command,
};
#[cfg(not(debug_assertions))]
fn visit_dirs(dir: &Path, cb: &dyn Fn(&DirEntry)) -> io::Result<()> {
if dir.is_dir() {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
visit_dirs(&path, cb)?;
} else {
cb(&entry);
}
}
}
Ok(())
}
#[cfg(not(debug_assertions))]
fn process_static(file: &DirEntry) {
let out_dir = env::var("OUT_DIR").unwrap();
let path = file.path();
let in_path = path.to_str().unwrap();
let art_path = format!("{}/{}", out_dir, in_path);
let art_dir = format!("{}/{}", out_dir, path.parent().unwrap().to_str().unwrap());
match path.extension().map(|o| o.to_str()).flatten() {
Some("ts") => {}
Some("js") => {
create_dir_all(art_dir).unwrap();
if art_path.ends_with(".min.js") {
Command::new("cp").arg(in_path).arg(art_path).spawn().expect("Could not copy");
} else {
let minified = Command::new("npx")
.arg("minify")
.arg(in_path)
.output()
.expect("Could not minify");
let mut fh = File::create(art_path).expect("Couldn't create file");
fh.write(&minified.stdout).unwrap();
}
}
Some("css") => {
create_dir_all(art_dir).unwrap();
if art_path.ends_with(".min.css") {
Command::new("cp").arg(in_path).arg(art_path).spawn().expect("Could not copy");
} else {
let minified = Command::new("npx")
.arg("minify")
.arg(in_path)
.output()
.expect("Could not minify");
let mut fh = File::create(art_path).expect("Couldn't create file");
fh.write(&minified.stdout).unwrap();
}
}
_ => {
create_dir_all(art_dir).unwrap();
Command::new("cp").arg(in_path).arg(art_path).spawn().expect("Could not copy");
}
}
}
// fn compile_tsc(file: &DirEntry) {
// if path.extension() == Some("ts") {
// let out_dir = env::var("OUT_DIR").unwrap();
// let path = file.path();
//
// Command::new("npx")
// .arg("tsc")
// .arg(in_path)
// .arg(art_path)
// .spawn()
// .expect("Could not compile");
// }
// }
fn main() { fn main() {
println!("cargo:rerun-if-changed=migrations"); println!("cargo:rerun-if-changed=migrations");
println!("cargo:rerun-if-changed=reminder-dashboard");
#[cfg(not(debug_assertions))] Command::new("npm")
visit_dirs("web/static".as_ref(), &process_static).unwrap(); .arg("run")
.arg("build")
// visit_dirs("web/static".as_ref(), &compile_tsc).unwrap(); .current_dir(Path::new("reminder-dashboard"))
.spawn()
.expect("Failed to build NPM");
} }
+46
View File
@@ -0,0 +1,46 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "extract_macro"
version = "0.1.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "extract_derive"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.35"
syn = { version = "2.0.49", features = ["full"] }
+53
View File
@@ -0,0 +1,53 @@
use proc_macro::TokenStream;
use syn::{spanned::Spanned, Data, Fields};
#[proc_macro_derive(Extract)]
pub fn extract(input: TokenStream) -> TokenStream {
let ast = syn::parse_macro_input!(input);
impl_extract(&ast)
}
fn impl_extract(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
match &ast.data {
// Dispatch over struct: extract args directly from context
Data::Struct(st) => match &st.fields {
Fields::Named(fields) => {
let extracted = fields.named.iter().map(|field| {
let ident = &field.ident;
let ty = &field.ty;
quote::quote_spanned! {field.span()=>
#ident : crate::utils::extract_arg!(ctx, #ident, #ty)
}
});
TokenStream::from(quote::quote! {
impl Extract for #name {
fn extract(ctx: crate::ApplicationContext) -> Self {
Self {
#(#extracted,)*
}
}
}
})
}
Fields::Unit => TokenStream::from(quote::quote! {
impl Extract for #name {
fn extract(ctx: crate::ApplicationContext) -> Self {
Self {}
}
}
}),
_ => {
panic!("Only named/unit structs can derive Extract");
}
},
_ => {
panic!("Only structs can derive Extract");
}
}
}
-13
View File
@@ -1,13 +0,0 @@
#!/bin/bash
export $(grep -v '^#' /etc/reminder-rs/config.env | xargs -d '\n')
REGEX='mysql://([A-Za-z]+)@(.+)/(.+)'
[[ $DATABASE_URL =~ $REGEX ]]
VAR=$(mysql -u "${BASH_REMATCH[1]}" -h "${BASH_REMATCH[2]}" -N -D "${BASH_REMATCH[3]}" -e "SELECT COUNT(1) FROM reminders WHERE utc_time < NOW() - INTERVAL 10 MINUTE AND enabled = 1 AND status = 'pending'")
if [ "$VAR" -gt 0 ]
then
echo "This is to inform that there is a reminder backlog which must be resolved." | mail -s "Backlog: $VAR" "$REPORT_EMAIL"
fi
@@ -0,0 +1,3 @@
ALTER TABLE `reminder_template` ADD COLUMN `interval_seconds` INT UNSIGNED;
ALTER TABLE `reminder_template` ADD COLUMN `interval_days` INT UNSIGNED;
ALTER TABLE `reminder_template` ADD COLUMN `interval_months` INT UNSIGNED;
@@ -0,0 +1,50 @@
CREATE TABLE command_macro (
id INT UNSIGNED AUTO_INCREMENT,
guild_id INT UNSIGNED NOT NULL,
name VARCHAR(100) NOT NULL,
description VARCHAR(100),
commands JSON NOT NULL,
FOREIGN KEY (guild_id) REFERENCES guilds(id) ON DELETE CASCADE,
PRIMARY KEY (id)
);
# New JSON structure is {command_name: "Remind", "<option name>": "<option value>", ...}
INSERT INTO command_macro (guild_id, description, name, commands)
SELECT
guild_id,
description,
name,
(
SELECT JSON_ARRAYAGG(
(
SELECT JSON_OBJECTAGG(t2.name, t2.value)
FROM JSON_TABLE(
JSON_ARRAY_APPEND(t1.options, '$', JSON_OBJECT('name', 'command_name', 'value', t1.command_name)),
'$[*]' COLUMNS (
name VARCHAR(64) PATH '$.name' ERROR ON ERROR,
value TEXT PATH '$.value' ERROR ON ERROR
)) AS t2
)
)
FROM macro m2
JOIN JSON_TABLE(
commands,
'$[*]' COLUMNS (
command_name VARCHAR(64) PATH '$.command_name' ERROR ON ERROR,
options JSON PATH '$.options' ERROR ON ERROR
)) AS t1
WHERE m1.id = m2.id
)
FROM macro m1;
# # Check which commands are used in macros
# SELECT DISTINCT command_name
# FROM macro m2
# JOIN JSON_TABLE(
# commands,
# '$[*]' COLUMNS (
# command_name VARCHAR(64) PATH '$.command_name' ERROR ON ERROR,
# options JSON PATH '$.options' ERROR ON ERROR
# )) AS t1
@@ -0,0 +1,5 @@
-- Add migration script here
ALTER TABLE reminders
ADD INDEX `utc_time_index` (`utc_time`);
ALTER TABLE reminders
ADD INDEX `status_index` (`status`);
+53
View File
@@ -0,0 +1,53 @@
server {
server_name www.reminder-bot.com;
return 301 https://reminder-bot.com$request_uri;
}
server {
listen 80;
server_name beta.reminder-bot.com;
return 301 https://reminder-bot.com$request_uri;
}
server {
listen 443 ssl;
server_name beta.reminder-bot.com;
ssl_certificate /etc/letsencrypt/live/beta.reminder-bot.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/beta.reminder-bot.com/privkey.pem;
return 301 https://reminder-bot.com$request_uri;
}
server {
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;
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;
client_max_body_size 10M;
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;
}
}
-41
View File
@@ -1,41 +0,0 @@
server {
server_name www.reminder-bot.com;
return 301 $scheme://reminder-bot.com$request_uri;
}
server {
listen 80;
server_name reminder-bot.com;
return 301 https://reminder-bot.com$request_uri;
}
server {
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;
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;
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;
}
}
-485
View File
@@ -1,485 +0,0 @@
{
"name": "reminder-rs",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"devDependencies": {
"minify": "^10.3.0",
"prettier": "^3.0.1",
"tsc": "^2.0.4"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
"dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
"dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.19",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@putout/minify": {
"version": "1.49.0",
"resolved": "https://registry.npmjs.org/@putout/minify/-/minify-1.49.0.tgz",
"integrity": "sha512-T/eS9rJC0tgq/s8uLpB0cpbsUaY7KSML3UbvPri2qjVCcEK/qwi8+lNWdp8VSyOWiC25Ntrt/DewOu6dXRX1ng==",
"dev": true,
"engines": {
"node": ">=16"
}
},
"node_modules/acorn": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"node_modules/camel-case": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
"integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
"dev": true,
"dependencies": {
"pascal-case": "^3.1.2",
"tslib": "^2.0.3"
}
},
"node_modules/clean-css": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz",
"integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==",
"dev": true,
"dependencies": {
"source-map": "~0.6.0"
},
"engines": {
"node": ">= 10.0"
}
},
"node_modules/commander": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
"dev": true,
"engines": {
"node": ">=14"
}
},
"node_modules/css-b64-images": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/css-b64-images/-/css-b64-images-0.2.5.tgz",
"integrity": "sha512-TgQBEdP07adhrDfXvI5o6bHGukKBNMzp2Ngckc/6d09zpjD2gc1Hl3Ca1CKgb8FXjHi88+Phv2Uegs2kTL4zjg==",
"dev": true,
"bin": {
"css-b64-images": "bin/css-b64-images"
},
"engines": {
"node": "*"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/dot-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
"dev": true,
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/find-up": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
"integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
"dev": true,
"dependencies": {
"locate-path": "^7.1.0",
"path-exists": "^5.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/html-minifier-terser": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz",
"integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==",
"dev": true,
"dependencies": {
"camel-case": "^4.1.2",
"clean-css": "~5.3.2",
"commander": "^10.0.0",
"entities": "^4.4.0",
"param-case": "^3.0.4",
"relateurl": "^0.2.7",
"terser": "^5.15.1"
},
"bin": {
"html-minifier-terser": "cli.js"
},
"engines": {
"node": "^14.13.1 || >=16.0.0"
}
},
"node_modules/jju": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
"integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
"dev": true
},
"node_modules/locate-path": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
"integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
"dev": true,
"dependencies": {
"p-locate": "^6.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lower-case": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
"dev": true,
"dependencies": {
"tslib": "^2.0.3"
}
},
"node_modules/minify": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/minify/-/minify-10.3.0.tgz",
"integrity": "sha512-eRkx2J1ykkGBVi1gI2sksmovWFzts+GYi2u3Jd/S5eNIkzj0pidciICsWRWdTKTLZVFUP7b6IvoAzasvQkMicg==",
"dev": true,
"dependencies": {
"@putout/minify": "^1.0.4",
"clean-css": "^5.0.1",
"css-b64-images": "~0.2.5",
"debug": "^4.1.0",
"find-up": "^6.1.0",
"html-minifier-terser": "^7.1.0",
"readjson": "^2.2.2",
"simport": "^1.2.0",
"try-catch": "^3.0.0",
"try-to-catch": "^3.0.0"
},
"bin": {
"minify": "bin/minify.js"
},
"engines": {
"node": ">=16"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/no-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
"dev": true,
"dependencies": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
}
},
"node_modules/p-limit": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
"integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
"dev": true,
"dependencies": {
"yocto-queue": "^1.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-locate": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
"integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
"dev": true,
"dependencies": {
"p-limit": "^4.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/param-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
"integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
"dev": true,
"dependencies": {
"dot-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/pascal-case": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
"dev": true,
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/path-exists": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
"integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
"dev": true,
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/prettier": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.1.tgz",
"integrity": "sha512-fcOWSnnpCrovBsmFZIGIy9UqK2FaI7Hqax+DIO0A9UxeVoY4iweyaFjS5TavZN97Hfehph0nhsZnjlVKzEQSrQ==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/readjson": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/readjson/-/readjson-2.2.2.tgz",
"integrity": "sha512-PdeC9tsmLWBiL8vMhJvocq+OezQ3HhsH2HrN7YkhfYcTjQSa/iraB15A7Qvt7Xpr0Yd2rDNt6GbFwVQDg3HcAw==",
"dev": true,
"dependencies": {
"jju": "^1.4.0",
"try-catch": "^3.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/relateurl": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
"integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
"dev": true,
"engines": {
"node": ">= 0.10"
}
},
"node_modules/simport": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/simport/-/simport-1.2.0.tgz",
"integrity": "sha512-85Bm7pKsqiiQ8rmYCaPDdlXZjJvuW6/k/FY8MTtLFMgU7f8S00CgTHfRtWB6KwSb6ek4p9YyG2enG1+yJbl+CA==",
"dev": true,
"dependencies": {
"readjson": "^2.2.0",
"try-to-catch": "^3.0.0"
},
"engines": {
"node": ">=12.2"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/terser": {
"version": "5.19.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
"integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
"dev": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"node_modules/try-catch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/try-catch/-/try-catch-3.0.1.tgz",
"integrity": "sha512-91yfXw1rr/P6oLpHSyHDOHm0vloVvUoo9FVdw8YwY05QjJQG9OT0LUxe2VRAzmHG+0CUOmI3nhxDUMLxDN/NEQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/try-to-catch": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/try-to-catch/-/try-to-catch-3.0.1.tgz",
"integrity": "sha512-hOY83V84Hx/1sCzDSaJA+Xz2IIQOHRvjxzt+F0OjbQGPZ6yLPLArMA0gw/484MlfUkQbCpKYMLX3VDCAjWKfzQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/tsc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/tsc/-/tsc-2.0.4.tgz",
"integrity": "sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q==",
"dev": true,
"bin": {
"tsc": "bin/tsc"
}
},
"node_modules/tslib": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
"integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==",
"dev": true
},
"node_modules/yocto-queue": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
"integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
"dev": true,
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}
-7
View File
@@ -1,7 +0,0 @@
{
"devDependencies": {
"minify": "^10.3.0",
"prettier": "^3.0.1",
"tsc": "^2.0.4"
}
}
-16
View File
@@ -1,16 +0,0 @@
[package]
name = "postman"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["process", "full"] }
regex = "1.4"
log = "0.4"
chrono = "0.4"
chrono-tz = { version = "0.5", features = ["serde"] }
lazy_static = "1.4"
num-integer = "0.1"
serde = "1.0"
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono", "json"]}
serenity = { version = "0.11.1", 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.
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "recordable_derive"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.35"
syn = { version = "2.0.49", features = ["full"] }
+42
View File
@@ -0,0 +1,42 @@
use proc_macro::TokenStream;
use syn::{spanned::Spanned, Data};
/// Macro to allow Recordable to be implemented on an enum by dispatching over each variant.
#[proc_macro_derive(Recordable)]
pub fn extract(input: TokenStream) -> TokenStream {
let ast = syn::parse_macro_input!(input);
impl_recordable(&ast)
}
fn impl_recordable(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
match &ast.data {
Data::Enum(en) => {
let extracted = en.variants.iter().map(|var| {
let ident = &var.ident;
quote::quote_spanned! {var.span()=>
Self::#ident (opt) => opt.run(ctx).await?
}
});
TokenStream::from(quote::quote! {
impl Recordable for #name {
async fn run(self, ctx: crate::Context<'_>) -> Result<(), crate::Error> {
match self {
#(#extracted,)*
}
Ok(())
}
}
})
}
_ => {
panic!("Only enums can derive Recordable");
}
}
}
+2
View File
@@ -0,0 +1,2 @@
printWidth = 100
tabWidth = 4
+19
View File
@@ -0,0 +1,19 @@
# reminder-dashboard
The re-re-rewrite of the dashboard.
## Why
The existing beta variant of the dashboard is written using vanilla JavaScript. This is fine,
but annoying to update. This would've been okay if I was more dedicated to updating the vanilla
JavaScript too, but I want to experiment with "new" things.
This also allows me to expand my frontend skills, which is relevant to part of my job.
## Developing
1. Run both `npm run dev` and `cargo run`
2. Symlink assets: assuming cloned
into `$HOME`, `ln -s $HOME/reminder-bot/reminder-dashboard/dist/index.html $HOME/reminder-bot/web/static/index.html`
and
`ln -s $HOME/reminder-bot/reminder-dashboard/dist/static/assets $HOME/reminder-bot/web/static/assets`
+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="EN">
<head>
<meta name="description" content="The most powerful Discord Reminders Bot">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8">
<meta name="yandex-verification" content="bb77b8681eb64a90"/>
<meta name="google-site-verification" content="7h7UVTeEe0AOzHiH3cFtsqMULYGN-zCZdMT_YCkW1Ho"/>
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src *; font-src fonts.gstatic.com 'self'"> -->
<!-- favicon -->
<link rel="apple-touch-icon" sizes="180x180"
href="/static/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32"
href="/static/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16"
href="/static/favicon/favicon-16x16.png">
<link rel="manifest" href="/static/site.webmanifest">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<title>Reminder Bot | Dashboard</title>
<!-- styles -->
<link rel="stylesheet" href="/static/css/bulma.min.css">
<link rel="stylesheet" href="/static/css/fa.css">
<link rel="stylesheet" href="/static/css/font.css">
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
File diff suppressed because it is too large. Load diff
+32
View File
@@ -0,0 +1,32 @@
{
"name": "example",
"private": true,
"type": "module",
"scripts": {
"dev": "vite build --watch --mode development",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.5.1",
"bulma": "^0.9.4",
"luxon": "^3.4.3",
"preact": "^10.13.1",
"react-colorful": "^5.6.1",
"react-query": "^3.39.3",
"tributejs": "^5.1.3",
"use-debounce": "^10.0.0",
"wouter": "^3.0"
},
"devDependencies": {
"@preact/preset-vite": "^2.5.0",
"@types/luxon": "^3.3.2",
"eslint": "^8.50.0",
"eslint-config-preact": "^1.3.0",
"prettier": "^3.0.3",
"react-datepicker": "^4.21.0",
"sass": "^1.71.1",
"typescript": "^5.2.2",
"vite": "^5.1"
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -15,6 +15,22 @@ div.reminderContent.is-collapsed .column.settings {
display: none; display: none;
} }
div.reminderContent.is-collapsed .reminder-settings {
margin-bottom: 0;
}
div.reminderContent.is-collapsed .button-row {
display: none;
}
div.reminderContent.is-collapsed .button-row-edit {
display: none;
}
div.reminderContent.is-collapsed .reminder-topbar {
padding-bottom: 0;
}
div.reminderContent.is-collapsed .invert-collapses { div.reminderContent.is-collapsed .invert-collapses {
display: inline-flex; display: inline-flex;
} }
@@ -129,6 +145,12 @@ div.split-controls {
margin-top: 0 !important; margin-top: 0 !important;
} }
.reminder-settings > .column {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 50%;
}
div.reminderContent { div.reminderContent {
margin-top: 10px; margin-top: 10px;
margin-bottom: 10px; margin-bottom: 10px;
@@ -249,11 +271,11 @@ div#pageNavbar a {
.navbar-item.pageTitle { .navbar-item.pageTitle {
flex-shrink: 1; flex-shrink: 1;
text-wrap: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
.navbar-burger, .navbar-burger:active, .navbar-burger.is-active { .dashboard-burger, .dashboard-burger:active, .dashboard-burger.is-active {
background-color: #adc99c !important; background-color: #adc99c !important;
border-radius: 14px; border-radius: 14px;
padding: 6px; padding: 6px;
@@ -286,17 +308,24 @@ div.dashboard-sidebar {
padding-right: 0; padding-right: 0;
} }
div.dashboard-sidebar:not(.mobile-sidebar) { ul.guildList {
display: flex; flex-grow: 1;
flex-direction: column; flex-shrink: 1;
overflow: auto;
} }
div.dashboard-sidebar:not(.mobile-sidebar) .aside-footer { div.dashboard-sidebar:not(.mobile-sidebar) .aside-footer {
flex-shrink: 0;
flex-grow: 0;
position: fixed; position: fixed;
bottom: 0; bottom: 0;
width: 226px; width: 226px;
} }
div.dashboard-sidebar svg {
flex-shrink: 0;
}
div.mobile-sidebar { div.mobile-sidebar {
z-index: 100; z-index: 100;
min-height: 100vh; min-height: 100vh;
@@ -444,8 +473,7 @@ input.default-width {
.customizable.is-400x300 img { .customizable.is-400x300 img {
margin-top: 10px; margin-top: 10px;
width: 100%; width: 100%;
min-height: 100px; height: 100px;
max-height: 400px;
} }
.customizable.is-32x32 img { .customizable.is-32x32 img {
@@ -589,6 +617,14 @@ input.default-width {
border-bottom: 1px solid #fff; border-bottom: 1px solid #fff;
} }
.channel-selector {
width: 100%;
}
.select {
width: 100%;
}
li.highlight { li.highlight {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
@@ -612,7 +648,22 @@ li.highlight {
padding: 2px; padding: 2px;
} }
@media only screen and (max-width: 1408px) { @media only screen and (max-width: 1023px) {
p.title.pageTitle {
display: none;
}
.dashboard-frame {
margin-top: 4rem !important;
}
.customizable.thumbnail img {
width: 60px;
height: 60px;
}
}
@media only screen and (max-width: 768px) {
.button-row { .button-row {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -630,41 +681,20 @@ li.highlight {
.button-row button { .button-row button {
width: 100%; width: 100%;
} }
}
@media only screen and (max-width: 768px) { .reminder-settings {
.button-row-edit { margin-bottom: 0 !important;
display: flex;
flex-direction: column;
} }
.button-row-edit > button { .tts-row {
width: 100%; padding-bottom: 0;
margin: 4px;
}
p.title.pageTitle {
visibility: hidden;
text-wrap: nowrap;
overflow: hidden;
}
}
@media only screen and (max-width: 768px) {
.customizable.thumbnail img {
width: 60px;
height: 60px;
}
.customizable.is-24x24 img {
width: 16px;
height: 16px;
} }
} }
/* loader */ /* loader */
#loader { #loader {
position: fixed; position: fixed;
top: 0;
background-color: rgba(255, 255, 255, 0.8); background-color: rgba(255, 255, 255, 0.8);
width: 100vw; width: 100vw;
z-index: 999; z-index: 999;
@@ -676,6 +706,86 @@ li.highlight {
/* END */ /* END */
div.reminderError {
margin: 10px;
padding: 14px;
background-color: #f5f5f5;
border-radius: 8px;
}
div.reminderError .errorHead {
display: flex;
flex-direction: row;
}
div.reminderError .errorIcon {
padding: 8px;
border-radius: 4px;
margin-right: 12px;
}
div.reminderError .errorIcon .fas {
display: none
}
div.reminderError[data-case="deleted"] .errorIcon {
background-color: #e7e5e4;
}
div.reminderError[data-case="failed"] .errorIcon {
background-color: #fecaca;
}
div.reminderError[data-case="sent"] .errorIcon {
background-color: #d9f99d;
}
div.reminderError[data-case="deleted"] .errorIcon .fas.fa-trash {
display: block;
}
div.reminderError[data-case="failed"] .errorIcon .fas.fa-exclamation-triangle {
display: block;
}
div.reminderError[data-case="sent"] .errorIcon .fas.fa-check {
display: block;
}
div.reminderError .errorHead .reminderName {
font-size: 1rem;
display: flex;
flex-direction: column;
justify-content: center;
color: rgb(54, 54, 54);
flex-grow: 1;
}
div.reminderError .errorHead .reminderTime {
font-size: 1rem;
display: flex;
flex-direction: column;
flex-shrink: 1;
justify-content: center;
color: rgb(54, 54, 54);
background-color: #ffffff;
padding: 8px;
border-radius: 4px;
border-color: #e5e5e5;
border-width: 1px;
border-style: solid;
}
div.reminderError .reminderMessage {
font-size: 1rem;
display: flex;
flex-direction: column;
justify-content: center;
color: rgb(54, 54, 54);
flex-grow: 1;
font-style: italic;
}
/* other stuff */ /* other stuff */
.half-rem { .half-rem {
@@ -713,15 +823,38 @@ a.switch-pane {
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.guild-submenu {
display: none;
}
.guild-submenu li {
font-size: 0.8rem;
}
a.switch-pane.is-active ~ .guild-submenu {
display: block;
}
.feedback { .feedback {
background-color: #5865F2; background-color: #5865F2;
} }
.is-locked { .is-locked {
pointer-events: none; pointer-events: none;
}
.is-locked > :not(.patreon-invert) {
opacity: 0.4; opacity: 0.4;
} }
.is-locked .patreon-invert {
display: block;
}
.patreon-invert {
display: none;
}
.is-locked .foreground { .is-locked .foreground {
pointer-events: auto; pointer-events: auto;
} }
@@ -751,5 +884,5 @@ a.switch-pane {
} }
.figure-num { .figure-num {
font-size: 2em; font-size: 2rem;
} }
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.
@@ -223,11 +223,10 @@ async function fetch_reminders(guild_id) {
} }
async function serialize_reminder(node, mode) { async function serialize_reminder(node, mode) {
let interval, utc_time, expiration_time; let utc_time, expiration_time;
let interval = get_interval(node);
if (mode !== "template") { if (mode !== "template") {
interval = get_interval(node);
utc_time = luxon.DateTime.fromISO( utc_time = luxon.DateTime.fromISO(
node.querySelector('input[name="time"]').value node.querySelector('input[name="time"]').value
).setZone("UTC"); ).setZone("UTC");
@@ -356,9 +355,9 @@ async function serialize_reminder(node, mode) {
embed_title: embed_title, embed_title: embed_title,
embed_fields: fields, embed_fields: fields,
expires: expiration_time, expires: expiration_time,
interval_seconds: mode !== "template" ? interval.seconds : null, interval_seconds: interval.seconds,
interval_days: mode !== "template" ? interval.days : null, interval_days: interval.days,
interval_months: mode !== "template" ? interval.months : null, interval_months: interval.months,
name: node.querySelector('input[name="name"]').value, name: node.querySelector('input[name="name"]').value,
tts: node.querySelector('input[name="tts"]').checked, tts: node.querySelector('input[name="tts"]').checked,
username: node.querySelector('input[name="username"]').value, username: node.querySelector('input[name="username"]').value,
@@ -420,9 +419,9 @@ function deserialize_reminder(reminder, frame, mode) {
.insertBefore(embed_field, lastChild); .insertBefore(embed_field, lastChild);
} }
if (mode !== "template") { if (reminder["interval_seconds"]) update_interval(frame);
if (reminder["interval_seconds"]) update_interval(frame);
if (mode !== "template") {
let $enableBtn = frame.querySelector(".disable-enable"); let $enableBtn = frame.querySelector(".disable-enable");
$enableBtn.dataset["action"] = reminder["enabled"] ? "disable" : "enable"; $enableBtn.dataset["action"] = reminder["enabled"] ? "disable" : "enable";
@@ -604,6 +603,16 @@ function show_error(error) {
}, 5000); }, 5000);
} }
function show_success(error) {
document.getElementById("success").querySelector("span.success-message").textContent =
error;
document.getElementById("success").classList.add("is-active");
window.setTimeout(() => {
document.getElementById("success").classList.remove("is-active");
}, 5000);
}
$colorPickerInput.value = colorPicker.color.hexString; $colorPickerInput.value = colorPicker.color.hexString;
$colorPickerInput.addEventListener("input", () => { $colorPickerInput.addEventListener("input", () => {
@@ -754,12 +763,26 @@ $uploader.addEventListener("change", (ev) => {
fileReader.onload = (e) => resolve(fileReader.result); fileReader.onload = (e) => resolve(fileReader.result);
fileReader.readAsDataURL($uploader.files[0]); fileReader.readAsDataURL($uploader.files[0]);
}).then((dataUrl) => { }).then((dataUrl) => {
$importBtn.setAttribute("disabled", true);
fetch(`/dashboard/api/guild/${guildId()}/export/${urlTail}`, { fetch(`/dashboard/api/guild/${guildId()}/export/${urlTail}`, {
method: "PUT", method: "PUT",
body: JSON.stringify({ body: dataUrl.split(",")[1] }), body: JSON.stringify({ body: dataUrl.split(",")[1] }),
}).then(() => { })
delete $uploader.files[0]; .then((response) => response.json())
}); .then((data) => {
$importBtn.removeAttribute("disabled");
if (data.error) {
show_error(data.error);
} else {
show_success(data.message);
}
})
.then(() => {
delete $uploader.files[0];
fetch_reminders(guild);
});
}); });
}); });
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 366 files, more files were not shown because too many files have changed in this diff. Show more