Skip to content

Commit

Permalink
Merge pull request #24 from sebadob/admin-ui-users-language-edit
Browse files Browse the repository at this point in the history
make user language editable in the admin ui
  • Loading branch information
sebadob committed Aug 16, 2023
2 parents 7517693 + ef00f1e commit 77886a9
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 12 deletions.
20 changes: 19 additions & 1 deletion frontend/src/components/admin/users/UserInfo.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
import Switch from "$lib/Switch.svelte";
import {globalGroupsNames, globalRolesNames} from "../../../stores/admin.js";
import Button from "$lib/Button.svelte";
import {REGEX_NAME} from "../../../utils/constants.js";
import {LANGUAGES, REGEX_NAME} from "../../../utils/constants.js";
import {putUser} from "../../../utils/dataFetchingAdmin.js";
import {onMount} from "svelte";
import CheckIcon from "$lib/CheckIcon.svelte";
import Input from "$lib/inputs/Input.svelte";
import ItemTiles from "$lib/itemTiles/ItemTiles.svelte";
import OptionSelect from "$lib/OptionSelect.svelte";
export let user = {};
export let onSave;
Expand All @@ -18,6 +19,7 @@
let err = '';
let success = false;
let timer;
let language = user.language.toUpperCase();
let allRoles = [];
globalRolesNames.subscribe(rls => {
Expand Down Expand Up @@ -65,6 +67,7 @@
email: user.email,
given_name: user.given_name,
family_name: user.family_name,
language: language.toLowerCase(),
roles: user.roles,
groups: user.groups,
enabled: user.enabled,
Expand Down Expand Up @@ -160,6 +163,16 @@
FAMILY NAME
</Input>

<!-- Language-->
<div class="unit language">
<div class="label">
LANGUAGE
</div>
<div style="margin-top: .085rem">
<OptionSelect bind:value={language} options={LANGUAGES} />
</div>
</div>

<!-- Roles-->
<div class="unit" style:margin-top="-3px">
<div class="label">
Expand Down Expand Up @@ -268,6 +281,11 @@
font-size: .9rem;
}
.language {
display: flex;
gap: .33rem;
}
.success {
color: var(--col-ok);
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib/LangSelector.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script>
import {onMount} from "svelte";
import OptionSelect from "$lib/OptionSelect.svelte";
import {LANGUAGES} from "../utils/constants.js";
export let absolute = false;
Expand Down Expand Up @@ -33,7 +34,7 @@
<div class:absolute>
<OptionSelect
bind:value={langSelected}
options={['DE', 'EN']}
options={LANGUAGES}
/>
</div>

Expand Down
2 changes: 2 additions & 0 deletions frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export const REGEX_URI = /^[a-zA-Z0-9,.:/_\-&?=~#!$'()*+%]+$/gm;
// https://gist.github.com/olmokramer/82ccce673f86db7cda5e
export const REGEX_CSS_COLOR = /(#(?:[0-9a-f]{2}){2,4}$|(#[0-9a-f]{3}$)|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d\.]+%?\)$|black$|silver$|gray$|whitesmoke$|maroon$|red$|purple$|fuchsia$|green$|lime$|olivedrab$|yellow$|navy$|blue$|teal$|aquamarine$|orange$|aliceblue$|antiquewhite$|aqua$|azure$|beige$|bisque$|blanchedalmond$|blueviolet$|brown$|burlywood$|cadetblue$|chartreuse$|chocolate$|coral$|cornflowerblue$|cornsilk$|crimson$|currentcolor$|darkblue$|darkcyan$|darkgoldenrod$|darkgray$|darkgreen$|darkgrey$|darkkhaki$|darkmagenta$|darkolivegreen$|darkorange$|darkorchid$|darkred$|darksalmon$|darkseagreen$|darkslateblue$|darkslategray$|darkslategrey$|darkturquoise$|darkviolet$|deeppink$|deepskyblue$|dimgray$|dimgrey$|dodgerblue$|firebrick$|floralwhite$|forestgreen$|gainsboro$|ghostwhite$|goldenrod$|gold$|greenyellow$|grey$|honeydew$|hotpink$|indianred$|indigo$|ivory$|khaki$|lavenderblush$|lavender$|lawngreen$|lemonchiffon$|lightblue$|lightcoral$|lightcyan$|lightgoldenrodyellow$|lightgray$|lightgreen$|lightgrey$|lightpink$|lightsalmon$|lightseagreen$|lightskyblue$|lightslategray$|lightslategrey$|lightsteelblue$|lightyellow$|limegreen$|linen$|mediumaquamarine$|mediumblue$|mediumorchid$|mediumpurple$|mediumseagreen$|mediumslateblue$|mediumspringgreen$|mediumturquoise$|mediumvioletred$|midnightblue$|mintcream$|mistyrose$|moccasin$|navajowhite$|oldlace$|olive$|orangered$|orchid$|palegoldenrod$|palegreen$|paleturquoise$|palevioletred$|papayawhip$|peachpuff$|peru$|pink$|plum$|powderblue$|rosybrown$|royalblue$|saddlebrown$|salmon$|sandybrown$|seagreen$|seashell$|sienna$|skyblue$|slateblue$|slategray$|slategrey$|snow$|springgreen$|steelblue$|tan$|thistle$|tomato$|transparent$|turquoise$|violet$|wheat$|white$|yellowgreen$|rebeccapurple$)/i;


export const LANGUAGES = ['DE', 'EN'];
export const TOKEN_ALGS = [
'RS256',
'RS384',
Expand Down
2 changes: 2 additions & 0 deletions rauthy-handlers/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use actix_web::web;
use rauthy_common::constants::{PROXY_MODE, RAUTHY_VERSION};
use rauthy_common::error_response::{ErrorResponse, ErrorResponseType};
use rauthy_models::app_state::{AppState, WellKnown};
use rauthy_models::language;
use rauthy_models::ListenScheme;
use rauthy_models::{entity, request, response};
use rauthy_service::token_set;
Expand Down Expand Up @@ -117,6 +118,7 @@ use utoipa::{openapi, OpenApi};
ErrorResponse,
ErrorResponseType,
language::Language,
request::AuthCodeRequest,
request::AuthRequest,
Expand Down
2 changes: 2 additions & 0 deletions rauthy-main/tests/yyy_handler_password_policy.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::common::{check_status, get_auth_headers, get_backend_url};
use pretty_assertions::assert_eq;
use rauthy_common::error_response::{ErrorResponse, ErrorResponseType};
use rauthy_models::language::Language;
use rauthy_models::request::{NewUserRequest, PasswordPolicyRequest, UpdateUserRequest};
use rauthy_models::response::{PasswordPolicyResponse, UserResponse};
use std::error::Error;
Expand Down Expand Up @@ -101,6 +102,7 @@ async fn test_password_policy() -> Result<(), Box<dyn Error>> {
email: user.email,
given_name: user.given_name,
family_name: user.family_name,
language: Some(Language::De),
password: Some("sosafe".to_string()),
roles: user.roles,
groups: None,
Expand Down
24 changes: 15 additions & 9 deletions rauthy-models/src/entity/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@ pub struct User {
pub mfa_app: Option<String>,
pub sec_key_1: Option<String>,
pub sec_key_2: Option<String>,
pub language: String,
pub language: Language,
}

// CRUD
impl User {
// Inserts a user into the database
pub async fn create(data: &web::Data<AppState>, new_user: User) -> Result<Self, ErrorResponse> {
let lang = new_user.language.as_str();
sqlx::query!(
r#"insert into users
(id, email, given_name, family_name, roles, groups, enabled, email_verified, created_at,
Expand All @@ -66,7 +67,7 @@ impl User {
new_user.enabled,
new_user.email_verified,
new_user.created_at,
new_user.language,
lang,
)
.execute(&data.db)
.await?;
Expand Down Expand Up @@ -288,6 +289,7 @@ impl User {
User::is_email_free(data, self.email.clone()).await?;
}

let lang = self.language.as_str();
let q = sqlx::query(r#"update users set
email = $1, given_name = $2, family_name = $3, password = $4, roles = $5, groups = $6,
enabled = $7, email_verified = $8, password_expires = $9, created_at = $10, last_login = $11,
Expand All @@ -309,7 +311,7 @@ impl User {
.bind(&self.mfa_app)
.bind(&self.sec_key_1)
.bind(&self.sec_key_2)
.bind(&self.language)
.bind(lang)
.bind(&self.id);

if let Some(txn) = txn {
Expand Down Expand Up @@ -388,9 +390,12 @@ impl User {
user.given_name = upd_user.given_name;
user.family_name = upd_user.family_name;

if upd_user.password.is_some() {
let new_pwd = upd_user.password.unwrap();
user.apply_password_rules(data, &new_pwd).await?;
if let Some(lang) = upd_user.language {
user.language = lang;
}

if let Some(password) = upd_user.password {
user.apply_password_rules(data, &password).await?;
}

// sanitize roles
Expand Down Expand Up @@ -440,6 +445,7 @@ impl User {
email: upd_user.email,
given_name: upd_user.given_name,
family_name: upd_user.family_name,
language: upd_user.language,
password,
roles: user.get_roles(),
groups,
Expand Down Expand Up @@ -962,7 +968,7 @@ impl Default for User {
mfa_app: None,
sec_key_1: None,
sec_key_2: None,
language: Language::En.to_string(),
language: Language::En,
}
}
}
Expand Down Expand Up @@ -993,7 +999,7 @@ mod tests {
mfa_app: None,
sec_key_1: None,
sec_key_2: None,
language: Language::En.to_string(),
language: Language::En,
};
let session = Session::new(Some(&user), 1);

Expand Down Expand Up @@ -1049,7 +1055,7 @@ mod tests {
mfa_app: None,
sec_key_1: None,
sec_key_2: None,
language: Language::En.to_string(),
language: Language::En,
};

// enabled
Expand Down
14 changes: 13 additions & 1 deletion rauthy-models/src/language.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ use actix_web::HttpRequest;
use rauthy_common::constants::COOKIE_LOCALE;
use rauthy_common::error_response::{ErrorResponse, ErrorResponseType};
use serde::{Deserialize, Serialize};
use sqlx::Type;
use tracing::debug;
use utoipa::ToSchema;

#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
// Note: Updating this enum will require an update on the LANGUAGES constant for the frontend too
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Type, ToSchema)]
#[sqlx(type_name = "varchar")]
#[sqlx(rename_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum Language {
En,
De,
Expand Down Expand Up @@ -42,6 +48,12 @@ impl From<&HeaderValue> for Language {
}
}

impl From<String> for Language {
fn from(value: String) -> Self {
Self::from(value.as_str())
}
}

impl From<&str> for Language {
fn from(value: &str) -> Self {
match value {
Expand Down
5 changes: 5 additions & 0 deletions rauthy-models/src/request.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::language::Language;
use css_color::Srgb;
use rauthy_common::constants::{
RE_ALG, RE_ALNUM, RE_ALNUM_24, RE_ALNUM_48, RE_ALNUM_64, RE_ALNUM_SPACE, RE_APP_ID, RE_ATTR,
Expand Down Expand Up @@ -473,6 +474,8 @@ pub struct UpdateUserRequest {
/// Validation: `[a-zA-Z0-9À-ÿ-\\s]{2,128}`
#[validate(regex(path = "RE_CLIENT_NAME", code = "[a-zA-Z0-9À-ÿ-\\s]{2,128}"))]
pub family_name: String,
// optional to not break the public API and need a new major release
pub language: Option<Language>,
/// Validation: Applies password policy
pub password: Option<String>,
/// Validation: `Vec<^[a-z0-9-_/]{2,128}$>`
Expand All @@ -496,6 +499,8 @@ pub struct UpdateUserSelfRequest {
/// Validation: `[a-zA-Z0-9À-ÿ-\\s]{2,128}`
#[validate(regex(path = "RE_CLIENT_NAME", code = "[a-zA-Z0-9À-ÿ-\\s]{2,128}"))]
pub family_name: String,
// optional to not break the public API and need a new major release
pub language: Option<Language>,
pub password_current: Option<String>,
/// Validation: Applies password policy
pub password_new: Option<String>,
Expand Down
3 changes: 3 additions & 0 deletions rauthy-models/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::entity::scopes::Scope;
use crate::entity::sessions::SessionState;
use crate::entity::user_attr::{UserAttrConfigEntity, UserAttrValueEntity};
use crate::entity::users::User;
use crate::language::Language;
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use tracing::debug;
Expand Down Expand Up @@ -298,6 +299,7 @@ pub struct UserResponse {
pub email: String,
pub given_name: String,
pub family_name: String,
pub language: Language,
pub roles: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub groups: Option<Vec<String>>,
Expand Down Expand Up @@ -337,6 +339,7 @@ impl From<User> for UserResponse {
email: u.email,
given_name: u.given_name,
family_name: u.family_name,
language: u.language,
roles,
groups,
enabled: u.enabled,
Expand Down

0 comments on commit 77886a9

Please sign in to comment.