feature: Implement random theme and theme enum #8
					 17 changed files with 214 additions and 99 deletions
				
			
		
							
								
								
									
										23
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										23
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -278,6 +278,8 @@ dependencies = [
 | 
				
			||||||
 "rmp-serde",
 | 
					 "rmp-serde",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 | 
					 "strum 0.27.1",
 | 
				
			||||||
 | 
					 "strum_macros",
 | 
				
			||||||
 "time",
 | 
					 "time",
 | 
				
			||||||
 "tokio",
 | 
					 "tokio",
 | 
				
			||||||
 "tower-http",
 | 
					 "tower-http",
 | 
				
			||||||
| 
						 | 
					@ -4146,7 +4148,7 @@ dependencies = [
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 "sqlx",
 | 
					 "sqlx",
 | 
				
			||||||
 "strum",
 | 
					 "strum 0.26.3",
 | 
				
			||||||
 "thiserror 1.0.69",
 | 
					 "thiserror 1.0.69",
 | 
				
			||||||
 "time",
 | 
					 "time",
 | 
				
			||||||
 "tracing",
 | 
					 "tracing",
 | 
				
			||||||
| 
						 | 
					@ -4907,6 +4909,25 @@ version = "0.26.3"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
 | 
					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]]
 | 
					[[package]]
 | 
				
			||||||
name = "subtle"
 | 
					name = "subtle"
 | 
				
			||||||
version = "2.6.1"
 | 
					version = "2.6.1"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,5 +36,7 @@ once_cell = "1.19.0"
 | 
				
			||||||
chrono = "0.4.33"
 | 
					chrono = "0.4.33"
 | 
				
			||||||
rand = "0.8.5"
 | 
					rand = "0.8.5"
 | 
				
			||||||
url_encoded_data = "0.6.1"
 | 
					url_encoded_data = "0.6.1"
 | 
				
			||||||
 | 
					strum = "0.27.1"
 | 
				
			||||||
 | 
					strum_macros = "0.27.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
env_logger = "*"
 | 
					env_logger = "*"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ use tracing::{debug, error};
 | 
				
			||||||
use tracing::log::warn;
 | 
					use tracing::log::warn;
 | 
				
			||||||
use crate::{Opts, ALPHA, BUILT_ON, GIT_COMMIT, VERSION, YEAR};
 | 
					use crate::{Opts, ALPHA, BUILT_ON, GIT_COMMIT, VERSION, YEAR};
 | 
				
			||||||
use crate::routes::index::FrontpageAnnouncement;
 | 
					use crate::routes::index::FrontpageAnnouncement;
 | 
				
			||||||
 | 
					use crate::routes::Themes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Debug)]
 | 
					#[derive(Serialize, Debug)]
 | 
				
			||||||
struct FullAnnouncement {
 | 
					struct FullAnnouncement {
 | 
				
			||||||
| 
						 | 
					@ -96,7 +97,7 @@ pub struct AnnouncementTemplate {
 | 
				
			||||||
    built_on: String,
 | 
					    built_on: String,
 | 
				
			||||||
    year: String,
 | 
					    year: String,
 | 
				
			||||||
    alpha: bool,
 | 
					    alpha: bool,
 | 
				
			||||||
    theme: String,
 | 
					    theme: Themes,
 | 
				
			||||||
    announcement: FullAnnouncement,
 | 
					    announcement: FullAnnouncement,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -109,7 +110,7 @@ pub async fn announcement_full(Extension(nats): Extension<Arc<jetstream::Context
 | 
				
			||||||
            built_on: BUILT_ON.to_string(),
 | 
					            built_on: BUILT_ON.to_string(),
 | 
				
			||||||
            year: YEAR.to_string(),
 | 
					            year: YEAR.to_string(),
 | 
				
			||||||
            alpha: ALPHA,
 | 
					            alpha: ALPHA,
 | 
				
			||||||
            theme: "default".to_string(),
 | 
					            theme: Themes::Default,
 | 
				
			||||||
            announcement,
 | 
					            announcement,
 | 
				
			||||||
        }.into_response()
 | 
					        }.into_response()
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ use tokio::sync::Mutex;
 | 
				
			||||||
use tracing::error;
 | 
					use tracing::error;
 | 
				
			||||||
use tracing::log::warn;
 | 
					use tracing::log::warn;
 | 
				
			||||||
use crate::{BUILT_ON, GIT_COMMIT, Opts, ALPHA, VERSION, WEBSITE_COUNT, YEAR};
 | 
					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)]
 | 
					#[derive(Serialize, Debug)]
 | 
				
			||||||
pub struct FrontpageAnnouncement {
 | 
					pub struct FrontpageAnnouncement {
 | 
				
			||||||
| 
						 | 
					@ -102,7 +102,7 @@ pub fn frontpage_error(error: &str, auth_url: String) -> FrontpageTemplate {
 | 
				
			||||||
        year: YEAR.to_string(),
 | 
					        year: YEAR.to_string(),
 | 
				
			||||||
        alpha: ALPHA,
 | 
					        alpha: ALPHA,
 | 
				
			||||||
        count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
					        count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
				
			||||||
        theme: "default".to_string(),
 | 
					        theme: Themes::Default,
 | 
				
			||||||
        announcement: None,
 | 
					        announcement: None,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -185,7 +185,7 @@ pub struct FrontpageTemplate {
 | 
				
			||||||
    year: String,
 | 
					    year: String,
 | 
				
			||||||
    alpha: bool,
 | 
					    alpha: bool,
 | 
				
			||||||
    count: u64,
 | 
					    count: u64,
 | 
				
			||||||
    theme: String,
 | 
					    theme: Themes,
 | 
				
			||||||
    announcement: Option<FrontpageAnnouncement>,
 | 
					    announcement: Option<FrontpageAnnouncement>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,7 +202,7 @@ pub async fn frontpage(
 | 
				
			||||||
        year: YEAR.to_string(),
 | 
					        year: YEAR.to_string(),
 | 
				
			||||||
        alpha: ALPHA,
 | 
					        alpha: ALPHA,
 | 
				
			||||||
        count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
					        count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
				
			||||||
        theme: "default".to_string(),
 | 
					        theme: Themes::Default,
 | 
				
			||||||
        announcement,
 | 
					        announcement,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -217,7 +217,7 @@ struct IndexTemplate {
 | 
				
			||||||
    year: String,
 | 
					    year: String,
 | 
				
			||||||
    alpha: bool,
 | 
					    alpha: bool,
 | 
				
			||||||
    count: u64,
 | 
					    count: u64,
 | 
				
			||||||
    theme: String,
 | 
					    theme: Themes,
 | 
				
			||||||
    announcement: Option<FrontpageAnnouncement>,
 | 
					    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();
 | 
					                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;
 | 
					        let announcement = latest_announcement(nats.clone()).await;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
| 
						 | 
					@ -260,7 +260,7 @@ pub async fn index(
 | 
				
			||||||
            year: YEAR.to_string(),
 | 
					            year: YEAR.to_string(),
 | 
				
			||||||
            alpha: ALPHA,
 | 
					            alpha: ALPHA,
 | 
				
			||||||
            count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
					            count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
				
			||||||
            theme: "default".to_string(),
 | 
					            theme: Themes::Default,
 | 
				
			||||||
            announcement,
 | 
					            announcement,
 | 
				
			||||||
        }.into_response()
 | 
					        }.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/>.
 | 
					 * 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 std::sync::Arc;
 | 
				
			||||||
use askama::Template;
 | 
					use askama::Template;
 | 
				
			||||||
use askama_axum::IntoResponse;
 | 
					use askama_axum::IntoResponse;
 | 
				
			||||||
| 
						 | 
					@ -21,7 +22,13 @@ use asklyphe_common::nats::comms::ServiceResponse;
 | 
				
			||||||
use async_nats::jetstream;
 | 
					use async_nats::jetstream;
 | 
				
			||||||
use axum::http::StatusCode;
 | 
					use axum::http::StatusCode;
 | 
				
			||||||
use serde::Serialize;
 | 
					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 search;
 | 
				
			||||||
pub mod index;
 | 
					pub mod index;
 | 
				
			||||||
| 
						 | 
					@ -30,7 +37,102 @@ pub mod user_settings;
 | 
				
			||||||
pub mod admin;
 | 
					pub mod admin;
 | 
				
			||||||
pub mod announcement;
 | 
					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 struct UserInfo {
 | 
				
			||||||
    pub username: String,
 | 
					    pub username: String,
 | 
				
			||||||
    pub email: String,
 | 
					    pub email: String,
 | 
				
			||||||
| 
						 | 
					@ -39,6 +141,27 @@ pub struct UserInfo {
 | 
				
			||||||
    pub administrator: bool,
 | 
					    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> {
 | 
					pub async fn authenticate_user(nats: Arc<jetstream::Context>, token: String) -> Result<UserInfo, String> {
 | 
				
			||||||
    let response = comms::query_service(
 | 
					    let response = comms::query_service(
 | 
				
			||||||
        comms::Query::AuthService(AuthServiceQuery {
 | 
					        comms::Query::AuthService(AuthServiceQuery {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::routes::index::frontpage_error;
 | 
					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::searchbot::{gather_image_results, gather_search_results};
 | 
				
			||||||
use crate::unit_converter;
 | 
					use crate::unit_converter;
 | 
				
			||||||
use crate::unit_converter::UnitConversion;
 | 
					use crate::unit_converter::UnitConversion;
 | 
				
			||||||
| 
						 | 
					@ -111,7 +111,7 @@ struct SearchTemplateJavascript {
 | 
				
			||||||
    built_on: String,
 | 
					    built_on: String,
 | 
				
			||||||
    year: String,
 | 
					    year: String,
 | 
				
			||||||
    alpha: bool,
 | 
					    alpha: bool,
 | 
				
			||||||
    theme: String,
 | 
					    theme: Themes,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn search_js(
 | 
					pub async fn search_js(
 | 
				
			||||||
| 
						 | 
					@ -121,7 +121,7 @@ pub async fn search_js(
 | 
				
			||||||
    Extension(opts): Extension<Opts>,
 | 
					    Extension(opts): Extension<Opts>,
 | 
				
			||||||
) -> impl IntoResponse {
 | 
					) -> impl IntoResponse {
 | 
				
			||||||
    fn error_response(query: String, info: UserInfo, error: &str) -> SearchTemplateJavascript {
 | 
					    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())]);
 | 
					        let querystr = url_encoded_data::stringify(&[("q", query.as_str())]);
 | 
				
			||||||
        SearchTemplateJavascript {
 | 
					        SearchTemplateJavascript {
 | 
				
			||||||
            info,
 | 
					            info,
 | 
				
			||||||
| 
						 | 
					@ -175,7 +175,7 @@ pub async fn search_js(
 | 
				
			||||||
            query = query.replace("-complications", "");
 | 
					            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())]);
 | 
					        let querystr = url_encoded_data::stringify(&[("q", og_query.as_str())]);
 | 
				
			||||||
        SearchTemplateJavascript {
 | 
					        SearchTemplateJavascript {
 | 
				
			||||||
            info,
 | 
					            info,
 | 
				
			||||||
| 
						 | 
					@ -217,7 +217,7 @@ pub struct SearchTemplate {
 | 
				
			||||||
    pub built_on: String,
 | 
					    pub built_on: String,
 | 
				
			||||||
    pub year: String,
 | 
					    pub year: String,
 | 
				
			||||||
    pub alpha: bool,
 | 
					    pub alpha: bool,
 | 
				
			||||||
    pub theme: String,
 | 
					    pub theme: Themes,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn search_nojs(
 | 
					pub async fn search_nojs(
 | 
				
			||||||
| 
						 | 
					@ -227,7 +227,7 @@ pub async fn search_nojs(
 | 
				
			||||||
    Extension(opts): Extension<Opts>,
 | 
					    Extension(opts): Extension<Opts>,
 | 
				
			||||||
) -> impl IntoResponse {
 | 
					) -> impl IntoResponse {
 | 
				
			||||||
    fn error_response(query: String, info: UserInfo, error: &str) -> SearchTemplate {
 | 
					    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())]);
 | 
					        let querystr = url_encoded_data::stringify(&[("q", query.as_str())]);
 | 
				
			||||||
        SearchTemplate {
 | 
					        SearchTemplate {
 | 
				
			||||||
            info,
 | 
					            info,
 | 
				
			||||||
| 
						 | 
					@ -416,7 +416,7 @@ pub struct ImageSearchTemplate {
 | 
				
			||||||
    pub built_on: String,
 | 
					    pub built_on: String,
 | 
				
			||||||
    pub year: String,
 | 
					    pub year: String,
 | 
				
			||||||
    pub alpha: bool,
 | 
					    pub alpha: bool,
 | 
				
			||||||
    pub theme: String,
 | 
					    pub theme: Themes,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
pub async fn image_search(
 | 
					pub async fn image_search(
 | 
				
			||||||
    jar: CookieJar,
 | 
					    jar: CookieJar,
 | 
				
			||||||
| 
						 | 
					@ -425,7 +425,7 @@ pub async fn image_search(
 | 
				
			||||||
    Extension(opts): Extension<Opts>,
 | 
					    Extension(opts): Extension<Opts>,
 | 
				
			||||||
) -> impl IntoResponse {
 | 
					) -> impl IntoResponse {
 | 
				
			||||||
    fn error_response(query: String, info: UserInfo, error: &str) -> ImageSearchTemplate {
 | 
					    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())]);
 | 
					        let querystr = url_encoded_data::stringify(&[("q", query.as_str())]);
 | 
				
			||||||
        ImageSearchTemplate {
 | 
					        ImageSearchTemplate {
 | 
				
			||||||
            info,
 | 
					            info,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,49 +27,12 @@ use serde::Deserialize;
 | 
				
			||||||
use tokio::sync::Mutex;
 | 
					use tokio::sync::Mutex;
 | 
				
			||||||
use tracing::error;
 | 
					use tracing::error;
 | 
				
			||||||
use crate::{BUILT_ON, GIT_COMMIT, Opts, ALPHA, VERSION, WEBSITE_COUNT, YEAR};
 | 
					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};
 | 
				
			||||||
 | 
					 | 
				
			||||||
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",
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Template)]
 | 
					#[derive(Template)]
 | 
				
			||||||
#[template(path = "user_settings.html")]
 | 
					#[template(path = "user_settings.html")]
 | 
				
			||||||
pub struct SettingsTemplate {
 | 
					pub struct SettingsTemplate {
 | 
				
			||||||
    themes: &'static [Theme<'static>],
 | 
					    themes: Vec<Themes>,
 | 
				
			||||||
 | 
					 | 
				
			||||||
    error: Option<String>,
 | 
					    error: Option<String>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    info: UserInfo,
 | 
					    info: UserInfo,
 | 
				
			||||||
| 
						 | 
					@ -80,7 +43,8 @@ pub struct SettingsTemplate {
 | 
				
			||||||
    year: String,
 | 
					    year: String,
 | 
				
			||||||
    alpha: bool,
 | 
					    alpha: bool,
 | 
				
			||||||
    count: u64,
 | 
					    count: u64,
 | 
				
			||||||
    theme: String,
 | 
					    theme: Themes,
 | 
				
			||||||
 | 
					    true_theme: Themes,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn user_settings(
 | 
					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();
 | 
					                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 {
 | 
					        SettingsTemplate {
 | 
				
			||||||
            themes: THEMES,
 | 
					            themes: Themes::get_all_themes(),
 | 
				
			||||||
            error: None,
 | 
					            error: None,
 | 
				
			||||||
            info,
 | 
					            info: info.clone(),
 | 
				
			||||||
            search_query: "".to_string(),
 | 
					            search_query: "".to_string(),
 | 
				
			||||||
            version: VERSION.to_string(),
 | 
					            version: VERSION.to_string(),
 | 
				
			||||||
            git_commit: GIT_COMMIT.to_string(),
 | 
					            git_commit: GIT_COMMIT.to_string(),
 | 
				
			||||||
| 
						 | 
					@ -109,6 +73,7 @@ pub async fn user_settings(
 | 
				
			||||||
            alpha: ALPHA,
 | 
					            alpha: ALPHA,
 | 
				
			||||||
            count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
					            count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
				
			||||||
            theme,
 | 
					            theme,
 | 
				
			||||||
 | 
					            true_theme: info.get_true_theme(),
 | 
				
			||||||
        }.into_response()
 | 
					        }.into_response()
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        Redirect::temporary("/").into_response()
 | 
					        Redirect::temporary("/").into_response()
 | 
				
			||||||
| 
						 | 
					@ -126,11 +91,11 @@ pub async fn theme_change_post(
 | 
				
			||||||
    Extension(opts): Extension<Opts>,
 | 
					    Extension(opts): Extension<Opts>,
 | 
				
			||||||
    Form(input): Form<ThemeChangeForm>,
 | 
					    Form(input): Form<ThemeChangeForm>,
 | 
				
			||||||
) -> impl IntoResponse {
 | 
					) -> 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 {
 | 
					        SettingsTemplate {
 | 
				
			||||||
            themes: THEMES,
 | 
					            themes: Themes::get_all_themes(),
 | 
				
			||||||
            error: Some(error),
 | 
					            error: Some(error),
 | 
				
			||||||
            info,
 | 
					            info: info.clone(),
 | 
				
			||||||
            search_query: "".to_string(),
 | 
					            search_query: "".to_string(),
 | 
				
			||||||
            version: VERSION.to_string(),
 | 
					            version: VERSION.to_string(),
 | 
				
			||||||
            git_commit: GIT_COMMIT.to_string(),
 | 
					            git_commit: GIT_COMMIT.to_string(),
 | 
				
			||||||
| 
						 | 
					@ -139,6 +104,7 @@ pub async fn theme_change_post(
 | 
				
			||||||
            alpha: ALPHA,
 | 
					            alpha: ALPHA,
 | 
				
			||||||
            count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
					            count: WEBSITE_COUNT.load(Ordering::Relaxed),
 | 
				
			||||||
            theme,
 | 
					            theme,
 | 
				
			||||||
 | 
					            true_theme: info.get_true_theme(),
 | 
				
			||||||
        }.into_response()
 | 
					        }.into_response()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -151,10 +117,12 @@ pub async fn theme_change_post(
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let theme = info.theme.clone();
 | 
					        let theme = info.get_theme();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if !THEMES.iter().map(|v| v.value.to_string()).collect::<Vec<String>>().contains(&input.theme.clone().unwrap_or("default".to_string())) {
 | 
					        if let Some(theme_input) = &input.theme {
 | 
				
			||||||
            return settings_error(info, theme, "invalid input, please try again!".to_string()).into_response();
 | 
					            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 {
 | 
					        let response = comms::query_service(comms::Query::AuthService(AuthServiceQuery {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -341,7 +341,7 @@ pub async fn gather_search_results(nats: Arc<jetstream::Context>, query: &str, u
 | 
				
			||||||
        search_results.remove(rm - i);
 | 
					        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)]);
 | 
					    let querystr = url_encoded_data::stringify(&[("q", query)]);
 | 
				
			||||||
    SearchTemplate {
 | 
					    SearchTemplate {
 | 
				
			||||||
        info: user_info,
 | 
					        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);
 | 
					        result.src = format!("/imgproxy?{}", url);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let theme = user_info.theme.clone();
 | 
					    let theme = user_info.get_theme();
 | 
				
			||||||
    ImageSearchTemplate {
 | 
					    ImageSearchTemplate {
 | 
				
			||||||
        info: user_info,
 | 
					        info: user_info,
 | 
				
			||||||
        error: None,
 | 
					        error: None,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,8 +3,8 @@
 | 
				
			||||||
{% block title %}the best search engine{% endblock %}
 | 
					{% block title %}the best search engine{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block head %}
 | 
					{% block head %}
 | 
				
			||||||
<link rel="stylesheet" href="/static/themes/{{theme}}/frontpage.css"/>
 | 
					<link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/frontpage.css"/>
 | 
				
			||||||
<link rel="stylesheet" href="/static/themes/{{theme}}/inline-announcement.css"/>
 | 
					<link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/inline-announcement.css"/>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block page %}
 | 
					{% block page %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,8 +4,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block head %}
 | 
					{% block head %}
 | 
				
			||||||
<link rel="stylesheet" href="/static/themes/default/home.css"/>
 | 
					<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.internal_name()}}/home.css"/>
 | 
				
			||||||
<link rel="stylesheet" href="/static/themes/{{theme}}/inline-announcement.css"/>
 | 
					<link rel="stylesheet" href="/static/themes/{{theme.internal_name()}}/inline-announcement.css"/>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block page %}
 | 
					{% block page %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block head %}
 | 
					{% block head %}
 | 
				
			||||||
<link rel="stylesheet" href="/static/themes/default/imagesearch.css"/>
 | 
					<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 %}
 | 
					{% if search_query == "notnite" %}<link rel="stylesheet" href="/static/creature.css"/>{% endif %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block head %}
 | 
					{% block head %}
 | 
				
			||||||
<link rel="stylesheet" href="/static/themes/default/search.css"/>
 | 
					<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 %}
 | 
					{% if search_query == "notnite" %}<link rel="stylesheet" href="/static/creature.css"/>{% endif %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block head %}
 | 
					{% block head %}
 | 
				
			||||||
<link rel="stylesheet" href="/static/themes/default/search.css"/>
 | 
					<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 %}
 | 
					{% if search_query == "notnite" %}<link rel="stylesheet" href="/static/creature.css"/>{% endif %}
 | 
				
			||||||
<script src="/static/js/search.js" defer></script>
 | 
					<script src="/static/js/search.js" defer></script>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@
 | 
				
			||||||
              href="/static/osd.xml" />
 | 
					              href="/static/osd.xml" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <link rel="stylesheet" href="/static/themes/default/shell.css" />
 | 
					        <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 %}
 | 
					        {% block head %}{% endblock %}
 | 
				
			||||||
    </head>
 | 
					    </head>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block head %}
 | 
					{% block head %}
 | 
				
			||||||
<link rel="stylesheet" href="/static/themes/default/settings.css"/>
 | 
					<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 %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block page %}
 | 
					{% block page %}
 | 
				
			||||||
| 
						 | 
					@ -43,16 +43,15 @@
 | 
				
			||||||
                <div class="settings-row">
 | 
					                <div class="settings-row">
 | 
				
			||||||
                    <div id="theme" class="settings-section">
 | 
					                    <div id="theme" class="settings-section">
 | 
				
			||||||
                        <h2>theme</h2>
 | 
					                        <h2>theme</h2>
 | 
				
			||||||
                        {% for t in themes %}
 | 
					                        <p>your current theme is: "{{true_theme.display_name()}}"</p>
 | 
				
			||||||
                        {%if theme==t.value%}
 | 
					                        {% if true_theme.internal_name() != theme.internal_name() %}
 | 
				
			||||||
                        <p>your current theme is: "{{t.name}}"</p>
 | 
					                        <p>today's random theme is {{ theme.display_name() }}</p>
 | 
				
			||||||
                        {%endif%}
 | 
					                        {% endif %}
 | 
				
			||||||
                        {% endfor %}
 | 
					 | 
				
			||||||
                        <form action="/user_settings/set_theme" method="post">
 | 
					                        <form action="/user_settings/set_theme" method="post">
 | 
				
			||||||
                            <label for="theme-selector">theme</label>
 | 
					                            <label for="theme-selector">theme</label>
 | 
				
			||||||
                            <select name="theme" id="theme-selector">
 | 
					                            <select name="theme" id="theme-selector">
 | 
				
			||||||
                                {% for t in themes %}
 | 
					                                {% 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 %}
 | 
					                                {% endfor %}
 | 
				
			||||||
                            </select>
 | 
					                            </select>
 | 
				
			||||||
                            <button type="submit" id="theme-submit">change theme!</button>
 | 
					                            <button type="submit" id="theme-submit">change theme!</button>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
					/// returns the number of users in the database who are admins
 | 
				
			||||||
pub async fn admin_count(db: &DatabaseConnection) -> Result<usize, FetchUserError> {
 | 
					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
 | 
					    // 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)))
 | 
					    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| {
 | 
					        .count(db).await.map_err(|e| {
 | 
				
			||||||
        error!("DATABASE ERROR WHILE ADMINCOUNT: {e}");
 | 
					        error!("DATABASE ERROR WHILE ADMINCOUNT: {e}");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue