Add role delete and change update

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/13/head
trivernis 4 years ago
parent a0e6e4fb07
commit 7359c259eb
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -4,7 +4,9 @@
use crate::database::models::Role; use crate::database::models::Role;
use crate::database::role_permissions::RolePermissions; use crate::database::role_permissions::RolePermissions;
use crate::database::{DatabaseResult, PostgresPool, Table, DEFAULT_ADMIN_EMAIL, ENV_ADMIN_EMAIL}; use crate::database::{
DatabaseResult, PostgresPool, Table, ADMIN_ROLE_NAME, DEFAULT_ADMIN_EMAIL, ENV_ADMIN_EMAIL,
};
use crate::utils::error::DBError; use crate::utils::error::DBError;
use std::collections::HashSet; use std::collections::HashSet;
use std::iter::FromIterator; use std::iter::FromIterator;
@ -112,21 +114,35 @@ impl Roles {
pub fn update_role( pub fn update_role(
&self, &self,
old_name: String,
name: String, name: String,
description: Option<String>, description: Option<String>,
permissions: Vec<i32>, permissions: Vec<i32>,
) -> DatabaseResult<Role> { ) -> DatabaseResult<Role> {
if old_name == ADMIN_ROLE_NAME {
return Err(DBError::GenericError(
"The admin role can't be altered!".to_string(),
));
}
let permissions = HashSet::from_iter(permissions.into_iter()); let permissions = HashSet::from_iter(permissions.into_iter());
let mut connection = self.pool.get()?; let mut connection = self.pool.get()?;
let mut transaction = connection.transaction()?; let mut transaction = connection.transaction()?;
let id: i32 = transaction let id: i32 = transaction
.query_opt("SELECT id FROM roles WHERE name = $1", &[&name])? .query_opt("SELECT id FROM roles WHERE name = $1", &[&old_name])?
.ok_or(DBError::RecordDoesNotExist)? .ok_or(DBError::RecordDoesNotExist)?
.get(0); .get(0);
let name_exists =
transaction.query_opt("SELECT id FROM roles WHERE name = $1", &[&name])?;
if name_exists.is_some() {
return Err(DBError::GenericError(format!(
"A role with the name {} already exists!",
name
)));
}
let update_result = transaction.query_one( let update_result = transaction.query_one(
"UPDATE roles SET description = $2 WHERE id = $1 RETURNING *", "UPDATE roles SET name = $3, description = $2 WHERE id = $1 RETURNING *",
&[&id, &description], &[&id, &description, &name],
)?; )?;
let current_permissions = transaction let current_permissions = transaction
.query( .query(
@ -155,4 +171,23 @@ impl Roles {
Ok(serde_postgres::from_row::<Role>(&update_result)?) Ok(serde_postgres::from_row::<Role>(&update_result)?)
} }
/// Deletes a role if it exists
pub fn delete_role(&self, name: &String) -> DatabaseResult<()> {
if name == ADMIN_ROLE_NAME {
return Err(DBError::GenericError(
"The admin role can't be altered!".to_string(),
));
}
let mut connection = self.pool.get()?;
let result = connection.query_opt("SELECT id FROM roles WHERE name = $1", &[name])?;
if result.is_none() {
Err(DBError::RecordDoesNotExist)
} else {
connection.query("DELETE FROM roles WHERE name = $1", &[name])?;
Ok(())
}
}
} }

@ -32,7 +32,9 @@ impl RESTDocumentation {
} }
fn landing(&self) -> String { fn landing(&self) -> String {
let types = self.paths.keys().fold("".to_string(), |a, b| { let mut keys = self.paths.keys().cloned().collect::<Vec<String>>();
keys.sort();
let types = keys.into_iter().fold("".to_string(), |a, b| {
format!("{}<br><a href='{}?path={2}'>{2}</a>", a, self.base_path, b) format!("{}<br><a href='{}?path={2}'>{2}</a>", a, self.base_path, b)
}); });
@ -53,7 +55,7 @@ impl RESTDocumentation {
let content = format!( let content = format!(
"\ "\
<a href={}>Back</a> <a href={}>Back</a>
<h1>{}: {}</h1> <h1><code>{}: {}</code></h1>
<p>{}</p> <p>{}</p>
<h2>Input</h2> <h2>Input</h2>
<code>{}</code> <code>{}</code>

@ -8,6 +8,10 @@ body {
font-family: "Fira Sans", "Noto Sans", sans-serif; font-family: "Fira Sans", "Noto Sans", sans-serif;
} }
code {
font-family: "Fira Code", "DejaVu Sans Mono", monospace;
}
code > pre { code > pre {
font-family: "Fira Code", "DejaVu Sans Mono", monospace; font-family: "Fira Code", "DejaVu Sans Mono", monospace;
max-width: 100%; max-width: 100%;

@ -13,14 +13,14 @@ use serde::Serialize;
use crate::database::models::Role; use crate::database::models::Role;
use crate::database::permissions::{ use crate::database::permissions::{
CREATE_ROLE_PERMISSION, UPDATE_ROLE_PERMISSION, VIEW_ROLE_PERMISSION, CREATE_ROLE_PERMISSION, DELETE_ROLE_PERMISSION, UPDATE_ROLE_PERMISSION, VIEW_ROLE_PERMISSION,
}; };
use crate::database::tokens::SessionTokens; use crate::database::tokens::SessionTokens;
use crate::database::Database; use crate::database::Database;
use crate::server::documentation::RESTDocumentation; use crate::server::documentation::RESTDocumentation;
use crate::server::messages::{ use crate::server::messages::{
ErrorMessage, FullRoleData, LoginMessage, LogoutConfirmation, LogoutMessage, ModifyRoleRequest, DeleteRoleResponse, ErrorMessage, FullRoleData, LoginMessage, LogoutConfirmation,
RefreshMessage, LogoutMessage, ModifyRoleRequest, RefreshMessage,
}; };
use crate::utils::error::DBError; use crate::utils::error::DBError;
use crate::utils::get_user_id_from_token; use crate::utils::get_user_id_from_token;
@ -121,8 +121,11 @@ impl UserHttpServer {
(POST) (/roles/create) => { (POST) (/roles/create) => {
Self::create_role(&database, request).unwrap_or_else(HTTPError::into) Self::create_role(&database, request).unwrap_or_else(HTTPError::into)
}, },
(POST) (/roles/update) => { (POST) (/roles/{name:String}/update) => {
Self::update_role(&database, request).unwrap_or_else(HTTPError::into) Self::update_role(&database, request, name).unwrap_or_else(HTTPError::into)
},
(POST) (/roles/{name: String}/delete) => {
Self::delete_role(&database, request, name).unwrap_or_else(HTTPError::into)
}, },
_ => if request.method() == "OPTIONS" { _ => if request.method() == "OPTIONS" {
Response::empty_204() Response::empty_204()
@ -184,10 +187,15 @@ impl UserHttpServer {
"Creates a new role", "Creates a new role",
)?; )?;
doc.add_path::<ModifyRoleRequest, FullRoleData>( doc.add_path::<ModifyRoleRequest, FullRoleData>(
"/roles/update", "/roles/{name:String}/update",
"POST", "POST",
"Updates an existing role", "Updates an existing role",
)?; )?;
doc.add_path::<(), DeleteRoleResponse>(
"/roles/{name:String}/delete",
"POST",
"Deletes a role",
)?;
Ok(doc) Ok(doc)
} }
@ -280,7 +288,7 @@ impl UserHttpServer {
.with_status_code(201)) .with_status_code(201))
} }
fn update_role(database: &Database, request: &Request) -> HTTPResult<Response> { fn update_role(database: &Database, request: &Request, name: String) -> HTTPResult<Response> {
require_permission!(database, request, UPDATE_ROLE_PERMISSION); require_permission!(database, request, UPDATE_ROLE_PERMISSION);
let message: ModifyRoleRequest = serde_json::from_str(parse_string_body(request)?.as_str()) let message: ModifyRoleRequest = serde_json::from_str(parse_string_body(request)?.as_str())
.map_err(|e| HTTPError::new(e.to_string(), 400))?; .map_err(|e| HTTPError::new(e.to_string(), 400))?;
@ -294,10 +302,12 @@ impl UserHttpServer {
))) )))
.with_status_code(400)); .with_status_code(400));
} }
let role = let role = database.roles.update_role(
database name,
.roles message.name,
.update_role(message.name, message.description, message.permissions)?; message.description,
message.permissions,
)?;
let permissions = database.role_permission.by_role(role.id)?; let permissions = database.role_permission.by_role(role.id)?;
Ok(Response::json(&FullRoleData { Ok(Response::json(&FullRoleData {
@ -306,6 +316,16 @@ impl UserHttpServer {
name: role.name, name: role.name,
})) }))
} }
fn delete_role(database: &Database, request: &Request, role: String) -> HTTPResult<Response> {
require_permission!(database, request, DELETE_ROLE_PERMISSION);
database.roles.delete_role(&role)?;
Ok(Response::json(&DeleteRoleResponse {
success: true,
role,
}))
}
} }
/// Parses the body of a http request into a string representation /// Parses the body of a http request into a string representation

@ -113,3 +113,9 @@ pub struct FullRoleData {
pub name: String, pub name: String,
pub permissions: Vec<Permission>, pub permissions: Vec<Permission>,
} }
#[derive(Serialize, JsonSchema)]
pub struct DeleteRoleResponse {
pub success: bool,
pub role: String,
}

Loading…
Cancel
Save