feature: Implement random theme and theme enum
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				/ build-all-services (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	/ build-all-services (push) Has been cancelled
				
			For task T155
This commit is contained in:
		
							parent
							
								
									96478fb5d2
								
							
						
					
					
						commit
						95ba628934
					
				
					 17 changed files with 216 additions and 132 deletions
				
			
		
							
								
								
									
										23
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										23
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -278,6 +278,8 @@ dependencies = [ | |||
|  "rmp-serde", | ||||
|  "serde", | ||||
|  "serde_json", | ||||
|  "strum 0.27.1", | ||||
|  "strum_macros", | ||||
|  "time", | ||||
|  "tokio", | ||||
|  "tower-http", | ||||
|  | @ -4146,7 +4148,7 @@ dependencies = [ | |||
|  "serde", | ||||
|  "serde_json", | ||||
|  "sqlx", | ||||
|  "strum", | ||||
|  "strum 0.26.3", | ||||
|  "thiserror 1.0.69", | ||||
|  "time", | ||||
|  "tracing", | ||||
|  | @ -4907,6 +4909,25 @@ version = "0.26.3" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "strum" | ||||
| version = "0.27.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "strum_macros" | ||||
| version = "0.27.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" | ||||
| dependencies = [ | ||||
|  "heck 0.5.0", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
|  "rustversion", | ||||
|  "syn 2.0.100", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "subtle" | ||||
| version = "2.6.1" | ||||
|  |  | |||
|  | @ -36,5 +36,7 @@ once_cell = "1.19.0" | |||
| chrono = "0.4.33" | ||||
| rand = "0.8.5" | ||||
| url_encoded_data = "0.6.1" | ||||
| strum = "0.27.1" | ||||
| strum_macros = "0.27.1" | ||||
| 
 | ||||
| env_logger = "*" | ||||
|  |  | |||
|  | @ -343,45 +343,14 @@ pub async fn admin_invitecode( | |||
|         } | ||||
|         
 | ||||
|         let active_codes = match list_invite_codes(nats.clone(), token.clone(), false).await { | ||||
|             Ok(mut v) => { | ||||
|                 for v in &mut v { | ||||
|                     if let Some(used_by) = &v.used_by { | ||||
|                         if used_by.len() > 32 { | ||||
|                             v.used_by = Some(format!("{}...", &used_by[0..32])); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     if v.creator.len() > 32 { | ||||
|                         v.creator = format!("{}...", &v.creator[0..32]); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 v | ||||
|             }, | ||||
|             Ok(v) => v, | ||||
|             Err(e) => { | ||||
|                 return e.into_response(); | ||||
|             } | ||||
|         }; | ||||
|         
 | ||||
|         let used_codes = match list_invite_codes(nats.clone(), token.clone(), true).await { | ||||
|             Ok(v) => v.into_iter().map(|mut v| { | ||||
|                 if let Some(used_by) = &v.used_by { | ||||
|                     if used_by.len() > 32 { | ||||
|                         v.used_by = Some(format!("{}...", &used_by[0..32])); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if v.creator.len() > 32 { | ||||
|                     v.creator = format!("{}...", &v.creator[0..32]); | ||||
|                 } | ||||
| 
 | ||||
|                 if v.used_at.is_none() { | ||||
|                     v.used_at = Some(String::from("unset")); | ||||
|                     v | ||||
|                 } else { | ||||
|                     v | ||||
|                 } | ||||
|             }).collect(), | ||||
|             Ok(v) => v.into_iter().map(|mut v| if v.used_at.is_none() { v.used_at = Some(String::from("unset")); v } else { v }).collect(), | ||||
|             Err(e) => { | ||||
|                 return e.into_response(); | ||||
|             } | ||||
|  | @ -657,4 +626,4 @@ pub async fn admin_user_list( | |||
|     } else { | ||||
|         Redirect::to("/").into_response() | ||||
|     } | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ use tracing::{debug, error}; | |||
| use tracing::log::warn; | ||||
| use crate::{Opts, ALPHA, BUILT_ON, GIT_COMMIT, VERSION, YEAR}; | ||||
| use crate::routes::index::FrontpageAnnouncement; | ||||
| use crate::routes::Themes; | ||||
| 
 | ||||
| #[derive(Serialize, Debug)] | ||||
| struct FullAnnouncement { | ||||
|  | @ -96,7 +97,7 @@ pub struct AnnouncementTemplate { | |||
|     built_on: String, | ||||
|     year: String, | ||||
|     alpha: bool, | ||||
|     theme: String, | ||||
|     theme: Themes, | ||||
|     announcement: FullAnnouncement, | ||||
| } | ||||
| 
 | ||||
|  | @ -109,10 +110,10 @@ pub async fn announcement_full(Extension(nats): Extension<Arc<jetstream::Context | |||
|             built_on: BUILT_ON.to_string(), | ||||
|             year: YEAR.to_string(), | ||||
|             alpha: ALPHA, | ||||
|             theme: "default".to_string(), | ||||
|             theme: Themes::Default, | ||||
|             announcement, | ||||
|         }.into_response() | ||||
|     } else { | ||||
|         StatusCode::NOT_FOUND.into_response() | ||||
|     } | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ use tokio::sync::Mutex; | |||
| use tracing::error; | ||||
| use tracing::log::warn; | ||||
| use crate::{BUILT_ON, GIT_COMMIT, Opts, ALPHA, VERSION, WEBSITE_COUNT, YEAR}; | ||||
| use crate::routes::{authenticate_user, UserInfo}; | ||||
| use crate::routes::{authenticate_user, Themes, UserInfo}; | ||||
| 
 | ||||
| #[derive(Serialize, Debug)] | ||||
| pub struct FrontpageAnnouncement { | ||||
|  | @ -102,7 +102,7 @@ pub fn frontpage_error(error: &str, auth_url: String) -> FrontpageTemplate { | |||
|         year: YEAR.to_string(), | ||||
|         alpha: ALPHA, | ||||
|         count: WEBSITE_COUNT.load(Ordering::Relaxed), | ||||
|         theme: "default".to_string(), | ||||
|         theme: Themes::Default, | ||||
|         announcement: None, | ||||
|     } | ||||
| } | ||||
|  | @ -185,7 +185,7 @@ pub struct FrontpageTemplate { | |||
|     year: String, | ||||
|     alpha: bool, | ||||
|     count: u64, | ||||
|     theme: String, | ||||
|     theme: Themes, | ||||
|     announcement: Option<FrontpageAnnouncement>, | ||||
| } | ||||
| 
 | ||||
|  | @ -202,7 +202,7 @@ pub async fn frontpage( | |||
|         year: YEAR.to_string(), | ||||
|         alpha: ALPHA, | ||||
|         count: WEBSITE_COUNT.load(Ordering::Relaxed), | ||||
|         theme: "default".to_string(), | ||||
|         theme: Themes::Default, | ||||
|         announcement, | ||||
|     } | ||||
| } | ||||
|  | @ -217,7 +217,7 @@ struct IndexTemplate { | |||
|     year: String, | ||||
|     alpha: bool, | ||||
|     count: u64, | ||||
|     theme: String, | ||||
|     theme: Themes, | ||||
|     announcement: Option<FrontpageAnnouncement>, | ||||
| } | ||||
| 
 | ||||
|  | @ -234,7 +234,7 @@ pub async fn index( | |||
|                 return (jar.remove("token"), frontpage_error(e.as_str(), opts.auth_url.clone())).into_response(); | ||||
|             } | ||||
|         }; | ||||
|         let theme = info.theme.clone(); | ||||
|         let theme = info.get_theme(); | ||||
|         
 | ||||
|         let announcement = latest_announcement(nats.clone()).await; | ||||
|         
 | ||||
|  | @ -260,7 +260,7 @@ pub async fn index( | |||
|             year: YEAR.to_string(), | ||||
|             alpha: ALPHA, | ||||
|             count: WEBSITE_COUNT.load(Ordering::Relaxed), | ||||
|             theme: "default".to_string(), | ||||
|             theme: Themes::Default, | ||||
|             announcement, | ||||
|         }.into_response() | ||||
|     } | ||||
|  |  | |||
|  | @ -10,7 +10,8 @@ | |||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
 | ||||
| */ | ||||
| 
 | ||||
| use std::fmt::Display; | ||||
| use std::str::FromStr; | ||||
| use std::sync::Arc; | ||||
| use askama::Template; | ||||
| use askama_axum::IntoResponse; | ||||
|  | @ -21,7 +22,13 @@ use asklyphe_common::nats::comms::ServiceResponse; | |||
| use async_nats::jetstream; | ||||
| use axum::http::StatusCode; | ||||
| use serde::Serialize; | ||||
| use tracing::error; | ||||
| use strum::IntoEnumIterator; | ||||
| use strum_macros::EnumIter; | ||||
| use time::macros::utc_datetime; | ||||
| use time::{OffsetDateTime, UtcDateTime}; | ||||
| use tracing::{debug, error}; | ||||
| 
 | ||||
| const RANDOM_THEME_EPOCH: UtcDateTime = utc_datetime!(2025-03-19 00:00); | ||||
| 
 | ||||
| pub mod search; | ||||
| pub mod index; | ||||
|  | @ -30,7 +37,102 @@ pub mod user_settings; | |||
| pub mod admin; | ||||
| pub mod announcement; | ||||
| 
 | ||||
| #[derive(Serialize)] | ||||
| #[derive(Default, EnumIter, PartialEq, Eq, Copy, Clone)] | ||||
| pub enum Themes { | ||||
|     Classic, | ||||
|     Dark, | ||||
|     #[default] | ||||
|     Default, | ||||
|     Freaky, | ||||
|     Gloss, | ||||
|     Oled, | ||||
|     Water, | ||||
|     Random | ||||
| } | ||||
| 
 | ||||
| impl Themes { | ||||
|     pub fn get_all_themes() -> Vec<Themes> { | ||||
|         Self::iter().collect() | ||||
|     } | ||||
| 
 | ||||
|     pub fn display_name(&self) -> String { | ||||
|         match self { | ||||
|             Themes::Classic => { | ||||
|                 "classic".to_string() | ||||
|             } | ||||
|             Themes::Dark => { | ||||
|                 "dark theme".to_string() | ||||
|             } | ||||
|             Themes::Default => { | ||||
|                 "default theme".to_string() | ||||
|             } | ||||
|             Themes::Freaky => { | ||||
|                 "freaky".to_string() | ||||
|             } | ||||
|             Themes::Gloss => { | ||||
|                 "gloss".to_string() | ||||
|             } | ||||
|             Themes::Oled => { | ||||
|                 "lights out".to_string() | ||||
|             } | ||||
|             Themes::Water => { | ||||
|                 "water".to_string() | ||||
|             } | ||||
|             Themes::Random => { | ||||
|                 "random".to_string() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn internal_name(&self) -> String { | ||||
|         match self { | ||||
|             Themes::Classic => { | ||||
|                 "classic".to_string() | ||||
|             } | ||||
|             Themes::Dark => { | ||||
|                 "dark".to_string() | ||||
|             } | ||||
|             Themes::Default => { | ||||
|                 "default".to_string() | ||||
|             } | ||||
|             Themes::Freaky => { | ||||
|                 "freaky".to_string() | ||||
|             } | ||||
|             Themes::Gloss => { | ||||
|                 "gloss".to_string() | ||||
|             } | ||||
|             Themes::Oled => { | ||||
|                 "oled".to_string() | ||||
|             } | ||||
|             Themes::Water => { | ||||
|                 "water".to_string() | ||||
|             } | ||||
|             Themes::Random => { | ||||
|                 "random".to_string() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl FromStr for Themes { | ||||
|     type Err = (); | ||||
| 
 | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         match s { | ||||
|             "classic" => Ok(Themes::Classic), | ||||
|             "dark" => Ok(Themes::Dark), | ||||
|             "default" => Ok(Themes::Default), | ||||
|             "freaky" => Ok(Themes::Freaky), | ||||
|             "gloss" => Ok(Themes::Gloss), | ||||
|             "oled" => Ok(Themes::Oled), | ||||
|             "water" => Ok(Themes::Water), | ||||
|             "random" => Ok(Themes::Random), | ||||
|             _ => Err(()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Serialize, Clone)] | ||||
| pub struct UserInfo { | ||||
|     pub username: String, | ||||
|     pub email: String, | ||||
|  | @ -39,6 +141,27 @@ pub struct UserInfo { | |||
|     pub administrator: bool, | ||||
| } | ||||
| 
 | ||||
| impl UserInfo { | ||||
|     pub fn get_theme(&self) -> Themes { | ||||
|         let theme: Themes = self.theme.parse().unwrap_or_default(); | ||||
| 
 | ||||
|         if theme.eq(&Themes::Random) { | ||||
|             let possible_themes = Themes::get_all_themes(); | ||||
|             let current_day = UtcDateTime::now(); | ||||
| 
 | ||||
|             let rand_value = (((current_day - RANDOM_THEME_EPOCH).as_seconds_f64() / 86400.0) % possible_themes.len() as f64) as usize; | ||||
|             
 | ||||
|             *possible_themes.get(rand_value).unwrap_or(&Themes::Default) | ||||
|         } else { | ||||
|             theme | ||||
|         } | ||||
|     } | ||||
|     
 | ||||
|     pub fn get_true_theme(&self) -> Themes { | ||||
|         self.theme.parse().unwrap() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub async fn authenticate_user(nats: Arc<jetstream::Context>, token: String) -> Result<UserInfo, String> { | ||||
|     let response = comms::query_service( | ||||
|         comms::Query::AuthService(AuthServiceQuery { | ||||
|  | @ -114,4 +237,4 @@ pub struct NotFoundTemplate; | |||
| 
 | ||||
| pub async fn not_found() -> impl IntoResponse { | ||||
|     (StatusCode::NOT_FOUND, NotFoundTemplate).into_response() | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
| */ | ||||
| 
 | ||||
| use crate::routes::index::frontpage_error; | ||||
| use crate::routes::{authenticate_user, UserInfo}; | ||||
| use crate::routes::{authenticate_user, Themes, UserInfo}; | ||||
| use crate::searchbot::{gather_image_results, gather_search_results}; | ||||
| use crate::unit_converter; | ||||
| use crate::unit_converter::UnitConversion; | ||||
|  | @ -111,7 +111,7 @@ struct SearchTemplateJavascript { | |||
|     built_on: String, | ||||
|     year: String, | ||||
|     alpha: bool, | ||||
|     theme: String, | ||||
|     theme: Themes, | ||||
| } | ||||
| 
 | ||||
| pub async fn search_js( | ||||
|  | @ -121,7 +121,7 @@ pub async fn search_js( | |||
|     Extension(opts): Extension<Opts>, | ||||
| ) -> impl IntoResponse { | ||||
|     fn error_response(query: String, info: UserInfo, error: &str) -> SearchTemplateJavascript { | ||||
|         let theme = info.theme.clone(); | ||||
|         let theme = info.get_theme(); | ||||
|         let querystr = url_encoded_data::stringify(&[("q", query.as_str())]); | ||||
|         SearchTemplateJavascript { | ||||
|             info, | ||||
|  | @ -175,7 +175,7 @@ pub async fn search_js( | |||
|             query = query.replace("-complications", ""); | ||||
|         } | ||||
| 
 | ||||
|         let theme = info.theme.clone(); | ||||
|         let theme = info.get_theme(); | ||||
|         let querystr = url_encoded_data::stringify(&[("q", og_query.as_str())]); | ||||
|         SearchTemplateJavascript { | ||||
|             info, | ||||
|  | @ -217,7 +217,7 @@ pub struct SearchTemplate { | |||
|     pub built_on: String, | ||||
|     pub year: String, | ||||
|     pub alpha: bool, | ||||
|     pub theme: String, | ||||
|     pub theme: Themes, | ||||
| } | ||||
| 
 | ||||
| pub async fn search_nojs( | ||||
|  | @ -227,7 +227,7 @@ pub async fn search_nojs( | |||
|     Extension(opts): Extension<Opts>, | ||||
| ) -> impl IntoResponse { | ||||
|     fn error_response(query: String, info: UserInfo, error: &str) -> SearchTemplate { | ||||
|         let theme = info.theme.clone(); | ||||
|         let theme = info.get_theme(); | ||||
|         let querystr = url_encoded_data::stringify(&[("q", query.as_str())]); | ||||
|         SearchTemplate { | ||||
|             info, | ||||
|  | @ -416,7 +416,7 @@ pub struct ImageSearchTemplate { | |||
|     pub built_on: String, | ||||
|     pub year: String, | ||||
|     pub alpha: bool, | ||||
|     pub theme: String, | ||||
|     pub theme: Themes, | ||||
| } | ||||
| pub async fn image_search( | ||||
|     jar: CookieJar, | ||||
|  | @ -425,7 +425,7 @@ pub async fn image_search( | |||
|     Extension(opts): Extension<Opts>, | ||||
| ) -> impl IntoResponse { | ||||
|     fn error_response(query: String, info: UserInfo, error: &str) -> ImageSearchTemplate { | ||||
|         let theme = info.theme.clone(); | ||||
|         let theme = info.get_theme(); | ||||
|         let querystr = url_encoded_data::stringify(&[("q", query.as_str())]); | ||||
|         ImageSearchTemplate { | ||||
|             info, | ||||
|  |  | |||
|  | @ -27,49 +27,12 @@ use serde::Deserialize; | |||
| use tokio::sync::Mutex; | ||||
| use tracing::error; | ||||
| use crate::{BUILT_ON, GIT_COMMIT, Opts, ALPHA, VERSION, WEBSITE_COUNT, YEAR}; | ||||
| use crate::routes::{authenticate_user, UserInfo}; | ||||
| 
 | ||||
| pub struct Theme<'a> { | ||||
|     pub value: &'a str, | ||||
|     pub name: &'a str, | ||||
| } | ||||
| 
 | ||||
| pub static THEMES: &[Theme] = &[ | ||||
|     Theme { | ||||
|         value: "default", | ||||
|         name: "default theme", | ||||
|     }, | ||||
|     Theme { | ||||
|         value: "dark", | ||||
|         name: "dark theme", | ||||
|     }, | ||||
|     Theme { | ||||
|         value: "oled", | ||||
|         name: "lights out", | ||||
|     }, | ||||
|     Theme { | ||||
|         value: "classic", | ||||
|         name: "classic", | ||||
|     }, | ||||
|     Theme { | ||||
|         value: "freaky", | ||||
|         name: "freaky", | ||||
|     }, | ||||
|     Theme { | ||||
|         value: "water", | ||||
|         name: "water", | ||||
|     }, | ||||
|     Theme { | ||||
|         value: "gloss", | ||||
|         name: "gloss", | ||||
|     }, | ||||
| ]; | ||||
| use crate::routes::{authenticate_user, Themes, UserInfo}; | ||||
| 
 | ||||
| #[derive(Template)] | ||||
| #[template(path = "user_settings.html")] | ||||
| pub struct SettingsTemplate { | ||||
|     themes: &'static [Theme<'static>], | ||||
| 
 | ||||
|     themes: Vec<Themes>, | ||||
|     error: Option<String>, | ||||
| 
 | ||||
|     info: UserInfo, | ||||
|  | @ -80,7 +43,8 @@ pub struct SettingsTemplate { | |||
|     year: String, | ||||
|     alpha: bool, | ||||
|     count: u64, | ||||
|     theme: String, | ||||
|     theme: Themes, | ||||
|     true_theme: Themes, | ||||
| } | ||||
| 
 | ||||
| pub async fn user_settings( | ||||
|  | @ -96,11 +60,11 @@ pub async fn user_settings( | |||
|                 return (jar.remove("token"), crate::routes::index::frontpage_error(e.as_str(), opts.auth_url.clone())).into_response(); | ||||
|             } | ||||
|         }; | ||||
|         let theme = info.theme.clone(); | ||||
|         let theme = info.get_theme(); | ||||
|         SettingsTemplate { | ||||
|             themes: THEMES, | ||||
|             themes: Themes::get_all_themes(), | ||||
|             error: None, | ||||
|             info, | ||||
|             info: info.clone(), | ||||
|             search_query: "".to_string(), | ||||
|             version: VERSION.to_string(), | ||||
|             git_commit: GIT_COMMIT.to_string(), | ||||
|  | @ -109,6 +73,7 @@ pub async fn user_settings( | |||
|             alpha: ALPHA, | ||||
|             count: WEBSITE_COUNT.load(Ordering::Relaxed), | ||||
|             theme, | ||||
|             true_theme: info.get_true_theme(), | ||||
|         }.into_response() | ||||
|     } else { | ||||
|         Redirect::temporary("/").into_response() | ||||
|  | @ -126,11 +91,11 @@ pub async fn theme_change_post( | |||
|     Extension(opts): Extension<Opts>, | ||||
|     Form(input): Form<ThemeChangeForm>, | ||||
| ) -> impl IntoResponse { | ||||
|     fn settings_error(info: UserInfo, theme: String, error: String) -> impl IntoResponse { | ||||
|     fn settings_error(info: UserInfo, theme: Themes, error: String) -> impl IntoResponse { | ||||
|         SettingsTemplate { | ||||
|             themes: THEMES, | ||||
|             themes: Themes::get_all_themes(), | ||||
|             error: Some(error), | ||||
|             info, | ||||
|             info: info.clone(), | ||||
|             search_query: "".to_string(), | ||||
|             version: VERSION.to_string(), | ||||
|             git_commit: GIT_COMMIT.to_string(), | ||||
|  | @ -139,6 +104,7 @@ pub async fn theme_change_post( | |||
|             alpha: ALPHA, | ||||
|             count: WEBSITE_COUNT.load(Ordering::Relaxed), | ||||
|             theme, | ||||
|             true_theme: info.get_true_theme(), | ||||
|         }.into_response() | ||||
|     } | ||||
| 
 | ||||
|  | @ -151,10 +117,12 @@ pub async fn theme_change_post( | |||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         let theme = info.theme.clone(); | ||||
|         
 | ||||
|         if !THEMES.iter().map(|v| v.value.to_string()).collect::<Vec<String>>().contains(&input.theme.clone().unwrap_or("default".to_string())) { | ||||
|             return settings_error(info, theme, "invalid input, please try again!".to_string()).into_response(); | ||||
|         let theme = info.get_theme(); | ||||
| 
 | ||||
|         if let Some(theme_input) = &input.theme { | ||||
|             if !Themes::get_all_themes().iter().map(|x| x.internal_name().to_string()).collect::<Vec<String>>().contains(&theme_input) { | ||||
|                 return settings_error(info, theme.clone(), "invalid input, please try again!".to_string()).into_response(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let response = comms::query_service(comms::Query::AuthService(AuthServiceQuery { | ||||
|  | @ -200,4 +168,4 @@ pub async fn theme_change_post( | |||
|     } else { | ||||
|         Redirect::to("/").into_response() | ||||
|     } | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -341,7 +341,7 @@ pub async fn gather_search_results(nats: Arc<jetstream::Context>, query: &str, u | |||
|         search_results.remove(rm - i); | ||||
|     } | ||||
| 
 | ||||
|     let theme = user_info.theme.clone(); | ||||
|     let theme = user_info.get_theme(); | ||||
|     let querystr = url_encoded_data::stringify(&[("q", query)]); | ||||
|     SearchTemplate { | ||||
|         info: user_info, | ||||
|  | @ -489,7 +489,7 @@ pub async fn gather_image_results(nats: Arc<jetstream::Context>, query: &str, us | |||
|         result.src = format!("/imgproxy?{}", url); | ||||
|     } | ||||
| 
 | ||||
|     let theme = user_info.theme.clone(); | ||||
|     let theme = user_info.get_theme(); | ||||
|     ImageSearchTemplate { | ||||
|         info: user_info, | ||||
|         error: None, | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ | |||
| {% block title %}the best search engine{% endblock %} | ||||
| 
 | ||||
| {% block head %} | ||||
| <link rel="stylesheet" href="/static/themes/{{theme}}/frontpage.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme}}/inline-announcement.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/frontpage.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/inline-announcement.css"/> | ||||
| {% endblock %} | ||||
| 
 | ||||
| {% block page %} | ||||
|  |  | |||
|  | @ -4,8 +4,8 @@ | |||
| 
 | ||||
| {% block head %} | ||||
| <link rel="stylesheet" href="/static/themes/default/home.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme}}/home.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme}}/inline-announcement.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/home.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/inline-announcement.css"/> | ||||
| {% endblock %} | ||||
| 
 | ||||
| {% block page %} | ||||
|  | @ -71,4 +71,4 @@ | |||
|     </div> | ||||
|     {% include "ui/footer.html" %} | ||||
| </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| 
 | ||||
| {% block head %} | ||||
| <link rel="stylesheet" href="/static/themes/default/imagesearch.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme}}/imagesearch.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/imagesearch.css"/> | ||||
| {% if search_query == "notnite" %}<link rel="stylesheet" href="/static/creature.css"/>{% endif %} | ||||
| {% endblock %} | ||||
| 
 | ||||
|  | @ -61,4 +61,4 @@ | |||
| 
 | ||||
|     {% include "ui/footer.html" %} | ||||
| </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| 
 | ||||
| {% block head %} | ||||
| <link rel="stylesheet" href="/static/themes/default/search.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme}}/search.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/search.css"/> | ||||
| {% if search_query == "notnite" %}<link rel="stylesheet" href="/static/creature.css"/>{% endif %} | ||||
| {% endblock %} | ||||
| 
 | ||||
|  | @ -97,4 +97,4 @@ | |||
| 
 | ||||
|     {% include "ui/footer.html" %} | ||||
| </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| 
 | ||||
| {% block head %} | ||||
| <link rel="stylesheet" href="/static/themes/default/search.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme}}/search.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/search.css"/> | ||||
| {% if search_query == "notnite" %}<link rel="stylesheet" href="/static/creature.css"/>{% endif %} | ||||
| <script src="/static/js/search.js" defer></script> | ||||
| {% endblock %} | ||||
|  | @ -76,4 +76,4 @@ | |||
| 
 | ||||
|     {% include "ui/footer.html" %} | ||||
| </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -12,11 +12,11 @@ | |||
|               href="/static/osd.xml" /> | ||||
| 
 | ||||
|         <link rel="stylesheet" href="/static/themes/default/shell.css" /> | ||||
|         <link rel="stylesheet" href="/static/themes/{{theme}}/shell.css" /> | ||||
|         <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/shell.css" /> | ||||
| 
 | ||||
|         {% block head %}{% endblock %} | ||||
|     </head> | ||||
|     <body> | ||||
|         {% block page %}{% endblock %} | ||||
|     </body> | ||||
| </html> | ||||
| </html> | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| 
 | ||||
| {% block head %} | ||||
| <link rel="stylesheet" href="/static/themes/default/settings.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme}}/settings.css"/> | ||||
| <link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/settings.css"/> | ||||
| {% endblock %} | ||||
| 
 | ||||
| {% block page %} | ||||
|  | @ -43,16 +43,15 @@ | |||
|                 <div class="settings-row"> | ||||
|                     <div id="theme" class="settings-section"> | ||||
|                         <h2>theme</h2> | ||||
|                         {% for t in themes %} | ||||
|                         {%if theme==t.value%} | ||||
|                         <p>your current theme is: "{{t.name}}"</p> | ||||
|                         {%endif%} | ||||
|                         {% endfor %} | ||||
|                         <p>your current theme is: "{{true_theme.display_name()}}"</p> | ||||
|                         {% if true_theme.internal_name() != theme.internal_name() %} | ||||
|                         <p>today's random theme is {{ theme.display_name() }}</p> | ||||
|                         {% endif %} | ||||
|                         <form action="/user_settings/set_theme" method="post"> | ||||
|                             <label for="theme-selector">theme</label> | ||||
|                             <select name="theme" id="theme-selector"> | ||||
|                                 {% for t in themes %} | ||||
|                                 <option value="{{t.value}}" {%if theme==t.value%}selected{%endif%}>{{t.name}}</option> | ||||
|                                 <option value="{{t.internal_name()}}" {%if true_theme.internal_name()==t.internal_name()%}selected{%endif%}>{{t.display_name()}}</option> | ||||
|                                 {% endfor %} | ||||
|                             </select> | ||||
|                             <button type="submit" id="theme-submit">change theme!</button> | ||||
|  | @ -65,4 +64,4 @@ | |||
| 
 | ||||
|     {% include "ui/footer.html" %} | ||||
| </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -457,6 +457,7 @@ pub async fn user_count(db: &DatabaseConnection) -> Result<usize, FetchUserError | |||
| /// returns the number of users in the database who are admins
 | ||||
| pub async fn admin_count(db: &DatabaseConnection) -> Result<usize, FetchUserError> { | ||||
|     // dont fucking touch this, i don't know why it works but it does, it's actually evil
 | ||||
|     // note: doesn't work
 | ||||
|     Ok(user::Entity::find().filter(user::Column::Flags.into_expr().binary(BinOper::LShift, Expr::value(63 - 2)).lt(1 << (63 - 2))) | ||||
|         .count(db).await.map_err(|e| { | ||||
|         error!("DATABASE ERROR WHILE ADMINCOUNT: {e}"); | ||||
|  | @ -482,4 +483,4 @@ pub async fn email_list(db: &DatabaseConnection) -> Result<Vec<(String, String)> | |||
|     })?.into_iter().map(|v| { | ||||
|         (v.username, v.email) | ||||
|     }).collect()) | ||||
| } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue