Skip to content

Add folder management, move/rename, and nested path support to User Files#283

Merged
pellecchialuigi merged 5 commits into
mainfrom
fix-upload-user-files
Apr 24, 2026
Merged

Add folder management, move/rename, and nested path support to User Files#283
pellecchialuigi merged 5 commits into
mainfrom
fix-upload-user-files

Conversation

@pellecchialuigi
Copy link
Copy Markdown
Collaborator

Extend the User Files feature with full directory support: users can now create folders, navigate into them via breadcrumb navigation, rename and move files or directories, and delete directories recursively. All new and existing endpoints are hardened against path traversal attacks.

Backend (api/api.py, api/api_utils.py):

  • Add is_safe_user_path() utility that resolves symlinks and verifies the target stays under the user's root directory; applied to every UserFiles, UserFileContent, and UserFileFolder endpoint
  • GET /user/files now accepts path (sub-directory listing) and recursive (walk all nested files) query parameters; response includes name, type ("file" or "directory"), and relative_path fields; sorting places directories before files
  • POST /user/files supports nested filenames (e.g. "folder/sub/file.txt") by auto-creating intermediate directories; dot-filename validation now checks only the basename so nested paths are accepted
  • PUT /user/files (new) moves or renames a file or directory, with conflict detection and auto-creation of the destination parent directory
  • DELETE /user/files now handles directories via shutil.rmtree in addition to single files; response uses api_response.return_ok() consistently
  • POST /user/files/folder (new UserFileFolder resource) creates a directory, supporting nested paths and rejecting dot-prefixed leaf names

Frontend (app/src/app/UserFiles/*, Constants/constants.tsx):

  • Add createUserFolder, moveUserFile, and deleteUserFile helper functions in constants.tsx; loadUserFiles gains _path and _recursive parameters; loadFileContent URL-encodes the filename for nested paths
  • Forms that list user files (APIForm, DocumentForm, TestCaseForm, TestRunConfigForm, TestCaseImport) now request a recursive listing and display relative_path as the label so nested files are distinguishable
  • New form components: UserFilesCreateFolderForm, UserFilesRenameForm, UserFilesMoveForm, UserFilesDeleteConfirm
  • UserFilesModal becomes a multi-action modal dispatching to the correct form based on the action (add / edit / create-folder / rename / move / delete); delete action uses a danger-styled confirm button
  • UserFilesMenuKebab replaces inline delete logic with a unified openModal helper exposing Edit, Rename, Move, and Delete actions; Edit is hidden for directories
  • UserFiles page adds breadcrumb navigation for folder drill-down and a "New Folder" button; listing refreshes without full page reloads
  • UserFilesListing shows folder/file icons, clickable folder names for navigation, and an empty-state message

Tests (api/test/):

  • user_files_test_helpers.py: add move_file, create_folder helpers; remove_if_exists now handles directories
  • conftest.py: ut_user_files_dir cleanup removes directories as well
  • test_user_files.py: new tests for type field, directory-first sorting, path param, path traversal blocking, recursive listing, nested file creation, directory deletion, move/rename (file, directory, into subfolder, conflict, empty fields, path traversal)
  • test_user_file_content.py: new tests for nested file GET/PUT and path traversal blocking on both endpoints
  • test_user_file_folder.py (new): tests for folder creation (auth, missing fields, empty name, dot name, success, nested, conflict, path traversal)

…iles

Extend the User Files feature with full directory support: users can now create
folders, navigate into them via breadcrumb navigation, rename and move files or
directories, and delete directories recursively. All new and existing endpoints
are hardened against path traversal attacks.

Backend (api/api.py, api/api_utils.py):
- Add `is_safe_user_path()` utility that resolves symlinks and verifies the
  target stays under the user's root directory; applied to every UserFiles,
  UserFileContent, and UserFileFolder endpoint
- GET /user/files now accepts `path` (sub-directory listing) and `recursive`
  (walk all nested files) query parameters; response includes `name`, `type`
  ("file" or "directory"), and `relative_path` fields; sorting places
  directories before files
- POST /user/files supports nested filenames (e.g. "folder/sub/file.txt") by
  auto-creating intermediate directories; dot-filename validation now checks
  only the basename so nested paths are accepted
- PUT /user/files (new) moves or renames a file or directory, with conflict
  detection and auto-creation of the destination parent directory
- DELETE /user/files now handles directories via `shutil.rmtree` in addition
  to single files; response uses `api_response.return_ok()` consistently
- POST /user/files/folder (new `UserFileFolder` resource) creates a directory,
  supporting nested paths and rejecting dot-prefixed leaf names

Frontend (app/src/app/UserFiles/*, Constants/constants.tsx):
- Add `createUserFolder`, `moveUserFile`, and `deleteUserFile` helper functions
  in constants.tsx; `loadUserFiles` gains `_path` and `_recursive` parameters;
  `loadFileContent` URL-encodes the filename for nested paths
- Forms that list user files (APIForm, DocumentForm, TestCaseForm,
  TestRunConfigForm, TestCaseImport) now request a recursive listing and
  display `relative_path` as the label so nested files are distinguishable
- New form components: `UserFilesCreateFolderForm`, `UserFilesRenameForm`,
  `UserFilesMoveForm`, `UserFilesDeleteConfirm`
- `UserFilesModal` becomes a multi-action modal dispatching to the correct form
  based on the action (add / edit / create-folder / rename / move / delete);
  delete action uses a danger-styled confirm button
- `UserFilesMenuKebab` replaces inline delete logic with a unified `openModal`
  helper exposing Edit, Rename, Move, and Delete actions; Edit is hidden for
  directories
- `UserFiles` page adds breadcrumb navigation for folder drill-down and a
  "New Folder" button; listing refreshes without full page reloads
- `UserFilesListing` shows folder/file icons, clickable folder names for
  navigation, and an empty-state message

Tests (api/test/):
- `user_files_test_helpers.py`: add `move_file`, `create_folder` helpers;
  `remove_if_exists` now handles directories
- `conftest.py`: `ut_user_files_dir` cleanup removes directories as well
- `test_user_files.py`: new tests for type field, directory-first sorting,
  `path` param, path traversal blocking, recursive listing, nested file
  creation, directory deletion, move/rename (file, directory, into subfolder,
  conflict, empty fields, path traversal)
- `test_user_file_content.py`: new tests for nested file GET/PUT and path
  traversal blocking on both endpoints
- `test_user_file_folder.py` (new): tests for folder creation (auth, missing
  fields, empty name, dot name, success, nested, conflict, path traversal)

Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
@pellecchialuigi
Copy link
Copy Markdown
Collaborator Author

Refers to #224

Luigi Pellecchia added 4 commits April 23, 2026 11:50
Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
- Fix `add_test_case_to_user_files` command: update button selector from
  `#btn-user-file-add-confirm` to `#btn-user-file-modal-confirm` to match the
  renamed confirm button id in the refactored `UserFilesModal` component

Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
Signed-off-by: Luigi Pellecchia <lpellecc@redhat.com>
@pellecchialuigi pellecchialuigi added the enhancement New feature or request label Apr 24, 2026
@pellecchialuigi pellecchialuigi merged commit b91e0e9 into main Apr 24, 2026
6 of 7 checks passed
@pellecchialuigi pellecchialuigi deleted the fix-upload-user-files branch April 24, 2026 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant