mirror of
https://github.com/lldap/lldap.git
synced 2026-04-05 14:48:10 +00:00
Implement core modifyTimestamp functionality with database migration and backend support
Co-authored-by: nitnelave <796633+nitnelave@users.noreply.github.com>
This commit is contained in:
@@ -13,7 +13,12 @@ pub mod group {
|
||||
"creation_date" => Some(AttributeDescription {
|
||||
attribute_identifier: name,
|
||||
attribute_name: "creationdate",
|
||||
aliases: vec![name, "createtimestamp", "modifytimestamp"],
|
||||
aliases: vec![name, "createtimestamp"],
|
||||
}),
|
||||
"modified_date" => Some(AttributeDescription {
|
||||
attribute_identifier: name,
|
||||
attribute_name: "modifydate",
|
||||
aliases: vec![name, "modifytimestamp"],
|
||||
}),
|
||||
"display_name" => Some(AttributeDescription {
|
||||
attribute_identifier: name,
|
||||
@@ -60,7 +65,17 @@ pub mod user {
|
||||
"creation_date" => Some(AttributeDescription {
|
||||
attribute_identifier: name,
|
||||
attribute_name: "creationdate",
|
||||
aliases: vec![name, "createtimestamp", "modifytimestamp"],
|
||||
aliases: vec![name, "createtimestamp"],
|
||||
}),
|
||||
"modified_date" => Some(AttributeDescription {
|
||||
attribute_identifier: name,
|
||||
attribute_name: "modifydate",
|
||||
aliases: vec![name, "modifytimestamp"],
|
||||
}),
|
||||
"password_modified_date" => Some(AttributeDescription {
|
||||
attribute_identifier: name,
|
||||
attribute_name: "passwordmodifydate",
|
||||
aliases: vec![name, "pwdchangedtime"],
|
||||
}),
|
||||
"display_name" => Some(AttributeDescription {
|
||||
attribute_identifier: name,
|
||||
|
||||
@@ -14,6 +14,7 @@ pub struct Model {
|
||||
pub lowercase_display_name: String,
|
||||
pub creation_date: chrono::NaiveDateTime,
|
||||
pub uuid: Uuid,
|
||||
pub modified_date: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
@@ -39,6 +40,7 @@ impl From<Model> for lldap_domain::types::Group {
|
||||
uuid: group.uuid,
|
||||
users: vec![],
|
||||
attributes: Vec::new(),
|
||||
modified_date: group.modified_date,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +53,7 @@ impl From<Model> for lldap_domain::types::GroupDetails {
|
||||
creation_date: group.creation_date,
|
||||
uuid: group.uuid,
|
||||
attributes: Vec::new(),
|
||||
modified_date: group.modified_date,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ pub struct Model {
|
||||
pub totp_secret: Option<String>,
|
||||
pub mfa_type: Option<String>,
|
||||
pub uuid: Uuid,
|
||||
pub modified_date: chrono::NaiveDateTime,
|
||||
pub password_modified_date: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
impl EntityName for Entity {
|
||||
@@ -40,6 +42,8 @@ pub enum Column {
|
||||
TotpSecret,
|
||||
MfaType,
|
||||
Uuid,
|
||||
ModifiedDate,
|
||||
PasswordModifiedDate,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
@@ -56,6 +60,8 @@ impl ColumnTrait for Column {
|
||||
Column::TotpSecret => ColumnType::String(StringLen::N(64)),
|
||||
Column::MfaType => ColumnType::String(StringLen::N(64)),
|
||||
Column::Uuid => ColumnType::String(StringLen::N(36)),
|
||||
Column::ModifiedDate => ColumnType::DateTime,
|
||||
Column::PasswordModifiedDate => ColumnType::DateTime,
|
||||
}
|
||||
.def()
|
||||
}
|
||||
@@ -121,6 +127,8 @@ impl From<Model> for lldap_domain::types::User {
|
||||
creation_date: user.creation_date,
|
||||
uuid: user.uuid,
|
||||
attributes: Vec::new(),
|
||||
modified_date: user.modified_date,
|
||||
password_modified_date: user.password_modified_date,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,6 +546,8 @@ pub struct User {
|
||||
pub creation_date: NaiveDateTime,
|
||||
pub uuid: Uuid,
|
||||
pub attributes: Vec<Attribute>,
|
||||
pub modified_date: NaiveDateTime,
|
||||
pub password_modified_date: NaiveDateTime,
|
||||
}
|
||||
|
||||
#[cfg(feature = "test")]
|
||||
@@ -559,6 +561,8 @@ impl Default for User {
|
||||
creation_date: epoch,
|
||||
uuid: Uuid::from_name_and_date("", &epoch),
|
||||
attributes: Vec::new(),
|
||||
modified_date: epoch,
|
||||
password_modified_date: epoch,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -654,6 +658,7 @@ pub struct Group {
|
||||
pub uuid: Uuid,
|
||||
pub users: Vec<UserId>,
|
||||
pub attributes: Vec<Attribute>,
|
||||
pub modified_date: NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
@@ -663,6 +668,7 @@ pub struct GroupDetails {
|
||||
pub creation_date: NaiveDateTime,
|
||||
pub uuid: Uuid,
|
||||
pub attributes: Vec<Attribute>,
|
||||
pub modified_date: NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
||||
@@ -958,6 +958,7 @@ mod tests {
|
||||
name: "club_name".into(),
|
||||
value: "Gang of Four".to_string().into(),
|
||||
}],
|
||||
modified_date: chrono::Utc.timestamp_nanos(42).naive_utc(),
|
||||
});
|
||||
groups.insert(GroupDetails {
|
||||
group_id: GroupId(7),
|
||||
@@ -965,6 +966,7 @@ mod tests {
|
||||
creation_date: chrono::Utc.timestamp_nanos(12).naive_utc(),
|
||||
uuid: lldap_domain::uuid!("b1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_nanos(12).naive_utc(),
|
||||
});
|
||||
mock.expect_get_user_groups()
|
||||
.with(eq(UserId::new("bob")))
|
||||
|
||||
@@ -124,6 +124,7 @@ mod tests {
|
||||
users: vec![UserId::new("bob")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
}])
|
||||
});
|
||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||
@@ -218,6 +219,7 @@ mod tests {
|
||||
users: vec![UserId::new("bob")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
}])
|
||||
});
|
||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||
|
||||
@@ -72,6 +72,12 @@ pub fn get_group_attribute(
|
||||
.to_rfc3339()
|
||||
.into_bytes(),
|
||||
],
|
||||
GroupFieldType::ModifiedDate => vec![
|
||||
chrono::Utc
|
||||
.from_utc_datetime(&group.modified_date)
|
||||
.to_rfc3339()
|
||||
.into_bytes(),
|
||||
],
|
||||
GroupFieldType::Member => group
|
||||
.users
|
||||
.iter()
|
||||
@@ -260,6 +266,10 @@ fn convert_group_filter(
|
||||
code: LdapResultCode::UnwillingToPerform,
|
||||
message: "Creation date filter for groups not supported".to_owned(),
|
||||
}),
|
||||
GroupFieldType::ModifiedDate => Err(LdapError {
|
||||
code: LdapResultCode::UnwillingToPerform,
|
||||
message: "Modified date filter for groups not supported".to_owned(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
LdapFilter::And(filters) => Ok(GroupRequestFilter::And(
|
||||
|
||||
@@ -93,6 +93,18 @@ pub fn get_user_attribute(
|
||||
.to_rfc3339()
|
||||
.into_bytes(),
|
||||
],
|
||||
UserFieldType::PrimaryField(UserColumn::ModifiedDate) => vec![
|
||||
chrono::Utc
|
||||
.from_utc_datetime(&user.modified_date)
|
||||
.to_rfc3339()
|
||||
.into_bytes(),
|
||||
],
|
||||
UserFieldType::PrimaryField(UserColumn::PasswordModifiedDate) => vec![
|
||||
chrono::Utc
|
||||
.from_utc_datetime(&user.password_modified_date)
|
||||
.to_rfc3339()
|
||||
.into_bytes(),
|
||||
],
|
||||
UserFieldType::Attribute(attr, _, _) => get_custom_attribute(&user.attributes, &attr)?,
|
||||
UserFieldType::NoMatch => match attribute.as_str() {
|
||||
"1.1" => return None,
|
||||
|
||||
@@ -239,9 +239,15 @@ pub fn map_user_field(field: &AttributeName, schema: &PublicSchema) -> UserField
|
||||
AttributeType::JpegPhoto,
|
||||
false,
|
||||
),
|
||||
"creationdate" | "createtimestamp" | "modifytimestamp" | "creation_date" => {
|
||||
"creationdate" | "createtimestamp" | "creation_date" => {
|
||||
UserFieldType::PrimaryField(UserColumn::CreationDate)
|
||||
}
|
||||
"modifytimestamp" | "modifydate" | "modified_date" => {
|
||||
UserFieldType::PrimaryField(UserColumn::ModifiedDate)
|
||||
}
|
||||
"pwdchangedtime" | "passwordmodifydate" | "password_modified_date" => {
|
||||
UserFieldType::PrimaryField(UserColumn::PasswordModifiedDate)
|
||||
}
|
||||
"entryuuid" | "uuid" => UserFieldType::PrimaryField(UserColumn::Uuid),
|
||||
_ => schema
|
||||
.get_schema()
|
||||
@@ -257,6 +263,7 @@ pub enum GroupFieldType {
|
||||
GroupId,
|
||||
DisplayName,
|
||||
CreationDate,
|
||||
ModifiedDate,
|
||||
ObjectClass,
|
||||
Dn,
|
||||
// Like Dn, but returned as part of the attributes.
|
||||
@@ -272,9 +279,12 @@ pub fn map_group_field(field: &AttributeName, schema: &PublicSchema) -> GroupFie
|
||||
"entrydn" => GroupFieldType::EntryDn,
|
||||
"objectclass" => GroupFieldType::ObjectClass,
|
||||
"cn" | "displayname" | "uid" | "display_name" | "id" => GroupFieldType::DisplayName,
|
||||
"creationdate" | "createtimestamp" | "modifytimestamp" | "creation_date" => {
|
||||
"creationdate" | "createtimestamp" | "creation_date" => {
|
||||
GroupFieldType::CreationDate
|
||||
}
|
||||
"modifytimestamp" | "modifydate" | "modified_date" => {
|
||||
GroupFieldType::ModifiedDate
|
||||
}
|
||||
"member" | "uniquemember" => GroupFieldType::Member,
|
||||
"entryuuid" | "uuid" => GroupFieldType::Uuid,
|
||||
"group_id" | "groupid" => GroupFieldType::GroupId,
|
||||
|
||||
@@ -154,6 +154,7 @@ mod tests {
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
users: Vec::new(),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
}])
|
||||
});
|
||||
mock.expect_delete_group()
|
||||
@@ -284,6 +285,7 @@ mod tests {
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
users: Vec::new(),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
}])
|
||||
});
|
||||
mock.expect_delete_group()
|
||||
|
||||
@@ -398,6 +398,7 @@ pub mod tests {
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
});
|
||||
Ok(set)
|
||||
});
|
||||
|
||||
@@ -158,6 +158,7 @@ mod tests {
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
});
|
||||
}
|
||||
Ok(g)
|
||||
|
||||
@@ -263,6 +263,7 @@ pub mod tests {
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
});
|
||||
Ok(set)
|
||||
});
|
||||
@@ -520,6 +521,7 @@ pub mod tests {
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
});
|
||||
mock.expect_get_user_groups()
|
||||
.with(eq(UserId::new("bob")))
|
||||
|
||||
@@ -840,6 +840,14 @@ mod tests {
|
||||
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
||||
.unwrap()
|
||||
.naive_utc(),
|
||||
modified_date: Utc
|
||||
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
||||
.unwrap()
|
||||
.naive_utc(),
|
||||
password_modified_date: Utc
|
||||
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
||||
.unwrap()
|
||||
.naive_utc(),
|
||||
},
|
||||
groups: None,
|
||||
},
|
||||
|
||||
2132
crates/ldap/src/search.rs.bak
Normal file
2132
crates/ldap/src/search.rs.bak
Normal file
File diff suppressed because it is too large
Load Diff
@@ -268,10 +268,12 @@ impl SqlBackendHandler {
|
||||
.display_name
|
||||
.as_ref()
|
||||
.map(|s| s.as_str().to_lowercase());
|
||||
let now = chrono::Utc::now().naive_utc();
|
||||
let update_group = model::groups::ActiveModel {
|
||||
group_id: Set(request.group_id),
|
||||
display_name: request.display_name.map(Set).unwrap_or_default(),
|
||||
lowercase_display_name: lower_display_name.map(Set).unwrap_or_default(),
|
||||
modified_date: Set(now),
|
||||
..Default::default()
|
||||
};
|
||||
update_group.update(transaction).await?;
|
||||
|
||||
@@ -27,6 +27,8 @@ pub enum Users {
|
||||
TotpSecret,
|
||||
MfaType,
|
||||
Uuid,
|
||||
ModifiedDate,
|
||||
PasswordModifiedDate,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden, PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Copy)]
|
||||
@@ -37,6 +39,7 @@ pub(crate) enum Groups {
|
||||
LowercaseDisplayName,
|
||||
CreationDate,
|
||||
Uuid,
|
||||
ModifiedDate,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden, Clone, Copy)]
|
||||
@@ -1112,6 +1115,142 @@ async fn migrate_to_v10(transaction: DatabaseTransaction) -> Result<DatabaseTran
|
||||
Ok(transaction)
|
||||
}
|
||||
|
||||
async fn migrate_to_v11(transaction: DatabaseTransaction) -> Result<DatabaseTransaction, DbErr> {
|
||||
let builder = transaction.get_database_backend();
|
||||
// Add modified_date to users table
|
||||
transaction
|
||||
.execute(
|
||||
builder.build(
|
||||
Table::alter()
|
||||
.table(Users::Table)
|
||||
.add_column(
|
||||
ColumnDef::new(Users::ModifiedDate)
|
||||
.date_time()
|
||||
.not_null()
|
||||
.default("CURRENT_TIMESTAMP"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Add password_modified_date to users table
|
||||
transaction
|
||||
.execute(
|
||||
builder.build(
|
||||
Table::alter()
|
||||
.table(Users::Table)
|
||||
.add_column(
|
||||
ColumnDef::new(Users::PasswordModifiedDate)
|
||||
.date_time()
|
||||
.not_null()
|
||||
.default("CURRENT_TIMESTAMP"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Add modified_date to groups table
|
||||
transaction
|
||||
.execute(
|
||||
builder.build(
|
||||
Table::alter()
|
||||
.table(Groups::Table)
|
||||
.add_column(
|
||||
ColumnDef::new(Groups::ModifiedDate)
|
||||
.date_time()
|
||||
.not_null()
|
||||
.default("CURRENT_TIMESTAMP"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Initialize existing users with modified_date = creation_date
|
||||
transaction
|
||||
.execute(
|
||||
builder.build(
|
||||
Query::update()
|
||||
.table(Users::Table)
|
||||
.value(Users::ModifiedDate, Expr::col(Users::CreationDate))
|
||||
.value(Users::PasswordModifiedDate, Expr::col(Users::CreationDate)),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Initialize existing groups with modified_date = creation_date
|
||||
transaction
|
||||
.execute(
|
||||
builder.build(
|
||||
Query::update()
|
||||
.table(Groups::Table)
|
||||
.value(Groups::ModifiedDate, Expr::col(Groups::CreationDate)),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Add the new timestamp attributes to the user attribute schema as hardcoded read-only attributes
|
||||
transaction
|
||||
.execute(
|
||||
builder.build(
|
||||
Query::insert()
|
||||
.into_table(UserAttributeSchema::Table)
|
||||
.columns([
|
||||
UserAttributeSchema::UserAttributeSchemaName,
|
||||
UserAttributeSchema::UserAttributeSchemaType,
|
||||
UserAttributeSchema::UserAttributeSchemaIsList,
|
||||
UserAttributeSchema::UserAttributeSchemaIsUserVisible,
|
||||
UserAttributeSchema::UserAttributeSchemaIsUserEditable,
|
||||
UserAttributeSchema::UserAttributeSchemaIsHardcoded,
|
||||
])
|
||||
.values_panic([
|
||||
"modified_date".into(),
|
||||
AttributeType::DateTime.into(),
|
||||
false.into(),
|
||||
true.into(),
|
||||
false.into(),
|
||||
true.into(),
|
||||
])
|
||||
.values_panic([
|
||||
"password_modified_date".into(),
|
||||
AttributeType::DateTime.into(),
|
||||
false.into(),
|
||||
true.into(),
|
||||
false.into(),
|
||||
true.into(),
|
||||
]),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Add the new timestamp attribute to the group attribute schema as hardcoded read-only attribute
|
||||
transaction
|
||||
.execute(
|
||||
builder.build(
|
||||
Query::insert()
|
||||
.into_table(GroupAttributeSchema::Table)
|
||||
.columns([
|
||||
GroupAttributeSchema::GroupAttributeSchemaName,
|
||||
GroupAttributeSchema::GroupAttributeSchemaType,
|
||||
GroupAttributeSchema::GroupAttributeSchemaIsList,
|
||||
GroupAttributeSchema::GroupAttributeSchemaIsGroupVisible,
|
||||
GroupAttributeSchema::GroupAttributeSchemaIsGroupEditable,
|
||||
GroupAttributeSchema::GroupAttributeSchemaIsHardcoded,
|
||||
])
|
||||
.values_panic([
|
||||
"modified_date".into(),
|
||||
AttributeType::DateTime.into(),
|
||||
false.into(),
|
||||
true.into(),
|
||||
false.into(),
|
||||
true.into(),
|
||||
]),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(transaction)
|
||||
}
|
||||
|
||||
// This is needed to make an array of async functions.
|
||||
macro_rules! to_sync {
|
||||
($l:ident) => {
|
||||
@@ -1142,6 +1281,7 @@ pub(crate) async fn migrate_from_version(
|
||||
to_sync!(migrate_to_v8),
|
||||
to_sync!(migrate_to_v9),
|
||||
to_sync!(migrate_to_v10),
|
||||
to_sync!(migrate_to_v11),
|
||||
];
|
||||
assert_eq!(migrations.len(), (LAST_SCHEMA_VERSION.0 - 1) as usize);
|
||||
for migration in 2..=last_version.0 {
|
||||
|
||||
@@ -197,9 +197,11 @@ impl OpaqueHandler for SqlOpaqueHandler {
|
||||
let password_file =
|
||||
opaque::server::registration::get_password_file(request.registration_upload);
|
||||
// Set the user password to the new password.
|
||||
let now = chrono::Utc::now().naive_utc();
|
||||
let user_update = model::users::ActiveModel {
|
||||
user_id: ActiveValue::Set(username.clone()),
|
||||
password_hash: ActiveValue::Set(Some(password_file.serialize())),
|
||||
password_modified_date: ActiveValue::Set(now),
|
||||
..Default::default()
|
||||
};
|
||||
user_update.update(&self.sql_pool).await?;
|
||||
|
||||
@@ -9,7 +9,7 @@ pub type DbConnection = sea_orm::DatabaseConnection;
|
||||
#[derive(Copy, PartialEq, Eq, Debug, Clone, PartialOrd, Ord, DeriveValueType)]
|
||||
pub struct SchemaVersion(pub i16);
|
||||
|
||||
pub const LAST_SCHEMA_VERSION: SchemaVersion = SchemaVersion(10);
|
||||
pub const LAST_SCHEMA_VERSION: SchemaVersion = SchemaVersion(11);
|
||||
|
||||
#[derive(Copy, PartialEq, Eq, Debug, Clone, PartialOrd, Ord)]
|
||||
pub struct PrivateKeyHash(pub [u8; 32]);
|
||||
|
||||
@@ -190,11 +190,13 @@ impl SqlBackendHandler {
|
||||
request: UpdateUserRequest,
|
||||
) -> Result<()> {
|
||||
let lower_email = request.email.as_ref().map(|s| s.as_str().to_lowercase());
|
||||
let now = chrono::Utc::now().naive_utc();
|
||||
let update_user = model::users::ActiveModel {
|
||||
user_id: ActiveValue::Set(request.user_id.clone()),
|
||||
email: request.email.map(ActiveValue::Set).unwrap_or_default(),
|
||||
lowercase_email: lower_email.map(ActiveValue::Set).unwrap_or_default(),
|
||||
display_name: to_value(&request.display_name),
|
||||
modified_date: ActiveValue::Set(now),
|
||||
..Default::default()
|
||||
};
|
||||
let mut update_user_attributes = Vec::new();
|
||||
|
||||
Reference in New Issue
Block a user