Browse Source

[api] Refactor /mkdir API with better validation checks (#3985)

Harsh Gupta 9 tháng trước cách đây
mục cha
commit
bb3606ea99

+ 23 - 3
apps/filebrowser/src/filebrowser/api.py

@@ -536,14 +536,34 @@ def upload_file(request):
 
 @api_error_handler
 def mkdir(request):
+  """
+  Create a new directory at the specified path with the given name.
+
+  Args:
+    request (HttpRequest): The HTTP request object containing the data.
+
+  Returns:
+    A HttpResponse with a status code and message indicating the success or failure of the directory creation.
+  """
   # TODO: Check if this needs to be a PUT request
   path = request.POST.get('path')
   name = request.POST.get('name')
 
-  if name and (posixpath.sep in name or "#" in name):
-    return HttpResponse(f"Error creating {name} directory. Slashes or hashes are not allowed in directory name.", status=400)
+  # Check if source and destination paths are provided
+  if not path or not name:
+    return HttpResponse("Missing required parameters: path and name are required.", status=400)
+
+  # Validate the 'name' parameter for invalid characters
+  if posixpath.sep in name or "#" in name:
+    return HttpResponse(f"Slashes or hashes are not allowed in directory name. Please choose a different name.", status=400)
+
+  dir_path = request.fs.join(path, name)
+
+  # Check if the directory already exists
+  if request.fs.isdir(dir_path):
+    return HttpResponse(f"Error creating {name} directory: Directory already exists.", status=409)
 
-  request.fs.mkdir(request.fs.join(path, name))
+  request.fs.mkdir(dir_path)
   return HttpResponse(status=201)
 
 

+ 78 - 1
apps/filebrowser/src/filebrowser/api_test.py

@@ -20,7 +20,7 @@ from unittest.mock import Mock, patch
 
 from django.core.files.uploadedfile import SimpleUploadedFile
 
-from filebrowser.api import get_all_filesystems, rename, upload_file
+from filebrowser.api import get_all_filesystems, mkdir, rename, upload_file
 from filebrowser.conf import (
   MAX_FILE_SIZE_UPLOAD_LIMIT,
   RESTRICT_FILE_EXTENSIONS,
@@ -330,6 +330,83 @@ class TestSimpleFileUploadAPI:
           reset()
 
 
+class TestMkdirAPI:
+  def test_mkdir_success(self):
+    request = Mock(
+      method='POST',
+      POST={'path': 's3a://test-bucket/test-user/', 'name': 'new_dir'},
+      fs=Mock(
+        mkdir=Mock(),
+        isdir=Mock(return_value=False),
+        join=Mock(return_value='s3a://test-bucket/test-user/new_dir'),
+      ),
+    )
+    response = mkdir(request)
+
+    assert response.status_code == 201
+    request.fs.mkdir.assert_called_once_with('s3a://test-bucket/test-user/new_dir')
+
+  def test_mkdir_directory_exists(self):
+    request = Mock(
+      method='POST',
+      POST={'path': 's3a://test-bucket/test-user/', 'name': 'new_dir'},
+      fs=Mock(
+        mkdir=Mock(),
+        isdir=Mock(return_value=True),
+        join=Mock(return_value='s3a://test-bucket/test-user/new_dir'),
+      ),
+    )
+    response = mkdir(request)
+
+    assert response.status_code == 409
+    assert response.content.decode('utf-8') == 'Error creating new_dir directory: Directory already exists.'
+
+  def test_mkdir_invalid_name(self):
+    request = Mock(
+      method='POST',
+      POST={'path': 's3a://test-bucket/test-user/', 'name': 'new#dir'},
+      fs=Mock(
+        mkdir=Mock(),
+        isdir=Mock(return_value=False),
+        join=Mock(return_value='s3a://test-bucket/test-user/new#dir'),
+      ),
+    )
+    response = mkdir(request)
+
+    assert response.status_code == 400
+    assert response.content.decode('utf-8') == 'Slashes or hashes are not allowed in directory name. Please choose a different name.'
+
+  def test_mkdir_no_path(self):
+    request = Mock(
+      method='POST',
+      POST={'name': 'new_dir'},
+      fs=Mock(
+        mkdir=Mock(),
+        isdir=Mock(return_value=False),
+        join=Mock(return_value='s3a://test-bucket/test-user/new_dir'),
+      ),
+    )
+    response = mkdir(request)
+
+    assert response.status_code == 400
+    assert response.content.decode('utf-8') == 'Missing required parameters: path and name are required.'
+
+  def test_mkdir_no_name(self):
+    request = Mock(
+      method='POST',
+      POST={'path': 's3a://test-bucket/test-user/'},
+      fs=Mock(
+        mkdir=Mock(),
+        isdir=Mock(return_value=False),
+        join=Mock(return_value='s3a://test-bucket/test-user/new_dir'),
+      ),
+    )
+    response = mkdir(request)
+
+    assert response.status_code == 400
+    assert response.content.decode('utf-8') == 'Missing required parameters: path and name are required.'
+
+
 class TestRenameAPI:
   def test_rename_success(self):
     request = Mock(