Compare commits
	
		
			5 Commits
		
	
	
		
			current
			...
			06e1474396
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 06e1474396 | |||
|  | adb9c728f4 | ||
|  | fc02eaea4a | ||
|  | 91f87302fb | ||
|  | 97f186dc33 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,3 +3,5 @@ | |||||||
| /venv | /venv | ||||||
| .cargo | .cargo | ||||||
| /.idea | /.idea | ||||||
|  | web/static/index.html | ||||||
|  | web/static/assets | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | [submodule "reminder-dashboard"] | ||||||
|  | 	path = reminder-dashboard | ||||||
|  | 	url = gitea@gitea.jellypro.xyz:jude/reminder-dashboard | ||||||
							
								
								
									
										26
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										26
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -2059,6 +2059,27 @@ dependencies = [ | |||||||
|  "yansi", |  "yansi", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "prometheus" | ||||||
|  | version = "0.13.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" | ||||||
|  | dependencies = [ | ||||||
|  |  "cfg-if", | ||||||
|  |  "fnv", | ||||||
|  |  "lazy_static", | ||||||
|  |  "memchr", | ||||||
|  |  "parking_lot", | ||||||
|  |  "protobuf", | ||||||
|  |  "thiserror", | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "protobuf" | ||||||
|  | version = "2.28.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "quote" | name = "quote" | ||||||
| version = "1.0.33" | version = "1.0.33" | ||||||
| @@ -2173,7 +2194,7 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "reminder-rs" | name = "reminder-rs" | ||||||
| version = "1.6.47" | version = "1.6.48" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "base64 0.21.4", |  "base64 0.21.4", | ||||||
|  "chrono", |  "chrono", | ||||||
| @@ -2201,7 +2222,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "reminder_web" | name = "reminder_web" | ||||||
| version = "0.1.2" | version = "0.1.3" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "base64 0.13.1", |  "base64 0.13.1", | ||||||
|  "chrono", |  "chrono", | ||||||
| @@ -2210,6 +2231,7 @@ dependencies = [ | |||||||
|  "lazy_static", |  "lazy_static", | ||||||
|  "log", |  "log", | ||||||
|  "oauth2", |  "oauth2", | ||||||
|  |  "prometheus", | ||||||
|  "rand", |  "rand", | ||||||
|  "reqwest", |  "reqwest", | ||||||
|  "rocket", |  "rocket", | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| [package] | [package] | ||||||
| name = "reminder-rs" | name = "reminder-rs" | ||||||
| version = "1.6.47" | version = "1.6.48" | ||||||
| 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" | ||||||
| @@ -43,6 +43,7 @@ assets = [ | |||||||
|     ["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"], |     ["web/static/**/*", "lib/reminder-rs/static", "644"], | ||||||
|  |     ["reminder-dashboard/dist/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"], | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								reminder-dashboard
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								reminder-dashboard
									
									
									
									
									
										Submodule
									
								
							 Submodule reminder-dashboard added at 8ba7a39ce5
									
								
							| @@ -114,6 +114,8 @@ pub async fn offset( | |||||||
|     #[description = "Number of minutes to offset by"] minutes: Option<isize>, |     #[description = "Number of minutes to offset by"] minutes: Option<isize>, | ||||||
|     #[description = "Number of seconds to offset by"] seconds: Option<isize>, |     #[description = "Number of seconds to offset by"] seconds: Option<isize>, | ||||||
| ) -> Result<(), Error> { | ) -> Result<(), Error> { | ||||||
|  |     ctx.defer().await?; | ||||||
|  |  | ||||||
|     let combined_time = hours.map_or(0, |h| h * HOUR as isize) |     let combined_time = hours.map_or(0, |h| h * HOUR as isize) | ||||||
|         + minutes.map_or(0, |m| m * MINUTE as isize) |         + minutes.map_or(0, |m| m * MINUTE as isize) | ||||||
|         + seconds.map_or(0, |s| s); |         + seconds.map_or(0, |s| s); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| [package] | [package] | ||||||
| name = "reminder_web" | name = "reminder_web" | ||||||
| version = "0.1.2" | version = "0.1.3" | ||||||
| authors = ["jellywx <judesouthworth@pm.me>"] | authors = ["jellywx <judesouthworth@pm.me>"] | ||||||
| edition = "2018" | edition = "2018" | ||||||
|  |  | ||||||
| @@ -19,3 +19,4 @@ lazy_static = "1.4.0" | |||||||
| rand = "0.8" | rand = "0.8" | ||||||
| base64 = "0.13" | base64 = "0.13" | ||||||
| csv = "1.2" | csv = "1.2" | ||||||
|  | prometheus = "0.13.3" | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ mod consts; | |||||||
| mod macros; | mod macros; | ||||||
| mod catchers; | mod catchers; | ||||||
| mod guards; | mod guards; | ||||||
|  | mod metrics; | ||||||
| mod routes; | mod routes; | ||||||
|  |  | ||||||
| use std::{env, path::Path}; | use std::{env, path::Path}; | ||||||
| @@ -25,7 +26,10 @@ use serenity::{ | |||||||
| }; | }; | ||||||
| use sqlx::{MySql, Pool}; | use sqlx::{MySql, Pool}; | ||||||
|  |  | ||||||
| use crate::consts::{CNC_GUILD, DISCORD_OAUTH_AUTHORIZE, DISCORD_OAUTH_TOKEN, SUBSCRIPTION_ROLES}; | use crate::{ | ||||||
|  |     consts::{CNC_GUILD, DISCORD_OAUTH_AUTHORIZE, DISCORD_OAUTH_TOKEN, SUBSCRIPTION_ROLES}, | ||||||
|  |     metrics::{init_metrics, MetricProducer}, | ||||||
|  | }; | ||||||
|  |  | ||||||
| type Database = MySql; | type Database = MySql; | ||||||
|  |  | ||||||
| @@ -64,7 +68,10 @@ pub async fn initialize( | |||||||
|     let static_path = |     let static_path = | ||||||
|         if Path::new("web/static").exists() { "web/static" } else { "/lib/reminder-rs/static" }; |         if Path::new("web/static").exists() { "web/static" } else { "/lib/reminder-rs/static" }; | ||||||
|  |  | ||||||
|  |     init_metrics(); | ||||||
|  |  | ||||||
|     rocket::build() |     rocket::build() | ||||||
|  |         .attach(MetricProducer) | ||||||
|         .attach(Template::fairing()) |         .attach(Template::fairing()) | ||||||
|         .register( |         .register( | ||||||
|             "/", |             "/", | ||||||
| @@ -85,12 +92,13 @@ pub async fn initialize( | |||||||
|         .mount( |         .mount( | ||||||
|             "/", |             "/", | ||||||
|             routes![ |             routes![ | ||||||
|                 routes::index, |  | ||||||
|                 routes::cookies, |                 routes::cookies, | ||||||
|  |                 routes::index, | ||||||
|  |                 routes::metrics::metrics, | ||||||
|                 routes::privacy, |                 routes::privacy, | ||||||
|                 routes::terms, |  | ||||||
|                 routes::return_to_same_site, |  | ||||||
|                 routes::report::report_error, |                 routes::report::report_error, | ||||||
|  |                 routes::return_to_same_site, | ||||||
|  |                 routes::terms, | ||||||
|             ], |             ], | ||||||
|         ) |         ) | ||||||
|         .mount( |         .mount( | ||||||
|   | |||||||
							
								
								
									
										43
									
								
								web/src/metrics.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								web/src/metrics.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | use lazy_static::lazy_static; | ||||||
|  | use prometheus::{IntCounterVec, Opts, Registry}; | ||||||
|  | use rocket::{ | ||||||
|  |     fairing::{Fairing, Info, Kind}, | ||||||
|  |     Data, Request, Response, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | lazy_static! { | ||||||
|  |     pub static ref REGISTRY: Registry = Registry::new(); | ||||||
|  |     static ref REQUEST_COUNTER: IntCounterVec = | ||||||
|  |         IntCounterVec::new(Opts::new("requests", "Requests"), &["method", "route"]).unwrap(); | ||||||
|  |     static ref RESPONSE_COUNTER: IntCounterVec = | ||||||
|  |         IntCounterVec::new(Opts::new("responses", "Responses"), &["status", "route"]).unwrap(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn init_metrics() { | ||||||
|  |     REGISTRY.register(Box::new(REQUEST_COUNTER.clone())).unwrap(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub struct MetricProducer; | ||||||
|  |  | ||||||
|  | #[rocket::async_trait] | ||||||
|  | impl Fairing for MetricProducer { | ||||||
|  |     fn info(&self) -> Info { | ||||||
|  |         Info { name: "Metrics fairing", kind: Kind::Request } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async fn on_request(&self, req: &mut Request<'_>, _data: &mut Data<'_>) { | ||||||
|  |         if let Some(route) = req.route() { | ||||||
|  |             REQUEST_COUNTER | ||||||
|  |                 .with_label_values(&[req.method().as_str(), &route.uri.to_string()]) | ||||||
|  |                 .inc(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async fn on_response<'r>(&self, req: &'r Request<'_>, resp: &mut Response<'r>) { | ||||||
|  |         if let Some(route) = req.route() { | ||||||
|  |             RESPONSE_COUNTER | ||||||
|  |                 .with_label_values(&[&resp.status().code.to_string(), &route.uri.to_string()]) | ||||||
|  |                 .inc(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1 +0,0 @@ | |||||||
|  |  | ||||||
| @@ -1,9 +1,13 @@ | |||||||
| use std::collections::HashMap; | use std::path::Path; | ||||||
|  |  | ||||||
| use chrono::{naive::NaiveDateTime, Utc}; | use chrono::{naive::NaiveDateTime, Utc}; | ||||||
| use rand::{rngs::OsRng, seq::IteratorRandom}; | use rand::{rngs::OsRng, seq::IteratorRandom}; | ||||||
| use rocket::{http::CookieJar, response::Redirect, serde::json::json}; | use rocket::{ | ||||||
| use rocket_dyn_templates::Template; |     fs::{relative, NamedFile}, | ||||||
|  |     http::CookieJar, | ||||||
|  |     response::Redirect, | ||||||
|  |     serde::json::json, | ||||||
|  | }; | ||||||
| use serde::{Deserialize, Deserializer, Serialize}; | use serde::{Deserialize, Deserializer, Serialize}; | ||||||
| use serenity::{ | use serenity::{ | ||||||
|     client::Context, |     client::Context, | ||||||
| @@ -27,7 +31,6 @@ use crate::{ | |||||||
|  |  | ||||||
| pub mod api; | pub mod api; | ||||||
| pub mod export; | pub mod export; | ||||||
| pub mod guild; |  | ||||||
|  |  | ||||||
| type Unset<T> = Option<T>; | type Unset<T> = Option<T>; | ||||||
|  |  | ||||||
| @@ -657,22 +660,26 @@ async fn create_database_channel( | |||||||
| } | } | ||||||
|  |  | ||||||
| #[get("/")] | #[get("/")] | ||||||
| pub async fn dashboard_home(cookies: &CookieJar<'_>) -> Result<Template, Redirect> { | pub async fn dashboard_home(cookies: &CookieJar<'_>) -> Result<NamedFile, Redirect> { | ||||||
|     if cookies.get_private("userid").is_some() { |     if cookies.get_private("userid").is_some() { | ||||||
|         let mut map = HashMap::new(); |         NamedFile::open(Path::new(relative!("static/index.html"))).await.map_err(|e| { | ||||||
|         map.insert("version", env!("CARGO_PKG_VERSION")); |             warn!("Couldn't render dashboard: {:?}", e); | ||||||
|         Ok(Template::render("dashboard", &map)) |  | ||||||
|  |             Redirect::to("/login/discord") | ||||||
|  |         }) | ||||||
|     } else { |     } else { | ||||||
|         Err(Redirect::to("/login/discord")) |         Err(Redirect::to("/login/discord")) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[get("/<_..>")] | #[get("/<_..>")] | ||||||
| pub async fn dashboard(cookies: &CookieJar<'_>) -> Result<Template, Redirect> { | pub async fn dashboard(cookies: &CookieJar<'_>) -> Result<NamedFile, Redirect> { | ||||||
|     if cookies.get_private("userid").is_some() { |     if cookies.get_private("userid").is_some() { | ||||||
|         let mut map = HashMap::new(); |         NamedFile::open(Path::new(relative!("static/index.html"))).await.map_err(|e| { | ||||||
|         map.insert("version", env!("CARGO_PKG_VERSION")); |             warn!("Couldn't render dashboard: {:?}", e); | ||||||
|         Ok(Template::render("dashboard", &map)) |  | ||||||
|  |             Redirect::to("/login/discord") | ||||||
|  |         }) | ||||||
|     } else { |     } else { | ||||||
|         Err(Redirect::to("/login/discord")) |         Err(Redirect::to("/login/discord")) | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								web/src/routes/metrics.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								web/src/routes/metrics.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | use prometheus; | ||||||
|  |  | ||||||
|  | use crate::metrics::REGISTRY; | ||||||
|  |  | ||||||
|  | #[get("/metrics")] | ||||||
|  | pub async fn metrics() -> String { | ||||||
|  |     let encoder = prometheus::TextEncoder::new(); | ||||||
|  |     let res_custom = encoder.encode_to_string(®ISTRY.gather()); | ||||||
|  |  | ||||||
|  |     match res_custom { | ||||||
|  |         Ok(s) => s, | ||||||
|  |         Err(e) => { | ||||||
|  |             warn!("Error encoding metrics: {:?}", e); | ||||||
|  |  | ||||||
|  |             String::new() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,6 +1,7 @@ | |||||||
| pub mod admin; | pub mod admin; | ||||||
| pub mod dashboard; | pub mod dashboard; | ||||||
| pub mod login; | pub mod login; | ||||||
|  | pub mod metrics; | ||||||
| pub mod report; | pub mod report; | ||||||
|  |  | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
|   | |||||||
| @@ -218,17 +218,16 @@ div.inset-content { | |||||||
|     margin-right: 10%; |     margin-right: 10%; | ||||||
| } | } | ||||||
|  |  | ||||||
| div.flash-message { | div.flash-container { | ||||||
|     position: fixed; |     position: fixed; | ||||||
|  |     width: 100%; | ||||||
|  |     bottom: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | div.flash-message { | ||||||
|     width: calc(100% - 32px); |     width: calc(100% - 32px); | ||||||
|     margin: 16px !important; |     margin: 16px !important; | ||||||
|     z-index: 99; |     z-index: 99; | ||||||
|     bottom: 0; |  | ||||||
|     display: none; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| div.flash-message.is-active { |  | ||||||
|     display: block; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| body { | body { | ||||||
| @@ -633,6 +632,10 @@ li.highlight { | |||||||
|     display: flex; |     display: flex; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .button-row-edit > button { | ||||||
|  |     margin-right: 4px; | ||||||
|  | } | ||||||
|  |  | ||||||
| .button-row .button-row-reminder { | .button-row .button-row-reminder { | ||||||
|     flex-grow: 0; |     flex-grow: 0; | ||||||
|     padding: 2px; |     padding: 2px; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user