user permissions
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
CREATE TABLE user_warrens (
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
warren_id UUID NOT NULL REFERENCES warrens(id) ON DELETE CASCADE,
|
||||
can_create_children BOOLEAN NOT NULL,
|
||||
can_list_files BOOLEAN NOT NULL,
|
||||
can_read_files BOOLEAN NOT NULL,
|
||||
can_modify_files BOOLEAN NOT NULL,
|
||||
can_delete_files BOOLEAN NOT NULL,
|
||||
can_delete_warren BOOLEAN NOT NULL,
|
||||
PRIMARY KEY(user_id, warren_id)
|
||||
);
|
||||
@@ -1,8 +1,11 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use derive_more::Display;
|
||||
use requests::FetchAuthSessionError;
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::user_warren::requests::FetchUserWarrenError;
|
||||
|
||||
pub mod requests;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::FromRow)]
|
||||
@@ -41,6 +44,58 @@ impl AuthSession {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum AuthSessionType {
|
||||
WarrenAuth,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct AuthSessionIdWithType {
|
||||
session_type: AuthSessionType,
|
||||
session_id: AuthSessionId,
|
||||
}
|
||||
|
||||
impl AuthSessionIdWithType {
|
||||
pub fn from_str(raw: &str) -> Result<Self, AuthSessionIdWithTypeError> {
|
||||
let trimmed = raw.trim();
|
||||
|
||||
if trimmed.len() < 1 {
|
||||
return Err(AuthSessionIdWithTypeError::Empty);
|
||||
}
|
||||
|
||||
let (prefix_length, session_type) = if trimmed.starts_with("WarrenAuth ") {
|
||||
("WarrenAuth ".len(), AuthSessionType::WarrenAuth)
|
||||
} else {
|
||||
return Err(AuthSessionIdWithTypeError::InvalidType);
|
||||
};
|
||||
|
||||
let session_id = AuthSessionId::new(&trimmed[prefix_length..])?;
|
||||
|
||||
Ok(Self {
|
||||
session_type,
|
||||
session_id,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn session_type(&self) -> AuthSessionType {
|
||||
self.session_type
|
||||
}
|
||||
|
||||
pub fn session_id(&self) -> &AuthSessionId {
|
||||
&self.session_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AuthSessionIdWithTypeError {
|
||||
#[error("Invalid auth session type")]
|
||||
InvalidType,
|
||||
#[error(transparent)]
|
||||
AuthSessionId(#[from] AuthSessionIdError),
|
||||
#[error("The auth session id is empty")]
|
||||
Empty,
|
||||
}
|
||||
|
||||
/// A valid auth session id
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display, sqlx::Type)]
|
||||
#[sqlx(transparent)]
|
||||
@@ -67,3 +122,41 @@ pub enum AuthSessionIdError {
|
||||
#[error("An auth session id must not be empty")]
|
||||
Empty,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct AuthRequest<T> {
|
||||
auth: AuthSessionIdWithType,
|
||||
value: T,
|
||||
}
|
||||
|
||||
impl<T> AuthRequest<T> {
|
||||
pub fn new(auth: AuthSessionIdWithType, value: T) -> Self {
|
||||
Self { auth, value }
|
||||
}
|
||||
|
||||
pub fn auth(&self) -> &AuthSessionIdWithType {
|
||||
&self.auth
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &T {
|
||||
&self.value
|
||||
}
|
||||
|
||||
pub fn unpack(self) -> (AuthSessionIdWithType, T) {
|
||||
(self.auth, self.value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AuthError<T: std::error::Error> {
|
||||
#[error("The requested operation is not permitted")]
|
||||
InsufficientPermissions,
|
||||
#[error(transparent)]
|
||||
FetchAuthSession(#[from] FetchAuthSessionError),
|
||||
#[error(transparent)]
|
||||
FetchUserWarren(#[from] FetchUserWarrenError),
|
||||
#[error(transparent)]
|
||||
Custom(T),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod auth_session;
|
||||
pub mod file;
|
||||
pub mod user;
|
||||
pub mod user_warren;
|
||||
pub mod warren;
|
||||
|
||||
74
backend/src/lib/domain/warren/models/user_warren/mod.rs
Normal file
74
backend/src/lib/domain/warren/models/user_warren/mod.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
pub mod requests;
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::FromRow)]
|
||||
pub struct UserWarren {
|
||||
user_id: Uuid,
|
||||
warren_id: Uuid,
|
||||
can_create_children: bool,
|
||||
can_list_files: bool,
|
||||
can_read_files: bool,
|
||||
can_modify_files: bool,
|
||||
can_delete_files: bool,
|
||||
can_delete_warren: bool,
|
||||
}
|
||||
|
||||
impl UserWarren {
|
||||
pub fn new(
|
||||
user_id: Uuid,
|
||||
warren_id: Uuid,
|
||||
can_create_children: bool,
|
||||
can_list_files: bool,
|
||||
can_read_files: bool,
|
||||
can_modify_files: bool,
|
||||
can_delete_files: bool,
|
||||
can_delete_warren: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
user_id,
|
||||
warren_id,
|
||||
can_create_children,
|
||||
can_list_files,
|
||||
can_read_files,
|
||||
can_modify_files,
|
||||
can_delete_files,
|
||||
can_delete_warren,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user_id(&self) -> &Uuid {
|
||||
&self.user_id
|
||||
}
|
||||
|
||||
pub fn warren_id(&self) -> &Uuid {
|
||||
&self.warren_id
|
||||
}
|
||||
pub fn into_warren_id(self) -> Uuid {
|
||||
self.warren_id
|
||||
}
|
||||
|
||||
pub fn can_create_children(&self) -> bool {
|
||||
self.can_create_children
|
||||
}
|
||||
|
||||
pub fn can_list_files(&self) -> bool {
|
||||
self.can_list_files
|
||||
}
|
||||
|
||||
pub fn can_read_files(&self) -> bool {
|
||||
self.can_read_files
|
||||
}
|
||||
|
||||
pub fn can_modify_files(&self) -> bool {
|
||||
self.can_modify_files
|
||||
}
|
||||
|
||||
pub fn can_delete_files(&self) -> bool {
|
||||
self.can_delete_files
|
||||
}
|
||||
|
||||
pub fn can_delete_warren(&self) -> bool {
|
||||
self.can_delete_warren
|
||||
}
|
||||
}
|
||||
72
backend/src/lib/domain/warren/models/user_warren/requests.rs
Normal file
72
backend/src/lib/domain/warren/models/user_warren/requests.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::domain::warren::models::warren::FetchWarrensError;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FetchUserWarrensRequest {
|
||||
user_id: Uuid,
|
||||
}
|
||||
|
||||
impl FetchUserWarrensRequest {
|
||||
pub fn new(user_id: Uuid) -> Self {
|
||||
Self { user_id }
|
||||
}
|
||||
|
||||
pub fn user_id(&self) -> &Uuid {
|
||||
&self.user_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FetchUserWarrensError {
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct ListWarrensRequest {}
|
||||
|
||||
impl ListWarrensRequest {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ListWarrensError {
|
||||
#[error(transparent)]
|
||||
FetchUserWarrenIds(#[from] FetchUserWarrensError),
|
||||
#[error(transparent)]
|
||||
ListWarrens(#[from] FetchWarrensError),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FetchUserWarrenRequest {
|
||||
user_id: Uuid,
|
||||
warren_id: Uuid,
|
||||
}
|
||||
|
||||
impl FetchUserWarrenRequest {
|
||||
pub fn new(user_id: Uuid, warren_id: Uuid) -> Self {
|
||||
Self { user_id, warren_id }
|
||||
}
|
||||
|
||||
pub fn user_id(&self) -> &Uuid {
|
||||
&self.user_id
|
||||
}
|
||||
|
||||
pub fn warren_id(&self) -> &Uuid {
|
||||
&self.warren_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FetchUserWarrenError {
|
||||
#[error("This user warren does not exist")]
|
||||
NotFound,
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
@@ -4,8 +4,8 @@ use uuid::Uuid;
|
||||
use crate::domain::warren::models::file::{
|
||||
AbsoluteFilePath, CreateDirectoryError, CreateDirectoryRequest, CreateFileError,
|
||||
CreateFileRequest, DeleteDirectoryError, DeleteDirectoryRequest, DeleteFileError,
|
||||
DeleteFileRequest, FileName, FilePath, ListFilesError, ListFilesRequest, RelativeFilePath,
|
||||
RenameEntryError, RenameEntryRequest,
|
||||
DeleteFileRequest, File, FileName, FilePath, ListFilesError, ListFilesRequest,
|
||||
RelativeFilePath, RenameEntryError, RenameEntryRequest,
|
||||
};
|
||||
|
||||
use super::Warren;
|
||||
@@ -34,16 +34,22 @@ pub enum FetchWarrenError {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct ListWarrensRequest;
|
||||
pub struct FetchWarrensRequest {
|
||||
ids: Vec<Uuid>,
|
||||
}
|
||||
|
||||
impl ListWarrensRequest {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
impl FetchWarrensRequest {
|
||||
pub fn new(ids: Vec<Uuid>) -> Self {
|
||||
Self { ids }
|
||||
}
|
||||
|
||||
pub fn ids(&self) -> &Vec<Uuid> {
|
||||
&self.ids
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ListWarrensError {
|
||||
pub enum FetchWarrensError {
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
@@ -66,6 +72,11 @@ impl ListWarrenFilesRequest {
|
||||
pub fn path(&self) -> &AbsoluteFilePath {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn to_fs_request(self, warren: &Warren) -> ListFilesRequest {
|
||||
let path = warren.path().clone().join(&self.path.to_relative());
|
||||
ListFilesRequest::new(path)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<FetchWarrenRequest> for ListWarrenFilesRequest {
|
||||
@@ -74,10 +85,23 @@ impl Into<FetchWarrenRequest> for ListWarrenFilesRequest {
|
||||
}
|
||||
}
|
||||
|
||||
impl ListWarrenFilesRequest {
|
||||
pub fn to_fs_request(self, warren: &Warren) -> ListFilesRequest {
|
||||
let path = warren.path().clone().join(&self.path.to_relative());
|
||||
ListFilesRequest::new(path)
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct ListWarrenFilesResponse {
|
||||
warren: Warren,
|
||||
files: Vec<File>,
|
||||
}
|
||||
|
||||
impl ListWarrenFilesResponse {
|
||||
pub fn new(warren: Warren, files: Vec<File>) -> Self {
|
||||
Self { warren, files }
|
||||
}
|
||||
|
||||
pub fn warren(&self) -> &Warren {
|
||||
&self.warren
|
||||
}
|
||||
|
||||
pub fn files(&self) -> &Vec<File> {
|
||||
&self.files
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +110,8 @@ pub enum ListWarrenFilesError {
|
||||
#[error(transparent)]
|
||||
FileSystem(#[from] ListFilesError),
|
||||
#[error(transparent)]
|
||||
FetchWarren(#[from] FetchWarrenError),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
@@ -107,6 +133,11 @@ impl CreateWarrenDirectoryRequest {
|
||||
pub fn path(&self) -> &AbsoluteFilePath {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn to_fs_request(self, warren: &Warren) -> CreateDirectoryRequest {
|
||||
let path = warren.path().clone().join(&self.path.to_relative());
|
||||
CreateDirectoryRequest::new(path)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<FetchWarrenRequest> for CreateWarrenDirectoryRequest {
|
||||
@@ -115,10 +146,23 @@ impl Into<FetchWarrenRequest> for CreateWarrenDirectoryRequest {
|
||||
}
|
||||
}
|
||||
|
||||
impl CreateWarrenDirectoryRequest {
|
||||
pub fn to_fs_request(self, warren: &Warren) -> CreateDirectoryRequest {
|
||||
let path = warren.path().clone().join(&self.path.to_relative());
|
||||
CreateDirectoryRequest::new(path)
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct CreateWarrenDirectoryResponse {
|
||||
warren: Warren,
|
||||
path: FilePath,
|
||||
}
|
||||
|
||||
impl CreateWarrenDirectoryResponse {
|
||||
pub fn new(warren: Warren, path: FilePath) -> Self {
|
||||
Self { warren, path }
|
||||
}
|
||||
|
||||
pub fn warren(&self) -> &Warren {
|
||||
&self.warren
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &FilePath {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +171,8 @@ pub enum CreateWarrenDirectoryError {
|
||||
#[error(transparent)]
|
||||
FileSystem(#[from] CreateDirectoryError),
|
||||
#[error(transparent)]
|
||||
FetchWarren(#[from] FetchWarrenError),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
@@ -170,11 +216,33 @@ impl Into<FetchWarrenRequest> for &DeleteWarrenDirectoryRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct DeleteWarrenDirectoryResponse {
|
||||
warren: Warren,
|
||||
path: FilePath,
|
||||
}
|
||||
|
||||
impl DeleteWarrenDirectoryResponse {
|
||||
pub fn new(warren: Warren, path: FilePath) -> Self {
|
||||
Self { warren, path }
|
||||
}
|
||||
|
||||
pub fn warren(&self) -> &Warren {
|
||||
&self.warren
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &FilePath {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DeleteWarrenDirectoryError {
|
||||
#[error(transparent)]
|
||||
FileSystem(#[from] DeleteDirectoryError),
|
||||
#[error(transparent)]
|
||||
FetchWarren(#[from] FetchWarrenError),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
@@ -209,11 +277,33 @@ impl Into<FetchWarrenRequest> for &DeleteWarrenFileRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct DeleteWarrenFileResponse {
|
||||
warren: Warren,
|
||||
path: FilePath,
|
||||
}
|
||||
|
||||
impl DeleteWarrenFileResponse {
|
||||
pub fn new(warren: Warren, path: FilePath) -> Self {
|
||||
Self { warren, path }
|
||||
}
|
||||
|
||||
pub fn warren(&self) -> &Warren {
|
||||
&self.warren
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &FilePath {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DeleteWarrenFileError {
|
||||
#[error(transparent)]
|
||||
FileSystem(#[from] DeleteFileError),
|
||||
#[error(transparent)]
|
||||
FetchWarren(#[from] FetchWarrenError),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
@@ -263,6 +353,26 @@ impl Into<FetchWarrenRequest> for &UploadWarrenFilesRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct UploadWarrenFilesResponse {
|
||||
warren: Warren,
|
||||
paths: Vec<FilePath>,
|
||||
}
|
||||
|
||||
impl UploadWarrenFilesResponse {
|
||||
pub fn new(warren: Warren, paths: Vec<FilePath>) -> Self {
|
||||
Self { warren, paths }
|
||||
}
|
||||
|
||||
pub fn warren(&self) -> &Warren {
|
||||
&self.warren
|
||||
}
|
||||
|
||||
pub fn paths(&self) -> &Vec<FilePath> {
|
||||
&self.paths
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum UploadWarrenFilesError {
|
||||
#[error("Failed to upload the file at index {fail_index}")]
|
||||
@@ -270,6 +380,8 @@ pub enum UploadWarrenFilesError {
|
||||
#[error(transparent)]
|
||||
FileSystem(#[from] CreateFileError),
|
||||
#[error(transparent)]
|
||||
FetchWarren(#[from] FetchWarrenError),
|
||||
#[error(transparent)]
|
||||
Unknown(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
@@ -352,10 +464,39 @@ impl Into<FetchWarrenRequest> for &RenameWarrenEntryRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct RenameWarrenEntryResponse {
|
||||
warren: Warren,
|
||||
old_path: AbsoluteFilePath,
|
||||
path: FilePath,
|
||||
}
|
||||
|
||||
impl RenameWarrenEntryResponse {
|
||||
pub fn new(warren: Warren, old_path: AbsoluteFilePath, path: FilePath) -> Self {
|
||||
Self {
|
||||
warren,
|
||||
old_path,
|
||||
path,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn warren(&self) -> &Warren {
|
||||
&self.warren
|
||||
}
|
||||
|
||||
pub fn old_path(&self) -> &AbsoluteFilePath {
|
||||
&self.old_path
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &FilePath {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RenameWarrenEntryError {
|
||||
#[error(transparent)]
|
||||
Fetch(#[from] FetchWarrenError),
|
||||
FetchWarren(#[from] FetchWarrenError),
|
||||
#[error(transparent)]
|
||||
Rename(#[from] RenameEntryError),
|
||||
#[error(transparent)]
|
||||
|
||||
@@ -61,4 +61,33 @@ pub trait AuthMetrics: Clone + Send + Sync + 'static {
|
||||
|
||||
fn record_auth_session_fetch_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_session_fetch_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn record_auth_fetch_user_warrens_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_fetch_user_warrens_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn record_auth_fetch_user_warren_list_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_fetch_user_warren_list_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn record_auth_warren_fetch_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_warren_fetch_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn record_auth_warren_file_list_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_warren_file_list_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn record_auth_warren_directory_creation_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_warren_directory_creation_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn record_auth_warren_directory_deletion_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_warren_directory_deletion_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
/// An upload succeeded fully
|
||||
fn record_auth_warren_files_upload_success(&self) -> impl Future<Output = ()> + Send;
|
||||
/// An upload failed at least partially
|
||||
fn record_auth_warren_files_upload_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn record_auth_warren_file_deletion_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_warren_file_deletion_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn record_auth_warren_entry_rename_success(&self) -> impl Future<Output = ()> + Send;
|
||||
fn record_auth_warren_entry_rename_failure(&self) -> impl Future<Output = ()> + Send;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ pub use repository::*;
|
||||
|
||||
use super::models::{
|
||||
auth_session::{
|
||||
AuthSession,
|
||||
AuthError, AuthRequest, AuthSession,
|
||||
requests::{
|
||||
CreateAuthSessionError, CreateAuthSessionRequest, FetchAuthSessionError,
|
||||
FetchAuthSessionRequest, FetchAuthSessionResponse,
|
||||
@@ -23,54 +23,62 @@ use super::models::{
|
||||
LoginUserError, LoginUserRequest, LoginUserResponse, RegisterUserError,
|
||||
RegisterUserRequest, User,
|
||||
},
|
||||
user_warren::{
|
||||
UserWarren,
|
||||
requests::{
|
||||
FetchUserWarrensError, FetchUserWarrensRequest, ListWarrensError, ListWarrensRequest,
|
||||
},
|
||||
},
|
||||
warren::{
|
||||
CreateWarrenDirectoryError, CreateWarrenDirectoryRequest, DeleteWarrenDirectoryError,
|
||||
DeleteWarrenDirectoryRequest, DeleteWarrenFileError, DeleteWarrenFileRequest,
|
||||
FetchWarrenError, FetchWarrenRequest, ListWarrenFilesError, ListWarrenFilesRequest,
|
||||
ListWarrensError, ListWarrensRequest, RenameWarrenEntryError, RenameWarrenEntryRequest,
|
||||
UploadWarrenFilesError, UploadWarrenFilesRequest, Warren,
|
||||
CreateWarrenDirectoryError, CreateWarrenDirectoryRequest, CreateWarrenDirectoryResponse,
|
||||
DeleteWarrenDirectoryError, DeleteWarrenDirectoryRequest, DeleteWarrenDirectoryResponse,
|
||||
DeleteWarrenFileError, DeleteWarrenFileRequest, DeleteWarrenFileResponse, FetchWarrenError,
|
||||
FetchWarrenRequest, FetchWarrensError, FetchWarrensRequest, ListWarrenFilesError,
|
||||
ListWarrenFilesRequest, ListWarrenFilesResponse, RenameWarrenEntryError,
|
||||
RenameWarrenEntryRequest, RenameWarrenEntryResponse, UploadWarrenFilesError,
|
||||
UploadWarrenFilesRequest, UploadWarrenFilesResponse, Warren,
|
||||
},
|
||||
};
|
||||
|
||||
pub trait WarrenService: Clone + Send + Sync + 'static {
|
||||
fn list_warrens(
|
||||
&self,
|
||||
request: ListWarrensRequest,
|
||||
) -> impl Future<Output = Result<Vec<Warren>, ListWarrensError>> + Send;
|
||||
request: FetchWarrensRequest,
|
||||
) -> impl Future<Output = Result<Vec<Warren>, FetchWarrensError>> + Send;
|
||||
|
||||
fn fetch_warren(
|
||||
&self,
|
||||
request: FetchWarrenRequest,
|
||||
) -> impl Future<Output = Result<Warren, FetchWarrenError>> + Send;
|
||||
|
||||
fn list_files(
|
||||
fn list_warren_files(
|
||||
&self,
|
||||
request: ListWarrenFilesRequest,
|
||||
) -> impl Future<Output = Result<Vec<File>, ListWarrenFilesError>> + Send;
|
||||
) -> impl Future<Output = Result<ListWarrenFilesResponse, ListWarrenFilesError>> + Send;
|
||||
|
||||
fn create_warren_directory(
|
||||
&self,
|
||||
request: CreateWarrenDirectoryRequest,
|
||||
) -> impl Future<Output = Result<FilePath, CreateWarrenDirectoryError>> + Send;
|
||||
) -> impl Future<Output = Result<CreateWarrenDirectoryResponse, CreateWarrenDirectoryError>> + Send;
|
||||
|
||||
fn delete_warren_directory(
|
||||
&self,
|
||||
request: DeleteWarrenDirectoryRequest,
|
||||
) -> impl Future<Output = Result<FilePath, DeleteWarrenDirectoryError>> + Send;
|
||||
) -> impl Future<Output = Result<DeleteWarrenDirectoryResponse, DeleteWarrenDirectoryError>> + Send;
|
||||
|
||||
fn upload_warren_files(
|
||||
&self,
|
||||
request: UploadWarrenFilesRequest,
|
||||
) -> impl Future<Output = Result<Vec<FilePath>, UploadWarrenFilesError>> + Send;
|
||||
) -> impl Future<Output = Result<UploadWarrenFilesResponse, UploadWarrenFilesError>> + Send;
|
||||
fn delete_warren_file(
|
||||
&self,
|
||||
request: DeleteWarrenFileRequest,
|
||||
) -> impl Future<Output = Result<FilePath, DeleteWarrenFileError>> + Send;
|
||||
) -> impl Future<Output = Result<DeleteWarrenFileResponse, DeleteWarrenFileError>> + Send;
|
||||
|
||||
fn rename_warren_entry(
|
||||
&self,
|
||||
request: RenameWarrenEntryRequest,
|
||||
) -> impl Future<Output = Result<FilePath, RenameWarrenEntryError>> + Send;
|
||||
) -> impl Future<Output = Result<RenameWarrenEntryResponse, RenameWarrenEntryError>> + Send;
|
||||
}
|
||||
|
||||
pub trait FileSystemService: Clone + Send + Sync + 'static {
|
||||
@@ -112,6 +120,7 @@ pub trait AuthService: Clone + Send + Sync + 'static {
|
||||
&self,
|
||||
request: LoginUserRequest,
|
||||
) -> impl Future<Output = Result<LoginUserResponse, LoginUserError>> + Send;
|
||||
|
||||
fn create_auth_session(
|
||||
&self,
|
||||
request: CreateAuthSessionRequest,
|
||||
@@ -120,4 +129,60 @@ pub trait AuthService: Clone + Send + Sync + 'static {
|
||||
&self,
|
||||
request: FetchAuthSessionRequest,
|
||||
) -> impl Future<Output = Result<FetchAuthSessionResponse, FetchAuthSessionError>> + Send;
|
||||
|
||||
fn list_warrens<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<ListWarrensRequest>,
|
||||
warren_service: &WS,
|
||||
) -> impl Future<Output = Result<Vec<Warren>, AuthError<ListWarrensError>>> + Send;
|
||||
|
||||
fn fetch_user_warrens(
|
||||
&self,
|
||||
request: FetchUserWarrensRequest,
|
||||
) -> impl Future<Output = Result<Vec<UserWarren>, FetchUserWarrensError>> + Send;
|
||||
|
||||
fn fetch_warren<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<FetchWarrenRequest>,
|
||||
warren_service: &WS,
|
||||
) -> impl Future<Output = Result<Warren, AuthError<FetchWarrenError>>> + Send;
|
||||
|
||||
fn list_warren_files<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<ListWarrenFilesRequest>,
|
||||
warren_service: &WS,
|
||||
) -> impl Future<Output = Result<ListWarrenFilesResponse, AuthError<ListWarrenFilesError>>> + Send;
|
||||
|
||||
fn create_warren_directory<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<CreateWarrenDirectoryRequest>,
|
||||
warren_service: &WS,
|
||||
) -> impl Future<
|
||||
Output = Result<CreateWarrenDirectoryResponse, AuthError<CreateWarrenDirectoryError>>,
|
||||
> + Send;
|
||||
|
||||
fn delete_warren_directory<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<DeleteWarrenDirectoryRequest>,
|
||||
warren_service: &WS,
|
||||
) -> impl Future<
|
||||
Output = Result<DeleteWarrenDirectoryResponse, AuthError<DeleteWarrenDirectoryError>>,
|
||||
> + Send;
|
||||
|
||||
fn upload_warren_files<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<UploadWarrenFilesRequest>,
|
||||
warren_service: &WS,
|
||||
) -> impl Future<Output = Result<UploadWarrenFilesResponse, AuthError<UploadWarrenFilesError>>> + Send;
|
||||
fn delete_warren_file<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<DeleteWarrenFileRequest>,
|
||||
warren_service: &WS,
|
||||
) -> impl Future<Output = Result<DeleteWarrenFileResponse, AuthError<DeleteWarrenFileError>>> + Send;
|
||||
|
||||
fn rename_warren_entry<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<RenameWarrenEntryRequest>,
|
||||
warren_service: &WS,
|
||||
) -> impl Future<Output = Result<RenameWarrenEntryResponse, AuthError<RenameWarrenEntryError>>> + Send;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,13 @@ use uuid::Uuid;
|
||||
|
||||
use crate::domain::warren::models::{
|
||||
auth_session::requests::FetchAuthSessionResponse,
|
||||
file::{AbsoluteFilePath, File, FilePath},
|
||||
file::{File, FilePath},
|
||||
user::{LoginUserResponse, User},
|
||||
warren::Warren,
|
||||
user_warren::UserWarren,
|
||||
warren::{
|
||||
CreateWarrenDirectoryResponse, DeleteWarrenDirectoryResponse, DeleteWarrenFileResponse,
|
||||
ListWarrenFilesResponse, RenameWarrenEntryResponse, UploadWarrenFilesResponse, Warren,
|
||||
},
|
||||
};
|
||||
|
||||
pub trait WarrenNotifier: Clone + Send + Sync + 'static {
|
||||
@@ -12,18 +16,15 @@ pub trait WarrenNotifier: Clone + Send + Sync + 'static {
|
||||
fn warren_fetched(&self, warren: &Warren) -> impl Future<Output = ()> + Send;
|
||||
fn warren_files_listed(
|
||||
&self,
|
||||
warren: &Warren,
|
||||
files: &Vec<File>,
|
||||
response: &ListWarrenFilesResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
fn warren_directory_created(
|
||||
&self,
|
||||
warren: &Warren,
|
||||
path: &FilePath,
|
||||
response: &CreateWarrenDirectoryResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
fn warren_directory_deleted(
|
||||
&self,
|
||||
warren: &Warren,
|
||||
path: &FilePath,
|
||||
response: &DeleteWarrenDirectoryResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
/// A single file was uploaded
|
||||
///
|
||||
@@ -40,20 +41,16 @@ pub trait WarrenNotifier: Clone + Send + Sync + 'static {
|
||||
/// * `files`: The files' paths
|
||||
fn warren_files_uploaded(
|
||||
&self,
|
||||
warren: &Warren,
|
||||
files: &[FilePath],
|
||||
response: &UploadWarrenFilesResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
fn warren_file_deleted(
|
||||
&self,
|
||||
warren: &Warren,
|
||||
path: &FilePath,
|
||||
response: &DeleteWarrenFileResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn warren_entry_renamed(
|
||||
&self,
|
||||
warren: &Warren,
|
||||
old_path: &AbsoluteFilePath,
|
||||
new_path: &FilePath,
|
||||
response: &RenameWarrenEntryResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
}
|
||||
|
||||
@@ -81,4 +78,52 @@ pub trait AuthNotifier: Clone + Send + Sync + 'static {
|
||||
&self,
|
||||
response: &FetchAuthSessionResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn auth_user_warrens_listed(
|
||||
&self,
|
||||
user: &User,
|
||||
warrens: &Vec<Warren>,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
fn auth_user_warrens_fetched(
|
||||
&self,
|
||||
user_id: &Uuid,
|
||||
user_warrens: &Vec<UserWarren>,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn auth_warren_fetched(&self, user: &User, warren: &Warren) -> impl Future<Output = ()> + Send;
|
||||
fn auth_warren_files_listed(
|
||||
&self,
|
||||
user: &User,
|
||||
response: &ListWarrenFilesResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
fn auth_warren_directory_created(
|
||||
&self,
|
||||
user: &User,
|
||||
response: &CreateWarrenDirectoryResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
fn auth_warren_directory_deleted(
|
||||
&self,
|
||||
user: &User,
|
||||
response: &DeleteWarrenDirectoryResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
/// A collection of files was uploaded
|
||||
///
|
||||
/// * `warren`: The warren the file was uploaded to
|
||||
/// * `files`: The files' paths
|
||||
fn auth_warren_files_uploaded(
|
||||
&self,
|
||||
user: &User,
|
||||
response: &UploadWarrenFilesResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
fn auth_warren_file_deleted(
|
||||
&self,
|
||||
user: &User,
|
||||
response: &DeleteWarrenFileResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
|
||||
fn auth_warren_entry_renamed(
|
||||
&self,
|
||||
user: &User,
|
||||
response: &RenameWarrenEntryResponse,
|
||||
) -> impl Future<Output = ()> + Send;
|
||||
}
|
||||
|
||||
@@ -15,14 +15,23 @@ use crate::domain::warren::models::{
|
||||
RegisterUserError, RegisterUserRequest, User, VerifyUserPasswordError,
|
||||
VerifyUserPasswordRequest,
|
||||
},
|
||||
warren::{FetchWarrenError, FetchWarrenRequest, ListWarrensError, ListWarrensRequest, Warren},
|
||||
user_warren::{
|
||||
UserWarren,
|
||||
requests::{
|
||||
FetchUserWarrenError, FetchUserWarrenRequest, FetchUserWarrensError,
|
||||
FetchUserWarrensRequest,
|
||||
},
|
||||
},
|
||||
warren::{
|
||||
FetchWarrenError, FetchWarrenRequest, FetchWarrensError, FetchWarrensRequest, Warren,
|
||||
},
|
||||
};
|
||||
|
||||
pub trait WarrenRepository: Clone + Send + Sync + 'static {
|
||||
fn list_warrens(
|
||||
&self,
|
||||
request: ListWarrensRequest,
|
||||
) -> impl Future<Output = Result<Vec<Warren>, ListWarrensError>> + Send;
|
||||
request: FetchWarrensRequest,
|
||||
) -> impl Future<Output = Result<Vec<Warren>, FetchWarrensError>> + Send;
|
||||
|
||||
fn fetch_warren(
|
||||
&self,
|
||||
@@ -77,4 +86,12 @@ pub trait AuthRepository: Clone + Send + Sync + 'static {
|
||||
&self,
|
||||
request: FetchAuthSessionRequest,
|
||||
) -> impl Future<Output = Result<FetchAuthSessionResponse, FetchAuthSessionError>> + Send;
|
||||
fn fetch_user_warrens(
|
||||
&self,
|
||||
request: FetchUserWarrensRequest,
|
||||
) -> impl Future<Output = Result<Vec<UserWarren>, FetchUserWarrensError>> + Send;
|
||||
fn fetch_user_warren(
|
||||
&self,
|
||||
request: FetchUserWarrenRequest,
|
||||
) -> impl Future<Output = Result<UserWarren, FetchUserWarrenError>> + Send;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{
|
||||
domain::warren::{
|
||||
models::{
|
||||
auth_session::{
|
||||
AuthSession,
|
||||
AuthError, AuthRequest, AuthSession,
|
||||
requests::{
|
||||
CreateAuthSessionError, CreateAuthSessionRequest, FetchAuthSessionError,
|
||||
FetchAuthSessionRequest, FetchAuthSessionResponse, SessionExpirationTime,
|
||||
@@ -13,8 +13,25 @@ use crate::{
|
||||
LoginUserError, LoginUserRequest, LoginUserResponse, RegisterUserError,
|
||||
RegisterUserRequest, User,
|
||||
},
|
||||
user_warren::{
|
||||
UserWarren,
|
||||
requests::{
|
||||
FetchUserWarrenRequest, FetchUserWarrensError, FetchUserWarrensRequest,
|
||||
ListWarrensError, ListWarrensRequest,
|
||||
},
|
||||
},
|
||||
warren::{
|
||||
CreateWarrenDirectoryError, CreateWarrenDirectoryRequest,
|
||||
CreateWarrenDirectoryResponse, DeleteWarrenDirectoryError,
|
||||
DeleteWarrenDirectoryRequest, DeleteWarrenDirectoryResponse, DeleteWarrenFileError,
|
||||
DeleteWarrenFileRequest, DeleteWarrenFileResponse, FetchWarrenError,
|
||||
FetchWarrenRequest, FetchWarrensRequest, ListWarrenFilesError,
|
||||
ListWarrenFilesRequest, ListWarrenFilesResponse, RenameWarrenEntryError,
|
||||
RenameWarrenEntryRequest, RenameWarrenEntryResponse, UploadWarrenFilesError,
|
||||
UploadWarrenFilesRequest, UploadWarrenFilesResponse, Warren,
|
||||
},
|
||||
},
|
||||
ports::{AuthMetrics, AuthNotifier, AuthRepository, AuthService},
|
||||
ports::{AuthMetrics, AuthNotifier, AuthRepository, AuthService, WarrenService},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -153,4 +170,310 @@ where
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
async fn fetch_warren<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<FetchWarrenRequest>,
|
||||
warren_service: &WS,
|
||||
) -> Result<Warren, AuthError<FetchWarrenError>> {
|
||||
let (session, request) = request.unpack();
|
||||
|
||||
let response = self
|
||||
.fetch_auth_session(FetchAuthSessionRequest::new(session.session_id().clone()))
|
||||
.await?;
|
||||
|
||||
let result = warren_service.fetch_warren(request).await;
|
||||
|
||||
if let Ok(result) = result.as_ref() {
|
||||
self.metrics.record_auth_warren_fetch_success().await;
|
||||
self.notifier
|
||||
.auth_warren_fetched(response.user(), result)
|
||||
.await;
|
||||
} else {
|
||||
self.metrics.record_auth_warren_fetch_failure().await;
|
||||
}
|
||||
|
||||
result.map_err(AuthError::Custom)
|
||||
}
|
||||
|
||||
async fn fetch_user_warrens(
|
||||
&self,
|
||||
request: FetchUserWarrensRequest,
|
||||
) -> Result<Vec<UserWarren>, FetchUserWarrensError> {
|
||||
let user_id = request.user_id().clone();
|
||||
let result = self.repository.fetch_user_warrens(request).await;
|
||||
|
||||
if let Ok(warren_ids) = result.as_ref() {
|
||||
self.metrics.record_auth_fetch_user_warrens_success().await;
|
||||
self.notifier
|
||||
.auth_user_warrens_fetched(&user_id, warren_ids)
|
||||
.await;
|
||||
} else {
|
||||
self.metrics.record_auth_fetch_user_warrens_failure().await;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
async fn list_warrens<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<ListWarrensRequest>,
|
||||
warren_service: &WS,
|
||||
) -> Result<Vec<Warren>, AuthError<ListWarrensError>> {
|
||||
let (session, _) = request.unpack();
|
||||
|
||||
let session_response = self
|
||||
.fetch_auth_session(FetchAuthSessionRequest::new(session.session_id().clone()))
|
||||
.await?;
|
||||
|
||||
let ids = self
|
||||
.repository
|
||||
.fetch_user_warrens(FetchUserWarrensRequest::new(*session_response.user().id()))
|
||||
.await
|
||||
.map_err(|e| AuthError::Custom(e.into()))?;
|
||||
|
||||
let result = warren_service
|
||||
.list_warrens(FetchWarrensRequest::new(
|
||||
ids.into_iter().map(|uw| uw.into_warren_id()).collect(),
|
||||
))
|
||||
.await;
|
||||
|
||||
result.map_err(|e| AuthError::Custom(e.into()))
|
||||
}
|
||||
|
||||
async fn list_warren_files<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<ListWarrenFilesRequest>,
|
||||
warren_service: &WS,
|
||||
) -> Result<ListWarrenFilesResponse, AuthError<ListWarrenFilesError>> {
|
||||
let (session, request) = request.unpack();
|
||||
|
||||
let session_response = self
|
||||
.fetch_auth_session(FetchAuthSessionRequest::new(session.session_id().clone()))
|
||||
.await?;
|
||||
|
||||
let user_warren = self
|
||||
.repository
|
||||
.fetch_user_warren(FetchUserWarrenRequest::new(
|
||||
session_response.user().id().clone(),
|
||||
request.warren_id().clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
if !user_warren.can_list_files() {
|
||||
return Err(AuthError::InsufficientPermissions);
|
||||
}
|
||||
|
||||
let result = warren_service.list_warren_files(request).await;
|
||||
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics.record_auth_warren_file_list_success().await;
|
||||
self.notifier
|
||||
.auth_warren_files_listed(session_response.user(), response)
|
||||
.await;
|
||||
} else {
|
||||
self.metrics.record_auth_warren_file_list_failure().await;
|
||||
}
|
||||
|
||||
result.map_err(AuthError::Custom)
|
||||
}
|
||||
|
||||
async fn rename_warren_entry<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<RenameWarrenEntryRequest>,
|
||||
warren_service: &WS,
|
||||
) -> Result<RenameWarrenEntryResponse, AuthError<RenameWarrenEntryError>> {
|
||||
let (session, request) = request.unpack();
|
||||
|
||||
let session_response = self
|
||||
.fetch_auth_session(FetchAuthSessionRequest::new(session.session_id().clone()))
|
||||
.await?;
|
||||
|
||||
let user_warren = self
|
||||
.repository
|
||||
.fetch_user_warren(FetchUserWarrenRequest::new(
|
||||
session_response.user().id().clone(),
|
||||
request.warren_id().clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
if !user_warren.can_modify_files() {
|
||||
return Err(AuthError::InsufficientPermissions);
|
||||
}
|
||||
|
||||
let result = warren_service.rename_warren_entry(request).await;
|
||||
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics.record_auth_warren_entry_rename_success().await;
|
||||
self.notifier
|
||||
.auth_warren_entry_renamed(session_response.user(), response)
|
||||
.await;
|
||||
} else {
|
||||
self.metrics.record_auth_warren_entry_rename_failure().await;
|
||||
}
|
||||
|
||||
result.map_err(AuthError::Custom)
|
||||
}
|
||||
|
||||
async fn create_warren_directory<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<CreateWarrenDirectoryRequest>,
|
||||
warren_service: &WS,
|
||||
) -> Result<CreateWarrenDirectoryResponse, AuthError<CreateWarrenDirectoryError>> {
|
||||
let (session, request) = request.unpack();
|
||||
|
||||
let session_response = self
|
||||
.fetch_auth_session(FetchAuthSessionRequest::new(session.session_id().clone()))
|
||||
.await?;
|
||||
|
||||
let user_warren = self
|
||||
.repository
|
||||
.fetch_user_warren(FetchUserWarrenRequest::new(
|
||||
session_response.user().id().clone(),
|
||||
request.warren_id().clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
// TODO: Maybe create a separate permission for this
|
||||
if !user_warren.can_modify_files() {
|
||||
return Err(AuthError::InsufficientPermissions);
|
||||
}
|
||||
|
||||
let result = warren_service.create_warren_directory(request).await;
|
||||
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics
|
||||
.record_auth_warren_directory_creation_success()
|
||||
.await;
|
||||
self.notifier
|
||||
.auth_warren_directory_created(session_response.user(), response)
|
||||
.await;
|
||||
} else {
|
||||
self.metrics
|
||||
.record_auth_warren_directory_creation_failure()
|
||||
.await;
|
||||
}
|
||||
|
||||
result.map_err(AuthError::Custom)
|
||||
}
|
||||
|
||||
async fn delete_warren_file<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<DeleteWarrenFileRequest>,
|
||||
warren_service: &WS,
|
||||
) -> Result<DeleteWarrenFileResponse, AuthError<DeleteWarrenFileError>> {
|
||||
let (session, request) = request.unpack();
|
||||
|
||||
let session_response = self
|
||||
.fetch_auth_session(FetchAuthSessionRequest::new(session.session_id().clone()))
|
||||
.await?;
|
||||
|
||||
let user_warren = self
|
||||
.repository
|
||||
.fetch_user_warren(FetchUserWarrenRequest::new(
|
||||
session_response.user().id().clone(),
|
||||
request.warren_id().clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
if !user_warren.can_delete_files() {
|
||||
return Err(AuthError::InsufficientPermissions);
|
||||
}
|
||||
|
||||
let result = warren_service.delete_warren_file(request).await;
|
||||
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics
|
||||
.record_auth_warren_file_deletion_success()
|
||||
.await;
|
||||
self.notifier
|
||||
.auth_warren_file_deleted(session_response.user(), response)
|
||||
.await;
|
||||
} else {
|
||||
self.metrics
|
||||
.record_auth_warren_file_deletion_failure()
|
||||
.await;
|
||||
}
|
||||
|
||||
result.map_err(AuthError::Custom)
|
||||
}
|
||||
|
||||
async fn delete_warren_directory<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<DeleteWarrenDirectoryRequest>,
|
||||
warren_service: &WS,
|
||||
) -> Result<DeleteWarrenDirectoryResponse, AuthError<DeleteWarrenDirectoryError>> {
|
||||
let (session, request) = request.unpack();
|
||||
|
||||
let session_response = self
|
||||
.fetch_auth_session(FetchAuthSessionRequest::new(session.session_id().clone()))
|
||||
.await?;
|
||||
|
||||
let user_warren = self
|
||||
.repository
|
||||
.fetch_user_warren(FetchUserWarrenRequest::new(
|
||||
session_response.user().id().clone(),
|
||||
request.warren_id().clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
if !user_warren.can_delete_files() {
|
||||
return Err(AuthError::InsufficientPermissions);
|
||||
}
|
||||
|
||||
let result = warren_service.delete_warren_directory(request).await;
|
||||
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics
|
||||
.record_auth_warren_directory_deletion_success()
|
||||
.await;
|
||||
self.notifier
|
||||
.auth_warren_directory_deleted(session_response.user(), response)
|
||||
.await;
|
||||
} else {
|
||||
self.metrics
|
||||
.record_auth_warren_directory_deletion_failure()
|
||||
.await;
|
||||
}
|
||||
|
||||
result.map_err(AuthError::Custom)
|
||||
}
|
||||
|
||||
async fn upload_warren_files<WS: WarrenService>(
|
||||
&self,
|
||||
request: AuthRequest<UploadWarrenFilesRequest>,
|
||||
warren_service: &WS,
|
||||
) -> Result<UploadWarrenFilesResponse, AuthError<UploadWarrenFilesError>> {
|
||||
let (session, request) = request.unpack();
|
||||
|
||||
let session_response = self
|
||||
.fetch_auth_session(FetchAuthSessionRequest::new(session.session_id().clone()))
|
||||
.await?;
|
||||
|
||||
let user_warren = self
|
||||
.repository
|
||||
.fetch_user_warren(FetchUserWarrenRequest::new(
|
||||
session_response.user().id().clone(),
|
||||
request.warren_id().clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
// TODO: Maybe create a separate permission for this
|
||||
if !user_warren.can_modify_files() {
|
||||
return Err(AuthError::InsufficientPermissions);
|
||||
}
|
||||
|
||||
let result = warren_service.upload_warren_files(request).await;
|
||||
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics.record_auth_warren_files_upload_success().await;
|
||||
self.notifier
|
||||
.auth_warren_files_uploaded(session_response.user(), response)
|
||||
.await;
|
||||
} else {
|
||||
self.metrics.record_auth_warren_files_upload_failure().await;
|
||||
}
|
||||
|
||||
result.map_err(AuthError::Custom)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use anyhow::Context;
|
||||
|
||||
use crate::domain::warren::{
|
||||
models::{
|
||||
file::{File, FilePath},
|
||||
warren::{
|
||||
ListWarrensError, ListWarrensRequest, RenameWarrenEntryError, RenameWarrenEntryRequest,
|
||||
},
|
||||
models::warren::{
|
||||
CreateWarrenDirectoryResponse, DeleteWarrenDirectoryResponse, DeleteWarrenFileResponse,
|
||||
FetchWarrensError, FetchWarrensRequest, ListWarrenFilesResponse, RenameWarrenEntryError,
|
||||
RenameWarrenEntryRequest, RenameWarrenEntryResponse, UploadWarrenFilesResponse,
|
||||
},
|
||||
ports::FileSystemService,
|
||||
};
|
||||
@@ -60,8 +57,8 @@ where
|
||||
{
|
||||
async fn list_warrens(
|
||||
&self,
|
||||
request: ListWarrensRequest,
|
||||
) -> Result<Vec<Warren>, ListWarrensError> {
|
||||
request: FetchWarrensRequest,
|
||||
) -> Result<Vec<Warren>, FetchWarrensError> {
|
||||
let result = self.repository.list_warrens(request).await;
|
||||
|
||||
if let Ok(warren) = result.as_ref() {
|
||||
@@ -87,24 +84,21 @@ where
|
||||
result
|
||||
}
|
||||
|
||||
async fn list_files(
|
||||
async fn list_warren_files(
|
||||
&self,
|
||||
request: ListWarrenFilesRequest,
|
||||
) -> Result<Vec<File>, ListWarrenFilesError> {
|
||||
let warren = self
|
||||
.repository
|
||||
.fetch_warren(request.clone().into())
|
||||
.await
|
||||
.context("Failed to fetch warren")?;
|
||||
) -> Result<ListWarrenFilesResponse, ListWarrenFilesError> {
|
||||
let warren = self.repository.fetch_warren(request.clone().into()).await?;
|
||||
|
||||
let result = self
|
||||
.fs_service
|
||||
.list_files(request.to_fs_request(&warren))
|
||||
.await;
|
||||
.await
|
||||
.map(|files| ListWarrenFilesResponse::new(warren, files));
|
||||
|
||||
if let Ok(files) = result.as_ref() {
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics.record_list_warren_files_success().await;
|
||||
self.notifier.warren_files_listed(&warren, files).await;
|
||||
self.notifier.warren_files_listed(response).await;
|
||||
} else {
|
||||
self.metrics.record_list_warren_files_failure().await;
|
||||
}
|
||||
@@ -115,23 +109,20 @@ where
|
||||
async fn create_warren_directory(
|
||||
&self,
|
||||
request: CreateWarrenDirectoryRequest,
|
||||
) -> Result<FilePath, CreateWarrenDirectoryError> {
|
||||
let warren = self
|
||||
.repository
|
||||
.fetch_warren(request.clone().into())
|
||||
.await
|
||||
.context("Failed to fetch warren")?;
|
||||
) -> Result<CreateWarrenDirectoryResponse, CreateWarrenDirectoryError> {
|
||||
let warren = self.repository.fetch_warren(request.clone().into()).await?;
|
||||
|
||||
let result = self
|
||||
.fs_service
|
||||
.create_directory(request.to_fs_request(&warren))
|
||||
.await;
|
||||
.await
|
||||
.map(|path| CreateWarrenDirectoryResponse::new(warren, path));
|
||||
|
||||
if let Ok(path) = result.as_ref() {
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics
|
||||
.record_warren_directory_creation_success()
|
||||
.await;
|
||||
self.notifier.warren_directory_created(&warren, path).await;
|
||||
self.notifier.warren_directory_created(response).await;
|
||||
} else {
|
||||
self.metrics
|
||||
.record_warren_directory_creation_failure()
|
||||
@@ -144,23 +135,20 @@ where
|
||||
async fn delete_warren_directory(
|
||||
&self,
|
||||
request: DeleteWarrenDirectoryRequest,
|
||||
) -> Result<FilePath, DeleteWarrenDirectoryError> {
|
||||
let warren = self
|
||||
.repository
|
||||
.fetch_warren((&request).into())
|
||||
.await
|
||||
.context("Failed to fetch warren")?;
|
||||
) -> Result<DeleteWarrenDirectoryResponse, DeleteWarrenDirectoryError> {
|
||||
let warren = self.repository.fetch_warren((&request).into()).await?;
|
||||
|
||||
let result = self
|
||||
.fs_service
|
||||
.delete_directory(request.to_fs_request(&warren))
|
||||
.await;
|
||||
.await
|
||||
.map(|path| DeleteWarrenDirectoryResponse::new(warren, path));
|
||||
|
||||
if let Ok(path) = result.as_ref() {
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics
|
||||
.record_warren_directory_deletion_success()
|
||||
.await;
|
||||
self.notifier.warren_directory_deleted(&warren, path).await;
|
||||
self.notifier.warren_directory_deleted(response).await;
|
||||
} else {
|
||||
self.metrics
|
||||
.record_warren_directory_deletion_failure()
|
||||
@@ -174,12 +162,8 @@ where
|
||||
async fn upload_warren_files(
|
||||
&self,
|
||||
request: UploadWarrenFilesRequest,
|
||||
) -> Result<Vec<FilePath>, UploadWarrenFilesError> {
|
||||
let warren = self
|
||||
.repository
|
||||
.fetch_warren((&request).into())
|
||||
.await
|
||||
.context("Failed to fetch warren")?;
|
||||
) -> Result<UploadWarrenFilesResponse, UploadWarrenFilesError> {
|
||||
let warren = self.repository.fetch_warren((&request).into()).await?;
|
||||
|
||||
let fs_requests = request.to_fs_requests(&warren);
|
||||
|
||||
@@ -202,30 +186,29 @@ where
|
||||
paths.push(file_path);
|
||||
}
|
||||
|
||||
self.metrics.record_warren_files_upload_success().await;
|
||||
self.notifier.warren_files_uploaded(&warren, &paths).await;
|
||||
let response = UploadWarrenFilesResponse::new(warren, paths);
|
||||
|
||||
Ok(paths)
|
||||
self.metrics.record_warren_files_upload_success().await;
|
||||
self.notifier.warren_files_uploaded(&response).await;
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn delete_warren_file(
|
||||
&self,
|
||||
request: DeleteWarrenFileRequest,
|
||||
) -> Result<FilePath, DeleteWarrenFileError> {
|
||||
let warren = self
|
||||
.repository
|
||||
.fetch_warren((&request).into())
|
||||
.await
|
||||
.context("Failed to fetch warren")?;
|
||||
) -> Result<DeleteWarrenFileResponse, DeleteWarrenFileError> {
|
||||
let warren = self.repository.fetch_warren((&request).into()).await?;
|
||||
|
||||
let result = self
|
||||
.fs_service
|
||||
.delete_file(request.to_fs_request(&warren))
|
||||
.await;
|
||||
.await
|
||||
.map(|path| DeleteWarrenFileResponse::new(warren, path));
|
||||
|
||||
if let Ok(path) = result.as_ref() {
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics.record_warren_file_deletion_success().await;
|
||||
self.notifier.warren_file_deleted(&warren, path).await;
|
||||
self.notifier.warren_file_deleted(response).await;
|
||||
} else {
|
||||
self.metrics.record_warren_file_deletion_failure().await;
|
||||
}
|
||||
@@ -236,20 +219,19 @@ where
|
||||
async fn rename_warren_entry(
|
||||
&self,
|
||||
request: RenameWarrenEntryRequest,
|
||||
) -> Result<FilePath, RenameWarrenEntryError> {
|
||||
) -> Result<RenameWarrenEntryResponse, RenameWarrenEntryError> {
|
||||
let warren = self.repository.fetch_warren((&request).into()).await?;
|
||||
|
||||
let old_path = request.path().clone();
|
||||
let result = self
|
||||
.fs_service
|
||||
.rename_entry(request.to_fs_request(&warren))
|
||||
.await;
|
||||
.await
|
||||
.map(|new_path| RenameWarrenEntryResponse::new(warren, old_path, new_path));
|
||||
|
||||
if let Ok(new_path) = result.as_ref() {
|
||||
if let Ok(response) = result.as_ref() {
|
||||
self.metrics.record_warren_entry_rename_success().await;
|
||||
self.notifier
|
||||
.warren_entry_renamed(&warren, &old_path, new_path)
|
||||
.await;
|
||||
self.notifier.warren_entry_renamed(response).await;
|
||||
} else {
|
||||
self.metrics.record_warren_entry_rename_failure().await;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use crate::{
|
||||
domain::warren::models::{
|
||||
auth_session::requests::FetchAuthSessionError,
|
||||
auth_session::{AuthError, requests::FetchAuthSessionError},
|
||||
file::{CreateDirectoryError, DeleteDirectoryError, DeleteFileError, ListFilesError},
|
||||
user::{LoginUserError, RegisterUserError, VerifyUserPasswordError},
|
||||
user_warren::requests::FetchUserWarrenError,
|
||||
warren::{
|
||||
CreateWarrenDirectoryError, DeleteWarrenDirectoryError, DeleteWarrenFileError,
|
||||
FetchWarrenError, ListWarrenFilesError, ListWarrensError, RenameWarrenEntryError,
|
||||
FetchWarrenError, FetchWarrensError, ListWarrenFilesError, RenameWarrenEntryError,
|
||||
UploadWarrenFilesError,
|
||||
},
|
||||
},
|
||||
@@ -32,6 +33,7 @@ impl From<CreateWarrenDirectoryError> for ApiError {
|
||||
fn from(value: CreateWarrenDirectoryError) -> Self {
|
||||
match value {
|
||||
CreateWarrenDirectoryError::FileSystem(fs) => fs.into(),
|
||||
CreateWarrenDirectoryError::FetchWarren(err) => err.into(),
|
||||
CreateWarrenDirectoryError::Unknown(error) => {
|
||||
Self::InternalServerError(error.to_string())
|
||||
}
|
||||
@@ -57,6 +59,7 @@ impl From<DeleteWarrenDirectoryError> for ApiError {
|
||||
fn from(value: DeleteWarrenDirectoryError) -> Self {
|
||||
match value {
|
||||
DeleteWarrenDirectoryError::FileSystem(fs) => fs.into(),
|
||||
DeleteWarrenDirectoryError::FetchWarren(err) => err.into(),
|
||||
DeleteWarrenDirectoryError::Unknown(error) => {
|
||||
Self::InternalServerError(error.to_string())
|
||||
}
|
||||
@@ -74,6 +77,7 @@ impl From<DeleteWarrenFileError> for ApiError {
|
||||
fn from(value: DeleteWarrenFileError) -> Self {
|
||||
match value {
|
||||
DeleteWarrenFileError::FileSystem(fs) => fs.into(),
|
||||
DeleteWarrenFileError::FetchWarren(err) => err.into(),
|
||||
DeleteWarrenFileError::Unknown(error) => Self::InternalServerError(error.to_string()),
|
||||
}
|
||||
}
|
||||
@@ -105,13 +109,14 @@ impl From<ListWarrenFilesError> for ApiError {
|
||||
fn from(value: ListWarrenFilesError) -> Self {
|
||||
match value {
|
||||
ListWarrenFilesError::FileSystem(fs_error) => fs_error.into(),
|
||||
ListWarrenFilesError::FetchWarren(err) => err.into(),
|
||||
ListWarrenFilesError::Unknown(error) => Self::InternalServerError(error.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ListWarrensError> for ApiError {
|
||||
fn from(error: ListWarrensError) -> Self {
|
||||
impl From<FetchWarrensError> for ApiError {
|
||||
fn from(error: FetchWarrensError) -> Self {
|
||||
Self::InternalServerError(error.to_string())
|
||||
}
|
||||
}
|
||||
@@ -167,3 +172,28 @@ impl From<FetchAuthSessionError> for ApiError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FetchUserWarrenError> for ApiError {
|
||||
fn from(value: FetchUserWarrenError) -> Self {
|
||||
match value {
|
||||
FetchUserWarrenError::NotFound => {
|
||||
Self::NotFound("Could not find the requested warren".to_string())
|
||||
}
|
||||
FetchUserWarrenError::Unknown(err) => Self::InternalServerError(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::error::Error> From<AuthError<T>> for ApiError {
|
||||
fn from(value: AuthError<T>) -> Self {
|
||||
match value {
|
||||
AuthError::InsufficientPermissions => {
|
||||
Self::Unauthorized("Insufficient permissions".to_string())
|
||||
}
|
||||
AuthError::FetchAuthSession(err) => err.into(),
|
||||
AuthError::FetchUserWarren(err) => err.into(),
|
||||
AuthError::Custom(err) => Self::InternalServerError(err.to_string()),
|
||||
AuthError::Unknown(err) => Self::InternalServerError(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
backend/src/lib/inbound/http/handlers/extractors.rs
Normal file
35
backend/src/lib/inbound/http/handlers/extractors.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use axum::{
|
||||
extract::FromRequestParts,
|
||||
http::{header::AUTHORIZATION, request::Parts},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
domain::warren::models::auth_session::AuthSessionIdWithType, inbound::http::responses::ApiError,
|
||||
};
|
||||
|
||||
pub struct SessionIdHeader(pub AuthSessionIdWithType);
|
||||
|
||||
impl<S> FromRequestParts<S> for SessionIdHeader
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = ApiError;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let Some(header) = parts.headers.get(AUTHORIZATION) else {
|
||||
return Err(ApiError::Unauthorized(
|
||||
"Missing authorization header".to_string(),
|
||||
));
|
||||
};
|
||||
|
||||
let header_str = header.to_str().map_err(|_| {
|
||||
ApiError::InternalServerError(
|
||||
"Failed to get authorization header as string".to_string(),
|
||||
)
|
||||
})?;
|
||||
|
||||
AuthSessionIdWithType::from_str(header_str)
|
||||
.map(|session_id| SessionIdHeader(session_id))
|
||||
.map_err(|_| ApiError::BadRequest("Invalid session id".to_string()))
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ use uuid::Uuid;
|
||||
use crate::domain::warren::models::user::User;
|
||||
|
||||
pub mod auth;
|
||||
pub mod extractors;
|
||||
pub mod warrens;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
|
||||
@@ -6,6 +6,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
domain::warren::{
|
||||
models::{
|
||||
auth_session::AuthRequest,
|
||||
file::{AbsoluteFilePathError, FilePath, FilePathError},
|
||||
warren::CreateWarrenDirectoryRequest,
|
||||
},
|
||||
@@ -13,6 +14,7 @@ use crate::{
|
||||
},
|
||||
inbound::http::{
|
||||
AppState,
|
||||
handlers::extractors::SessionIdHeader,
|
||||
responses::{ApiError, ApiSuccess},
|
||||
},
|
||||
};
|
||||
@@ -64,13 +66,14 @@ impl CreateWarrenDirectoryHttpRequestBody {
|
||||
|
||||
pub async fn create_warren_directory<WS: WarrenService, AS: AuthService>(
|
||||
State(state): State<AppState<WS, AS>>,
|
||||
SessionIdHeader(session): SessionIdHeader,
|
||||
Json(request): Json<CreateWarrenDirectoryHttpRequestBody>,
|
||||
) -> Result<ApiSuccess<()>, ApiError> {
|
||||
let domain_request = request.try_into_domain()?;
|
||||
let domain_request = AuthRequest::new(session, request.try_into_domain()?);
|
||||
|
||||
state
|
||||
.warren_service
|
||||
.create_warren_directory(domain_request)
|
||||
.auth_service
|
||||
.create_warren_directory(domain_request, state.warren_service.as_ref())
|
||||
.await
|
||||
.map(|_| ApiSuccess::new(StatusCode::CREATED, ()))
|
||||
.map_err(ApiError::from)
|
||||
|
||||
@@ -6,6 +6,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
domain::warren::{
|
||||
models::{
|
||||
auth_session::AuthRequest,
|
||||
file::{AbsoluteFilePathError, FilePath, FilePathError},
|
||||
warren::DeleteWarrenDirectoryRequest,
|
||||
},
|
||||
@@ -13,6 +14,7 @@ use crate::{
|
||||
},
|
||||
inbound::http::{
|
||||
AppState,
|
||||
handlers::extractors::SessionIdHeader,
|
||||
responses::{ApiError, ApiSuccess},
|
||||
},
|
||||
};
|
||||
@@ -66,13 +68,14 @@ impl DeleteWarrenDirectoryHttpRequestBody {
|
||||
|
||||
pub async fn delete_warren_directory<WS: WarrenService, AS: AuthService>(
|
||||
State(state): State<AppState<WS, AS>>,
|
||||
SessionIdHeader(session): SessionIdHeader,
|
||||
Json(request): Json<DeleteWarrenDirectoryHttpRequestBody>,
|
||||
) -> Result<ApiSuccess<()>, ApiError> {
|
||||
let domain_request = request.try_into_domain()?;
|
||||
let domain_request = AuthRequest::new(session, request.try_into_domain()?);
|
||||
|
||||
state
|
||||
.warren_service
|
||||
.delete_warren_directory(domain_request)
|
||||
.auth_service
|
||||
.delete_warren_directory(domain_request, state.warren_service.as_ref())
|
||||
.await
|
||||
.map(|_| ApiSuccess::new(StatusCode::CREATED, ()))
|
||||
.map_err(ApiError::from)
|
||||
|
||||
@@ -6,6 +6,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
domain::warren::{
|
||||
models::{
|
||||
auth_session::AuthRequest,
|
||||
file::{AbsoluteFilePathError, FilePath, FilePathError},
|
||||
warren::DeleteWarrenFileRequest,
|
||||
},
|
||||
@@ -13,6 +14,7 @@ use crate::{
|
||||
},
|
||||
inbound::http::{
|
||||
AppState,
|
||||
handlers::extractors::SessionIdHeader,
|
||||
responses::{ApiError, ApiSuccess},
|
||||
},
|
||||
};
|
||||
@@ -64,13 +66,14 @@ impl DeleteWarrenFileHttpRequestBody {
|
||||
|
||||
pub async fn delete_warren_file<WS: WarrenService, AS: AuthService>(
|
||||
State(state): State<AppState<WS, AS>>,
|
||||
SessionIdHeader(session): SessionIdHeader,
|
||||
Json(request): Json<DeleteWarrenFileHttpRequestBody>,
|
||||
) -> Result<ApiSuccess<()>, ApiError> {
|
||||
let domain_request = request.try_into_domain()?;
|
||||
let domain_request = AuthRequest::new(session, request.try_into_domain()?);
|
||||
|
||||
state
|
||||
.warren_service
|
||||
.delete_warren_file(domain_request)
|
||||
.auth_service
|
||||
.delete_warren_file(domain_request, state.warren_service.as_ref())
|
||||
.await
|
||||
.map(|_| ApiSuccess::new(StatusCode::CREATED, ()))
|
||||
.map_err(ApiError::from)
|
||||
|
||||
@@ -5,11 +5,15 @@ use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
domain::warren::{
|
||||
models::warren::{FetchWarrenRequest, Warren},
|
||||
models::{
|
||||
auth_session::AuthRequest,
|
||||
warren::{FetchWarrenRequest, Warren},
|
||||
},
|
||||
ports::{AuthService, WarrenService},
|
||||
},
|
||||
inbound::http::{
|
||||
AppState,
|
||||
handlers::extractors::SessionIdHeader,
|
||||
responses::{ApiError, ApiSuccess},
|
||||
},
|
||||
};
|
||||
@@ -51,13 +55,14 @@ impl FetchWarrenHttpRequestBody {
|
||||
|
||||
pub async fn fetch_warren<WS: WarrenService, AS: AuthService>(
|
||||
State(state): State<AppState<WS, AS>>,
|
||||
SessionIdHeader(session): SessionIdHeader,
|
||||
Json(request): Json<FetchWarrenHttpRequestBody>,
|
||||
) -> Result<ApiSuccess<FetchWarrenResponseData>, ApiError> {
|
||||
let domain_request = request.try_into_domain()?;
|
||||
let domain_request = AuthRequest::new(session, request.try_into_domain()?);
|
||||
|
||||
state
|
||||
.warren_service
|
||||
.fetch_warren(domain_request)
|
||||
.auth_service
|
||||
.fetch_warren(domain_request, state.warren_service.as_ref())
|
||||
.await
|
||||
.map(|ref warren| ApiSuccess::new(StatusCode::OK, warren.into()))
|
||||
.map_err(ApiError::from)
|
||||
|
||||
@@ -6,6 +6,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
domain::warren::{
|
||||
models::{
|
||||
auth_session::AuthRequest,
|
||||
file::{AbsoluteFilePathError, File, FileMimeType, FilePath, FilePathError, FileType},
|
||||
warren::ListWarrenFilesRequest,
|
||||
},
|
||||
@@ -13,6 +14,7 @@ use crate::{
|
||||
},
|
||||
inbound::http::{
|
||||
AppState,
|
||||
handlers::extractors::SessionIdHeader,
|
||||
responses::{ApiError, ApiSuccess},
|
||||
},
|
||||
};
|
||||
@@ -75,8 +77,8 @@ pub struct ListWarrenFilesResponseData {
|
||||
files: Vec<WarrenFileElement>,
|
||||
}
|
||||
|
||||
impl From<File> for WarrenFileElement {
|
||||
fn from(value: File) -> Self {
|
||||
impl From<&File> for WarrenFileElement {
|
||||
fn from(value: &File) -> Self {
|
||||
Self {
|
||||
name: value.name().to_string(),
|
||||
file_type: value.file_type().to_owned(),
|
||||
@@ -86,24 +88,25 @@ impl From<File> for WarrenFileElement {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<File>> for ListWarrenFilesResponseData {
|
||||
fn from(value: Vec<File>) -> Self {
|
||||
impl From<&Vec<File>> for ListWarrenFilesResponseData {
|
||||
fn from(value: &Vec<File>) -> Self {
|
||||
Self {
|
||||
files: value.into_iter().map(WarrenFileElement::from).collect(),
|
||||
files: value.iter().map(WarrenFileElement::from).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_warren_files<WS: WarrenService, AS: AuthService>(
|
||||
State(state): State<AppState<WS, AS>>,
|
||||
SessionIdHeader(session): SessionIdHeader,
|
||||
Json(request): Json<ListWarrenFilesHttpRequestBody>,
|
||||
) -> Result<ApiSuccess<ListWarrenFilesResponseData>, ApiError> {
|
||||
let domain_request = request.try_into_domain()?;
|
||||
let domain_request = AuthRequest::new(session, request.try_into_domain()?);
|
||||
|
||||
state
|
||||
.warren_service
|
||||
.list_files(domain_request)
|
||||
.auth_service
|
||||
.list_warren_files(domain_request, state.warren_service.as_ref())
|
||||
.await
|
||||
.map(|files| ApiSuccess::new(StatusCode::OK, files.into()))
|
||||
.map(|response| ApiSuccess::new(StatusCode::OK, response.files().into()))
|
||||
.map_err(ApiError::from)
|
||||
}
|
||||
|
||||
@@ -4,11 +4,14 @@ use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
domain::warren::{
|
||||
models::warren::{ListWarrensRequest, Warren},
|
||||
models::{
|
||||
auth_session::AuthRequest, user_warren::requests::ListWarrensRequest, warren::Warren,
|
||||
},
|
||||
ports::{AuthService, WarrenService},
|
||||
},
|
||||
inbound::http::{
|
||||
AppState,
|
||||
handlers::extractors::SessionIdHeader,
|
||||
responses::{ApiError, ApiSuccess},
|
||||
},
|
||||
};
|
||||
@@ -43,12 +46,13 @@ impl From<&Vec<Warren>> for ListWarrensResponseData {
|
||||
|
||||
pub async fn list_warrens<WS: WarrenService, AS: AuthService>(
|
||||
State(state): State<AppState<WS, AS>>,
|
||||
SessionIdHeader(session): SessionIdHeader,
|
||||
) -> Result<ApiSuccess<ListWarrensResponseData>, ApiError> {
|
||||
let domain_request = ListWarrensRequest::new();
|
||||
let domain_request = AuthRequest::new(session, ListWarrensRequest::new());
|
||||
|
||||
state
|
||||
.warren_service
|
||||
.list_warrens(domain_request)
|
||||
.auth_service
|
||||
.list_warrens(domain_request, state.warren_service.as_ref())
|
||||
.await
|
||||
.map_err(ApiError::from)
|
||||
.map(|ref warrens| ApiSuccess::new(StatusCode::OK, warrens.into()))
|
||||
|
||||
@@ -6,6 +6,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
domain::warren::{
|
||||
models::{
|
||||
auth_session::AuthRequest,
|
||||
file::{
|
||||
AbsoluteFilePath, AbsoluteFilePathError, FileName, FileNameError, FilePath,
|
||||
FilePathError,
|
||||
@@ -16,6 +17,7 @@ use crate::{
|
||||
},
|
||||
inbound::http::{
|
||||
AppState,
|
||||
handlers::extractors::SessionIdHeader,
|
||||
responses::{ApiError, ApiSuccess},
|
||||
},
|
||||
};
|
||||
@@ -80,13 +82,14 @@ impl From<ParseRenameWarrenEntryHttpRequestError> for ApiError {
|
||||
|
||||
pub async fn rename_warren_entry<WS: WarrenService, AS: AuthService>(
|
||||
State(state): State<AppState<WS, AS>>,
|
||||
SessionIdHeader(session): SessionIdHeader,
|
||||
Json(request): Json<RenameWarrenEntryHttpRequestBody>,
|
||||
) -> Result<ApiSuccess<()>, ApiError> {
|
||||
let domain_request = request.try_into_domain()?;
|
||||
let domain_request = AuthRequest::new(session, request.try_into_domain()?);
|
||||
|
||||
state
|
||||
.warren_service
|
||||
.rename_warren_entry(domain_request)
|
||||
.auth_service
|
||||
.rename_warren_entry(domain_request, state.warren_service.as_ref())
|
||||
.await
|
||||
.map(|_| ApiSuccess::new(StatusCode::OK, ()))
|
||||
.map_err(ApiError::from)
|
||||
|
||||
@@ -6,6 +6,7 @@ use uuid::Uuid;
|
||||
use crate::{
|
||||
domain::warren::{
|
||||
models::{
|
||||
auth_session::AuthRequest,
|
||||
file::{AbsoluteFilePathError, FileName, FileNameError, FilePath, FilePathError},
|
||||
warren::{UploadFile, UploadFileList, UploadFileListError, UploadWarrenFilesRequest},
|
||||
},
|
||||
@@ -13,6 +14,7 @@ use crate::{
|
||||
},
|
||||
inbound::http::{
|
||||
AppState,
|
||||
handlers::extractors::SessionIdHeader,
|
||||
responses::{ApiError, ApiSuccess},
|
||||
},
|
||||
};
|
||||
@@ -94,13 +96,14 @@ impl From<ParseUploadWarrenFilesHttpRequestError> for ApiError {
|
||||
|
||||
pub async fn upload_warren_files<WS: WarrenService, AS: AuthService>(
|
||||
State(state): State<AppState<WS, AS>>,
|
||||
SessionIdHeader(session): SessionIdHeader,
|
||||
TypedMultipart(multipart): TypedMultipart<UploadWarrenFilesHttpRequestBody>,
|
||||
) -> Result<ApiSuccess<()>, ApiError> {
|
||||
let domain_request = multipart.try_into_domain()?;
|
||||
let domain_request = AuthRequest::new(session, multipart.try_into_domain()?);
|
||||
|
||||
state
|
||||
.warren_service
|
||||
.upload_warren_files(domain_request)
|
||||
.auth_service
|
||||
.upload_warren_files(domain_request, state.warren_service.as_ref())
|
||||
.await
|
||||
.map(|_| ApiSuccess::new(StatusCode::CREATED, ()))
|
||||
.map_err(ApiError::from)
|
||||
|
||||
@@ -50,6 +50,7 @@ impl<T: Serialize + PartialEq> IntoResponse for ApiSuccess<T> {
|
||||
pub enum ApiError {
|
||||
BadRequest(String),
|
||||
NotFound(String),
|
||||
Unauthorized(String),
|
||||
InternalServerError(String),
|
||||
}
|
||||
|
||||
@@ -66,6 +67,7 @@ impl IntoResponse for ApiError {
|
||||
match self {
|
||||
BadRequest(e) => (StatusCode::BAD_REQUEST, e).into_response(),
|
||||
NotFound(e) => (StatusCode::NOT_FOUND, e).into_response(),
|
||||
Unauthorized(e) => (StatusCode::UNAUTHORIZED, e).into_response(),
|
||||
InternalServerError(e) => {
|
||||
tracing::error!("{}", e);
|
||||
(
|
||||
|
||||
@@ -151,4 +151,67 @@ impl AuthMetrics for MetricsDebugLogger {
|
||||
async fn record_auth_session_fetch_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth session fetch failed");
|
||||
}
|
||||
|
||||
async fn record_auth_fetch_user_warren_list_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren list succeeded");
|
||||
}
|
||||
async fn record_auth_fetch_user_warren_list_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren list failed");
|
||||
}
|
||||
|
||||
async fn record_auth_fetch_user_warrens_success(&self) -> () {
|
||||
tracing::debug!("[Metrics] Auth user warren id fetch succeeded");
|
||||
}
|
||||
async fn record_auth_fetch_user_warrens_failure(&self) -> () {
|
||||
tracing::debug!("[Metrics] Auth user warren id fetch failed");
|
||||
}
|
||||
|
||||
async fn record_auth_warren_fetch_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren fetch succeeded");
|
||||
}
|
||||
async fn record_auth_warren_fetch_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren fetch failed");
|
||||
}
|
||||
|
||||
async fn record_auth_warren_file_list_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren file list succeeded");
|
||||
}
|
||||
async fn record_auth_warren_file_list_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren file list failed");
|
||||
}
|
||||
|
||||
async fn record_auth_warren_directory_creation_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren directory creation succeeded");
|
||||
}
|
||||
async fn record_auth_warren_directory_creation_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren directory creation failed");
|
||||
}
|
||||
|
||||
async fn record_auth_warren_directory_deletion_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren directory deletion succeeded");
|
||||
}
|
||||
async fn record_auth_warren_directory_deletion_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren directory deletion failed");
|
||||
}
|
||||
|
||||
async fn record_auth_warren_file_deletion_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren file deletion succeeded");
|
||||
}
|
||||
async fn record_auth_warren_file_deletion_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren file deletion failed");
|
||||
}
|
||||
|
||||
async fn record_auth_warren_entry_rename_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren entry rename succeeded");
|
||||
}
|
||||
async fn record_auth_warren_entry_rename_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren entry rename failed");
|
||||
}
|
||||
|
||||
async fn record_auth_warren_files_upload_success(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren files upload succeeded");
|
||||
}
|
||||
async fn record_auth_warren_files_upload_failure(&self) {
|
||||
tracing::debug!("[Metrics] Auth warren files upload failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ use crate::domain::warren::{
|
||||
auth_session::requests::FetchAuthSessionResponse,
|
||||
file::{File, FilePath},
|
||||
user::{LoginUserResponse, User},
|
||||
warren::Warren,
|
||||
user_warren::UserWarren,
|
||||
warren::{
|
||||
CreateWarrenDirectoryResponse, DeleteWarrenDirectoryResponse, DeleteWarrenFileResponse,
|
||||
ListWarrenFilesResponse, RenameWarrenEntryResponse, UploadWarrenFilesResponse, Warren,
|
||||
},
|
||||
},
|
||||
ports::{AuthNotifier, FileSystemNotifier, WarrenNotifier},
|
||||
};
|
||||
@@ -28,27 +32,27 @@ impl WarrenNotifier for NotifierDebugLogger {
|
||||
tracing::debug!("[Notifier] Fetched warren {}", warren.name());
|
||||
}
|
||||
|
||||
async fn warren_files_listed(&self, warren: &Warren, files: &Vec<File>) {
|
||||
async fn warren_files_listed(&self, response: &ListWarrenFilesResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Listed {} file(s) in warren {}",
|
||||
files.len(),
|
||||
warren.name()
|
||||
response.files().len(),
|
||||
response.warren().name()
|
||||
);
|
||||
}
|
||||
|
||||
async fn warren_directory_created(&self, warren: &Warren, path: &FilePath) {
|
||||
async fn warren_directory_created(&self, response: &CreateWarrenDirectoryResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Created directory {} in warren {}",
|
||||
path,
|
||||
warren.name()
|
||||
response.path(),
|
||||
response.warren().name()
|
||||
);
|
||||
}
|
||||
|
||||
async fn warren_directory_deleted(&self, warren: &Warren, path: &FilePath) {
|
||||
async fn warren_directory_deleted(&self, response: &DeleteWarrenDirectoryResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Deleted directory {} in warren {}",
|
||||
path,
|
||||
warren.name()
|
||||
response.path(),
|
||||
response.warren().name()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -60,33 +64,28 @@ impl WarrenNotifier for NotifierDebugLogger {
|
||||
);
|
||||
}
|
||||
|
||||
async fn warren_files_uploaded(&self, warren: &Warren, paths: &[FilePath]) {
|
||||
async fn warren_files_uploaded(&self, response: &UploadWarrenFilesResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Uploaded {} file(s) to warren {}",
|
||||
paths.len(),
|
||||
warren.name()
|
||||
response.paths().len(),
|
||||
response.warren().name()
|
||||
);
|
||||
}
|
||||
|
||||
async fn warren_file_deleted(&self, warren: &Warren, path: &FilePath) {
|
||||
async fn warren_file_deleted(&self, response: &DeleteWarrenFileResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Deleted file {} from warren {}",
|
||||
path,
|
||||
warren.name(),
|
||||
response.path(),
|
||||
response.warren().name(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn warren_entry_renamed(
|
||||
&self,
|
||||
warren: &Warren,
|
||||
old_path: &crate::domain::warren::models::file::AbsoluteFilePath,
|
||||
new_path: &FilePath,
|
||||
) {
|
||||
async fn warren_entry_renamed(&self, response: &RenameWarrenEntryResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Renamed file {} to {} in warren {}",
|
||||
old_path,
|
||||
new_path,
|
||||
warren.name(),
|
||||
response.old_path(),
|
||||
response.path(),
|
||||
response.warren().name(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -136,4 +135,91 @@ impl AuthNotifier for NotifierDebugLogger {
|
||||
response.user().id()
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_user_warrens_fetched(&self, user_id: &Uuid, warren_ids: &Vec<UserWarren>) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Fetched {} user warrens for authenticated user {}",
|
||||
warren_ids.len(),
|
||||
user_id
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_user_warrens_listed(&self, user: &User, warrens: &Vec<Warren>) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Fetched {} warren(s) for authenticated user {}",
|
||||
warrens.len(),
|
||||
user.id()
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_fetched(&self, user: &User, warren: &Warren) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Fetched warren {} for authenticated user {}",
|
||||
warren.name(),
|
||||
user.id(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_files_listed(&self, user: &User, response: &ListWarrenFilesResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Listed {} file(s) in warren {} for authenticated user {}",
|
||||
response.files().len(),
|
||||
response.warren().name(),
|
||||
user.id()
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_directory_created(
|
||||
&self,
|
||||
user: &User,
|
||||
response: &CreateWarrenDirectoryResponse,
|
||||
) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Created directory {} in warren {} for authenticated user {}",
|
||||
response.path(),
|
||||
response.warren().name(),
|
||||
user.id(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_directory_deleted(
|
||||
&self,
|
||||
user: &User,
|
||||
response: &DeleteWarrenDirectoryResponse,
|
||||
) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Deleted directory {} in warren {} for authenticated user {}",
|
||||
response.path(),
|
||||
response.warren().name(),
|
||||
user.id(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_files_uploaded(&self, user: &User, response: &UploadWarrenFilesResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Uploaded {} file(s) to warren {} for authenticated user {}",
|
||||
response.paths().len(),
|
||||
response.warren().name(),
|
||||
user.id(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_file_deleted(&self, user: &User, response: &DeleteWarrenFileResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Deleted file {} from warren {} for authenticated user {}",
|
||||
response.path(),
|
||||
response.warren().name(),
|
||||
user.id(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn auth_warren_entry_renamed(&self, user: &User, response: &RenameWarrenEntryResponse) {
|
||||
tracing::debug!(
|
||||
"[Notifier] Renamed file {} to {} in warren {} for authenticated user {}",
|
||||
response.old_path(),
|
||||
response.path(),
|
||||
response.warren().name(),
|
||||
user.id(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,15 @@ use crate::domain::warren::{
|
||||
RegisterUserError, RegisterUserRequest, User, UserEmail, UserName, UserPassword,
|
||||
VerifyUserPasswordError, VerifyUserPasswordRequest,
|
||||
},
|
||||
user_warren::{
|
||||
UserWarren,
|
||||
requests::{
|
||||
FetchUserWarrenError, FetchUserWarrenRequest, FetchUserWarrensError,
|
||||
FetchUserWarrensRequest,
|
||||
},
|
||||
},
|
||||
warren::{
|
||||
FetchWarrenError, FetchWarrenRequest, ListWarrensError, ListWarrensRequest, Warren,
|
||||
FetchWarrenError, FetchWarrenRequest, FetchWarrensError, FetchWarrensRequest, Warren,
|
||||
},
|
||||
},
|
||||
ports::{AuthRepository, WarrenRepository},
|
||||
@@ -103,6 +110,7 @@ impl Postgres {
|
||||
async fn list_warrens(
|
||||
&self,
|
||||
connection: &mut PgConnection,
|
||||
ids: &[Uuid],
|
||||
) -> Result<Vec<Warren>, sqlx::Error> {
|
||||
let warrens: Vec<Warren> = sqlx::query_as::<sqlx::Postgres, Warren>(
|
||||
"
|
||||
@@ -110,10 +118,11 @@ impl Postgres {
|
||||
*
|
||||
FROM
|
||||
warrens
|
||||
LIMIT
|
||||
50
|
||||
WHERE
|
||||
id = ANY($1)
|
||||
",
|
||||
)
|
||||
.bind(ids)
|
||||
.fetch_all(&mut *connection)
|
||||
.await?;
|
||||
|
||||
@@ -292,13 +301,60 @@ impl Postgres {
|
||||
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
async fn get_user_warrens(
|
||||
&self,
|
||||
connection: &mut PgConnection,
|
||||
user_id: &Uuid,
|
||||
) -> Result<Vec<UserWarren>, sqlx::Error> {
|
||||
let ids: Vec<UserWarren> = sqlx::query_as(
|
||||
"
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
user_warrens
|
||||
WHERE
|
||||
user_id = $1
|
||||
",
|
||||
)
|
||||
.bind(user_id)
|
||||
.fetch_all(connection)
|
||||
.await?;
|
||||
|
||||
Ok(ids)
|
||||
}
|
||||
|
||||
async fn get_user_warren(
|
||||
&self,
|
||||
connection: &mut PgConnection,
|
||||
user_id: &Uuid,
|
||||
warren_id: &Uuid,
|
||||
) -> Result<UserWarren, sqlx::Error> {
|
||||
let ids: UserWarren = sqlx::query_as(
|
||||
"
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
user_warrens
|
||||
WHERE
|
||||
user_id = $1 AND
|
||||
warren_id = $2
|
||||
",
|
||||
)
|
||||
.bind(user_id)
|
||||
.bind(warren_id)
|
||||
.fetch_one(connection)
|
||||
.await?;
|
||||
|
||||
Ok(ids)
|
||||
}
|
||||
}
|
||||
|
||||
impl WarrenRepository for Postgres {
|
||||
async fn list_warrens(
|
||||
&self,
|
||||
_request: ListWarrensRequest,
|
||||
) -> Result<Vec<Warren>, ListWarrensError> {
|
||||
request: FetchWarrensRequest,
|
||||
) -> Result<Vec<Warren>, FetchWarrensError> {
|
||||
let mut connection = self
|
||||
.pool
|
||||
.acquire()
|
||||
@@ -306,7 +362,7 @@ impl WarrenRepository for Postgres {
|
||||
.context("Failed to get a PostgreSQL connection")?;
|
||||
|
||||
let warrens = self
|
||||
.list_warrens(&mut connection)
|
||||
.list_warrens(&mut connection, request.ids())
|
||||
.await
|
||||
.map_err(|err| anyhow!(err).context("Failed to list warrens"))?;
|
||||
|
||||
@@ -424,6 +480,45 @@ impl AuthRepository for Postgres {
|
||||
|
||||
Ok(FetchAuthSessionResponse::new(session, user))
|
||||
}
|
||||
|
||||
async fn fetch_user_warrens(
|
||||
&self,
|
||||
request: FetchUserWarrensRequest,
|
||||
) -> Result<Vec<UserWarren>, FetchUserWarrensError> {
|
||||
let mut connection = self
|
||||
.pool
|
||||
.acquire()
|
||||
.await
|
||||
.context("Failed to get a PostgreSQL connection")?;
|
||||
|
||||
let warren_ids = self
|
||||
.get_user_warrens(&mut connection, request.user_id())
|
||||
.await
|
||||
.context("Failed to get user warrens")?;
|
||||
|
||||
Ok(warren_ids)
|
||||
}
|
||||
|
||||
async fn fetch_user_warren(
|
||||
&self,
|
||||
request: FetchUserWarrenRequest,
|
||||
) -> Result<UserWarren, FetchUserWarrenError> {
|
||||
let mut connection = self
|
||||
.pool
|
||||
.acquire()
|
||||
.await
|
||||
.context("Failed to get a PostgreSQL connection")?;
|
||||
|
||||
self.get_user_warren(&mut connection, request.user_id(), request.warren_id())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if is_not_found_error(&e) {
|
||||
FetchUserWarrenError::NotFound
|
||||
} else {
|
||||
FetchUserWarrenError::Unknown(anyhow!(e))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn is_not_found_error(err: &sqlx::Error) -> bool {
|
||||
|
||||
@@ -11,5 +11,7 @@ export function getApiHeaders(
|
||||
}
|
||||
}
|
||||
|
||||
headers['content-type'] = 'application/json';
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
@@ -34,9 +34,7 @@ export async function getWarrenDirectory(
|
||||
ApiResponse<{ files: DirectoryEntry[] }>
|
||||
>(getApiUrl(`warrens/files`), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
headers: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
warrenId,
|
||||
path,
|
||||
@@ -65,9 +63,7 @@ export async function createDirectory(
|
||||
|
||||
const { status } = await useFetch(getApiUrl(`warrens/files/directory`), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
headers: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
warrenId,
|
||||
path,
|
||||
@@ -106,9 +102,7 @@ export async function deleteWarrenDirectory(
|
||||
|
||||
const { status } = await useFetch(getApiUrl(`warrens/files/directory`), {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
headers: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
warrenId,
|
||||
path,
|
||||
@@ -148,9 +142,7 @@ export async function deleteWarrenFile(
|
||||
|
||||
const { status } = await useFetch(getApiUrl(`warrens/files/file`), {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
headers: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
warrenId,
|
||||
path,
|
||||
@@ -209,6 +201,11 @@ export async function uploadToWarren(
|
||||
body.append('files', file);
|
||||
}
|
||||
|
||||
const headers = getApiHeaders();
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
xhr.setRequestHeader(key, value);
|
||||
}
|
||||
|
||||
xhr.send(body);
|
||||
|
||||
try {
|
||||
@@ -244,9 +241,7 @@ export async function renameWarrenEntry(
|
||||
|
||||
const { status } = await useFetch(getApiUrl(`warrens/files/rename`), {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
headers: getApiHeaders(),
|
||||
body: JSON.stringify({
|
||||
warrenId,
|
||||
path,
|
||||
|
||||
@@ -21,7 +21,7 @@ export const useWarrenStore = defineStore('warrens', {
|
||||
}
|
||||
|
||||
if (!this.current.path.endsWith('/')) {
|
||||
this.current.path += '/';
|
||||
path = '/' + path;
|
||||
}
|
||||
|
||||
this.current.path += path;
|
||||
|
||||
Reference in New Issue
Block a user