add: update user secondary role api
This commit is contained in:
parent
9528d71b2a
commit
0ae64de989
3 changed files with 113 additions and 67 deletions
|
@ -3,8 +3,8 @@ use crate::{
|
||||||
get_user_from_token,
|
get_user_from_token,
|
||||||
model::{ApiReturn, Error},
|
model::{ApiReturn, Error},
|
||||||
routes::api::v1::{
|
routes::api::v1::{
|
||||||
AppendAssociations, DeleteUser, DisableTotp, RefreshGrantToken, UpdateUserIsVerified,
|
AppendAssociations, DeleteUser, DisableTotp, RefreshGrantToken, UpdateSecondaryUserRole,
|
||||||
UpdateUserPassword, UpdateUserRole, UpdateUserUsername,
|
UpdateUserIsVerified, UpdateUserPassword, UpdateUserRole, UpdateUserUsername,
|
||||||
},
|
},
|
||||||
State,
|
State,
|
||||||
};
|
};
|
||||||
|
@ -359,6 +359,34 @@ pub async fn update_user_role_request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the role of the given user.
|
||||||
|
///
|
||||||
|
/// Does not support third-party grants.
|
||||||
|
pub async fn update_user_secondary_role_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Path(id): Path<usize>,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
Json(req): Json<UpdateSecondaryUserRole>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let data = &(data.read().await).0;
|
||||||
|
let user = match get_user_from_token!(jar, data) {
|
||||||
|
Some(ua) => ua,
|
||||||
|
None => return Json(Error::NotAllowed.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match data
|
||||||
|
.update_user_secondary_role(id, req.role, user, false)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Json(ApiReturn {
|
||||||
|
ok: true,
|
||||||
|
message: "User updated".to_string(),
|
||||||
|
payload: (),
|
||||||
|
}),
|
||||||
|
Err(e) => Json(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Update the current user's last seen value.
|
/// Update the current user's last seen value.
|
||||||
pub async fn seen_request(jar: CookieJar, Extension(data): Extension<State>) -> impl IntoResponse {
|
pub async fn seen_request(jar: CookieJar, Extension(data): Extension<State>) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
|
|
|
@ -26,7 +26,7 @@ use tetratto_core::model::{
|
||||||
communities_permissions::CommunityPermission,
|
communities_permissions::CommunityPermission,
|
||||||
journals::JournalPrivacyPermission,
|
journals::JournalPrivacyPermission,
|
||||||
oauth::AppScope,
|
oauth::AppScope,
|
||||||
permissions::FinePermission,
|
permissions::{FinePermission, SecondaryPermission},
|
||||||
reactions::AssetType,
|
reactions::AssetType,
|
||||||
stacks::{StackMode, StackPrivacy, StackSort},
|
stacks::{StackMode, StackPrivacy, StackSort},
|
||||||
};
|
};
|
||||||
|
@ -296,6 +296,10 @@ pub fn routes() -> Router {
|
||||||
"/auth/user/{id}/role",
|
"/auth/user/{id}/role",
|
||||||
post(auth::profile::update_user_role_request),
|
post(auth::profile::update_user_role_request),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/auth/user/{id}/role/2",
|
||||||
|
post(auth::profile::update_user_secondary_role_request),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/auth/user/{id}",
|
"/auth/user/{id}",
|
||||||
delete(auth::profile::delete_user_request),
|
delete(auth::profile::delete_user_request),
|
||||||
|
@ -738,6 +742,11 @@ pub struct UpdateUserRole {
|
||||||
pub role: FinePermission,
|
pub role: FinePermission,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct UpdateSecondaryUserRole {
|
||||||
|
pub role: SecondaryPermission,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct DeleteUser {
|
pub struct DeleteUser {
|
||||||
pub password: String,
|
pub password: String,
|
||||||
|
|
|
@ -16,10 +16,73 @@ use tetratto_shared::{
|
||||||
unix_epoch_timestamp,
|
unix_epoch_timestamp,
|
||||||
};
|
};
|
||||||
use crate::{auto_method, DataManager};
|
use crate::{auto_method, DataManager};
|
||||||
|
use oiseau::{PostgresRow, execute, get, query_row, params};
|
||||||
|
|
||||||
use oiseau::PostgresRow;
|
macro_rules! update_role_fn {
|
||||||
|
($name:ident, $role_ty:ty, $col:literal) => {
|
||||||
|
pub async fn $name(
|
||||||
|
&self,
|
||||||
|
id: usize,
|
||||||
|
role: $role_ty,
|
||||||
|
user: User,
|
||||||
|
force: bool,
|
||||||
|
) -> Result<()> {
|
||||||
|
let other_user = self.get_user_by_id(id).await?;
|
||||||
|
|
||||||
use oiseau::{execute, get, query_row, params};
|
if !force {
|
||||||
|
// check permission
|
||||||
|
if !user.permissions.check(FinePermission::MANAGE_USERS) {
|
||||||
|
return Err(Error::NotAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if other_user.permissions.check_manager() && !user.permissions.check_admin() {
|
||||||
|
return Err(Error::MiscError(
|
||||||
|
"Cannot manage the role of other managers".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if other_user.permissions == user.permissions {
|
||||||
|
return Err(Error::MiscError(
|
||||||
|
"Cannot manage users of equal level to you".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
let conn = match self.0.connect().await {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = execute!(
|
||||||
|
&conn,
|
||||||
|
&format!("UPDATE users SET {} = $1 WHERE id = $2", $col),
|
||||||
|
params![&(role.bits() as i32), &(id as i64)]
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = res {
|
||||||
|
return Err(Error::DatabaseError(e.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cache_clear_user(&other_user).await;
|
||||||
|
|
||||||
|
// create audit log entry
|
||||||
|
self.create_audit_log_entry(AuditLogEntry::new(
|
||||||
|
user.id,
|
||||||
|
format!(
|
||||||
|
"invoked `{}` with x value `{}` and y value `{}`",
|
||||||
|
$col,
|
||||||
|
other_user.id,
|
||||||
|
role.bits()
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl DataManager {
|
impl DataManager {
|
||||||
/// Get a [`User`] from an SQL row.
|
/// Get a [`User`] from an SQL row.
|
||||||
|
@ -47,7 +110,7 @@ impl DataManager {
|
||||||
grants: serde_json::from_str(&get!(x->19(String)).to_string()).unwrap(),
|
grants: serde_json::from_str(&get!(x->19(String)).to_string()).unwrap(),
|
||||||
associated: serde_json::from_str(&get!(x->20(String)).to_string()).unwrap(),
|
associated: serde_json::from_str(&get!(x->20(String)).to_string()).unwrap(),
|
||||||
invite_code: get!(x->21(i64)) as usize,
|
invite_code: get!(x->21(i64)) as usize,
|
||||||
secondary_permissions: SecondaryPermission::from_bits(get!(x->7(i32)) as u32).unwrap(),
|
secondary_permissions: SecondaryPermission::from_bits(get!(x->22(i32)) as u32).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,67 +686,6 @@ impl DataManager {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_user_role(
|
|
||||||
&self,
|
|
||||||
id: usize,
|
|
||||||
role: FinePermission,
|
|
||||||
user: User,
|
|
||||||
force: bool,
|
|
||||||
) -> Result<()> {
|
|
||||||
let other_user = self.get_user_by_id(id).await?;
|
|
||||||
|
|
||||||
if !force {
|
|
||||||
// check permission
|
|
||||||
if !user.permissions.check(FinePermission::MANAGE_USERS) {
|
|
||||||
return Err(Error::NotAllowed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if other_user.permissions.check_manager() && !user.permissions.check_admin() {
|
|
||||||
return Err(Error::MiscError(
|
|
||||||
"Cannot manage the role of other managers".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if other_user.permissions == user.permissions {
|
|
||||||
return Err(Error::MiscError(
|
|
||||||
"Cannot manage users of equal level to you".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...
|
|
||||||
let conn = match self.0.connect().await {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
|
|
||||||
};
|
|
||||||
|
|
||||||
let res = execute!(
|
|
||||||
&conn,
|
|
||||||
"UPDATE users SET permissions = $1 WHERE id = $2",
|
|
||||||
params![&(role.bits() as i32), &(id as i64)]
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Err(e) = res {
|
|
||||||
return Err(Error::DatabaseError(e.to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.cache_clear_user(&other_user).await;
|
|
||||||
|
|
||||||
// create audit log entry
|
|
||||||
self.create_audit_log_entry(AuditLogEntry::new(
|
|
||||||
user.id,
|
|
||||||
format!(
|
|
||||||
"invoked `update_user_role` with x value `{}` and y value `{}`",
|
|
||||||
other_user.id,
|
|
||||||
role.bits()
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// ...
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn seen_user(&self, user: &User) -> Result<()> {
|
pub async fn seen_user(&self, user: &User) -> Result<()> {
|
||||||
let conn = match self.0.connect().await {
|
let conn = match self.0.connect().await {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
|
@ -843,6 +845,13 @@ impl DataManager {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_role_fn!(update_user_role, FinePermission, "permissions");
|
||||||
|
update_role_fn!(
|
||||||
|
update_user_secondary_role,
|
||||||
|
SecondaryPermission,
|
||||||
|
"secondary_permissions"
|
||||||
|
);
|
||||||
|
|
||||||
auto_method!(update_user_tokens(Vec<Token>)@get_user_by_id -> "UPDATE users SET tokens = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
auto_method!(update_user_tokens(Vec<Token>)@get_user_by_id -> "UPDATE users SET tokens = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
||||||
auto_method!(update_user_grants(Vec<AuthGrant>)@get_user_by_id -> "UPDATE users SET grants = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
auto_method!(update_user_grants(Vec<AuthGrant>)@get_user_by_id -> "UPDATE users SET grants = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
||||||
auto_method!(update_user_settings(UserSettings)@get_user_by_id -> "UPDATE users SET settings = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
auto_method!(update_user_settings(UserSettings)@get_user_by_id -> "UPDATE users SET settings = $1 WHERE id = $2" --serde --cache-key-tmpl=cache_clear_user);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue