diff --git a/database/migrations/20230817172329_functions.sql b/database/migrations/20230817172329_functions.sql index ff7d3c0..74bb0ba 100644 --- a/database/migrations/20230817172329_functions.sql +++ b/database/migrations/20230817172329_functions.sql @@ -37,77 +37,6 @@ end; $$; -- +goose StatementEnd - --- +goose StatementBegin -create function teldrive.update_folder(folder_id text, -new_name text default null, -new_path text default null) - returns setof teldrive.files - language plpgsql -as $$ -declare folder record; - -path_items text []; - -begin - -if new_path is null then -select - * -into - folder -from - teldrive.files -where - id = folder_id; - -path_items := string_to_array(folder.path, -'/'); - -path_items [array_length(path_items, -1)] := new_name; - -new_path := array_to_string(path_items, -'/'); -end if; - -update - teldrive.files -set - path = new_path, - name = new_name -where - id = folder_id; - -for folder in -select - * -from - teldrive.files -where - type = 'folder' - and parent_id = folder_id loop call teldrive.update_folder( - folder.id, - folder.name, - concat(new_path, - '/', - folder.name) -); -end loop; - -return query -select - * -from - teldrive.files -where - id = folder_id; -end; - -$$ -; --- +goose StatementEnd - -- +goose StatementBegin create procedure teldrive.delete_files(in file_ids text[], in op text default 'bulk') @@ -184,5 +113,4 @@ $$ -- +goose Down drop procedure if exists teldrive.update_size; -drop function if exists teldrive.update_folder; drop procedure if exists teldrive.delete_files; \ No newline at end of file diff --git a/database/migrations/20231102005615_functions.sql b/database/migrations/20231102005615_functions.sql new file mode 100644 index 0000000..693eded --- /dev/null +++ b/database/migrations/20231102005615_functions.sql @@ -0,0 +1,134 @@ +-- +goose Up +-- +goose StatementBegin + +CREATE OR REPLACE FUNCTION teldrive.split_path(path text, OUT parent text, OUT base text) AS $$ +BEGIN + IF path = '/' THEN + parent := '/'; + base := NULL; + RETURN; + END IF; + + IF left(path, 1) <> '/' THEN + path := '/' || path; + END IF; + + IF right(path, 1) = '/' THEN + path := left(path, length(path) - 1); + END IF; + + parent := left(path, length(path) - position('/' in reverse(path))); + base := right(path, position('/' in reverse(path)) - 1); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION teldrive.update_folder( + folder_id TEXT, + new_name TEXT, + new_path TEXT DEFAULT NULL +) RETURNS SETOF teldrive.files +LANGUAGE plpgsql +AS $$ +DECLARE + folder RECORD; + path_items TEXT[]; +BEGIN + IF new_path IS NULL THEN + SELECT + * + INTO + folder + FROM + teldrive.files + WHERE + id = folder_id; + + path_items := string_to_array(folder.path, '/'); + + path_items[array_length(path_items, 1)] := new_name; + + new_path := array_to_string(path_items, '/'); + END IF; + + UPDATE + teldrive.files + SET + path = new_path, + name = new_name + WHERE + id = folder_id; + + FOR folder IN + SELECT + * + FROM + teldrive.files + WHERE + type = 'folder' + AND parent_id = folder_id + LOOP + perform from teldrive.update_folder( + folder.id, + folder.name, + concat(new_path, '/', folder.name) + ); + END LOOP; + + RETURN QUERY + SELECT + * + FROM + teldrive.files + WHERE + id = folder_id; +END; +$$; + +CREATE OR REPLACE FUNCTION teldrive.move_directory(src text, dest text,user_id bigint) RETURNS VOID AS $$ +DECLARE + src_parent TEXT; + src_base TEXT; + dest_parent TEXT; + dest_base TEXT; + dest_id text; + src_id text; +BEGIN + + IF NOT EXISTS (SELECT 1 FROM teldrive.files WHERE path = src) THEN + RAISE EXCEPTION 'source directory not found'; + END IF; + + IF EXISTS (SELECT 1 FROM teldrive.files WHERE path = dest) THEN + RAISE EXCEPTION 'destination directory exists'; + END IF; + + SELECT parent, base INTO src_parent,src_base FROM teldrive.split_path(src); + + SELECT parent, base INTO dest_parent, dest_base FROM teldrive.split_path(dest); + + IF src_parent != dest_parent then + select id into dest_id from teldrive.create_directories(user_id,dest); + update teldrive.files set parent_id = dest_id where parent_id = (select id from teldrive.files where path = src) and id != dest_id; + + IF POSITION(CONCAT(src,'/') IN dest) = 0 then + delete from teldrive.files where path = src; + END IF; + + END IF; + + IF src_base != dest_base and src_parent = dest_parent then + select id into src_id from teldrive.files where path = src; + perform from teldrive.update_folder(src_id,dest_base); + END IF; + +END; +$$ LANGUAGE plpgsql; + +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +drop function if exists teldrive.split_path; +drop function if exists teldrive.update_folder; +drop function if exists teldrive.move_directory; +-- +goose StatementEnd diff --git a/routes/file.go b/routes/file.go index a2be27f..f7bcf9f 100644 --- a/routes/file.go +++ b/routes/file.go @@ -107,4 +107,16 @@ func addFileRoutes(rg *gin.RouterGroup) { c.JSON(http.StatusOK, res) }) + r.POST("/movedir", Authmiddleware, func(c *gin.Context) { + + res, err := fileService.MoveDirectory(c) + + if err != nil { + c.AbortWithError(err.Code, err.Error) + return + } + + c.JSON(http.StatusOK, res) + }) + } diff --git a/schemas/file.schema.go b/schemas/file.schema.go index 4c35f47..45fcaba 100644 --- a/schemas/file.schema.go +++ b/schemas/file.schema.go @@ -73,6 +73,11 @@ type FileOperation struct { Destination string `json:"destination,omitempty"` } +type DirMove struct { + Source string `json:"source"` + Destination string `json:"destination"` +} + type MkDir struct { Path string `json:"path"` } diff --git a/services/file.service.go b/services/file.service.go index fd5f5c9..2502a74 100644 --- a/services/file.service.go +++ b/services/file.service.go @@ -306,6 +306,23 @@ func (fs *FileService) DeleteFiles(c *gin.Context) (*schemas.Message, *types.App return &schemas.Message{Status: true, Message: "files deleted"}, nil } +func (fs *FileService) MoveDirectory(c *gin.Context) (*schemas.Message, *types.AppError) { + + var payload schemas.DirMove + + if err := c.ShouldBindJSON(&payload); err != nil { + return nil, &types.AppError{Error: errors.New("invalid request payload"), Code: http.StatusBadRequest} + } + + userId, _ := getUserAuth(c) + + if err := fs.Db.Exec("select * from teldrive.move_directory(? , ? , ?)", payload.Source, payload.Destination, userId).Error; err != nil { + return nil, &types.AppError{Error: errors.New("failed to move directory"), Code: http.StatusInternalServerError} + } + + return &schemas.Message{Status: true, Message: "directory moved"}, nil +} + func (fs *FileService) GetFileStream(c *gin.Context) { w := c.Writer