Add language switching, fix logout
This commit is contained in:
@@ -234,6 +234,7 @@ pub async fn webservice(
|
||||
// admin block
|
||||
.service(
|
||||
web::scope("/admin")
|
||||
.route("/logout/", web::to(views::logout))
|
||||
.service(
|
||||
web::scope("/download")
|
||||
.route("/png/{redirect_id}", web::get().to(views::download_png)),
|
||||
@@ -241,6 +242,8 @@ pub async fn webservice(
|
||||
.service(
|
||||
web::scope("/json")
|
||||
.route("/list_links/", web::post().to(views::index_json))
|
||||
.route("/get_language/", web::get().to(views::get_language))
|
||||
.route("/change_language/", web::post().to(views::set_language))
|
||||
.route(
|
||||
"/create_link/",
|
||||
web::post().to(views::process_create_link_json),
|
||||
|
||||
+11
-7
@@ -1,3 +1,5 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{forms::LinkForm, Secret, ServerConfig, ServerError};
|
||||
|
||||
use argonautica::Hasher;
|
||||
@@ -7,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use shared::{
|
||||
apirequests::links::LinkDelta,
|
||||
datatypes::{Count, Link, User},
|
||||
datatypes::{Count, Lang, Link, User},
|
||||
};
|
||||
use sqlx::Row;
|
||||
use tracing::{error, info, instrument};
|
||||
@@ -22,7 +24,7 @@ pub trait UserDbOperations<T> {
|
||||
async fn set_language(
|
||||
self,
|
||||
server_config: &ServerConfig,
|
||||
new_language: &str,
|
||||
new_language: Lang,
|
||||
) -> Result<(), ServerError>;
|
||||
async fn count_admins(server_config: &ServerConfig) -> Result<Count, ServerError>;
|
||||
}
|
||||
@@ -40,7 +42,7 @@ impl UserDbOperations<Self> for User {
|
||||
email: row.email,
|
||||
password: Secret::new(row.password),
|
||||
role: row.role,
|
||||
language: row.language,
|
||||
language: Lang::from_str(&row.language).expect("Should parse"),
|
||||
});
|
||||
user.map_err(ServerError::Database)
|
||||
}
|
||||
@@ -63,7 +65,7 @@ impl UserDbOperations<Self> for User {
|
||||
email: row.email,
|
||||
password: Secret::new(row.password),
|
||||
role: row.role,
|
||||
language: row.language,
|
||||
language: Lang::from_str(&row.language).expect("Should parse"),
|
||||
});
|
||||
user.map_err(ServerError::Database)
|
||||
}
|
||||
@@ -81,7 +83,8 @@ impl UserDbOperations<Self> for User {
|
||||
email: r.get("email"),
|
||||
password: Secret::new(r.get("password")),
|
||||
role: r.get("role"),
|
||||
language: r.get("language"),
|
||||
language: Lang::from_str(r.get("language"))
|
||||
.expect("should parse correctly"),
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
@@ -124,11 +127,12 @@ impl UserDbOperations<Self> for User {
|
||||
async fn set_language(
|
||||
self,
|
||||
server_config: &ServerConfig,
|
||||
new_language: &str,
|
||||
new_language: Lang,
|
||||
) -> Result<(), ServerError> {
|
||||
let lang_code = new_language.to_string();
|
||||
sqlx::query!(
|
||||
"UPDATE users SET language = ? where id = ?",
|
||||
new_language,
|
||||
lang_code,
|
||||
self.id
|
||||
)
|
||||
.execute(&server_config.db_pool)
|
||||
|
||||
+10
-18
@@ -1,3 +1,5 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use actix_identity::Identity;
|
||||
use actix_web::web;
|
||||
use enum_map::EnumMap;
|
||||
@@ -8,7 +10,7 @@ use shared::{
|
||||
links::{LinkDelta, LinkOverviewColumns, LinkRequestForm},
|
||||
users::{UserDelta, UserOverviewColumns, UserRequestForm},
|
||||
},
|
||||
datatypes::{Count, FullLink, Link, Secret, User},
|
||||
datatypes::{Count, FullLink, Lang, Link, Secret, User},
|
||||
};
|
||||
use sqlx::Row;
|
||||
use tracing::{info, instrument, warn};
|
||||
@@ -129,7 +131,7 @@ pub async fn list_all_allowed(
|
||||
email: v.get("uemail"),
|
||||
password: Secret::new("invalid".to_string()),
|
||||
role: v.get("urole"),
|
||||
language: v.get("ulang"),
|
||||
language: Lang::from_str(v.get("ulang")).expect("Should parse"),
|
||||
},
|
||||
clicks: Count {
|
||||
number: v.get("counter"), /* count is never None */
|
||||
@@ -242,7 +244,7 @@ pub async fn list_users(
|
||||
email: v.get("email"),
|
||||
password: Secret::new("".to_string()),
|
||||
role: v.get("role"),
|
||||
language: v.get("language"),
|
||||
language: Lang::from_str(v.get("language")).expect("Should parse"),
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -591,24 +593,14 @@ pub async fn toggle_admin(
|
||||
#[instrument(skip(id))]
|
||||
pub async fn set_language(
|
||||
id: &Identity,
|
||||
lang_code: &str,
|
||||
lang_code: Lang,
|
||||
server_config: &ServerConfig,
|
||||
) -> Result<(), ServerError> {
|
||||
match lang_code {
|
||||
"de" | "en" => match authenticate(id, server_config).await? {
|
||||
Role::Admin { user } | Role::Regular { user } => {
|
||||
user.set_language(server_config, lang_code).await
|
||||
}
|
||||
Role::Disabled | Role::NotAuthenticated => {
|
||||
Err(ServerError::User("Not Allowed".to_owned()))
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
warn!("An invalid language was selected!");
|
||||
Err(ServerError::User(
|
||||
"This language is not supported!".to_owned(),
|
||||
))
|
||||
match authenticate(id, server_config).await? {
|
||||
Role::Admin { user } | Role::Regular { user } => {
|
||||
user.set_language(server_config, lang_code).await
|
||||
}
|
||||
Role::Disabled | Role::NotAuthenticated => Err(ServerError::User("Not Allowed".to_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+53
-12
@@ -14,10 +14,13 @@ use fluent_templates::LanguageIdentifier;
|
||||
use image::{DynamicImage, ImageOutputFormat, Luma};
|
||||
use qrcode::QrCode;
|
||||
use queries::{authenticate, Role};
|
||||
use shared::apirequests::{
|
||||
general::{Message, Status},
|
||||
links::{LinkDelta, LinkRequestForm},
|
||||
users::{LoginUser, UserDelta, UserRequestForm},
|
||||
use shared::{
|
||||
apirequests::{
|
||||
general::{Message, Status},
|
||||
links::{LinkDelta, LinkRequestForm},
|
||||
users::{LoginUser, UserDelta, UserRequestForm},
|
||||
},
|
||||
datatypes::Lang,
|
||||
};
|
||||
use tracing::{error, info, instrument, warn};
|
||||
|
||||
@@ -38,7 +41,7 @@ fn redirect_builder(target: &str) -> HttpResponse {
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
fn detect_language(request: &HttpRequest) -> Result<String, ServerError> {
|
||||
fn detect_language(request: &HttpRequest) -> Result<Lang, ServerError> {
|
||||
let requested = parse_accepted_languages(
|
||||
request
|
||||
.headers()
|
||||
@@ -49,7 +52,9 @@ fn detect_language(request: &HttpRequest) -> Result<String, ServerError> {
|
||||
ServerError::User("Failed to convert Accept_language to str".to_owned())
|
||||
})?,
|
||||
);
|
||||
info!("accepted languages: {:?}", requested);
|
||||
let available = convert_vec_str_to_langids_lossy(&["de", "en"]);
|
||||
info!("available languages: {:?}", available);
|
||||
let default: LanguageIdentifier = "en"
|
||||
.parse()
|
||||
.map_err(|_| ServerError::User("Failed to parse a langid.".to_owned()))?;
|
||||
@@ -60,10 +65,18 @@ fn detect_language(request: &HttpRequest) -> Result<String, ServerError> {
|
||||
Some(&default),
|
||||
NegotiationStrategy::Filtering,
|
||||
);
|
||||
let languagecode = supported
|
||||
.get(0)
|
||||
.map_or("en".to_string(), std::string::ToString::to_string);
|
||||
Ok(languagecode)
|
||||
info!("supported languages: {:?}", supported);
|
||||
|
||||
if let Some(languagecode) = supported.get(0) {
|
||||
info!("Supported Language: {}", languagecode);
|
||||
Ok(languagecode
|
||||
.to_string()
|
||||
.parse()
|
||||
.expect("Failed to parse 2 language"))
|
||||
} else {
|
||||
info!("Unsupported language using default!");
|
||||
Ok("enEN".parse::<Lang>().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument()]
|
||||
@@ -201,14 +214,35 @@ pub async fn toggle_admin(
|
||||
)))
|
||||
}
|
||||
|
||||
#[instrument(skip(id))]
|
||||
pub async fn get_language(
|
||||
id: Option<Identity>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
req: HttpRequest,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
if let Some(id) = id {
|
||||
let user = authenticate(&id, &config).await?;
|
||||
match user {
|
||||
Role::NotAuthenticated | Role::Disabled => {
|
||||
Ok(HttpResponse::Ok().json2(&detect_language(&req)?))
|
||||
}
|
||||
Role::Regular { user } | Role::Admin { user } => {
|
||||
Ok(HttpResponse::Ok().json2(&user.language))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(HttpResponse::Ok().json2(&detect_language(&req)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(id))]
|
||||
pub async fn set_language(
|
||||
data: web::Path<String>,
|
||||
data: web::Json<Lang>,
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
id: Identity,
|
||||
) -> Result<HttpResponse, ServerError> {
|
||||
queries::set_language(&id, &data.0, &config).await?;
|
||||
Ok(redirect_builder("/admin/index/"))
|
||||
queries::set_language(&id, data.0, &config).await?;
|
||||
Ok(HttpResponse::Ok().json2(&data.0))
|
||||
}
|
||||
|
||||
#[instrument(skip(id))]
|
||||
@@ -259,6 +293,13 @@ pub async fn process_login_json(
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(id))]
|
||||
pub async fn logout(id: Identity) -> Result<HttpResponse, ServerError> {
|
||||
info!("Logging out the user");
|
||||
id.forget();
|
||||
Ok(redirect_builder("/app/"))
|
||||
}
|
||||
|
||||
#[instrument()]
|
||||
pub async fn redirect(
|
||||
config: web::Data<crate::ServerConfig>,
|
||||
|
||||
@@ -210,7 +210,14 @@ img.trashicon {
|
||||
width: 0.5cm;
|
||||
}
|
||||
|
||||
qrdownload {
|
||||
.qrdownload {
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.languageselector a {
|
||||
height: 70%;
|
||||
padding: 5px;
|
||||
margin: 3px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
Reference in New Issue
Block a user