Permissions
This commit is contained in:
parent
ffbb2a8bbc
commit
5d57c936a7
@ -32,5 +32,6 @@ CREATE TABLE
|
||||
permission_id SERIAL PRIMARY KEY,
|
||||
user_id INT REFERENCES users (user_id) ON DELETE CASCADE NOT NULL,
|
||||
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_name: String,
|
||||
file_size: i64,
|
||||
sha512: Vec<u8>,
|
||||
sha512: String,
|
||||
created_at: chrono::NaiveDateTime,
|
||||
updated_at: chrono::NaiveDateTime,
|
||||
}
|
||||
|
||||
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)
|
||||
.await
|
||||
}
|
||||
|
@ -2,11 +2,12 @@ use std::collections::HashMap;
|
||||
|
||||
use axum::http::StatusCode;
|
||||
use futures::TryStreamExt as _;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::Pool;
|
||||
|
||||
#[derive(sqlx::Type, Debug)]
|
||||
#[derive(sqlx::Type, Debug, Serialize, Deserialize)]
|
||||
#[sqlx(type_name = "permission")]
|
||||
#[sqlx(rename_all = "lowercase")]
|
||||
pub enum PermissionRaw {
|
||||
@ -76,13 +77,12 @@ impl PermissionType {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn insert_permissions(
|
||||
pub async fn insert(
|
||||
user_id: i32,
|
||||
folder_id: Uuid,
|
||||
permission_type: PermissionType,
|
||||
permission_type: PermissionRaw,
|
||||
pool: &Pool,
|
||||
) -> sqlx::Result<()> {
|
||||
let permission_type = PermissionRaw::from(permission_type);
|
||||
sqlx::query_file!(
|
||||
"sql/insert_permission.sql",
|
||||
folder_id,
|
||||
@ -94,13 +94,20 @@ pub async fn insert_permissions(
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub async fn get_permissions_for_folder(
|
||||
pub async fn get_all_for_folder(
|
||||
folder_id: Uuid,
|
||||
pool: &Pool,
|
||||
) -> sqlx::Result<HashMap<String, PermissionType>> {
|
||||
) -> sqlx::Result<HashMap<String, PermissionRaw>> {
|
||||
sqlx::query_file!("sql/get_all_permissions_for_folder.sql", folder_id)
|
||||
.fetch(pool)
|
||||
.map_ok(|record| (record.username, Some(record.permission_type).into()))
|
||||
.map_ok(|record| (record.username, record.permission_type))
|
||||
.try_collect()
|
||||
.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 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 {
|
||||
use axum::http::header;
|
||||
use endpoints::{file, folder};
|
||||
use endpoints::{file, folder, permissions};
|
||||
use tower_http::ServiceBuilderExt as _;
|
||||
|
||||
let sensitive_headers = [header::AUTHORIZATION, header::COOKIE];
|
||||
@ -110,6 +110,12 @@ fn app(state: AppState) -> Router {
|
||||
.post(folder::create::create)
|
||||
.delete(folder::delete::delete),
|
||||
)
|
||||
.route(
|
||||
"/permissions",
|
||||
get(permissions::get::get)
|
||||
.post(permissions::set::set)
|
||||
.delete(permissions::delete::delete),
|
||||
)
|
||||
.layer(middleware)
|
||||
.with_state(state)
|
||||
}
|
||||
|
Reference in New Issue
Block a user