Add set-role command

This commit is contained in:
silverpill 2023-01-25 05:52:58 +00:00
parent 01f956b6ce
commit 1f9669ad7c
6 changed files with 71 additions and 1 deletions

View file

@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Implemented roles & permissions. - Implemented roles & permissions.
- Added "read-only user" role. - Added "read-only user" role.
- Added configuration option for automatic assigning of "read-only user" role after registration. - Added configuration option for automatic assigning of "read-only user" role after registration.
- Added `set-role` command.
### Deprecated ### Deprecated

View file

@ -38,6 +38,12 @@ Set or change password:
mitractl set-password <user-id> <password> mitractl set-password <user-id> <password>
``` ```
Change user's role:
```shell
mitractl set-role <user-id> <role-name>
```
Delete profile: Delete profile:
```shell ```shell

View file

@ -39,7 +39,9 @@ use mitra::models::{
get_invite_codes, get_invite_codes,
get_user_by_id, get_user_by_id,
set_user_password, set_user_password,
set_user_role,
}, },
users::types::Role,
}; };
use mitra::monero::{ use mitra::monero::{
helpers::check_expired_invoice, helpers::check_expired_invoice,
@ -70,6 +72,7 @@ pub enum SubCommand {
GenerateInviteCode(GenerateInviteCode), GenerateInviteCode(GenerateInviteCode),
ListInviteCodes(ListInviteCodes), ListInviteCodes(ListInviteCodes),
SetPassword(SetPassword), SetPassword(SetPassword),
SetRole(SetRole),
RefetchActor(RefetchActor), RefetchActor(RefetchActor),
DeleteProfile(DeleteProfile), DeleteProfile(DeleteProfile),
DeletePost(DeletePost), DeletePost(DeletePost),
@ -169,6 +172,25 @@ impl SetPassword {
} }
} }
/// Change user's role
#[derive(Parser)]
pub struct SetRole {
id: Uuid,
role: String,
}
impl SetRole {
pub async fn execute(
&self,
db_client: &impl DatabaseClient,
) -> Result<(), Error> {
let role = Role::from_name(&self.role)?;
set_user_role(db_client, &self.id, role).await?;
println!("role changed");
Ok(())
}
}
/// Re-fetch actor profile by actor ID /// Re-fetch actor profile by actor ID
#[derive(Parser)] #[derive(Parser)]
pub struct RefetchActor { pub struct RefetchActor {

View file

@ -32,6 +32,7 @@ async fn main() {
SubCommand::GenerateInviteCode(cmd) => cmd.execute(db_client).await.unwrap(), SubCommand::GenerateInviteCode(cmd) => cmd.execute(db_client).await.unwrap(),
SubCommand::ListInviteCodes(cmd) => cmd.execute(db_client).await.unwrap(), SubCommand::ListInviteCodes(cmd) => cmd.execute(db_client).await.unwrap(),
SubCommand::SetPassword(cmd) => cmd.execute(db_client).await.unwrap(), SubCommand::SetPassword(cmd) => cmd.execute(db_client).await.unwrap(),
SubCommand::SetRole(cmd) => cmd.execute(db_client).await.unwrap(),
SubCommand::RefetchActor(cmd) => cmd.execute(&config, db_client).await.unwrap(), SubCommand::RefetchActor(cmd) => cmd.execute(&config, db_client).await.unwrap(),
SubCommand::DeleteProfile(cmd) => cmd.execute(&config, db_client).await.unwrap(), SubCommand::DeleteProfile(cmd) => cmd.execute(&config, db_client).await.unwrap(),
SubCommand::DeletePost(cmd) => cmd.execute(&config, db_client).await.unwrap(), SubCommand::DeletePost(cmd) => cmd.execute(&config, db_client).await.unwrap(),

View file

@ -9,7 +9,7 @@ use crate::identity::{did::Did, did_pkh::DidPkh};
use crate::models::profiles::queries::create_profile; use crate::models::profiles::queries::create_profile;
use crate::models::profiles::types::{DbActorProfile, ProfileCreateData}; use crate::models::profiles::types::{DbActorProfile, ProfileCreateData};
use crate::utils::currencies::Currency; use crate::utils::currencies::Currency;
use super::types::{DbUser, User, UserCreateData}; use super::types::{DbUser, Role, User, UserCreateData};
use super::utils::generate_invite_code; use super::utils::generate_invite_code;
pub async fn create_invite_code( pub async fn create_invite_code(
@ -154,6 +154,24 @@ pub async fn set_user_password(
Ok(()) Ok(())
} }
pub async fn set_user_role(
db_client: &impl DatabaseClient,
user_id: &Uuid,
role: Role,
) -> Result<(), DatabaseError> {
let updated_count = db_client.execute(
"
UPDATE user_account SET user_role = $1
WHERE id = $2
",
&[&role, &user_id],
).await?;
if updated_count == 0 {
return Err(DatabaseError::NotFound("user"));
};
Ok(())
}
pub async fn get_user_by_id( pub async fn get_user_by_id(
db_client: &impl DatabaseClient, db_client: &impl DatabaseClient,
user_id: &Uuid, user_id: &Uuid,
@ -307,4 +325,16 @@ mod tests {
let result = create_user(db_client, another_user_data).await; let result = create_user(db_client, another_user_data).await;
assert!(matches!(result, Err(DatabaseError::AlreadyExists("user")))); assert!(matches!(result, Err(DatabaseError::AlreadyExists("user"))));
} }
#[tokio::test]
#[serial]
async fn test_set_user_role() {
let db_client = &mut create_test_database().await;
let user_data = UserCreateData::default();
let user = create_user(db_client, user_data).await.unwrap();
assert_eq!(user.role, Role::NormalUser);
set_user_role(db_client, &user.id, Role::ReadOnlyUser).await.unwrap();
let user = get_user_by_id(db_client, &user.id).await.unwrap();
assert_eq!(user.role, Role::ReadOnlyUser);
}
} }

View file

@ -31,6 +31,16 @@ impl Default for Role {
} }
impl Role { impl Role {
pub fn from_name(name: &str) -> Result<Self, ValidationError> {
let role = match name {
"user" => Self::NormalUser,
"admin" => Self::Admin,
"read_only_user" => Self::ReadOnlyUser,
_ => return Err(ValidationError("unknown role")),
};
Ok(role)
}
pub fn get_permissions(&self) -> Vec<Permission> { pub fn get_permissions(&self) -> Vec<Permission> {
match self { match self {
Self::Guest => vec![], Self::Guest => vec![],