feat: identity: update_username service
This commit is contained in:
parent
8085f5e54b
commit
2d1fb4fd1c
4 changed files with 191 additions and 0 deletions
76
src/identity/application/services/update_username/command.rs
Normal file
76
src/identity/application/services/update_username/command.rs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// 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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
17
src/identity/application/services/update_username/events.rs
Normal file
17
src/identity/application/services/update_username/events.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// 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 }
|
||||||
|
}
|
||||||
|
}
|
16
src/identity/application/services/update_username/mod.rs
Normal file
16
src/identity/application/services/update_username/mod.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// 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>;
|
||||||
|
}
|
82
src/identity/application/services/update_username/service.rs
Normal file
82
src/identity/application/services/update_username/service.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// 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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue