feat: add create folder feature

This commit is contained in:
MedzikUser 2022-05-27 15:58:16 +02:00
parent ab7f1bc4ea
commit 403ed4199e
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
11 changed files with 183 additions and 7 deletions

View File

@ -0,0 +1,41 @@
use std::fs;
use axum::{extract::rejection::JsonRejection, Extension, Json};
use axum_auth::AuthBearer;
use homedisk_database::Database;
use homedisk_types::fs::create_dir::{Request, Response};
use homedisk_types::{
config::types::Config,
errors::{FsError, ServerError},
};
use crate::fs::validate_path;
use crate::middleware::{find_user, validate_json, validate_jwt};
pub async fn handle(
Extension(db): Extension<Database>,
Extension(config): Extension<Config>,
AuthBearer(token): AuthBearer,
request: Result<Json<Request>, JsonRejection>,
) -> Result<Json<Response>, ServerError> {
let Json(request) = validate_json::<Request>(request)?;
let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?;
// validate the `path` can be used
validate_path(&request.path)?;
// search for a user by UUID from a token
let user = find_user(db, token.claims.sub).await?;
// directory where the file will be placed
let path = format!(
"{user_dir}/{req_dir}",
user_dir = user.user_dir(&config.storage.path),
req_dir = request.path
);
fs::create_dir_all(path)
.map_err(|err| ServerError::FsError(FsError::CreateDirectory(err.to_string())))?;
Ok(Json(Response { created: true }))
}

View File

@ -6,10 +6,7 @@ use axum::Extension;
use axum_auth::AuthBearer;
use homedisk_database::Database;
use homedisk_types::fs::upload::Pagination;
use homedisk_types::{
config::types::Config,
errors::ServerError,
};
use homedisk_types::{config::types::Config, errors::ServerError};
use crate::middleware::{find_user, validate_jwt};

View File

@ -1,3 +1,4 @@
pub mod create_dir;
pub mod delete;
pub mod download;
pub mod list;
@ -11,6 +12,7 @@ pub fn app() -> axum::Router {
.route("/upload", post(upload::handle))
.route("/delete", delete(upload::handle))
.route("/download", get(download::handle))
.route("/createdir", post(create_dir::handle))
}
pub fn validate_path(path: &str) -> Result<(), homedisk_types::errors::ServerError> {

View File

@ -14,6 +14,9 @@ pub enum Error {
#[error("create file - {0}")]
CreateFile(String),
#[error("create dir - {0}")]
CreateDirectory(String),
#[error("delete file - {0}")]
DeleteFile(String),

View File

@ -55,6 +55,7 @@ impl axum::response::IntoResponse for ServerError {
FsError::FileDoesNotExist => StatusCode::BAD_REQUEST,
FsError::MultipartError => StatusCode::BAD_REQUEST,
FsError::CreateFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
FsError::CreateDirectory(_) => StatusCode::INTERNAL_SERVER_ERROR,
FsError::DeleteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
FsError::DeleteDirectory(_) => StatusCode::INTERNAL_SERVER_ERROR,
FsError::WriteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,

View File

@ -0,0 +1,11 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Request {
pub path: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Response {
pub created: bool,
}

View File

@ -1,3 +1,4 @@
pub mod create_dir;
pub mod delete;
pub mod download;
pub mod list;

View File

@ -0,0 +1,34 @@
import axios from './axios'
export default async function createDir(path: string, token: string): Promise<any> {
const request = axios.post("/fs/createdir", {
path
}, {
headers: {
Authorization: `Bearer ${token}`,
}
})
const response = request
.then(response => {
const { data } = response
return data
})
.catch(err => {
if (err.response?.data?.error_message) {
const error = err.response.data.error_message
if (error.toString() == "[object Object]") {
Object.keys(error).forEach(key => {
throw new Error(key)
})
}
throw new Error(error)
}
throw new Error(err)
})
return response
}

View File

@ -2,7 +2,8 @@ import list from "./list"
import login from "./login"
import register from "./register"
import upload from "./upload"
import createDir from "./create-directory"
const api = { list, login, register, upload }
const api = { list, login, register, upload, createDir }
export default api

View File

@ -0,0 +1,71 @@
import React, { useState } from 'react'
import { Backdrop, Box, Button, Fade, Link, Modal, TextField } from "@mui/material"
import { useCookies } from "react-cookie"
import api from '../../../api_utils'
import style from './style'
function CreateFolderModal({ open, setOpen, refresh }: Props) {
const [name, setName] = useState("")
const [cookies] = useCookies(["token"])
const handleChange: React.ChangeEventHandler<HTMLInputElement> = event => {
const value = event.target.value
setName(value)
}
// handle click "Enter (Return)"
const handleKeyPress = (event: React.KeyboardEvent) => {
if (event.keyCode === 13 || event.which === 13 || event.charCode === 13) {
handle()
}
}
const handle = () => {
setOpen(false)
const request = api.createDir(name, cookies.token)
request
.then(refresh)
}
return (
<Modal
open={open}
onClose={() => setOpen(false)}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<Box sx={style}>
<TextField
label="Folder"
placeholder="Folder"
margin="normal"
value={name}
onChange={handleChange}
onKeyPress={handleKeyPress}
/>
<Link>
<Button variant="outlined" onClick={handle}>
Create Folder
</Button>
</Link>
</Box>
</Fade>
</Modal>
)
}
export type Props = {
open: boolean,
setOpen: React.Dispatch<React.SetStateAction<boolean>>,
refresh: () => void,
}
export default CreateFolderModal

View File

@ -1,5 +1,5 @@
import { faFile, faFolder } from "@fortawesome/free-solid-svg-icons"
import { CloudUpload } from "@mui/icons-material"
import { CloudUpload, CreateNewFolder } from "@mui/icons-material"
import { IconButton, Link as MuiLink } from "@mui/material"
import Head from 'next/head'
import Link from 'next/link'
@ -10,6 +10,7 @@ import api from '../../api_utils'
import Icon from "../../components/other/icon"
import Table from "../../components/user/table"
import UploadModal from "../../components/user/modals/upload"
import CreateFolderModal from "../../components/user/modals/create-folder"
export default function Files() {
const [cookies] = useCookies(["token"])
@ -45,6 +46,7 @@ export default function Files() {
// modals
const [uploadModal, setUploadModal] = useState(false)
const [createFolderModal, setCreateFolderModal] = useState(false)
return (
<>
@ -52,18 +54,30 @@ export default function Files() {
<title>Files - HomeDisk</title>
</Head>
<MuiLink onClick={() => setUploadModal(true)}>
<MuiLink>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="logo"
onClick={() => setUploadModal(true)}
>
<CloudUpload />
</IconButton>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="logo"
onClick={() => setCreateFolderModal(true)}
>
<CreateNewFolder />
</IconButton>
</MuiLink>
<UploadModal open={uploadModal} setOpen={setUploadModal} path={path} refresh={refreshFolder} />
<CreateFolderModal open={createFolderModal} setOpen={setCreateFolderModal} refresh={refreshFolder} />
<Table>
<thead>