From 608ce1d9910cd68ce825838ea313e02c598f908e Mon Sep 17 00:00:00 2001 From: Mica White Date: Mon, 8 Dec 2025 20:08:21 -0500 Subject: Stuff --- src/resources/languages.rs | 134 +++++++++++++++--------------- src/resources/mod.rs | 8 +- src/resources/scripts.rs | 76 ++++++++--------- src/resources/style.rs | 108 ++++++++++++------------ src/resources/templates.rs | 202 ++++++++++++++++++++++----------------------- 5 files changed, 264 insertions(+), 264 deletions(-) (limited to 'src/resources') diff --git a/src/resources/languages.rs b/src/resources/languages.rs index 8ef7553..b01daf9 100644 --- a/src/resources/languages.rs +++ b/src/resources/languages.rs @@ -1,67 +1,67 @@ -use std::collections::HashMap; -use std::path::PathBuf; - -use actix_web::{get, web, HttpResponse, Scope}; -use exun::RawUnexpected; -use ini::{Ini, Properties}; -use raise::yeet; -use unic_langid::subtags::Language; - -#[derive(Debug, Clone, PartialEq)] -pub struct Translations { - languages: HashMap, -} - -pub fn initialize() -> Result { - let mut translations = Translations { - languages: HashMap::new(), - }; - translations.refresh()?; - Ok(translations) -} - -impl Translations { - pub fn languages(&self) -> Box<[Language]> { - self.languages.keys().cloned().collect() - } - - pub fn get_message(&self, language: Language, key: &str) -> Option { - Some(self.languages.get(&language)?.get(key)?.to_owned()) - } - - pub fn refresh(&mut self) -> Result<(), RawUnexpected> { - let mut languages = HashMap::with_capacity(1); - for entry in PathBuf::from("static/languages").read_dir()? { - let entry = entry?; - if entry.file_type()?.is_dir() { - continue; - } - - let path = entry.path(); - let path = path.to_string_lossy(); - let Some(language) = path.as_bytes().get(0..2) else { yeet!(RawUnexpected::msg(format!("{} not long enough to be a language name", path))) }; - let language = Language::from_bytes(language)?; - let messages = Ini::load_from_file(entry.path())?.general_section().clone(); - - languages.insert(language, messages); - } - - self.languages = languages; - Ok(()) - } -} - -#[get("")] -pub async fn all_languages(translations: web::Data) -> HttpResponse { - HttpResponse::Ok().json( - translations - .languages() - .into_iter() - .map(|l| l.as_str()) - .collect::>(), - ) -} - -pub fn languages() -> Scope { - web::scope("/languages").service(all_languages) -} +use std::collections::HashMap; +use std::path::PathBuf; + +use actix_web::{get, web, HttpResponse, Scope}; +use exun::RawUnexpected; +use ini::{Ini, Properties}; +use raise::yeet; +use unic_langid::subtags::Language; + +#[derive(Debug, Clone, PartialEq)] +pub struct Translations { + languages: HashMap, +} + +pub fn initialize() -> Result { + let mut translations = Translations { + languages: HashMap::new(), + }; + translations.refresh()?; + Ok(translations) +} + +impl Translations { + pub fn languages(&self) -> Box<[Language]> { + self.languages.keys().cloned().collect() + } + + pub fn get_message(&self, language: Language, key: &str) -> Option { + Some(self.languages.get(&language)?.get(key)?.to_owned()) + } + + pub fn refresh(&mut self) -> Result<(), RawUnexpected> { + let mut languages = HashMap::with_capacity(1); + for entry in PathBuf::from("static/languages").read_dir()? { + let entry = entry?; + if entry.file_type()?.is_dir() { + continue; + } + + let path = entry.path(); + let path = path.to_string_lossy(); + let Some(language) = path.as_bytes().get(0..2) else { yeet!(RawUnexpected::msg(format!("{} not long enough to be a language name", path))) }; + let language = Language::from_bytes(language)?; + let messages = Ini::load_from_file(entry.path())?.general_section().clone(); + + languages.insert(language, messages); + } + + self.languages = languages; + Ok(()) + } +} + +#[get("")] +pub async fn all_languages(translations: web::Data) -> HttpResponse { + HttpResponse::Ok().json( + translations + .languages() + .into_iter() + .map(|l| l.as_str()) + .collect::>(), + ) +} + +pub fn languages() -> Scope { + web::scope("/languages").service(all_languages) +} diff --git a/src/resources/mod.rs b/src/resources/mod.rs index 9251d2c..d9f14ba 100644 --- a/src/resources/mod.rs +++ b/src/resources/mod.rs @@ -1,4 +1,4 @@ -pub mod languages; -pub mod scripts; -pub mod style; -pub mod templates; +pub mod languages; +pub mod scripts; +pub mod style; +pub mod templates; diff --git a/src/resources/scripts.rs b/src/resources/scripts.rs index 1b27859..66b9693 100644 --- a/src/resources/scripts.rs +++ b/src/resources/scripts.rs @@ -1,38 +1,38 @@ -use std::path::Path; - -use actix_web::{get, http::StatusCode, web, HttpResponse, ResponseError}; -use exun::{Expect, ResultErrorExt}; -use path_clean::clean; -use raise::yeet; -use serde::Serialize; -use thiserror::Error; - -#[derive(Debug, Clone, Error, Serialize)] -pub enum LoadScriptError { - #[error("The requested script does not exist")] - FileNotFound(Box), -} - -impl ResponseError for LoadScriptError { - fn status_code(&self) -> StatusCode { - match self { - Self::FileNotFound(..) => StatusCode::NOT_FOUND, - } - } -} - -fn load(script: &str) -> Result> { - let path = clean(format!("static/scripts/{}.js", script)); - if !path.exists() { - yeet!(LoadScriptError::FileNotFound(path.into()).into()); - } - let js = std::fs::read_to_string(format!("static/scripts/{}.js", script)).unexpect()?; - Ok(js) -} - -#[get("/{script}.js")] -pub async fn get_js(script: web::Path>) -> Result { - let js = load(&script).map_err(|e| e.unwrap())?; - let response = HttpResponse::Ok().content_type("text/javascript").body(js); - Ok(response) -} +use std::path::Path; + +use actix_web::{get, http::StatusCode, web, HttpResponse, ResponseError}; +use exun::{Expect, ResultErrorExt}; +use path_clean::clean; +use raise::yeet; +use serde::Serialize; +use thiserror::Error; + +#[derive(Debug, Clone, Error, Serialize)] +pub enum LoadScriptError { + #[error("The requested script does not exist")] + FileNotFound(Box), +} + +impl ResponseError for LoadScriptError { + fn status_code(&self) -> StatusCode { + match self { + Self::FileNotFound(..) => StatusCode::NOT_FOUND, + } + } +} + +fn load(script: &str) -> Result> { + let path = clean(format!("static/scripts/{}.js", script)); + if !path.exists() { + yeet!(LoadScriptError::FileNotFound(path.into()).into()); + } + let js = std::fs::read_to_string(format!("static/scripts/{}.js", script)).unexpect()?; + Ok(js) +} + +#[get("/{script}.js")] +pub async fn get_js(script: web::Path>) -> Result { + let js = load(&script).map_err(|e| e.unwrap())?; + let response = HttpResponse::Ok().content_type("text/javascript").body(js); + Ok(response) +} diff --git a/src/resources/style.rs b/src/resources/style.rs index 3ea56d2..8b21dc4 100644 --- a/src/resources/style.rs +++ b/src/resources/style.rs @@ -1,54 +1,54 @@ -use std::path::Path; - -use actix_web::{get, http::StatusCode, web, HttpResponse, ResponseError}; -use exun::{Expect, ResultErrorExt}; -use grass::OutputStyle; -use path_clean::clean; -use raise::yeet; -use serde::Serialize; -use thiserror::Error; - -fn output_style() -> OutputStyle { - if cfg!(debug_assertions) { - OutputStyle::Expanded - } else { - OutputStyle::Compressed - } -} - -fn options() -> grass::Options<'static> { - grass::Options::default() - .load_path("static/style") - .style(output_style()) -} - -#[derive(Debug, Clone, Error, Serialize)] -pub enum LoadStyleError { - #[error("The requested stylesheet was not found")] - FileNotFound(Box), -} - -impl ResponseError for LoadStyleError { - fn status_code(&self) -> StatusCode { - match self { - Self::FileNotFound(..) => StatusCode::NOT_FOUND, - } - } -} - -pub fn load(stylesheet: &str) -> Result> { - let options = options(); - let path = clean(format!("static/style/{}.scss", stylesheet)); - if !path.exists() { - yeet!(LoadStyleError::FileNotFound(path.into()).into()); - } - let css = grass::from_path(format!("static/style/{}.scss", stylesheet), &options).unexpect()?; - Ok(css) -} - -#[get("/{stylesheet}.css")] -pub async fn get_css(stylesheet: web::Path>) -> Result { - let css = load(&stylesheet).map_err(|e| e.unwrap())?; - let response = HttpResponse::Ok().content_type("text/css").body(css); - Ok(response) -} +use std::path::Path; + +use actix_web::{get, http::StatusCode, web, HttpResponse, ResponseError}; +use exun::{Expect, ResultErrorExt}; +use grass::OutputStyle; +use path_clean::clean; +use raise::yeet; +use serde::Serialize; +use thiserror::Error; + +fn output_style() -> OutputStyle { + if cfg!(debug_assertions) { + OutputStyle::Expanded + } else { + OutputStyle::Compressed + } +} + +fn options() -> grass::Options<'static> { + grass::Options::default() + .load_path("static/style") + .style(output_style()) +} + +#[derive(Debug, Clone, Error, Serialize)] +pub enum LoadStyleError { + #[error("The requested stylesheet was not found")] + FileNotFound(Box), +} + +impl ResponseError for LoadStyleError { + fn status_code(&self) -> StatusCode { + match self { + Self::FileNotFound(..) => StatusCode::NOT_FOUND, + } + } +} + +pub fn load(stylesheet: &str) -> Result> { + let options = options(); + let path = clean(format!("static/style/{}.scss", stylesheet)); + if !path.exists() { + yeet!(LoadStyleError::FileNotFound(path.into()).into()); + } + let css = grass::from_path(format!("static/style/{}.scss", stylesheet), &options).unexpect()?; + Ok(css) +} + +#[get("/{stylesheet}.css")] +pub async fn get_css(stylesheet: web::Path>) -> Result { + let css = load(&stylesheet).map_err(|e| e.unwrap())?; + let response = HttpResponse::Ok().content_type("text/css").body(css); + Ok(response) +} diff --git a/src/resources/templates.rs b/src/resources/templates.rs index 9168fb9..baf2ee8 100644 --- a/src/resources/templates.rs +++ b/src/resources/templates.rs @@ -1,101 +1,101 @@ -use std::collections::HashMap; - -use exun::{RawUnexpected, ResultErrorExt}; -use raise::yeet; -use serde::Serialize; -use tera::{Function, Tera, Value}; -use unic_langid::subtags::Language; - -use crate::api::AuthorizationParameters; - -use super::languages; - -fn make_msg(language: Language, translations: languages::Translations) -> impl Function { - Box::new( - move |args: &HashMap| -> tera::Result { - let Some(key) = args.get("key") else { yeet!("No parameter 'key' provided".into()) }; - let Some(key) = key.as_str() else { yeet!(format!("{} is not a string", key).into()) }; - let Some(value) = translations.get_message(language, key) else { yeet!(format!("{} does not exist", key).into()) }; - Ok(Value::String(value)) - }, - ) -} - -fn extend_tera( - tera: &Tera, - language: Language, - translations: languages::Translations, -) -> Result { - let mut new_tera = initialize()?; - new_tera.extend(tera)?; - new_tera.register_function("msg", make_msg(language, translations)); - Ok(new_tera) -} - -pub fn initialize() -> tera::Result { - let tera = Tera::new("static/templates/*")?; - Ok(tera) -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] -#[serde(rename_all = "camelCase")] -pub enum ErrorPage { - InvalidRequest, - ClientNotFound, - MissingRedirectUri, - InvalidRedirectUri, - InternalServerError, -} - -pub fn error_page( - tera: &Tera, - language: Language, - mut translations: languages::Translations, - error: ErrorPage, -) -> Result { - translations.refresh()?; - let mut tera = extend_tera(tera, language, translations)?; - tera.full_reload()?; - - let error = serde_variant::to_variant_name(&error)?; - let header = format!("errorHeader_{error}"); - let message = format!("errorMessage_{error}"); - - let mut context = tera::Context::new(); - context.insert("lang", language.as_str()); - context.insert("errorHeader", &header); - context.insert("errormessage", &message); - - tera.render("error.html", &context).unexpect() -} - -pub fn login_page( - tera: &Tera, - params: &AuthorizationParameters, - language: Language, - mut translations: languages::Translations, -) -> Result { - translations.refresh()?; - let mut tera = extend_tera(tera, language, translations)?; - tera.full_reload()?; - let mut context = tera::Context::new(); - context.insert("lang", language.as_str()); - context.insert("params", &serde_urlencoded::to_string(params)?); - tera.render("login.html", &context).unexpect() -} - -pub fn login_error_page( - tera: &Tera, - params: &AuthorizationParameters, - language: Language, - mut translations: languages::Translations, -) -> Result { - translations.refresh()?; - let mut tera = extend_tera(tera, language, translations)?; - tera.full_reload()?; - let mut context = tera::Context::new(); - context.insert("lang", language.as_str()); - context.insert("params", &serde_urlencoded::to_string(params)?); - context.insert("errorMessage", "loginErrorMessage"); - tera.render("login.html", &context).unexpect() -} +use std::collections::HashMap; + +use exun::{RawUnexpected, ResultErrorExt}; +use raise::yeet; +use serde::Serialize; +use tera::{Function, Tera, Value}; +use unic_langid::subtags::Language; + +use crate::api::AuthorizationParameters; + +use super::languages; + +fn make_msg(language: Language, translations: languages::Translations) -> impl Function { + Box::new( + move |args: &HashMap| -> tera::Result { + let Some(key) = args.get("key") else { yeet!("No parameter 'key' provided".into()) }; + let Some(key) = key.as_str() else { yeet!(format!("{} is not a string", key).into()) }; + let Some(value) = translations.get_message(language, key) else { yeet!(format!("{} does not exist", key).into()) }; + Ok(Value::String(value)) + }, + ) +} + +fn extend_tera( + tera: &Tera, + language: Language, + translations: languages::Translations, +) -> Result { + let mut new_tera = initialize()?; + new_tera.extend(tera)?; + new_tera.register_function("msg", make_msg(language, translations)); + Ok(new_tera) +} + +pub fn initialize() -> tera::Result { + let tera = Tera::new("static/templates/*")?; + Ok(tera) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum ErrorPage { + InvalidRequest, + ClientNotFound, + MissingRedirectUri, + InvalidRedirectUri, + InternalServerError, +} + +pub fn error_page( + tera: &Tera, + language: Language, + mut translations: languages::Translations, + error: ErrorPage, +) -> Result { + translations.refresh()?; + let mut tera = extend_tera(tera, language, translations)?; + tera.full_reload()?; + + let error = serde_variant::to_variant_name(&error)?; + let header = format!("errorHeader_{error}"); + let message = format!("errorMessage_{error}"); + + let mut context = tera::Context::new(); + context.insert("lang", language.as_str()); + context.insert("errorHeader", &header); + context.insert("errormessage", &message); + + tera.render("error.html", &context).unexpect() +} + +pub fn login_page( + tera: &Tera, + params: &AuthorizationParameters, + language: Language, + mut translations: languages::Translations, +) -> Result { + translations.refresh()?; + let mut tera = extend_tera(tera, language, translations)?; + tera.full_reload()?; + let mut context = tera::Context::new(); + context.insert("lang", language.as_str()); + context.insert("params", &serde_urlencoded::to_string(params)?); + tera.render("login.html", &context).unexpect() +} + +pub fn login_error_page( + tera: &Tera, + params: &AuthorizationParameters, + language: Language, + mut translations: languages::Translations, +) -> Result { + translations.refresh()?; + let mut tera = extend_tera(tera, language, translations)?; + tera.full_reload()?; + let mut context = tera::Context::new(); + context.insert("lang", language.as_str()); + context.insert("params", &serde_urlencoded::to_string(params)?); + context.insert("errorMessage", "loginErrorMessage"); + tera.render("login.html", &context).unexpect() +} -- cgit v1.2.3