fix: update_user: delete module. Difficult to maintain consistency in

denormalized views
This commit is contained in:
Aravinth Manivannan 2024-05-18 00:03:26 +05:30
parent 33022dc4ea
commit b4e56cc9a1
Signed by: realaravinth
GPG key ID: F8F50389936984FF
10 changed files with 72 additions and 199 deletions

View file

@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use cqrs_es::DomainEvent;
use serde::{Deserialize, Serialize};
use super::login::events::*;
use super::register_user::events::*;
use super::set_user_admin::events::*;
use super::update_email::events::*;
use super::update_password::events::*;
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
pub enum UserEvent {
UserRegistered(UserRegisteredEvent),
UserDeleted,
Loggedin(LoginEvent),
PasswordUpdated(PasswordUpdatedEvent),
EmailUpdated(EmailUpdatedEvent),
UserVerified,
UserPromotedToAdmin(UserPromotedToAdminEvent),
}
//TODO: define password type that takes string and converts to hash
impl DomainEvent for UserEvent {
fn event_version(&self) -> String {
"1.0".to_string()
}
fn event_type(&self) -> String {
let e: &str = match self {
UserEvent::UserRegistered { .. } => "UserRegisteredAccount",
UserEvent::UserDeleted => "UserDeletedAccount",
UserEvent::Loggedin { .. } => "UserLoggedIn",
UserEvent::PasswordUpdated { .. } => "UserUpdatedAccountPassword",
UserEvent::EmailUpdated { .. } => "UserUpdatedAccountEmail",
UserEvent::UserVerified => "UserIsVerified",
UserEvent::UserPromotedToAdmin { .. } => "UserPromotedToAdmin",
};
e.to_string()
}
}

View file

@ -2,8 +2,33 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
mod create_user;
use serde::{Deserialize, Serialize};
mod delete_user;
mod login;
mod register_user;
mod update_email;
mod update_password;
mod update_user;
//mod resend_verification_email
pub mod errors;
pub mod events;
mod mark_user_verified;
mod set_user_admin;
use delete_user::command::*;
use login::command::*;
use register_user::command::*;
use set_user_admin::command::*;
use update_email::command::*;
use update_password::command::*;
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
pub enum UserCommand {
RegisterUser(RegisterUserCommand),
DeleteUser(DeleteUserCommand),
Login(LoginCommand),
UpdatePassword(UpdatePasswordCommand),
UpdateEmail(UpdateEmailCommand),
SetVerified,
SetAdmin(SetAdminCommand),
}

View file

@ -1,3 +0,0 @@
mod command;
mod error;
mod service;

View file

@ -1,76 +0,0 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use derive_getters::Getters;
use serde::{Deserialize, Serialize};
use super::*;
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters)]
pub struct UpdateUsernameCommand {
new_username: String,
}
impl UpdateUsernameCommand {
pub fn new(
new_username: String,
supplied_password: String,
actual_password_hash: &str,
config: &argon2_creds::Config,
) -> IdentityCommandResult<Self> {
if !argon2_creds::Config::verify(actual_password_hash, &supplied_password).unwrap() {
return Err(IdentityCommandError::WrongPassword);
}
let new_username = config.username(&new_username)?;
Ok(Self { new_username })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cmd() {
let config = argon2_creds::Config::default();
let password = "adsfasdfasd";
let new_username = "realaravinth";
let hashed_password = config.password(password).unwrap();
assert_eq!(
UpdateUsernameCommand::new(
new_username.into(),
password.into(),
&hashed_password,
&config
)
.unwrap()
.new_username,
new_username
);
// username is not valid
assert!(matches!(
UpdateUsernameCommand::new(
"username".into(),
password.into(),
&hashed_password,
&config,
)
.err(),
Some(IdentityCommandError::BadUsername(_))
));
// wrong password
assert_eq!(
UpdateUsernameCommand::new(
new_username.into(),
new_username.into(),
&hashed_password,
&config,
)
.err(),
Some(IdentityCommandError::WrongPassword)
);
}
}

View file

@ -1,17 +0,0 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use derive_getters::Getters;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, Getters, Eq, PartialEq, Ord, PartialOrd)]
pub struct UsernameUpdatedEvent {
username: String,
}
impl UsernameUpdatedEvent {
pub fn new(username: String) -> Self {
Self { username }
}
}

View file

@ -1,16 +0,0 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
pub mod command;
pub mod events;
pub mod service;
use super::errors::*;
#[async_trait::async_trait]
pub trait UpdateUsernameUseCase {
async fn update_username(
&self,
cmd: command::UpdateUsernameCommand,
) -> IdentityResult<events::UsernameUpdatedEvent>;
}

View file

@ -1,82 +0,0 @@
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use super::*;
use derive_builder::Builder;
use super::*;
use crate::identity::application::port::output::db::username_exists::*;
#[derive(Builder)]
pub struct UpdateUsernameService {
db_username_exists_adapter: UsernameExistsOutDBPortObj,
}
#[async_trait::async_trait]
impl UpdateUsernameUseCase for UpdateUsernameService {
async fn update_username(
&self,
cmd: command::UpdateUsernameCommand,
//) -> errors::ProcessAuthorizationServiceResult<String>;
) -> IdentityResult<events::UsernameUpdatedEvent> {
if self
.db_username_exists_adapter
.username_exists(cmd.new_username())
.await
.unwrap()
{
return Err(IdentityError::UsernameExists);
}
Ok(events::UsernameUpdatedEvent::new(cmd.new_username().into()))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::bdd::*;
#[actix_rt::test]
async fn test_service() {
let new_username = "realaravinth";
let password = "password";
let config = argon2_creds::Config::default();
let hashed_password = config.password(password).unwrap();
let cmd = command::UpdateUsernameCommand::new(
new_username.into(),
password.into(),
&hashed_password,
&config,
)
.unwrap();
{
let s = UpdateUsernameServiceBuilder::default()
.db_username_exists_adapter(mock_username_exists_db_port(
IS_CALLED_ONLY_ONCE,
RETURNS_FALSE,
))
.build()
.unwrap();
let res = s.update_username(cmd.clone()).await.unwrap();
assert_eq!(res.username(), cmd.new_username());
}
{
let s = UpdateUsernameServiceBuilder::default()
.db_username_exists_adapter(mock_username_exists_db_port(
IS_CALLED_ONLY_ONCE,
RETURNS_TRUE,
))
.build()
.unwrap();
assert_eq!(
s.update_username(cmd.clone()).await.err(),
Some(IdentityError::UsernameExists)
);
}
}
}