Permissions
This commit is contained in:
parent
ffbb2a8bbc
commit
5d57c936a7
@ -32,5 +32,6 @@ CREATE TABLE
|
|||||||
permission_id SERIAL PRIMARY KEY,
|
permission_id SERIAL PRIMARY KEY,
|
||||||
user_id INT REFERENCES users (user_id) ON DELETE CASCADE NOT NULL,
|
user_id INT REFERENCES users (user_id) ON DELETE CASCADE NOT NULL,
|
||||||
folder_id UUID REFERENCES folders (folder_id) ON DELETE CASCADE,
|
folder_id UUID REFERENCES folders (folder_id) ON DELETE CASCADE,
|
||||||
permission_type permission NOT NULL
|
permission_type permission NOT NULL,
|
||||||
|
UNIQUE (user_id, folder_id)
|
||||||
);
|
);
|
20
sql/delete_permissions.sql
Normal file
20
sql/delete_permissions.sql
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
WITH RECURSIVE folder_hierarchy AS (
|
||||||
|
-- Start with the given directory
|
||||||
|
SELECT
|
||||||
|
folder_id
|
||||||
|
FROM
|
||||||
|
folders
|
||||||
|
WHERE
|
||||||
|
folder_id = $1
|
||||||
|
|
||||||
|
UNION ALL
|
||||||
|
|
||||||
|
-- Recursively find all subdirectories
|
||||||
|
SELECT
|
||||||
|
f.folder_id
|
||||||
|
FROM
|
||||||
|
folders f
|
||||||
|
INNER JOIN
|
||||||
|
folder_hierarchy fh ON f.parent_folder_id = fh.folder_id
|
||||||
|
)
|
||||||
|
DELETE FROM permissions WHERE user_id = $2 AND folder_id IN (SELECT folder_id FROM folder_hierarchy)
|
@ -36,13 +36,13 @@ pub struct FileWithoutParentId {
|
|||||||
file_id: Uuid,
|
file_id: Uuid,
|
||||||
file_name: String,
|
file_name: String,
|
||||||
file_size: i64,
|
file_size: i64,
|
||||||
sha512: Vec<u8>,
|
sha512: String,
|
||||||
created_at: chrono::NaiveDateTime,
|
created_at: chrono::NaiveDateTime,
|
||||||
updated_at: chrono::NaiveDateTime,
|
updated_at: chrono::NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_files(folder_id: Uuid, pool: &Pool) -> sqlx::Result<Vec<FileWithoutParentId>> {
|
pub async fn get_files(folder_id: Uuid, pool: &Pool) -> sqlx::Result<Vec<FileWithoutParentId>> {
|
||||||
sqlx::query_as!(FileWithoutParentId, "SELECT file_id, file_name, file_size, sha512, created_at, updated_at FROM files WHERE folder_id = $1", folder_id)
|
sqlx::query_as!(FileWithoutParentId, r#"SELECT file_id, file_name, file_size, encode(sha512, 'base64') as "sha512!", created_at, updated_at FROM files WHERE folder_id = $1"#, folder_id)
|
||||||
.fetch_all(pool)
|
.fetch_all(pool)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,12 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use futures::TryStreamExt as _;
|
use futures::TryStreamExt as _;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::Pool;
|
use crate::Pool;
|
||||||
|
|
||||||
#[derive(sqlx::Type, Debug)]
|
#[derive(sqlx::Type, Debug, Serialize, Deserialize)]
|
||||||
#[sqlx(type_name = "permission")]
|
#[sqlx(type_name = "permission")]
|
||||||
#[sqlx(rename_all = "lowercase")]
|
#[sqlx(rename_all = "lowercase")]
|
||||||
pub enum PermissionRaw {
|
pub enum PermissionRaw {
|
||||||
@ -76,13 +77,12 @@ impl PermissionType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn insert_permissions(
|
pub async fn insert(
|
||||||
user_id: i32,
|
user_id: i32,
|
||||||
folder_id: Uuid,
|
folder_id: Uuid,
|
||||||
permission_type: PermissionType,
|
permission_type: PermissionRaw,
|
||||||
pool: &Pool,
|
pool: &Pool,
|
||||||
) -> sqlx::Result<()> {
|
) -> sqlx::Result<()> {
|
||||||
let permission_type = PermissionRaw::from(permission_type);
|
|
||||||
sqlx::query_file!(
|
sqlx::query_file!(
|
||||||
"sql/insert_permission.sql",
|
"sql/insert_permission.sql",
|
||||||
folder_id,
|
folder_id,
|
||||||
@ -94,13 +94,20 @@ pub async fn insert_permissions(
|
|||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_permissions_for_folder(
|
pub async fn get_all_for_folder(
|
||||||
folder_id: Uuid,
|
folder_id: Uuid,
|
||||||
pool: &Pool,
|
pool: &Pool,
|
||||||
) -> sqlx::Result<HashMap<String, PermissionType>> {
|
) -> sqlx::Result<HashMap<String, PermissionRaw>> {
|
||||||
sqlx::query_file!("sql/get_all_permissions_for_folder.sql", folder_id)
|
sqlx::query_file!("sql/get_all_permissions_for_folder.sql", folder_id)
|
||||||
.fetch(pool)
|
.fetch(pool)
|
||||||
.map_ok(|record| (record.username, Some(record.permission_type).into()))
|
.map_ok(|record| (record.username, record.permission_type))
|
||||||
.try_collect()
|
.try_collect()
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_for_folder(folder_id: Uuid, user_id: i32, pool: &Pool) -> sqlx::Result<()> {
|
||||||
|
sqlx::query_file!("sql/delete_permissions.sql", folder_id, user_id)
|
||||||
|
.execute(pool)
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod folder;
|
pub mod folder;
|
||||||
|
pub mod permissions;
|
||||||
|
26
src/endpoints/permissions/delete.rs
Normal file
26
src/endpoints/permissions/delete.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Params {
|
||||||
|
folder_id: Uuid,
|
||||||
|
user_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete(
|
||||||
|
claims: Claims,
|
||||||
|
State(state): State<AppState>,
|
||||||
|
Json(params): Json<Params>,
|
||||||
|
) -> Result<StatusCode, StatusCode> {
|
||||||
|
if params.user_id != claims.user_id {
|
||||||
|
db::folder::get_permissions(params.folder_id, claims.user_id, &state.pool)
|
||||||
|
.await
|
||||||
|
.handle_internal()?
|
||||||
|
.can_manage_guard()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
db::permissions::delete_for_folder(params.folder_id, params.user_id, &state.pool)
|
||||||
|
.await
|
||||||
|
.handle_internal()?;
|
||||||
|
|
||||||
|
Ok(StatusCode::NO_CONTENT)
|
||||||
|
}
|
26
src/endpoints/permissions/get.rs
Normal file
26
src/endpoints/permissions/get.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use db::permissions::PermissionRaw;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Params {
|
||||||
|
folder_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get(
|
||||||
|
Query(params): Query<Params>,
|
||||||
|
claims: Claims,
|
||||||
|
State(state): State<AppState>,
|
||||||
|
) -> Result<Json<HashMap<String, PermissionRaw>>, StatusCode> {
|
||||||
|
db::folder::get_permissions(params.folder_id, claims.user_id, &state.pool)
|
||||||
|
.await
|
||||||
|
.handle_internal()?
|
||||||
|
.can_manage_guard()?;
|
||||||
|
|
||||||
|
let permissions = db::permissions::get_all_for_folder(params.folder_id, &state.pool)
|
||||||
|
.await
|
||||||
|
.handle_internal()?;
|
||||||
|
Ok(Json(permissions))
|
||||||
|
}
|
3
src/endpoints/permissions/mod.rs
Normal file
3
src/endpoints/permissions/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod delete;
|
||||||
|
pub mod get;
|
||||||
|
pub mod set;
|
32
src/endpoints/permissions/set.rs
Normal file
32
src/endpoints/permissions/set.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use db::permissions::PermissionRaw;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Params {
|
||||||
|
folder_id: Uuid,
|
||||||
|
permission_type: PermissionRaw,
|
||||||
|
user_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set(
|
||||||
|
claims: Claims,
|
||||||
|
State(state): State<AppState>,
|
||||||
|
Json(params): Json<Params>,
|
||||||
|
) -> Result<StatusCode, StatusCode> {
|
||||||
|
db::folder::get_permissions(params.folder_id, claims.user_id, &state.pool)
|
||||||
|
.await
|
||||||
|
.handle_internal()?
|
||||||
|
.can_manage_guard()?;
|
||||||
|
|
||||||
|
db::permissions::insert(
|
||||||
|
params.user_id,
|
||||||
|
params.folder_id,
|
||||||
|
params.permission_type,
|
||||||
|
&state.pool,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.handle_internal()?;
|
||||||
|
|
||||||
|
Ok(StatusCode::NO_CONTENT)
|
||||||
|
}
|
@ -85,7 +85,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
fn app(state: AppState) -> Router {
|
fn app(state: AppState) -> Router {
|
||||||
use axum::http::header;
|
use axum::http::header;
|
||||||
use endpoints::{file, folder};
|
use endpoints::{file, folder, permissions};
|
||||||
use tower_http::ServiceBuilderExt as _;
|
use tower_http::ServiceBuilderExt as _;
|
||||||
|
|
||||||
let sensitive_headers = [header::AUTHORIZATION, header::COOKIE];
|
let sensitive_headers = [header::AUTHORIZATION, header::COOKIE];
|
||||||
@ -110,6 +110,12 @@ fn app(state: AppState) -> Router {
|
|||||||
.post(folder::create::create)
|
.post(folder::create::create)
|
||||||
.delete(folder::delete::delete),
|
.delete(folder::delete::delete),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/permissions",
|
||||||
|
get(permissions::get::get)
|
||||||
|
.post(permissions::set::set)
|
||||||
|
.delete(permissions::delete::delete),
|
||||||
|
)
|
||||||
.layer(middleware)
|
.layer(middleware)
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user