Compare commits
	
		
			1 Commits
		
	
	
		
			next
			...
			jude/confi
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 53aa5ebc55 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,3 +3,5 @@ | |||||||
| /venv | /venv | ||||||
| .cargo | .cargo | ||||||
| /.idea | /.idea | ||||||
|  |  | ||||||
|  | node_modules/ | ||||||
|   | |||||||
							
								
								
									
										1389
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1389
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										12
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								Cargo.toml
									
									
									
									
									
								
							| @@ -1,18 +1,18 @@ | |||||||
| [package] | [package] | ||||||
| name = "reminder-rs" | name = "reminder-rs" | ||||||
| version = "1.6.40" | version = "1.6.36" | ||||||
| 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" | poise = "0.5.5" | ||||||
| dotenv = "0.15" | dotenv = "0.15" | ||||||
| tokio = { version = "1", features = ["process", "full"] } | tokio = { version = "1", features = ["process", "full"] } | ||||||
| reqwest = "0.11" | reqwest = "0.11" | ||||||
| lazy-regex = "3.0" | lazy-regex = "2.3.0" | ||||||
| regex = "1.9" | regex = "1.6" | ||||||
| log = "0.4" | log = "0.4" | ||||||
| env_logger = "0.10" | env_logger = "0.10" | ||||||
| chrono = "0.4" | chrono = "0.4" | ||||||
| @@ -25,7 +25,7 @@ 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.7", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono", "migrate"]} | sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono", "migrate"]} | ||||||
| base64 = "0.21.0" | base64 = "0.21.0" | ||||||
|  |  | ||||||
| [dependencies.postman] | [dependencies.postman] | ||||||
| @@ -42,7 +42,7 @@ assets = [ | |||||||
|     ["target/release/reminder-rs", "usr/bin/reminder-rs", "755"], |     ["target/release/reminder-rs", "usr/bin/reminder-rs", "755"], | ||||||
|     ["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"], | ||||||
|     ["web/static/**/*", "lib/reminder-rs/static", "644"], |     ["$OUT_DIR/web/static/**/*", "lib/reminder-rs/static", "644"], | ||||||
|     ["web/templates/**/*", "lib/reminder-rs/templates", "644"], |     ["web/templates/**/*", "lib/reminder-rs/templates", "644"], | ||||||
|     ["healthcheck", "lib/reminder-rs/healthcheck", "755"], |     ["healthcheck", "lib/reminder-rs/healthcheck", "755"], | ||||||
|     ["cron.d/reminder_health", "etc/cron.d/reminder_health", "644"], |     ["cron.d/reminder_health", "etc/cron.d/reminder_health", "644"], | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								build.rs
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								build.rs
									
									
									
									
									
								
							| @@ -1,3 +1,99 @@ | |||||||
|  | #[cfg(not(debug_assertions))] | ||||||
|  | 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"); | ||||||
|  |  | ||||||
|  |     #[cfg(not(debug_assertions))] | ||||||
|  |     visit_dirs("web/static".as_ref(), &process_static).unwrap(); | ||||||
|  |  | ||||||
|  |     // visit_dirs("web/static".as_ref(), &compile_tsc).unwrap(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,19 +0,0 @@ | |||||||
| -- Drop existing constraint |  | ||||||
| ALTER TABLE `reminders` DROP CONSTRAINT `reminders_ibfk_1`; |  | ||||||
|  |  | ||||||
| ALTER TABLE `reminders` MODIFY COLUMN `channel_id` INT UNSIGNED; |  | ||||||
| ALTER TABLE `reminders` ADD COLUMN `guild_id` INT UNSIGNED; |  | ||||||
|  |  | ||||||
| ALTER TABLE `reminders` |  | ||||||
|     ADD CONSTRAINT `guild_id_fk` |  | ||||||
|         FOREIGN KEY (`guild_id`) |  | ||||||
|         REFERENCES `guilds`(`id`) |  | ||||||
|         ON DELETE CASCADE; |  | ||||||
|  |  | ||||||
| ALTER TABLE `reminders` |  | ||||||
|     ADD CONSTRAINT `channel_id_fk` |  | ||||||
|         FOREIGN KEY (`channel_id`) |  | ||||||
|         REFERENCES `channels`(`id`) |  | ||||||
|         ON DELETE SET NULL; |  | ||||||
|  |  | ||||||
| UPDATE `reminders` SET `guild_id` = (SELECT guilds.`id` FROM `channels` INNER JOIN `guilds` ON channels.guild_id = guilds.id WHERE reminders.channel_id = channels.id); |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| ALTER TABLE reminders ADD COLUMN `status_change_time` DATETIME; |  | ||||||
|  |  | ||||||
| -- This is a best-guess as to the status change time. |  | ||||||
| UPDATE reminders SET `status_change_time` = `utc_time` WHERE `status` != 'pending'; |  | ||||||
							
								
								
									
										485
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										485
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,485 @@ | |||||||
|  | { | ||||||
|  |   "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
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |   "devDependencies": { | ||||||
|  |     "minify": "^10.3.0", | ||||||
|  |     "prettier": "^3.0.1", | ||||||
|  |     "tsc": "^2.0.4" | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -5,12 +5,12 @@ edition = "2021" | |||||||
|  |  | ||||||
| [dependencies] | [dependencies] | ||||||
| tokio = { version = "1", features = ["process", "full"] } | tokio = { version = "1", features = ["process", "full"] } | ||||||
| regex = "1.9" | regex = "1.4" | ||||||
| log = "0.4" | log = "0.4" | ||||||
| chrono = "0.4" | chrono = "0.4" | ||||||
| chrono-tz = { version = "0.8", features = ["serde"] } | chrono-tz = { version = "0.5", features = ["serde"] } | ||||||
| lazy_static = "1.4" | lazy_static = "1.4" | ||||||
| num-integer = "0.1" | num-integer = "0.1" | ||||||
| serde = "1.0" | serde = "1.0" | ||||||
| sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono", "json"]} | sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono", "json"]} | ||||||
| serenity = { version = "0.11", 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"] } | ||||||
|   | |||||||
| @@ -237,11 +237,11 @@ impl Into<CreateEmbed> for Embed { | |||||||
| pub struct Reminder { | pub struct Reminder { | ||||||
|     id: u32, |     id: u32, | ||||||
|  |  | ||||||
|     channel_id: Option<u64>, |     channel_id: u64, | ||||||
|     webhook_id: Option<u64>, |     webhook_id: Option<u64>, | ||||||
|     webhook_token: Option<String>, |     webhook_token: Option<String>, | ||||||
|  |  | ||||||
|     channel_paused: Option<bool>, |     channel_paused: bool, | ||||||
|     channel_paused_until: Option<NaiveDateTime>, |     channel_paused_until: Option<NaiveDateTime>, | ||||||
|     enabled: bool, |     enabled: bool, | ||||||
|  |  | ||||||
| @@ -297,7 +297,7 @@ SELECT | |||||||
|     reminders.`username` AS username |     reminders.`username` AS username | ||||||
| FROM | FROM | ||||||
|     reminders |     reminders | ||||||
| LEFT JOIN | INNER JOIN | ||||||
|     channels |     channels | ||||||
| ON | ON | ||||||
|     reminders.channel_id = channels.id |     reminders.channel_id = channels.id | ||||||
| @@ -343,10 +343,7 @@ WHERE | |||||||
|  |  | ||||||
|     async fn reset_webhook(&self, pool: impl Executor<'_, Database = Database> + Copy) { |     async fn reset_webhook(&self, pool: impl Executor<'_, Database = Database> + Copy) { | ||||||
|         let _ = sqlx::query!( |         let _ = sqlx::query!( | ||||||
|             " |             "UPDATE channels SET webhook_id = NULL, webhook_token = NULL WHERE channel = ?", | ||||||
|             UPDATE channels SET webhook_id = NULL, webhook_token = NULL |  | ||||||
|             WHERE channel = ? |  | ||||||
|             ", |  | ||||||
|             self.channel_id |             self.channel_id | ||||||
|         ) |         ) | ||||||
|         .execute(pool) |         .execute(pool) | ||||||
| @@ -418,9 +415,7 @@ WHERE | |||||||
|                 self.set_sent(pool).await; |                 self.set_sent(pool).await; | ||||||
|             } else { |             } else { | ||||||
|                 sqlx::query!( |                 sqlx::query!( | ||||||
|                     " |                     "UPDATE reminders SET `utc_time` = ? WHERE `id` = ?", | ||||||
|                     UPDATE reminders SET `utc_time` = ? WHERE `id` = ? |  | ||||||
|                     ", |  | ||||||
|                     updated_reminder_time.with_timezone(&Utc), |                     updated_reminder_time.with_timezone(&Utc), | ||||||
|                     self.id |                     self.id | ||||||
|                 ) |                 ) | ||||||
| @@ -453,10 +448,7 @@ WHERE | |||||||
|  |  | ||||||
|         if *LOG_TO_DATABASE { |         if *LOG_TO_DATABASE { | ||||||
|             sqlx::query!( |             sqlx::query!( | ||||||
|                 " |                 "INSERT INTO stat (type, reminder_id, message) VALUES ('reminder_failed', ?, ?)", | ||||||
|                 INSERT INTO stat (type, reminder_id, message) |  | ||||||
|                 VALUES ('reminder_failed', ?, ?) |  | ||||||
|                 ", |  | ||||||
|                 self.id, |                 self.id, | ||||||
|                 message, |                 message, | ||||||
|             ) |             ) | ||||||
| @@ -469,10 +461,7 @@ WHERE | |||||||
|     async fn log_success(&self, pool: impl Executor<'_, Database = Database> + Copy) { |     async fn log_success(&self, pool: impl Executor<'_, Database = Database> + Copy) { | ||||||
|         if *LOG_TO_DATABASE { |         if *LOG_TO_DATABASE { | ||||||
|             sqlx::query!( |             sqlx::query!( | ||||||
|                 " |                 "INSERT INTO stat (type, reminder_id) VALUES ('reminder_sent', ?)", | ||||||
|                 INSERT INTO stat (type, reminder_id) |  | ||||||
|                 VALUES ('reminder_sent', ?) |  | ||||||
|                 ", |  | ||||||
|                 self.id, |                 self.id, | ||||||
|             ) |             ) | ||||||
|             .execute(pool) |             .execute(pool) | ||||||
| @@ -482,14 +471,7 @@ WHERE | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async fn set_sent(&self, pool: impl Executor<'_, Database = Database> + Copy) { |     async fn set_sent(&self, pool: impl Executor<'_, Database = Database> + Copy) { | ||||||
|         sqlx::query!( |         sqlx::query!("UPDATE reminders SET `status` = 'sent' WHERE `id` = ?", self.id) | ||||||
|             " |  | ||||||
|             UPDATE reminders |  | ||||||
|             SET `status` = 'sent', `status_change_time` = NOW() |  | ||||||
|             WHERE `id` = ? |  | ||||||
|             ", |  | ||||||
|             self.id |  | ||||||
|         ) |  | ||||||
|             .execute(pool) |             .execute(pool) | ||||||
|             .await |             .await | ||||||
|             .expect(&format!("Could not delete Reminder {}", self.id)); |             .expect(&format!("Could not delete Reminder {}", self.id)); | ||||||
| @@ -501,11 +483,7 @@ WHERE | |||||||
|         message: &'static str, |         message: &'static str, | ||||||
|     ) { |     ) { | ||||||
|         sqlx::query!( |         sqlx::query!( | ||||||
|             " |             "UPDATE reminders SET `status` = 'failed', `status_message` = ? WHERE `id` = ?", | ||||||
|             UPDATE reminders |  | ||||||
|             SET `status` = 'failed', `status_message` = ?, `status_change_time` = NOW() |  | ||||||
|             WHERE `id` = ? |  | ||||||
|             ", |  | ||||||
|             message, |             message, | ||||||
|             self.id |             self.id | ||||||
|         ) |         ) | ||||||
| @@ -515,9 +493,7 @@ WHERE | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async fn pin_message<M: Into<u64>>(&self, message_id: M, http: impl AsRef<Http>) { |     async fn pin_message<M: Into<u64>>(&self, message_id: M, http: impl AsRef<Http>) { | ||||||
|         if let Some(channel_id) = self.channel_id { |         let _ = http.as_ref().pin_message(self.channel_id, message_id.into(), None).await; | ||||||
|             let _ = http.as_ref().pin_message(channel_id, message_id.into(), None).await; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub async fn send( |     pub async fn send( | ||||||
| @@ -527,11 +503,10 @@ WHERE | |||||||
|     ) { |     ) { | ||||||
|         async fn send_to_channel( |         async fn send_to_channel( | ||||||
|             cache_http: impl CacheHttp, |             cache_http: impl CacheHttp, | ||||||
|             channel_id: u64, |  | ||||||
|             reminder: &Reminder, |             reminder: &Reminder, | ||||||
|             embed: Option<CreateEmbed>, |             embed: Option<CreateEmbed>, | ||||||
|         ) -> Result<()> { |         ) -> Result<()> { | ||||||
|             let channel = ChannelId(channel_id).to_channel(&cache_http).await; |             let channel = ChannelId(reminder.channel_id).to_channel(&cache_http).await; | ||||||
|  |  | ||||||
|             match channel { |             match channel { | ||||||
|                 Ok(Channel::Guild(channel)) => { |                 Ok(Channel::Guild(channel)) => { | ||||||
| @@ -563,7 +538,6 @@ WHERE | |||||||
|                         Err(e) => Err(e), |                         Err(e) => Err(e), | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Ok(Channel::Private(channel)) => { |                 Ok(Channel::Private(channel)) => { | ||||||
|                     match channel |                     match channel | ||||||
|                         .send_message(&cache_http.http(), |m| { |                         .send_message(&cache_http.http(), |m| { | ||||||
| @@ -593,9 +567,7 @@ WHERE | |||||||
|                         Err(e) => Err(e), |                         Err(e) => Err(e), | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Err(e) => Err(e), |                 Err(e) => Err(e), | ||||||
|  |  | ||||||
|                 _ => Err(Error::Other("Channel not of valid type")), |                 _ => Err(Error::Other("Channel not of valid type")), | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -650,20 +622,14 @@ WHERE | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         match self.channel_id { |  | ||||||
|             Some(channel_id) => { |  | ||||||
|         if self.enabled |         if self.enabled | ||||||
|                     && !(self.channel_paused.unwrap_or(false) |             && !(self.channel_paused | ||||||
|                 && self |                 && self | ||||||
|                     .channel_paused_until |                     .channel_paused_until | ||||||
|                     .map_or(true, |inner| inner >= Utc::now().naive_local())) |                     .map_or(true, |inner| inner >= Utc::now().naive_local())) | ||||||
|         { |         { | ||||||
|             let _ = sqlx::query!( |             let _ = sqlx::query!( | ||||||
|                         " |                 "UPDATE `channels` SET paused = 0, paused_until = NULL WHERE `channel` = ?", | ||||||
|                         UPDATE `channels` |  | ||||||
|                         SET paused = 0, paused_until = NULL |  | ||||||
|                         WHERE `channel` = ? |  | ||||||
|                         ", |  | ||||||
|                 self.channel_id |                 self.channel_id | ||||||
|             ) |             ) | ||||||
|             .execute(pool) |             .execute(pool) | ||||||
| @@ -674,10 +640,8 @@ WHERE | |||||||
|             let result = if let (Some(webhook_id), Some(webhook_token)) = |             let result = if let (Some(webhook_id), Some(webhook_token)) = | ||||||
|                 (self.webhook_id, &self.webhook_token) |                 (self.webhook_id, &self.webhook_token) | ||||||
|             { |             { | ||||||
|                         let webhook_res = cache_http |                 let webhook_res = | ||||||
|                             .http() |                     cache_http.http().get_webhook_with_token(webhook_id, webhook_token).await; | ||||||
|                             .get_webhook_with_token(webhook_id, webhook_token) |  | ||||||
|                             .await; |  | ||||||
|  |  | ||||||
|                 if let Ok(webhook) = webhook_res { |                 if let Ok(webhook) = webhook_res { | ||||||
|                     send_to_webhook(cache_http, &self, webhook, embed).await |                     send_to_webhook(cache_http, &self, webhook, embed).await | ||||||
| @@ -685,10 +649,10 @@ WHERE | |||||||
|                     warn!("Webhook vanished for reminder {}: {:?}", self.id, webhook_res); |                     warn!("Webhook vanished for reminder {}: {:?}", self.id, webhook_res); | ||||||
|  |  | ||||||
|                     self.reset_webhook(pool).await; |                     self.reset_webhook(pool).await; | ||||||
|                             send_to_channel(cache_http, channel_id, &self, embed).await |                     send_to_channel(cache_http, &self, embed).await | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                         send_to_channel(cache_http, channel_id, &self, embed).await |                 send_to_channel(cache_http, &self, embed).await | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             if let Err(e) = result { |             if let Err(e) = result { | ||||||
| @@ -715,10 +679,7 @@ WHERE | |||||||
|                                     None::<&'static str>, |                                     None::<&'static str>, | ||||||
|                                 ) |                                 ) | ||||||
|                                 .await; |                                 .await; | ||||||
|                                         self.set_failed( |                                 self.set_failed(pool, "Could not be sent as guild does not exist") | ||||||
|                                             pool, |  | ||||||
|                                             "Could not be sent as guild does not exist", |  | ||||||
|                                         ) |  | ||||||
|                                     .await; |                                     .await; | ||||||
|                             } |                             } | ||||||
|                             50001 => { |                             50001 => { | ||||||
| @@ -728,11 +689,7 @@ WHERE | |||||||
|                                     None::<&'static str>, |                                     None::<&'static str>, | ||||||
|                                 ) |                                 ) | ||||||
|                                 .await; |                                 .await; | ||||||
|                                         self.set_failed( |                                 self.set_failed(pool, "Could not be sent as missing access").await; | ||||||
|                                             pool, |  | ||||||
|                                             "Could not be sent as missing access", |  | ||||||
|                                         ) |  | ||||||
|                                         .await; |  | ||||||
|                             } |                             } | ||||||
|                             50007 => { |                             50007 => { | ||||||
|                                 self.log_error( |                                 self.log_error( | ||||||
| @@ -741,10 +698,7 @@ WHERE | |||||||
|                                     None::<&'static str>, |                                     None::<&'static str>, | ||||||
|                                 ) |                                 ) | ||||||
|                                 .await; |                                 .await; | ||||||
|                                         self.set_failed( |                                 self.set_failed(pool, "Could not be sent as user has DMs disabled") | ||||||
|                                             pool, |  | ||||||
|                                             "Could not be sent as user has DMs disabled", |  | ||||||
|                                         ) |  | ||||||
|                                     .await; |                                     .await; | ||||||
|                             } |                             } | ||||||
|                             50013 => { |                             50013 => { | ||||||
| @@ -788,13 +742,4 @@ WHERE | |||||||
|             self.refresh(pool).await; |             self.refresh(pool).await; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|             None => { |  | ||||||
|                 info!("Reminder {} is orphaned", self.id); |  | ||||||
|  |  | ||||||
|                 self.log_error(pool, "Orphaned", Option::<u8>::None).await; |  | ||||||
|                 self.set_failed(pool, "Could not be sent as channel was deleted").await; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ pub async fn migrate_macro(ctx: Context<'_>) -> Result<(), Error> { | |||||||
|         "SELECT name, command FROM command_aliases WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)", |         "SELECT name, command FROM command_aliases WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)", | ||||||
|         guild_id.0 |         guild_id.0 | ||||||
|     ) |     ) | ||||||
|     .fetch_all(&mut *transaction) |     .fetch_all(&mut transaction) | ||||||
|     .await?; |     .await?; | ||||||
|  |  | ||||||
|     let mut added_aliases = 0; |     let mut added_aliases = 0; | ||||||
| @@ -42,7 +42,7 @@ pub async fn migrate_macro(ctx: Context<'_>) -> Result<(), Error> { | |||||||
|                     cmd_macro.description, |                     cmd_macro.description, | ||||||
|                     cmd_macro.commands |                     cmd_macro.commands | ||||||
|                 ) |                 ) | ||||||
|                 .execute(&mut *transaction) |                 .execute(&mut transaction) | ||||||
|                 .await?; |                 .await?; | ||||||
|  |  | ||||||
|                 added_aliases += 1; |                 added_aliases += 1; | ||||||
|   | |||||||
| @@ -166,21 +166,15 @@ impl ComponentDataModel { | |||||||
|                     .await; |                     .await; | ||||||
|             } |             } | ||||||
|             ComponentDataModel::DelSelector(selector) => { |             ComponentDataModel::DelSelector(selector) => { | ||||||
|                 for id in &component.data.values { |                 let selected_id = component.data.values.join(","); | ||||||
|                     match id.parse::<u32>() { |  | ||||||
|                         Ok(id) => { |  | ||||||
|                             if let Some(reminder) = Reminder::from_id(&data.database, id).await { |  | ||||||
|                                 reminder.delete(&data.database).await.unwrap(); |  | ||||||
|                             } else { |  | ||||||
|                                 warn!("Attempt to delete non-existent reminder"); |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                         Err(e) => { |                 sqlx::query!( | ||||||
|                             warn!("Error casting ID to integer: {:?}.", e); |                     "UPDATE reminders SET `status` = 'pending' WHERE FIND_IN_SET(id, ?)", | ||||||
|                         } |                     selected_id | ||||||
|                     } |                 ) | ||||||
|                 } |                 .execute(&data.database) | ||||||
|  |                 .await | ||||||
|  |                 .unwrap(); | ||||||
|  |  | ||||||
|                 let reminders = Reminder::from_guild( |                 let reminders = Reminder::from_guild( | ||||||
|                     &ctx, |                     &ctx, | ||||||
|   | |||||||
| @@ -10,7 +10,6 @@ pub struct ChannelData { | |||||||
|     pub webhook_id: Option<u64>, |     pub webhook_id: Option<u64>, | ||||||
|     pub webhook_token: Option<String>, |     pub webhook_token: Option<String>, | ||||||
|     pub paused: bool, |     pub paused: bool, | ||||||
|     pub db_guild_id: Option<u32>, |  | ||||||
|     pub paused_until: Option<NaiveDateTime>, |     pub paused_until: Option<NaiveDateTime>, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -23,11 +22,7 @@ impl ChannelData { | |||||||
|  |  | ||||||
|         if let Ok(c) = sqlx::query_as_unchecked!( |         if let Ok(c) = sqlx::query_as_unchecked!( | ||||||
|             Self, |             Self, | ||||||
|             " |             "SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_until FROM channels WHERE channel = ?", | ||||||
|             SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_until, |  | ||||||
|                 guild_id AS db_guild_id |  | ||||||
|             FROM channels WHERE channel = ? |  | ||||||
|             ", |  | ||||||
|             channel_id |             channel_id | ||||||
|         ) |         ) | ||||||
|         .fetch_one(pool) |         .fetch_one(pool) | ||||||
| @@ -35,18 +30,12 @@ impl ChannelData { | |||||||
|         { |         { | ||||||
|             Ok(c) |             Ok(c) | ||||||
|         } else { |         } else { | ||||||
|             let props = |             let props = channel.to_owned().guild().map(|g| (g.guild_id.as_u64().to_owned(), g.name)); | ||||||
|                 channel.to_owned().guild().map(|g| (g.guild_id.as_u64().to_owned(), g.name)); |  | ||||||
|  |  | ||||||
|             let (guild_id, channel_name) = |             let (guild_id, channel_name) = if let Some((a, b)) = props { (Some(a), Some(b)) } else { (None, None) }; | ||||||
|                 if let Some((a, b)) = props { (Some(a), Some(b)) } else { (None, None) }; |  | ||||||
|  |  | ||||||
|             sqlx::query!( |             sqlx::query!( | ||||||
|                 " |                 "INSERT IGNORE INTO channels (channel, name, guild_id) VALUES (?, ?, (SELECT id FROM guilds WHERE guild = ?))", | ||||||
|                 INSERT IGNORE INTO channels |  | ||||||
|                 (channel, name, guild_id) |  | ||||||
|                 VALUES (?, ?, (SELECT id FROM guilds WHERE guild = ?)) |  | ||||||
|                 ", |  | ||||||
|                 channel_id, |                 channel_id, | ||||||
|                 channel_name, |                 channel_name, | ||||||
|                 guild_id |                 guild_id | ||||||
| @@ -57,10 +46,7 @@ impl ChannelData { | |||||||
|             Ok(sqlx::query_as_unchecked!( |             Ok(sqlx::query_as_unchecked!( | ||||||
|                 Self, |                 Self, | ||||||
|                 " |                 " | ||||||
|                 SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, | SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_until FROM channels WHERE channel = ? | ||||||
|                     paused_until, guild_id AS db_guild_id |  | ||||||
|                 FROM channels |  | ||||||
|                 WHERE channel = ? |  | ||||||
|                 ", |                 ", | ||||||
|                 channel_id |                 channel_id | ||||||
|             ) |             ) | ||||||
| @@ -72,10 +58,8 @@ impl ChannelData { | |||||||
|     pub async fn commit_changes(&self, pool: &MySqlPool) { |     pub async fn commit_changes(&self, pool: &MySqlPool) { | ||||||
|         sqlx::query!( |         sqlx::query!( | ||||||
|             " |             " | ||||||
|             UPDATE channels | UPDATE channels SET name = ?, nudge = ?, blacklisted = ?, webhook_id = ?, webhook_token = ?, paused = ?, paused_until \ | ||||||
|             SET name = ?, nudge = ?, blacklisted = ?, webhook_id = ?, webhook_token = ?, |              = ? WHERE id = ? | ||||||
|                 paused = ?, paused_until = ? |  | ||||||
|             WHERE id = ? |  | ||||||
|             ", |             ", | ||||||
|             self.name, |             self.name, | ||||||
|             self.nudge, |             self.nudge, | ||||||
|   | |||||||
| @@ -51,7 +51,6 @@ pub struct ReminderBuilder { | |||||||
|     pool: MySqlPool, |     pool: MySqlPool, | ||||||
|     uid: String, |     uid: String, | ||||||
|     channel: u32, |     channel: u32, | ||||||
|     guild: Option<u32>, |  | ||||||
|     thread_id: Option<u64>, |     thread_id: Option<u64>, | ||||||
|     utc_time: NaiveDateTime, |     utc_time: NaiveDateTime, | ||||||
|     timezone: String, |     timezone: String, | ||||||
| @@ -87,7 +86,6 @@ impl ReminderBuilder { | |||||||
| INSERT INTO reminders ( | INSERT INTO reminders ( | ||||||
|     `uid`, |     `uid`, | ||||||
|     `channel_id`, |     `channel_id`, | ||||||
|     `guild_id`, |  | ||||||
|     `utc_time`, |     `utc_time`, | ||||||
|     `timezone`, |     `timezone`, | ||||||
|     `interval_seconds`, |     `interval_seconds`, | ||||||
| @@ -112,13 +110,11 @@ INSERT INTO reminders ( | |||||||
|     ?, |     ?, | ||||||
|     ?, |     ?, | ||||||
|     ?, |     ?, | ||||||
|     ?, |  | ||||||
|     ? |     ? | ||||||
| ) | ) | ||||||
|             ", |             ", | ||||||
|                         self.uid, |                         self.uid, | ||||||
|                         self.channel, |                         self.channel, | ||||||
|                         self.guild, |  | ||||||
|                         utc_time, |                         utc_time, | ||||||
|                         self.timezone, |                         self.timezone, | ||||||
|                         self.interval_seconds, |                         self.interval_seconds, | ||||||
| @@ -251,10 +247,10 @@ impl<'a> MultiReminderBuilder<'a> { | |||||||
|                                 { |                                 { | ||||||
|                                     Err(ReminderError::UserBlockedDm) |                                     Err(ReminderError::UserBlockedDm) | ||||||
|                                 } else { |                                 } else { | ||||||
|                                     Ok((user_data.dm_channel, None)) |                                     Ok(user_data.dm_channel) | ||||||
|                                 } |                                 } | ||||||
|                             } else { |                             } else { | ||||||
|                                 Ok((user_data.dm_channel, None)) |                                 Ok(user_data.dm_channel) | ||||||
|                             } |                             } | ||||||
|                         } else { |                         } else { | ||||||
|                             Err(ReminderError::InvalidTag) |                             Err(ReminderError::InvalidTag) | ||||||
| @@ -301,13 +297,13 @@ impl<'a> MultiReminderBuilder<'a> { | |||||||
|                                                 .commit_changes(&self.ctx.data().database) |                                                 .commit_changes(&self.ctx.data().database) | ||||||
|                                                 .await; |                                                 .await; | ||||||
|  |  | ||||||
|                                             Ok((channel_data.id, channel_data.db_guild_id)) |                                             Ok(channel_data.id) | ||||||
|                                         } |                                         } | ||||||
|  |  | ||||||
|                                         Err(e) => Err(ReminderError::DiscordError(e.to_string())), |                                         Err(e) => Err(ReminderError::DiscordError(e.to_string())), | ||||||
|                                     } |                                     } | ||||||
|                                 } else { |                                 } else { | ||||||
|                                     Ok((channel_data.id, channel_data.db_guild_id)) |                                     Ok(channel_data.id) | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } else { |                         } else { | ||||||
| @@ -321,8 +317,7 @@ impl<'a> MultiReminderBuilder<'a> { | |||||||
|                         let builder = ReminderBuilder { |                         let builder = ReminderBuilder { | ||||||
|                             pool: self.ctx.data().database.clone(), |                             pool: self.ctx.data().database.clone(), | ||||||
|                             uid: generate_uid(), |                             uid: generate_uid(), | ||||||
|                             channel: c.0, |                             channel: c, | ||||||
|                             guild: c.1, |  | ||||||
|                             thread_id, |                             thread_id, | ||||||
|                             utc_time: self.utc_time, |                             utc_time: self.utc_time, | ||||||
|                             timezone: self.timezone.to_string(), |                             timezone: self.timezone.to_string(), | ||||||
|   | |||||||
| @@ -304,10 +304,7 @@ WHERE | |||||||
|         &self, |         &self, | ||||||
|         db: impl Executor<'_, Database = Database>, |         db: impl Executor<'_, Database = Database>, | ||||||
|     ) -> Result<(), sqlx::Error> { |     ) -> Result<(), sqlx::Error> { | ||||||
|         sqlx::query!( |         sqlx::query!("UPDATE reminders SET `status` = 'deleted' WHERE uid = ?", self.uid) | ||||||
|             "UPDATE reminders SET `status` = 'deleted', `status_change_time` = NOW() WHERE uid = ?", |  | ||||||
|             self.uid |  | ||||||
|         ) |  | ||||||
|             .execute(db) |             .execute(db) | ||||||
|             .await |             .await | ||||||
|             .map(|_| ()) |             .map(|_| ()) | ||||||
|   | |||||||
| @@ -7,14 +7,14 @@ edition = "2018" | |||||||
| [dependencies] | [dependencies] | ||||||
| rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "master", features = ["tls", "secrets", "json"] } | 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"] } | rocket_dyn_templates = { git = "https://github.com/SergioBenitez/Rocket", branch = "master", features = ["tera"] } | ||||||
| serenity = { version = "0.11", 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" | oauth2 = "4" | ||||||
| log = "0.4" | log = "0.4" | ||||||
| reqwest = "0.11" | reqwest = "0.11" | ||||||
| serde = { version = "1.0", features = ["derive"] } | serde = { version = "1.0", features = ["derive"] } | ||||||
| sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "macros", "mysql", "chrono", "json"] } | sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "macros", "mysql", "chrono", "json"] } | ||||||
| chrono = "0.4" | chrono = "0.4" | ||||||
| chrono-tz = "0.8" | chrono-tz = "0.5" | ||||||
| lazy_static = "1.4.0" | lazy_static = "1.4.0" | ||||||
| rand = "0.7" | rand = "0.7" | ||||||
| base64 = "0.13" | base64 = "0.13" | ||||||
|   | |||||||
| @@ -72,14 +72,10 @@ pub async fn initialize( | |||||||
|     db_pool: Pool<Database>, |     db_pool: Pool<Database>, | ||||||
| ) -> Result<(), Box<dyn std::error::Error>> { | ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|     info!("Checking environment variables..."); |     info!("Checking environment variables..."); | ||||||
|  |  | ||||||
|     if env::var("OFFLINE").map_or(true, |v| v != "1") { |  | ||||||
|     env::var("OAUTH2_CLIENT_ID").expect("`OAUTH2_CLIENT_ID' not supplied"); |     env::var("OAUTH2_CLIENT_ID").expect("`OAUTH2_CLIENT_ID' not supplied"); | ||||||
|     env::var("OAUTH2_CLIENT_SECRET").expect("`OAUTH2_CLIENT_SECRET' not supplied"); |     env::var("OAUTH2_CLIENT_SECRET").expect("`OAUTH2_CLIENT_SECRET' not supplied"); | ||||||
|     env::var("OAUTH2_DISCORD_CALLBACK").expect("`OAUTH2_DISCORD_CALLBACK' not supplied"); |     env::var("OAUTH2_DISCORD_CALLBACK").expect("`OAUTH2_DISCORD_CALLBACK' not supplied"); | ||||||
|     env::var("PATREON_GUILD_ID").expect("`PATREON_GUILD_ID' not supplied"); |     env::var("PATREON_GUILD_ID").expect("`PATREON_GUILD_ID' not supplied"); | ||||||
|     } |  | ||||||
|  |  | ||||||
|     info!("Done!"); |     info!("Done!"); | ||||||
|  |  | ||||||
|     let oauth2_client = BasicClient::new( |     let oauth2_client = BasicClient::new( | ||||||
| @@ -150,8 +146,7 @@ pub async fn initialize( | |||||||
|         .mount( |         .mount( | ||||||
|             "/dashboard", |             "/dashboard", | ||||||
|             routes![ |             routes![ | ||||||
|                 routes::dashboard::dashboard_1, |                 routes::dashboard::dashboard, | ||||||
|                 routes::dashboard::dashboard_2, |  | ||||||
|                 routes::dashboard::dashboard_home, |                 routes::dashboard::dashboard_home, | ||||||
|                 routes::dashboard::user::get_user_info, |                 routes::dashboard::user::get_user_info, | ||||||
|                 routes::dashboard::user::update_user_info, |                 routes::dashboard::user::update_user_info, | ||||||
| @@ -190,8 +185,6 @@ pub async fn initialize( | |||||||
| } | } | ||||||
|  |  | ||||||
| pub async fn check_subscription(cache_http: impl CacheHttp, user_id: impl Into<UserId>) -> bool { | pub async fn check_subscription(cache_http: impl CacheHttp, user_id: impl Into<UserId>) -> bool { | ||||||
|     offline!(true); |  | ||||||
|  |  | ||||||
|     if let Some(subscription_guild) = *CNC_GUILD { |     if let Some(subscription_guild) = *CNC_GUILD { | ||||||
|         let guild_member = GuildId(subscription_guild).member(cache_http, user_id).await; |         let guild_member = GuildId(subscription_guild).member(cache_http, user_id).await; | ||||||
|  |  | ||||||
| @@ -213,8 +206,6 @@ pub async fn check_guild_subscription( | |||||||
|     cache_http: impl CacheHttp, |     cache_http: impl CacheHttp, | ||||||
|     guild_id: impl Into<GuildId>, |     guild_id: impl Into<GuildId>, | ||||||
| ) -> bool { | ) -> bool { | ||||||
|     offline!(true); |  | ||||||
|  |  | ||||||
|     if let Some(guild) = cache_http.cache().unwrap().guild(guild_id) { |     if let Some(guild) = cache_http.cache().unwrap().guild(guild_id) { | ||||||
|         let owner = guild.owner_id; |         let owner = guild.owner_id; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,11 +1,3 @@ | |||||||
| macro_rules! offline { |  | ||||||
|     ($field:expr) => { |  | ||||||
|         if std::env::var("OFFLINE").map_or(false, |v| v == "1") { |  | ||||||
|             return $field; |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| macro_rules! check_length { | macro_rules! check_length { | ||||||
|     ($max:ident, $field:expr) => { |     ($max:ident, $field:expr) => { | ||||||
|         if $field.len() > $max { |         if $field.len() > $max { | ||||||
| @@ -60,7 +52,6 @@ macro_rules! check_authorization { | |||||||
|  |  | ||||||
|         let user_id = $cookies.get_private("userid").map(|c| c.value().parse::<u64>().ok()).flatten(); |         let user_id = $cookies.get_private("userid").map(|c| c.value().parse::<u64>().ok()).flatten(); | ||||||
|  |  | ||||||
|         if std::env::var("OFFLINE").map_or(true, |v| v != "1") { |  | ||||||
|         match user_id { |         match user_id { | ||||||
|             Some(user_id) => { |             Some(user_id) => { | ||||||
|                 match GuildId($guild).to_guild_cached($ctx) { |                 match GuildId($guild).to_guild_cached($ctx) { | ||||||
| @@ -102,7 +93,6 @@ macro_rules! check_authorization { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| } |  | ||||||
|  |  | ||||||
| macro_rules! update_field { | macro_rules! update_field { | ||||||
|     ($pool:expr, $error:ident, $reminder:ident.[$field:ident]) => { |     ($pool:expr, $error:ident, $reminder:ident.[$field:ident]) => { | ||||||
|   | |||||||
| @@ -12,7 +12,8 @@ use sqlx::{MySql, Pool}; | |||||||
|  |  | ||||||
| use crate::routes::{ | use crate::routes::{ | ||||||
|     dashboard::{ |     dashboard::{ | ||||||
|         create_reminder, ImportBody, ReminderCreate, ReminderCsv, ReminderTemplateCsv, TodoCsv, |         create_reminder, generate_uid, ImportBody, Reminder, ReminderCsv, ReminderTemplateCsv, | ||||||
|  |         TodoCsv, | ||||||
|     }, |     }, | ||||||
|     JsonResult, |     JsonResult, | ||||||
| }; | }; | ||||||
| @@ -140,7 +141,7 @@ pub async fn import_reminders( | |||||||
|  |  | ||||||
|                         match channel_id.parse::<u64>() { |                         match channel_id.parse::<u64>() { | ||||||
|                             Ok(channel_id) => { |                             Ok(channel_id) => { | ||||||
|                                 let reminder = ReminderCreate { |                                 let reminder = Reminder { | ||||||
|                                     attachment: record.attachment, |                                     attachment: record.attachment, | ||||||
|                                     attachment_name: record.attachment_name, |                                     attachment_name: record.attachment_name, | ||||||
|                                     avatar: record.avatar, |                                     avatar: record.avatar, | ||||||
| @@ -167,6 +168,7 @@ pub async fn import_reminders( | |||||||
|                                     name: record.name, |                                     name: record.name, | ||||||
|                                     restartable: record.restartable, |                                     restartable: record.restartable, | ||||||
|                                     tts: record.tts, |                                     tts: record.tts, | ||||||
|  |                                     uid: generate_uid(), | ||||||
|                                     username: record.username, |                                     username: record.username, | ||||||
|                                     utc_time: record.utc_time, |                                     utc_time: record.utc_time, | ||||||
|                                 }; |                                 }; | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ use crate::{ | |||||||
|     routes::{ |     routes::{ | ||||||
|         dashboard::{ |         dashboard::{ | ||||||
|             create_database_channel, create_reminder, template_name_default, DeleteReminder, |             create_database_channel, create_reminder, template_name_default, DeleteReminder, | ||||||
|             DeleteReminderTemplate, PatchReminder, Reminder, ReminderCreate, ReminderTemplate, |             DeleteReminderTemplate, PatchReminder, Reminder, ReminderTemplate, | ||||||
|         }, |         }, | ||||||
|         JsonResult, |         JsonResult, | ||||||
|     }, |     }, | ||||||
| @@ -46,7 +46,6 @@ pub async fn get_guild_patreon( | |||||||
|     cookies: &CookieJar<'_>, |     cookies: &CookieJar<'_>, | ||||||
|     ctx: &State<Context>, |     ctx: &State<Context>, | ||||||
| ) -> JsonResult { | ) -> JsonResult { | ||||||
|     offline!(Ok(json!({ "patreon": true }))); |  | ||||||
|     check_authorization!(cookies, ctx.inner(), id); |     check_authorization!(cookies, ctx.inner(), id); | ||||||
|  |  | ||||||
|     match GuildId(id).to_guild_cached(ctx.inner()) { |     match GuildId(id).to_guild_cached(ctx.inner()) { | ||||||
| @@ -74,12 +73,6 @@ pub async fn get_guild_channels( | |||||||
|     cookies: &CookieJar<'_>, |     cookies: &CookieJar<'_>, | ||||||
|     ctx: &State<Context>, |     ctx: &State<Context>, | ||||||
| ) -> JsonResult { | ) -> JsonResult { | ||||||
|     offline!(Ok(json!(vec![ChannelInfo { |  | ||||||
|         name: "general".to_string(), |  | ||||||
|         id: "1".to_string(), |  | ||||||
|         webhook_avatar: None, |  | ||||||
|         webhook_name: None, |  | ||||||
|     }]))); |  | ||||||
|     check_authorization!(cookies, ctx.inner(), id); |     check_authorization!(cookies, ctx.inner(), id); | ||||||
|  |  | ||||||
|     match GuildId(id).to_guild_cached(ctx.inner()) { |     match GuildId(id).to_guild_cached(ctx.inner()) { | ||||||
| @@ -118,7 +111,6 @@ struct RoleInfo { | |||||||
|  |  | ||||||
| #[get("/api/guild/<id>/roles")] | #[get("/api/guild/<id>/roles")] | ||||||
| pub async fn get_guild_roles(id: u64, cookies: &CookieJar<'_>, ctx: &State<Context>) -> JsonResult { | pub async fn get_guild_roles(id: u64, cookies: &CookieJar<'_>, ctx: &State<Context>) -> JsonResult { | ||||||
|     offline!(Ok(json!(vec![RoleInfo { name: "@everyone".to_string(), id: "1".to_string() }]))); |  | ||||||
|     check_authorization!(cookies, ctx.inner(), id); |     check_authorization!(cookies, ctx.inner(), id); | ||||||
|  |  | ||||||
|     let roles_res = ctx.cache.guild_roles(id); |     let roles_res = ctx.cache.guild_roles(id); | ||||||
| @@ -298,7 +290,7 @@ pub async fn delete_reminder_template( | |||||||
| #[post("/api/guild/<id>/reminders", data = "<reminder>")] | #[post("/api/guild/<id>/reminders", data = "<reminder>")] | ||||||
| pub async fn create_guild_reminder( | pub async fn create_guild_reminder( | ||||||
|     id: u64, |     id: u64, | ||||||
|     reminder: Json<ReminderCreate>, |     reminder: Json<Reminder>, | ||||||
|     cookies: &CookieJar<'_>, |     cookies: &CookieJar<'_>, | ||||||
|     serenity_context: &State<Context>, |     serenity_context: &State<Context>, | ||||||
|     pool: &State<Pool<MySql>>, |     pool: &State<Pool<MySql>>, | ||||||
| @@ -318,22 +310,30 @@ pub async fn create_guild_reminder( | |||||||
|     .await |     .await | ||||||
| } | } | ||||||
|  |  | ||||||
| #[get("/api/guild/<id>/reminders?<status>")] | #[get("/api/guild/<id>/reminders")] | ||||||
| pub async fn get_reminders( | pub async fn get_reminders( | ||||||
|     id: u64, |     id: u64, | ||||||
|     cookies: &CookieJar<'_>, |     cookies: &CookieJar<'_>, | ||||||
|  |     ctx: &State<Context>, | ||||||
|     serenity_context: &State<Context>, |     serenity_context: &State<Context>, | ||||||
|     pool: &State<Pool<MySql>>, |     pool: &State<Pool<MySql>>, | ||||||
|     status: Option<String>, |  | ||||||
| ) -> JsonResult { | ) -> JsonResult { | ||||||
|     check_authorization!(cookies, serenity_context.inner(), id); |     check_authorization!(cookies, serenity_context.inner(), id); | ||||||
|  |  | ||||||
|     let status = status.unwrap_or("pending".to_string()); |     let channels_res = GuildId(id).channels(&ctx.inner()).await; | ||||||
|  |  | ||||||
|  |     match channels_res { | ||||||
|  |         Ok(channels) => { | ||||||
|  |             let channels = channels | ||||||
|  |                 .keys() | ||||||
|  |                 .into_iter() | ||||||
|  |                 .map(|k| k.as_u64().to_string()) | ||||||
|  |                 .collect::<Vec<String>>() | ||||||
|  |                 .join(","); | ||||||
|  |  | ||||||
|             sqlx::query_as_unchecked!( |             sqlx::query_as_unchecked!( | ||||||
|                 Reminder, |                 Reminder, | ||||||
|         " |                 "SELECT | ||||||
|         SELECT |  | ||||||
|                  reminders.attachment, |                  reminders.attachment, | ||||||
|                  reminders.attachment_name, |                  reminders.attachment_name, | ||||||
|                  reminders.avatar, |                  reminders.avatar, | ||||||
| @@ -359,15 +359,11 @@ pub async fn get_reminders( | |||||||
|                  reminders.tts, |                  reminders.tts, | ||||||
|                  reminders.uid, |                  reminders.uid, | ||||||
|                  reminders.username, |                  reminders.username, | ||||||
|          reminders.utc_time, |                  reminders.utc_time | ||||||
|          reminders.status, |  | ||||||
|          reminders.status_change_time, |  | ||||||
|          reminders.status_message |  | ||||||
|                 FROM reminders |                 FROM reminders | ||||||
|                 LEFT JOIN channels ON channels.id = reminders.channel_id |                 LEFT JOIN channels ON channels.id = reminders.channel_id | ||||||
|         WHERE FIND_IN_SET(`status`, ?) AND reminders.guild_id = (SELECT id FROM guilds WHERE guild = ?)", |                 WHERE `status` = 'pending' AND FIND_IN_SET(channels.channel, ?)", | ||||||
|         status, |                 channels | ||||||
|         id |  | ||||||
|             ) |             ) | ||||||
|             .fetch_all(pool.inner()) |             .fetch_all(pool.inner()) | ||||||
|             .await |             .await | ||||||
| @@ -378,6 +374,13 @@ pub async fn get_reminders( | |||||||
|                 json_err!("Could not load reminders") |                 json_err!("Could not load reminders") | ||||||
|             }) |             }) | ||||||
|         } |         } | ||||||
|  |         Err(e) => { | ||||||
|  |             warn!("Could not fetch channels from {}: {:?}", id, e); | ||||||
|  |  | ||||||
|  |             Ok(json!([])) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| #[patch("/api/guild/<id>/reminders", data = "<reminder>")] | #[patch("/api/guild/<id>/reminders", data = "<reminder>")] | ||||||
| pub async fn edit_reminder( | pub async fn edit_reminder( | ||||||
| @@ -550,8 +553,7 @@ pub async fn edit_reminder( | |||||||
|  |  | ||||||
|     match sqlx::query_as_unchecked!( |     match sqlx::query_as_unchecked!( | ||||||
|         Reminder, |         Reminder, | ||||||
|         " |         "SELECT reminders.attachment, | ||||||
|         SELECT reminders.attachment, |  | ||||||
|          reminders.attachment_name, |          reminders.attachment_name, | ||||||
|          reminders.avatar, |          reminders.avatar, | ||||||
|          channels.channel, |          channels.channel, | ||||||
| @@ -576,10 +578,7 @@ pub async fn edit_reminder( | |||||||
|          reminders.tts, |          reminders.tts, | ||||||
|          reminders.uid, |          reminders.uid, | ||||||
|          reminders.username, |          reminders.username, | ||||||
|          reminders.utc_time, |          reminders.utc_time | ||||||
|          reminders.status, |  | ||||||
|          reminders.status_change_time, |  | ||||||
|          reminders.status_message |  | ||||||
|         FROM reminders |         FROM reminders | ||||||
|         LEFT JOIN channels ON channels.id = reminders.channel_id |         LEFT JOIN channels ON channels.id = reminders.channel_id | ||||||
|         WHERE uid = ?", |         WHERE uid = ?", | ||||||
| @@ -603,10 +602,7 @@ pub async fn delete_reminder( | |||||||
|     reminder: Json<DeleteReminder>, |     reminder: Json<DeleteReminder>, | ||||||
|     pool: &State<Pool<MySql>>, |     pool: &State<Pool<MySql>>, | ||||||
| ) -> JsonResult { | ) -> JsonResult { | ||||||
|     match sqlx::query!( |     match sqlx::query!("UPDATE reminders SET `status` = 'deleted' WHERE uid = ?", reminder.uid) | ||||||
|         "UPDATE reminders SET `status` = 'deleted', `status_change_time` = NOW() WHERE uid = ?", |  | ||||||
|         reminder.uid |  | ||||||
|     ) |  | ||||||
|         .execute(pool.inner()) |         .execute(pool.inner()) | ||||||
|         .await |         .await | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -118,8 +118,8 @@ pub struct EmbedField { | |||||||
|     inline: bool, |     inline: bool, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Deserialize)] | #[derive(Serialize, Deserialize)] | ||||||
| pub struct ReminderCreate { | pub struct Reminder { | ||||||
|     #[serde(with = "base64s")] |     #[serde(with = "base64s")] | ||||||
|     attachment: Option<Vec<u8>>, |     attachment: Option<Vec<u8>>, | ||||||
|     attachment_name: Option<String>, |     attachment_name: Option<String>, | ||||||
| @@ -146,45 +146,10 @@ pub struct ReminderCreate { | |||||||
|     name: String, |     name: String, | ||||||
|     restartable: bool, |     restartable: bool, | ||||||
|     tts: bool, |     tts: bool, | ||||||
|     username: Option<String>, |  | ||||||
|     utc_time: NaiveDateTime, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize)] |  | ||||||
| pub struct Reminder { |  | ||||||
|     #[serde(with = "base64s")] |  | ||||||
|     attachment: Option<Vec<u8>>, |  | ||||||
|     attachment_name: Option<String>, |  | ||||||
|     avatar: Option<String>, |  | ||||||
|     #[serde(with = "string_opt")] |  | ||||||
|     channel: Option<u64>, |  | ||||||
|     content: String, |  | ||||||
|     embed_author: String, |  | ||||||
|     embed_author_url: Option<String>, |  | ||||||
|     embed_color: u32, |  | ||||||
|     embed_description: String, |  | ||||||
|     embed_footer: String, |  | ||||||
|     embed_footer_url: Option<String>, |  | ||||||
|     embed_image_url: Option<String>, |  | ||||||
|     embed_thumbnail_url: Option<String>, |  | ||||||
|     embed_title: String, |  | ||||||
|     embed_fields: Option<Json<Vec<EmbedField>>>, |  | ||||||
|     enabled: bool, |  | ||||||
|     expires: Option<NaiveDateTime>, |  | ||||||
|     interval_seconds: Option<u32>, |  | ||||||
|     interval_days: Option<u32>, |  | ||||||
|     interval_months: Option<u32>, |  | ||||||
|     #[serde(default = "name_default")] |  | ||||||
|     name: String, |  | ||||||
|     restartable: bool, |  | ||||||
|     tts: bool, |  | ||||||
|     #[serde(default)] |     #[serde(default)] | ||||||
|     uid: String, |     uid: String, | ||||||
|     username: Option<String>, |     username: Option<String>, | ||||||
|     utc_time: NaiveDateTime, |     utc_time: NaiveDateTime, | ||||||
|     status: String, |  | ||||||
|     status_message: Option<String>, |  | ||||||
|     status_change_time: Option<NaiveDateTime>, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize)] | #[derive(Serialize, Deserialize)] | ||||||
| @@ -323,7 +288,15 @@ pub fn generate_uid() -> String { | |||||||
| mod string { | mod string { | ||||||
|     use std::{fmt::Display, str::FromStr}; |     use std::{fmt::Display, str::FromStr}; | ||||||
|  |  | ||||||
|     use serde::{de, Deserialize, Deserializer}; |     use serde::{de, Deserialize, Deserializer, Serializer}; | ||||||
|  |  | ||||||
|  |     pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error> | ||||||
|  |     where | ||||||
|  |         T: Display, | ||||||
|  |         S: Serializer, | ||||||
|  |     { | ||||||
|  |         serializer.collect_str(value) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error> |     pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error> | ||||||
|     where |     where | ||||||
| @@ -335,34 +308,6 @@ mod string { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| mod string_opt { |  | ||||||
|     use std::{fmt::Display, str::FromStr}; |  | ||||||
|  |  | ||||||
|     use serde::{de, Deserialize, Deserializer, Serializer}; |  | ||||||
|  |  | ||||||
|     pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error> |  | ||||||
|     where |  | ||||||
|         T: Display, |  | ||||||
|         S: Serializer, |  | ||||||
|     { |  | ||||||
|         match value { |  | ||||||
|             Some(value) => serializer.collect_str(value), |  | ||||||
|             None => serializer.serialize_none(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error> |  | ||||||
|     where |  | ||||||
|         T: FromStr, |  | ||||||
|         T::Err: Display, |  | ||||||
|         D: Deserializer<'de>, |  | ||||||
|     { |  | ||||||
|         Option::deserialize(deserializer)? |  | ||||||
|             .map(|d: String| d.parse().map_err(de::Error::custom)) |  | ||||||
|             .transpose() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| mod base64s { | mod base64s { | ||||||
|     use serde::{de, Deserialize, Deserializer, Serializer}; |     use serde::{de, Deserialize, Deserializer, Serializer}; | ||||||
|  |  | ||||||
| @@ -407,7 +352,7 @@ pub async fn create_reminder( | |||||||
|     pool: impl sqlx::Executor<'_, Database = Database> + Copy, |     pool: impl sqlx::Executor<'_, Database = Database> + Copy, | ||||||
|     guild_id: GuildId, |     guild_id: GuildId, | ||||||
|     user_id: UserId, |     user_id: UserId, | ||||||
|     reminder: ReminderCreate, |     reminder: Reminder, | ||||||
| ) -> JsonResult { | ) -> JsonResult { | ||||||
|     // check guild in db |     // check guild in db | ||||||
|     match sqlx::query!("SELECT 1 as A FROM guilds WHERE guild = ?", guild_id.0) |     match sqlx::query!("SELECT 1 as A FROM guilds WHERE guild = ?", guild_id.0) | ||||||
| @@ -435,7 +380,7 @@ pub async fn create_reminder( | |||||||
|  |  | ||||||
|     if !channel_matches_guild || !channel_exists { |     if !channel_matches_guild || !channel_exists { | ||||||
|         warn!( |         warn!( | ||||||
|             "Error in `create_reminder`: channel {:?} not found for guild {} (channel exists: {})", |             "Error in `create_reminder`: channel {} not found for guild {} (channel exists: {})", | ||||||
|             reminder.channel, guild_id, channel_exists |             reminder.channel, guild_id, channel_exists | ||||||
|         ); |         ); | ||||||
|  |  | ||||||
| @@ -529,13 +474,11 @@ pub async fn create_reminder( | |||||||
|  |  | ||||||
|     // write to db |     // write to db | ||||||
|     match sqlx::query!( |     match sqlx::query!( | ||||||
|         " |         "INSERT INTO reminders ( | ||||||
|         INSERT INTO reminders ( |  | ||||||
|          uid, |          uid, | ||||||
|          attachment, |          attachment, | ||||||
|          attachment_name, |          attachment_name, | ||||||
|          channel_id, |          channel_id, | ||||||
|          guild_id, |  | ||||||
|          avatar, |          avatar, | ||||||
|          content, |          content, | ||||||
|          embed_author, |          embed_author, | ||||||
| @@ -558,14 +501,11 @@ pub async fn create_reminder( | |||||||
|          tts, |          tts, | ||||||
|          username, |          username, | ||||||
|          `utc_time` |          `utc_time` | ||||||
|         ) VALUES (?, ?, ?, ?, |         ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||||||
|         (SELECT id FROM guilds WHERE guild = ?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, |  | ||||||
|         ?, ?, ?, ?, ?)", |  | ||||||
|         new_uid, |         new_uid, | ||||||
|         attachment_data, |         attachment_data, | ||||||
|         reminder.attachment_name, |         reminder.attachment_name, | ||||||
|         channel, |         channel, | ||||||
|         guild_id.0, |  | ||||||
|         reminder.avatar, |         reminder.avatar, | ||||||
|         reminder.content, |         reminder.content, | ||||||
|         reminder.embed_author, |         reminder.embed_author, | ||||||
| @@ -620,10 +560,7 @@ pub async fn create_reminder( | |||||||
|              reminders.tts, |              reminders.tts, | ||||||
|              reminders.uid, |              reminders.uid, | ||||||
|              reminders.username, |              reminders.username, | ||||||
|              reminders.utc_time, |              reminders.utc_time | ||||||
|              reminders.status, |  | ||||||
|              reminders.status_change_time, |  | ||||||
|              reminders.status_message |  | ||||||
|             FROM reminders |             FROM reminders | ||||||
|             LEFT JOIN channels ON channels.id = reminders.channel_id |             LEFT JOIN channels ON channels.id = reminders.channel_id | ||||||
|             WHERE uid = ?", |             WHERE uid = ?", | ||||||
| @@ -725,17 +662,7 @@ pub async fn dashboard_home(cookies: &CookieJar<'_>) -> Result<Template, Redirec | |||||||
| } | } | ||||||
|  |  | ||||||
| #[get("/<_>")] | #[get("/<_>")] | ||||||
| pub async fn dashboard_1(cookies: &CookieJar<'_>) -> Result<Template, Redirect> { | pub async fn dashboard(cookies: &CookieJar<'_>) -> Result<Template, Redirect> { | ||||||
|     if cookies.get_private("userid").is_some() { |  | ||||||
|         let map: HashMap<&str, String> = HashMap::new(); |  | ||||||
|         Ok(Template::render("dashboard", &map)) |  | ||||||
|     } else { |  | ||||||
|         Err(Redirect::to("/login/discord")) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[get("/<_>/<_>")] |  | ||||||
| pub async fn dashboard_2(cookies: &CookieJar<'_>) -> Result<Template, Redirect> { |  | ||||||
|     if cookies.get_private("userid").is_some() { |     if cookies.get_private("userid").is_some() { | ||||||
|         let map: HashMap<&str, String> = HashMap::new(); |         let map: HashMap<&str, String> = HashMap::new(); | ||||||
|         Ok(Template::render("dashboard", &map)) |         Ok(Template::render("dashboard", &map)) | ||||||
|   | |||||||
| @@ -54,8 +54,6 @@ pub async fn get_user_info( | |||||||
|     ctx: &State<Context>, |     ctx: &State<Context>, | ||||||
|     pool: &State<Pool<MySql>>, |     pool: &State<Pool<MySql>>, | ||||||
| ) -> JsonValue { | ) -> JsonValue { | ||||||
|     offline!(json!(UserInfo { name: "Discord".to_string(), patreon: true, timezone: None })); |  | ||||||
|  |  | ||||||
|     if let Some(user_id) = |     if let Some(user_id) = | ||||||
|         cookies.get_private("userid").map(|u| u.value().parse::<u64>().ok()).flatten() |         cookies.get_private("userid").map(|u| u.value().parse::<u64>().ok()).flatten() | ||||||
|     { |     { | ||||||
| @@ -118,8 +116,6 @@ pub async fn update_user_info( | |||||||
|  |  | ||||||
| #[get("/api/user/guilds")] | #[get("/api/user/guilds")] | ||||||
| pub async fn get_user_guilds(cookies: &CookieJar<'_>, reqwest_client: &State<Client>) -> JsonValue { | pub async fn get_user_guilds(cookies: &CookieJar<'_>, reqwest_client: &State<Client>) -> JsonValue { | ||||||
|     offline!(json!(vec![GuildInfo { id: "1".to_string(), name: "Guild".to_string() }])); |  | ||||||
|  |  | ||||||
|     if let Some(access_token) = cookies.get_private("access_token") { |     if let Some(access_token) = cookies.get_private("access_token") { | ||||||
|         let request_res = reqwest_client |         let request_res = reqwest_client | ||||||
|             .get(format!("{}/users/@me/guilds", DISCORD_API)) |             .get(format!("{}/users/@me/guilds", DISCORD_API)) | ||||||
|   | |||||||
| @@ -15,18 +15,6 @@ div.reminderContent.is-collapsed .column.settings { | |||||||
|     display: none; |     display: none; | ||||||
| } | } | ||||||
|  |  | ||||||
| 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; | ||||||
| } | } | ||||||
| @@ -141,12 +129,6 @@ 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; | ||||||
| @@ -267,11 +249,11 @@ div#pageNavbar a { | |||||||
|  |  | ||||||
| .navbar-item.pageTitle { | .navbar-item.pageTitle { | ||||||
|     flex-shrink: 1; |     flex-shrink: 1; | ||||||
|     white-space: nowrap; |     text-wrap: nowrap; | ||||||
|     overflow: hidden; |     overflow: hidden; | ||||||
| } | } | ||||||
|  |  | ||||||
| .dashboard-burger, .dashboard-burger:active, .dashboard-burger.is-active { | .navbar-burger, .navbar-burger:active, .navbar-burger.is-active { | ||||||
|     background-color: #adc99c !important; |     background-color: #adc99c !important; | ||||||
|     border-radius: 14px; |     border-radius: 14px; | ||||||
|     padding: 6px; |     padding: 6px; | ||||||
| @@ -309,19 +291,10 @@ div.dashboard-sidebar:not(.mobile-sidebar) { | |||||||
|     flex-direction: column; |     flex-direction: column; | ||||||
| } | } | ||||||
|  |  | ||||||
| ul.guildList { |  | ||||||
|     flex-grow: 1; |  | ||||||
|     flex-shrink: 1; |  | ||||||
|     overflow: auto; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| div.dashboard-sidebar:not(.mobile-sidebar) .aside-footer { | div.dashboard-sidebar:not(.mobile-sidebar) .aside-footer { | ||||||
|     flex-shrink: 0; |     position: fixed; | ||||||
|     flex-grow: 0; |     bottom: 0; | ||||||
| } |     width: 226px; | ||||||
|  |  | ||||||
| div.dashboard-sidebar svg { |  | ||||||
|     flex-shrink: 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| div.mobile-sidebar { | div.mobile-sidebar { | ||||||
| @@ -471,7 +444,8 @@ input.default-width { | |||||||
| .customizable.is-400x300 img { | .customizable.is-400x300 img { | ||||||
|     margin-top: 10px; |     margin-top: 10px; | ||||||
|     width: 100%; |     width: 100%; | ||||||
|     height: 100px; |     min-height: 100px; | ||||||
|  |     max-height: 400px; | ||||||
| } | } | ||||||
|  |  | ||||||
| .customizable.is-32x32 img { | .customizable.is-32x32 img { | ||||||
| @@ -615,14 +589,6 @@ 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; | ||||||
| } | } | ||||||
| @@ -646,22 +612,7 @@ li.highlight { | |||||||
|     padding: 2px; |     padding: 2px; | ||||||
| } | } | ||||||
|  |  | ||||||
| @media only screen and (max-width: 1023px) { | @media only screen and (max-width: 1408px) { | ||||||
|     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; | ||||||
| @@ -679,20 +630,41 @@ li.highlight { | |||||||
|     .button-row button { |     .button-row button { | ||||||
|         width: 100%; |         width: 100%; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     .reminder-settings { |  | ||||||
|         margin-bottom: 0 !important; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|     .tts-row { | @media only screen and (max-width: 768px) { | ||||||
|         padding-bottom: 0; |     .button-row-edit { | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .button-row-edit > button { | ||||||
|  |         width: 100%; | ||||||
|  |         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; | ||||||
| @@ -704,86 +676,6 @@ 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 { | ||||||
| @@ -821,38 +713,15 @@ 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; | ||||||
| } | } | ||||||
| @@ -882,5 +751,5 @@ a.switch-pane.is-active ~ .guild-submenu { | |||||||
| } | } | ||||||
|  |  | ||||||
| .figure-num { | .figure-num { | ||||||
|     font-size: 2rem; |     font-size: 2em; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ const $downloader = document.querySelector("a#downloader"); | |||||||
| const $uploader = document.querySelector("input#uploader"); | const $uploader = document.querySelector("input#uploader"); | ||||||
|  |  | ||||||
| let channels = []; | let channels = []; | ||||||
| let reminderErrors = []; |  | ||||||
| let guildNames = {}; | let guildNames = {}; | ||||||
| let roles = []; | let roles = []; | ||||||
| let templates = {}; | let templates = {}; | ||||||
| @@ -34,11 +33,7 @@ let globalPatreon = false; | |||||||
| let guildPatreon = false; | let guildPatreon = false; | ||||||
|  |  | ||||||
| function guildId() { | function guildId() { | ||||||
|     return document.querySelector("li > a.is-active").parentElement.dataset["guild"]; |     return document.querySelector(".guildList a.is-active").dataset["guild"]; | ||||||
| } |  | ||||||
|  |  | ||||||
| function guildName() { |  | ||||||
|     return guildNames[guildId()]; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function colorToInt(r, g, b) { | function colorToInt(r, g, b) { | ||||||
| @@ -57,7 +52,7 @@ function switch_pane(selector) { | |||||||
|         el.classList.add("is-hidden"); |         el.classList.add("is-hidden"); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     document.querySelector(`*[data-name=${selector}]`).classList.remove("is-hidden"); |     document.getElementById(selector).classList.remove("is-hidden"); | ||||||
| } | } | ||||||
|  |  | ||||||
| function update_select(sel) { | function update_select(sel) { | ||||||
| @@ -454,27 +449,21 @@ document.addEventListener("guildSwitched", async (e) => { | |||||||
|         .querySelectorAll(".patreon-only") |         .querySelectorAll(".patreon-only") | ||||||
|         .forEach((el) => el.classList.add("is-locked")); |         .forEach((el) => el.classList.add("is-locked")); | ||||||
|  |  | ||||||
|     let $li = document.querySelectorAll(`li[data-guild="${e.detail.guild_id}"]`); |     let $anchor = document.querySelector( | ||||||
|  |         `.switch-pane[data-guild="${e.detail.guild_id}"]` | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     if ($li.length === 0) { |     let hasError = false; | ||||||
|  |  | ||||||
|  |     if ($anchor === null) { | ||||||
|         switch_pane("user-error"); |         switch_pane("user-error"); | ||||||
|  |         hasError = true; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     switch_pane(e.detail.pane); |     switch_pane($anchor.dataset["pane"]); | ||||||
|     reset_guild_pane(); |     reset_guild_pane(); | ||||||
|     document |     $anchor.classList.add("is-active"); | ||||||
|         .querySelectorAll(`li[data-guild="${e.detail.guild_id}"] > a`) |  | ||||||
|         .forEach((el) => { |  | ||||||
|             el.classList.add("is-active"); |  | ||||||
|         }); |  | ||||||
|     document |  | ||||||
|         .querySelectorAll( |  | ||||||
|             `li[data-guild="${e.detail.guild_id}"] *[data-pane="${e.detail.pane}"]` |  | ||||||
|         ) |  | ||||||
|         .forEach((el) => { |  | ||||||
|             el.classList.add("is-active"); |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|     if (globalPatreon || (await fetch_patreon(e.detail.guild_id))) { |     if (globalPatreon || (await fetch_patreon(e.detail.guild_id))) { | ||||||
|         document |         document | ||||||
| @@ -482,26 +471,15 @@ document.addEventListener("guildSwitched", async (e) => { | |||||||
|             .forEach((el) => el.classList.remove("is-locked")); |             .forEach((el) => el.classList.remove("is-locked")); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const event = new CustomEvent("paneLoad", { |     hasError = await fetch_channels(e.detail.guild_id); | ||||||
|         detail: { |  | ||||||
|             guild_id: e.detail.guild_id, |  | ||||||
|             pane: e.detail.pane, |  | ||||||
|         }, |  | ||||||
|     }); |  | ||||||
|     document.dispatchEvent(event); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| document.addEventListener("paneLoad", async (ev) => { |  | ||||||
|     const hasError = await fetch_channels(ev.detail.guild_id); |  | ||||||
|     if (!hasError) { |     if (!hasError) { | ||||||
|         fetch_roles(ev.detail.guild_id); |         fetch_roles(e.detail.guild_id); | ||||||
|         fetch_templates(ev.detail.guild_id); |         fetch_templates(e.detail.guild_id); | ||||||
|         fetch_reminders(ev.detail.guild_id); |         fetch_reminders(e.detail.guild_id); | ||||||
|  |  | ||||||
|         document.querySelectorAll("p.pageTitle").forEach((el) => { |         document.querySelectorAll("p.pageTitle").forEach((el) => { | ||||||
|             el.textContent = `${guildName()} Reminders`; |             el.textContent = `${e.detail.guild_name} Reminders`; | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         document.querySelectorAll("select.channel-selector").forEach((el) => { |         document.querySelectorAll("select.channel-selector").forEach((el) => { | ||||||
|             el.addEventListener("change", (e) => { |             el.addEventListener("change", (e) => { | ||||||
|                 update_select(e.target); |                 update_select(e.target); | ||||||
| @@ -706,56 +684,36 @@ document.addEventListener("DOMContentLoaded", async () => { | |||||||
|                             "%guildname%", |                             "%guildname%", | ||||||
|                             guild.name |                             guild.name | ||||||
|                         ); |                         ); | ||||||
|  |                         $anchor.dataset["guild"] = guild.id; | ||||||
|                         $anchor.dataset["name"] = guild.name; |                         $anchor.dataset["name"] = guild.name; | ||||||
|                         $anchor.href = `/dashboard/${guild.id}/reminders`; |                         $anchor.href = `/dashboard/${guild.id}?name=${guild.name}`; | ||||||
|  |  | ||||||
|                         const $li = $anchor.parentElement; |                         $anchor.addEventListener("click", async (e) => { | ||||||
|                         $li.dataset["guild"] = guild.id; |  | ||||||
|  |  | ||||||
|                         $li.querySelectorAll("a").forEach((el) => { |  | ||||||
|                             el.addEventListener("click", (e) => { |  | ||||||
|                                 const pane = el.dataset["pane"]; |  | ||||||
|                                 const slug = el.dataset["slug"]; |  | ||||||
|  |  | ||||||
|                                 if (pane !== undefined && slug !== undefined) { |  | ||||||
|                             e.preventDefault(); |                             e.preventDefault(); | ||||||
|  |                             window.history.pushState({}, "", `/dashboard/${guild.id}`); | ||||||
|                                     switch_pane(pane); |  | ||||||
|  |  | ||||||
|                                     window.history.pushState( |  | ||||||
|                                         {}, |  | ||||||
|                                         "", |  | ||||||
|                                         `/dashboard/${guild.id}/${slug}` |  | ||||||
|                                     ); |  | ||||||
|                             const event = new CustomEvent("guildSwitched", { |                             const event = new CustomEvent("guildSwitched", { | ||||||
|                                 detail: { |                                 detail: { | ||||||
|  |                                     guild_name: guild.name, | ||||||
|                                     guild_id: guild.id, |                                     guild_id: guild.id, | ||||||
|                                             pane, |  | ||||||
|                                 }, |                                 }, | ||||||
|                             }); |                             }); | ||||||
|  |  | ||||||
|                             document.dispatchEvent(event); |                             document.dispatchEvent(event); | ||||||
|                                 } |  | ||||||
|                             }); |  | ||||||
|                         }); |                         }); | ||||||
|  |  | ||||||
|                         element.append($clone); |                         element.append($clone); | ||||||
|                     }); |                     }); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 const matches = window.location.href.match( |                 const matches = window.location.href.match(/dashboard\/(\d+)/); | ||||||
|                     /dashboard\/(\d+)(\/)?([a-zA-Z\-]+)?/ |  | ||||||
|                 ); |  | ||||||
|                 if (matches) { |                 if (matches) { | ||||||
|                     let id = matches[1]; |                     let id = matches[1]; | ||||||
|                     let kind = matches[3]; |  | ||||||
|                     let name = guildNames[id]; |                     let name = guildNames[id]; | ||||||
|  |  | ||||||
|                     const event = new CustomEvent("guildSwitched", { |                     const event = new CustomEvent("guildSwitched", { | ||||||
|                         detail: { |                         detail: { | ||||||
|                             guild_name: name, |                             guild_name: name, | ||||||
|                             guild_id: id, |                             guild_id: id, | ||||||
|                             pane: kind, |  | ||||||
|                         }, |                         }, | ||||||
|                     }); |                     }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,45 +0,0 @@ | |||||||
| function loadErrors() { |  | ||||||
|     return fetch( |  | ||||||
|         `/dashboard/api/guild/${guildId()}/reminders?status=deleted,sent,failed` |  | ||||||
|     ).then((response) => response.json()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| document.addEventListener("paneLoad", (ev) => { |  | ||||||
|     if (ev.detail.pane !== "errors") { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     document.querySelectorAll(".reminderError").forEach((el) => el.remove()); |  | ||||||
|  |  | ||||||
|     const template = document.getElementById("reminderError"); |  | ||||||
|     const container = document.getElementById("reminderLog"); |  | ||||||
|  |  | ||||||
|     loadErrors() |  | ||||||
|         .then((res) => { |  | ||||||
|             res = res |  | ||||||
|                 .filter((r) => r.status_change_time !== null) |  | ||||||
|                 .sort((a, b) => a.status_change_time < b.status_change_time); |  | ||||||
|  |  | ||||||
|             for (const reminder of res) { |  | ||||||
|                 const newRow = template.content.cloneNode(true); |  | ||||||
|  |  | ||||||
|                 newRow.querySelector(".reminderError").dataset["case"] = reminder.status; |  | ||||||
|  |  | ||||||
|                 const statusTime = new luxon.DateTime.fromISO( |  | ||||||
|                     reminder.status_change_time, |  | ||||||
|                     { zone: "UTC" } |  | ||||||
|                 ); |  | ||||||
|                 newRow.querySelector(".reminderName").textContent = reminder.name; |  | ||||||
|                 newRow.querySelector(".reminderMessage").textContent = |  | ||||||
|                     reminder.status_message; |  | ||||||
|                 newRow.querySelector(".reminderTime").textContent = statusTime |  | ||||||
|                     .toLocal() |  | ||||||
|                     .toLocaleString(luxon.DateTime.DATETIME_MED); |  | ||||||
|  |  | ||||||
|                 container.appendChild(newRow); |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
|         .finally(() => { |  | ||||||
|             $loader.classList.add("is-hidden"); |  | ||||||
|         }); |  | ||||||
| }); |  | ||||||
							
								
								
									
										19
									
								
								web/static/js/reminder_errors.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/static/js/reminder_errors.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | let _reminderErrors = []; | ||||||
|  |  | ||||||
|  | const reminderErrors = () => { | ||||||
|  |     return _reminderErrors; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const guildId = () => { | ||||||
|  |     let selected: HTMLElement = document.querySelector(".guildList a.is-active"); | ||||||
|  |     return selected.dataset["guild"]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function loadErrors() { | ||||||
|  |     fetch(`/dashboard/api/guild/${guildId()}/errors`).then(response => response.json()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | document.addEventListener('DOMContentLoaded', () => { | ||||||
|  |  | ||||||
|  | }) | ||||||
| @@ -40,14 +40,14 @@ | |||||||
|     <div class="navbar-brand"> |     <div class="navbar-brand"> | ||||||
|         <a class="navbar-item" href="/"> |         <a class="navbar-item" href="/"> | ||||||
|             <figure class="image"> |             <figure class="image"> | ||||||
|                 <img width="28px" height="28px" src="/static/img/logo_nobg.webp" alt="Reminder Bot Logo"> |                 <img src="/static/img/logo_nobg.webp" alt="Reminder Bot Logo"> | ||||||
|             </figure> |             </figure> | ||||||
|         </a> |         </a> | ||||||
|  |  | ||||||
|         <p class="navbar-item pageTitle"> |         <p class="navbar-item pageTitle"> | ||||||
|         </p> |         </p> | ||||||
|  |  | ||||||
|         <a role="button" class="dashboard-burger navbar-burger is-right" aria-label="menu" aria-expanded="false" |         <a role="button" class="navbar-burger is-right" aria-label="menu" aria-expanded="false" | ||||||
|            data-target="mobileSidebar"> |            data-target="mobileSidebar"> | ||||||
|             <span aria-hidden="true"></span> |             <span aria-hidden="true"></span> | ||||||
|             <span aria-hidden="true"></span> |             <span aria-hidden="true"></span> | ||||||
| @@ -234,7 +234,6 @@ | |||||||
|         <a href="/"> |         <a href="/"> | ||||||
|             <div class="brand"> |             <div class="brand"> | ||||||
|                 <img src="/static/img/logo_nobg.webp" alt="Reminder bot logo" |                 <img src="/static/img/logo_nobg.webp" alt="Reminder bot logo" | ||||||
|                      width="52px" height="52px" |  | ||||||
|                      class="dashboard-brand"> |                      class="dashboard-brand"> | ||||||
|             </div> |             </div> | ||||||
|         </a> |         </a> | ||||||
| @@ -333,16 +332,16 @@ | |||||||
|                 <p class="subtitle is-hidden-desktop">Press the <span class="icon"><i class="fal fa-bars"></i></span> to get started</p> |                 <p class="subtitle is-hidden-desktop">Press the <span class="icon"><i class="fal fa-bars"></i></span> to get started</p> | ||||||
|             </div> |             </div> | ||||||
|         </section> |         </section> | ||||||
|         <section data-name="reminders" class="is-hidden"> |         <section id="guild" class="is-hidden"> | ||||||
|             {% include "reminder_dashboard/reminder_dashboard" %} |             {% include "reminder_dashboard/reminder_dashboard" %} | ||||||
|         </section> |         </section> | ||||||
|         <section data-name="errors" class="is-hidden"> |         <section id="reminder-errors" class="is-hidden"> | ||||||
|             {% include "reminder_dashboard/reminder_errors" %} |             {% include "reminder_dashboard/reminder_errors" %} | ||||||
|         </section> |         </section> | ||||||
|         <section data-name="guild-error" class="is-hidden"> |         <section id="guild-error" class="is-hidden"> | ||||||
|             {% include "reminder_dashboard/guild_error" %} |             {% include "reminder_dashboard/guild_error" %} | ||||||
|         </section> |         </section> | ||||||
|         <section data-name="user-error" class="is-hidden"> |         <section id="user-error" class="is-hidden"> | ||||||
|             {% include "reminder_dashboard/user_error" %} |             {% include "reminder_dashboard/user_error" %} | ||||||
|         </section> |         </section> | ||||||
|     </div> |     </div> | ||||||
| @@ -376,28 +375,14 @@ | |||||||
|  |  | ||||||
| <template id="guildListEntry"> | <template id="guildListEntry"> | ||||||
|     <li> |     <li> | ||||||
|         <a class="switch-pane" data-pane="reminders" data-slug="reminders"> |         <a class="switch-pane" data-pane="guild"> | ||||||
|             <span class="icon"><i class="fas fa-map-pin"></i></span> <span class="guild-name">%guildname%</span> |             <span class="icon"><i class="fas fa-map-pin"></i></span> <span class="guild-name">%guildname%</span> | ||||||
|         </a> |         </a> | ||||||
|         <ul class="guild-submenu"> |  | ||||||
|             <li> |  | ||||||
|                 <a class="switch-pane" data-pane="reminders" data-slug="reminders"> |  | ||||||
|                     <span class="icon"><i class="fas fa-calendar-alt"></i></span> Reminders |  | ||||||
|                 </a> |  | ||||||
|                 <a class="switch-pane" data-pane="errors" data-slug="errors"> |  | ||||||
|                     <span class="icon"><i class="fas fa-file-alt"></i></span> Logs |  | ||||||
|                 </a> |  | ||||||
|             </li> |  | ||||||
|         </ul> |  | ||||||
|     </li> |     </li> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <template id="guildReminder"> | <template id="guildReminder"> | ||||||
|     {% include "reminder_dashboard/templates/guild_reminder" %} |     {% include "reminder_dashboard/guild_reminder" %} | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <template id="reminderError"> |  | ||||||
|     {% include "reminder_dashboard/templates/reminder_error" %} |  | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script src="/static/js/iro.js"></script> | <script src="/static/js/iro.js"></script> | ||||||
|   | |||||||
| @@ -133,6 +133,8 @@ | |||||||
|             </article> |             </article> | ||||||
|         </div> |         </div> | ||||||
|         <div class="column settings"> |         <div class="column settings"> | ||||||
|  |             <div class="columns"> | ||||||
|  |                 <div class="column"> | ||||||
|                     <div class="field channel-field"> |                     <div class="field channel-field"> | ||||||
|                         <div class="collapses"> |                         <div class="collapses"> | ||||||
|                             <label class="label" for="channelOption">Channel*</label> |                             <label class="label" for="channelOption">Channel*</label> | ||||||
| @@ -147,7 +149,8 @@ | |||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
| 
 |                 </div> | ||||||
|  |                 <div class="column"> | ||||||
|                     <div class="field"> |                     <div class="field"> | ||||||
|                         <div class="control"> |                         <div class="control"> | ||||||
|                             <label class="label collapses"> |                             <label class="label collapses"> | ||||||
| @@ -156,13 +159,12 @@ | |||||||
|                             </label> |                             </label> | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
| 
 | 
 | ||||||
|             <div class="collapses split-controls"> |             <div class="collapses split-controls"> | ||||||
|                 <div> |                 <div> | ||||||
|                     <div class="patreon-only"> |                     <div class="patreon-only"> | ||||||
|                         <div class="patreon-invert foreground"> |  | ||||||
|                             Intervals available on <a href="https://patreon.com/jellywx">Patreon</a> or <a href="https://gitea.jellypro.xyz/jude/reminder-bot">self-hosting</a> |  | ||||||
|                         </div> |  | ||||||
|                         <div class="field"> |                         <div class="field"> | ||||||
|                             <label class="label">Interval <a class="foreground" href="/help/intervals"><i class="fas fa-question-circle"></i></a></label> |                             <label class="label">Interval <a class="foreground" href="/help/intervals"><i class="fas fa-question-circle"></i></a></label> | ||||||
|                             <div class="control intervalSelector"> |                             <div class="control intervalSelector"> | ||||||
| @@ -231,9 +233,7 @@ | |||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> | 
 | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
|                 {% if creating %} |                 {% if creating %} | ||||||
|                     <div class="button-row"> |                     <div class="button-row"> | ||||||
|                         <div class="button-row-reminder"> |                         <div class="button-row-reminder"> | ||||||
| @@ -267,3 +267,6 @@ | |||||||
|                     </div> |                     </div> | ||||||
|                 {% endif %} |                 {% endif %} | ||||||
|             </div> |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
| @@ -2,7 +2,7 @@ | |||||||
|     <strong>Create Reminder</strong> |     <strong>Create Reminder</strong> | ||||||
|     <div id="reminderCreator"> |     <div id="reminderCreator"> | ||||||
|         {% set creating = true %} |         {% set creating = true %} | ||||||
|         {% include "reminder_dashboard/templates/guild_reminder" %} |         {% include "reminder_dashboard/guild_reminder" %} | ||||||
|         {% set creating = false %} |         {% set creating = false %} | ||||||
|     </div> |     </div> | ||||||
|     <br> |     <br> | ||||||
| @@ -46,10 +46,6 @@ | |||||||
|     <div id="guildReminders"> |     <div id="guildReminders"> | ||||||
|  |  | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|     <div id="guildErrors"> |  | ||||||
|  |  | ||||||
|     </div> |  | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| <script src="/static/js/sort.js"></script> | <script src="/static/js/sort.js"></script> | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| <div id="reminderLog"> | <div> | ||||||
|  |  | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,20 +0,0 @@ | |||||||
| <div class="reminderError" data-case="success"> |  | ||||||
|     <div class="errorHead"> |  | ||||||
|         <div class="errorIcon"> |  | ||||||
|             <span class="icon"> |  | ||||||
|                 <i class="fas fa-trash"></i> |  | ||||||
|                 <i class="fas fa-check"></i> |  | ||||||
|                 <i class="fas fa-exclamation-triangle"></i> |  | ||||||
|             </span> |  | ||||||
|         </div> |  | ||||||
|         <div class="reminderName"> |  | ||||||
|             Reminder |  | ||||||
|         </div> |  | ||||||
|         <div class="reminderMessage"> |  | ||||||
|  |  | ||||||
|         </div> |  | ||||||
|         <div class="reminderTime"> |  | ||||||
|  |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
		Reference in New Issue
	
	Block a user