Changed the struct to make things launch. I've done no testing.

This commit is contained in:
moovlin 2022-12-04 22:23:50 -05:00
parent 665e525f0a
commit cef5252a60
14 changed files with 124 additions and 43 deletions

View File

@ -86,7 +86,7 @@ impl CommonComponent<CreateUserForm> for CreateUserForm {
user: create_user::CreateUserInput {
id: model.username,
email: model.email,
displayName: to_option(model.display_name),
displayName: model.display_name,
firstName: to_option(model.first_name),
lastName: to_option(model.last_name),
avatar: None,

View File

@ -355,7 +355,7 @@ impl UserDetailsForm {
let mut user_input = update_user::UpdateUserInput {
id: self.common.user.id.clone(),
email: None,
displayName: None,
displayName: self.common.user.id.clone(),
firstName: None,
lastName: None,
avatar: None,
@ -367,7 +367,7 @@ impl UserDetailsForm {
user_input.email = Some(email);
}
if base_user.display_name != model.display_name {
user_input.displayName = Some(model.display_name);
user_input.displayName = model.display_name;
}
if base_user.first_name != model.first_name {
user_input.firstName = Some(model.first_name);

View File

@ -57,7 +57,7 @@ type Query {
input CreateUserInput {
id: String!
email: String!
displayName: String
displayName: String!
firstName: String
lastName: String
avatar: String
@ -84,7 +84,7 @@ type Success {
input UpdateUserInput {
id: String!
email: String
displayName: String
displayName: String!
firstName: String
lastName: String
avatar: String

View File

@ -1,7 +1,8 @@
use super::{
error::Result,
types::{
Group, GroupDetails, GroupId, JpegPhoto, User, UserAndGroups, UserColumn, UserId, Uuid,
DisplayName, Group, GroupDetails, GroupId, JpegPhoto, User, UserAndGroups, UserColumn,
UserId, Uuid,
},
};
use async_trait::async_trait;
@ -44,7 +45,7 @@ pub struct CreateUserRequest {
// Same fields as User, but no creation_date, and with password.
pub user_id: UserId,
pub email: String,
pub display_name: Option<String>,
pub display_name: DisplayName,
pub first_name: Option<String>,
pub last_name: Option<String>,
pub avatar: Option<JpegPhoto>,
@ -55,7 +56,7 @@ pub struct UpdateUserRequest {
// Same fields as CreateUserRequest, but no with an extra layer of Option.
pub user_id: UserId,
pub email: Option<String>,
pub display_name: Option<String>,
pub display_name: DisplayName,
pub first_name: Option<String>,
pub last_name: Option<String>,
pub avatar: Option<JpegPhoto>,

View File

@ -48,7 +48,7 @@ fn get_user_attribute(
.into_bytes()
})
.collect(),
"cn" | "displayname" => vec![user.display_name.clone()?.into_bytes()],
"cn" | "displayname" => vec![user.display_name.to_string().into_bytes()],
"createtimestamp" | "modifytimestamp" => vec![user.creation_date.to_rfc3339().into_bytes()],
"1.1" => return None,
// We ignore the operational attribute wildcard.

View File

@ -3,7 +3,7 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
use crate::domain::types::{JpegPhoto, UserId, Uuid};
use crate::domain::types::{DisplayName, JpegPhoto, UserId, Uuid};
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
@ -14,7 +14,7 @@ pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub user_id: UserId,
pub email: String,
pub display_name: Option<String>,
pub display_name: DisplayName,
pub first_name: Option<String>,
pub last_name: Option<String>,
pub avatar: Option<JpegPhoto>,

View File

@ -26,7 +26,7 @@ pub mod tests {
CreateUserRequest, GroupBackendHandler, UserBackendHandler, UserRequestFilter,
},
sql_tables::init_table,
types::{GroupId, UserId},
types::{DisplayName, GroupId, UserId},
},
infra::configuration::ConfigurationBuilder,
};
@ -86,7 +86,7 @@ pub mod tests {
.create_user(CreateUserRequest {
user_id: UserId::new(name),
email: "bob@bob.bob".to_string(),
display_name: Some("display ".to_string() + name),
display_name: DisplayName::new(("display ".to_owned() + name).as_str()),
first_name: Some("first ".to_string() + name),
last_name: Some("last ".to_string() + name),
..Default::default()

View File

@ -163,7 +163,7 @@ impl UserBackendHandler for SqlBackendHandler {
let new_user = model::users::ActiveModel {
user_id: Set(request.user_id),
email: Set(request.email),
display_name: to_value(&request.display_name),
display_name: ActiveValue::Set(request.display_name),
first_name: to_value(&request.first_name),
last_name: to_value(&request.last_name),
avatar: request.avatar.into_active_value(),
@ -181,7 +181,7 @@ impl UserBackendHandler for SqlBackendHandler {
let update_user = model::users::ActiveModel {
user_id: ActiveValue::Set(request.user_id),
email: request.email.map(ActiveValue::Set).unwrap_or_default(),
display_name: to_value(&request.display_name),
display_name: ActiveValue::Set(request.display_name),
first_name: to_value(&request.first_name),
last_name: to_value(&request.last_name),
avatar: request.avatar.into_active_value(),
@ -238,7 +238,7 @@ mod tests {
use super::*;
use crate::domain::{
sql_backend_handler::tests::*,
types::{JpegPhoto, UserColumn},
types::{DisplayName, JpegPhoto, UserColumn},
};
#[tokio::test]
@ -407,11 +407,7 @@ mod tests {
.map(|u| {
(
u.user.user_id.to_string(),
u.user
.display_name
.as_deref()
.unwrap_or("<unknown>")
.to_owned(),
u.user.display_name.to_string(),
u.groups
.unwrap_or_default()
.into_iter()
@ -567,7 +563,7 @@ mod tests {
.update_user(UpdateUserRequest {
user_id: UserId::new("bob"),
email: Some("email".to_string()),
display_name: Some("display_name".to_string()),
display_name: DisplayName::new("display_name"),
first_name: Some("first_name".to_string()),
last_name: Some("last_name".to_string()),
avatar: Some(JpegPhoto::for_tests()),
@ -581,7 +577,7 @@ mod tests {
.await
.unwrap();
assert_eq!(user.email, "email");
assert_eq!(user.display_name.unwrap(), "display_name");
assert_eq!(user.display_name.as_str(), "display_name");
assert_eq!(user.first_name.unwrap(), "first_name");
assert_eq!(user.last_name.unwrap(), "last_name");
assert_eq!(user.avatar, Some(JpegPhoto::for_tests()));
@ -607,7 +603,7 @@ mod tests {
.get_user_details(&UserId::new("bob"))
.await
.unwrap();
assert_eq!(user.display_name.unwrap(), "display bob");
assert_eq!(user.display_name.as_str(), "display bob");
assert_eq!(user.first_name.unwrap(), "first_name");
assert_eq!(user.last_name, None);
assert_eq!(user.avatar, None);

View File

@ -167,6 +167,82 @@ impl ValueType for UserId {
}
}
#[derive(PartialEq, Eq, Clone, Debug, Default, Serialize, Deserialize)]
#[serde(from = "String")]
pub struct DisplayName(String);
impl DisplayName {
pub fn new(display_name: &str) -> Self {
Self(display_name.to_string())
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
pub fn into_string(self) -> String {
self.0
}
}
impl std::fmt::Display for DisplayName {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<String> for DisplayName {
fn from(s: String) -> Self {
Self::new(&s)
}
}
impl From<DisplayName> for Value {
fn from(display_name: DisplayName) -> Self {
display_name.into_string().into()
}
}
impl From<&DisplayName> for Value {
fn from(display_name: &DisplayName) -> Self {
display_name.as_str().into()
}
}
impl TryGetable for DisplayName {
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> {
Ok(DisplayName::new(&String::try_get(res, pre, col)?))
}
}
impl TryFromU64 for DisplayName {
fn try_from_u64(_n: u64) -> Result<Self, DbErr> {
Err(DbErr::ConvertFromU64(
"DisplayName cannot be constructed from u64",
))
}
}
impl ValueType for DisplayName {
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
Ok(DisplayName::new(
<String as ValueType>::try_from(v)?.as_str(),
))
}
fn type_name() -> String {
"DisplayName".to_owned()
}
fn array_type() -> ArrayType {
ArrayType::String
}
fn column_type() -> ColumnType {
ColumnType::String(Some(255))
}
}
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
pub struct JpegPhoto(#[serde(with = "serde_bytes")] Vec<u8>);
@ -304,7 +380,7 @@ impl IntoActiveValue<JpegPhoto> for JpegPhoto {
pub struct User {
pub user_id: UserId,
pub email: String,
pub display_name: Option<String>,
pub display_name: DisplayName,
pub first_name: Option<String>,
pub last_name: Option<String>,
pub avatar: Option<JpegPhoto>,
@ -320,7 +396,7 @@ impl Default for User {
User {
user_id: UserId::default(),
email: String::new(),
display_name: None,
display_name: DisplayName::default(),
first_name: None,
last_name: None,
avatar: None,

View File

@ -171,9 +171,7 @@ where
Some(token) => token,
};
if let Err(e) = super::mail::send_password_reset_email(
user.display_name
.as_deref()
.unwrap_or_else(|| user.user_id.as_str()),
user.display_name.as_str(),
&user.email,
&token,
&data.server_url,

View File

@ -1,6 +1,6 @@
use crate::domain::{
handler::{BackendHandler, CreateUserRequest, UpdateGroupRequest, UpdateUserRequest},
types::{GroupId, JpegPhoto, UserId},
types::{DisplayName, GroupId, JpegPhoto, UserId},
};
use anyhow::Context as AnyhowContext;
use juniper::{graphql_object, FieldResult, GraphQLInputObject, GraphQLObject};
@ -27,7 +27,7 @@ impl<Handler: BackendHandler> Mutation<Handler> {
pub struct CreateUserInput {
id: String,
email: String,
display_name: Option<String>,
display_name: String,
first_name: Option<String>,
last_name: Option<String>,
// Base64 encoded JpegPhoto.
@ -39,7 +39,7 @@ pub struct CreateUserInput {
pub struct UpdateUserInput {
id: String,
email: Option<String>,
display_name: Option<String>,
display_name: String,
first_name: Option<String>,
last_name: Option<String>,
// Base64 encoded JpegPhoto.
@ -79,6 +79,7 @@ impl<Handler: BackendHandler + Sync> Mutation<Handler> {
return Err("Unauthorized user creation".into());
}
let user_id = UserId::new(&user.id);
let display_name = DisplayName::new(&user.display_name);
let avatar = user
.avatar
.map(base64::decode)
@ -92,7 +93,7 @@ impl<Handler: BackendHandler + Sync> Mutation<Handler> {
.create_user(CreateUserRequest {
user_id: user_id.clone(),
email: user.email,
display_name: user.display_name,
display_name: display_name.clone(),
first_name: user.first_name,
last_name: user.last_name,
avatar,
@ -137,6 +138,7 @@ impl<Handler: BackendHandler + Sync> Mutation<Handler> {
debug!(?user.id);
});
let user_id = UserId::new(&user.id);
let display_name = DisplayName::new(&user.display_name);
if !context.validation_result.can_write(&user_id) {
span.in_scope(|| debug!("Unauthorized"));
return Err("Unauthorized user update".into());
@ -154,7 +156,7 @@ impl<Handler: BackendHandler + Sync> Mutation<Handler> {
.update_user(UpdateUserRequest {
user_id,
email: user.email,
display_name: user.display_name,
display_name: display_name.clone(),
first_name: user.first_name,
last_name: user.last_name,
avatar,

View File

@ -214,7 +214,7 @@ impl<Handler: BackendHandler + Sync> User<Handler> {
}
fn display_name(&self) -> &str {
self.user.display_name.as_deref().unwrap_or("")
self.user.display_name.as_str()
}
fn first_name(&self) -> &str {

View File

@ -10,7 +10,7 @@ use crate::{
},
},
opaque_handler::OpaqueHandler,
types::{JpegPhoto, UserId},
types::{DisplayName, JpegPhoto, UserId},
},
infra::auth_service::{Permission, ValidationResults},
};
@ -460,6 +460,8 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
&self.ldap_info.base_dn,
&self.ldap_info.base_dn_str,
)?;
//
fn parse_attribute(mut attr: LdapPartialAttribute) -> LdapResult<(String, Vec<u8>)> {
if attr.vals.len() > 1 {
Err(LdapError {
@ -506,7 +508,12 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
.or_else(|| get_attribute("email"))
.transpose()?
.unwrap_or_default(),
display_name: get_attribute("cn").transpose()?,
display_name: DisplayName::new(
get_attribute("cn")
.transpose()?
.unwrap_or_default()
.as_str(),
),
first_name: get_attribute("givenname").transpose()?,
last_name: get_attribute("sn").transpose()?,
avatar: attributes
@ -989,7 +996,7 @@ mod tests {
user: User {
user_id: UserId::new("bob_1"),
email: "bob@bobmail.bob".to_string(),
display_name: Some("Bôb Böbberson".to_string()),
display_name: DisplayName::new("Bôb Böbberson"),
first_name: Some("Bôb".to_string()),
last_name: Some("Böbberson".to_string()),
uuid: uuid!("698e1d5f-7a40-3151-8745-b9b8a37839da"),
@ -1001,7 +1008,7 @@ mod tests {
user: User {
user_id: UserId::new("jim"),
email: "jim@cricket.jim".to_string(),
display_name: Some("Jimminy Cricket".to_string()),
display_name: DisplayName::new("Jimminy Cricket"),
first_name: Some("Jim".to_string()),
last_name: Some("Cricket".to_string()),
avatar: Some(JpegPhoto::for_tests()),
@ -1540,7 +1547,7 @@ mod tests {
user: User {
user_id: UserId::new("bob_1"),
email: "bob@bobmail.bob".to_string(),
display_name: Some("Bôb Böbberson".to_string()),
display_name: DisplayName::new("Bôb Böbberson"),
first_name: Some("Bôb".to_string()),
last_name: Some("Böbberson".to_string()),
..Default::default()
@ -1614,7 +1621,7 @@ mod tests {
user: User {
user_id: UserId::new("bob_1"),
email: "bob@bobmail.bob".to_string(),
display_name: Some("Bôb Böbberson".to_string()),
display_name: DisplayName::new("Bôb Böbberson"),
last_name: Some("Böbberson".to_string()),
avatar: Some(JpegPhoto::for_tests()),
uuid: uuid!("b4ac75e0-2900-3e21-926c-2f732c26b3fc"),
@ -2041,7 +2048,7 @@ mod tests {
.with(eq(CreateUserRequest {
user_id: UserId::new("bob"),
email: "".to_owned(),
display_name: Some("Bob".to_string()),
display_name: DisplayName::new("Bob"),
..Default::default()
}))
.times(1)

View File

@ -9,6 +9,7 @@ use crate::{
handler::{CreateUserRequest, GroupBackendHandler, GroupRequestFilter, UserBackendHandler},
sql_backend_handler::SqlBackendHandler,
sql_opaque_handler::register_password,
types::DisplayName,
},
infra::{cli::*, configuration::Configuration, db_cleaner::Scheduler, healthcheck, mail},
};
@ -33,7 +34,7 @@ async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration)
.create_user(CreateUserRequest {
user_id: config.ldap_user_dn.clone(),
email: config.ldap_user_email.clone(),
display_name: Some("Administrator".to_string()),
display_name: DisplayName::new("Administrator"),
..Default::default()
})
.and_then(|_| register_password(handler, &config.ldap_user_dn, &config.ldap_user_pass))