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",
|
"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 = "*"
|
||||||
|
|
|
@ -343,45 +343,14 @@ pub async fn admin_invitecode(
|
||||||
}
|
}
|
||||||
|
|
||||||
let active_codes = match list_invite_codes(nats.clone(), token.clone(), false).await {
|
let active_codes = match list_invite_codes(nats.clone(), token.clone(), false).await {
|
||||||
Ok(mut v) => {
|
Ok(v) => 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
|
|
||||||
},
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return e.into_response();
|
return e.into_response();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let used_codes = match list_invite_codes(nats.clone(), token.clone(), true).await {
|
let used_codes = match list_invite_codes(nats.clone(), token.clone(), true).await {
|
||||||
Ok(v) => v.into_iter().map(|mut v| {
|
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(),
|
||||||
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(),
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return e.into_response();
|
return e.into_response();
|
||||||
}
|
}
|
||||||
|
@ -657,4 +626,4 @@ pub async fn admin_user_list(
|
||||||
} else {
|
} else {
|
||||||
Redirect::to("/").into_response()
|
Redirect::to("/").into_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,10 +110,10 @@ 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 {
|
||||||
StatusCode::NOT_FOUND.into_response()
|
StatusCode::NOT_FOUND.into_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
@ -114,4 +237,4 @@ pub struct NotFoundTemplate;
|
||||||
|
|
||||||
pub async fn not_found() -> impl IntoResponse {
|
pub async fn not_found() -> impl IntoResponse {
|
||||||
(StatusCode::NOT_FOUND, NotFoundTemplate).into_response()
|
(StatusCode::NOT_FOUND, NotFoundTemplate).into_response()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
@ -200,4 +168,4 @@ pub async fn theme_change_post(
|
||||||
} else {
|
} else {
|
||||||
Redirect::to("/").into_response()
|
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);
|
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 %}
|
||||||
|
@ -71,4 +71,4 @@
|
||||||
</div>
|
</div>
|
||||||
{% include "ui/footer.html" %}
|
{% include "ui/footer.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
||||||
|
@ -61,4 +61,4 @@
|
||||||
|
|
||||||
{% include "ui/footer.html" %}
|
{% include "ui/footer.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% 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 %}
|
||||||
|
|
||||||
|
@ -97,4 +97,4 @@
|
||||||
|
|
||||||
{% include "ui/footer.html" %}
|
{% include "ui/footer.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% 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 %}
|
||||||
|
@ -76,4 +76,4 @@
|
||||||
|
|
||||||
{% include "ui/footer.html" %}
|
{% include "ui/footer.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
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>
|
||||||
<body>
|
<body>
|
||||||
{% block page %}{% endblock %}
|
{% block page %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -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>
|
||||||
|
@ -65,4 +64,4 @@
|
||||||
|
|
||||||
{% include "ui/footer.html" %}
|
{% include "ui/footer.html" %}
|
||||||
</div>
|
</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
|
/// 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}");
|
||||||
|
@ -482,4 +483,4 @@ pub async fn email_list(db: &DatabaseConnection) -> Result<Vec<(String, String)>
|
||||||
})?.into_iter().map(|v| {
|
})?.into_iter().map(|v| {
|
||||||
(v.username, v.email)
|
(v.username, v.email)
|
||||||
}).collect())
|
}).collect())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue