feat: Enhance WebDAV file management and UI
- Add functionality to create new collections via API - Implement copy and move operations between collections - Improve image rendering in markdown preview with relative path resolution - Add support for previewing binary files (images, PDFs) - Refactor modal styling to use flat buttons and improve accessibility
This commit is contained in:
		| @@ -28,8 +28,16 @@ class MarkdownEditorApp: | ||||
|      | ||||
|     def load_config(self, config_path): | ||||
|         """Load configuration from YAML file""" | ||||
|         self.config_path = config_path | ||||
|         with open(config_path, 'r') as f: | ||||
|             return yaml.safe_load(f) | ||||
|  | ||||
|     def save_config(self): | ||||
|         """Save configuration to YAML file""" | ||||
|         # Update config with current collections | ||||
|         self.config['collections'] = self.collections | ||||
|         with open(self.config_path, 'w') as f: | ||||
|             yaml.dump(self.config, f, default_flow_style=False, sort_keys=False) | ||||
|      | ||||
|     def setup_collections(self): | ||||
|         """Create collection directories if they don't exist""" | ||||
| @@ -92,6 +100,10 @@ class MarkdownEditorApp: | ||||
|         if path == '/fs/' and method == 'GET': | ||||
|             return self.handle_collections_list(environ, start_response) | ||||
|  | ||||
|         # API to create new collection | ||||
|         if path == '/fs/' and method == 'POST': | ||||
|             return self.handle_create_collection(environ, start_response) | ||||
|  | ||||
|         # Check if path starts with a collection name (for SPA routing) | ||||
|         # This handles URLs like /notes/ttt or /documents/file.md | ||||
|         # MUST be checked BEFORE WebDAV routing to prevent WebDAV from intercepting SPA routes | ||||
| @@ -113,14 +125,86 @@ class MarkdownEditorApp: | ||||
|         """Return list of available collections""" | ||||
|         collections = list(self.collections.keys()) | ||||
|         response_body = json.dumps(collections).encode('utf-8') | ||||
|          | ||||
|  | ||||
|         start_response('200 OK', [ | ||||
|             ('Content-Type', 'application/json'), | ||||
|             ('Content-Length', str(len(response_body))), | ||||
|             ('Access-Control-Allow-Origin', '*') | ||||
|         ]) | ||||
|          | ||||
|  | ||||
|         return [response_body] | ||||
|  | ||||
|     def handle_create_collection(self, environ, start_response): | ||||
|         """Create a new collection""" | ||||
|         try: | ||||
|             # Read request body | ||||
|             content_length = int(environ.get('CONTENT_LENGTH', 0)) | ||||
|             request_body = environ['wsgi.input'].read(content_length) | ||||
|             data = json.loads(request_body.decode('utf-8')) | ||||
|  | ||||
|             collection_name = data.get('name') | ||||
|             if not collection_name: | ||||
|                 start_response('400 Bad Request', [('Content-Type', 'application/json')]) | ||||
|                 return [json.dumps({'error': 'Collection name is required'}).encode('utf-8')] | ||||
|  | ||||
|             # Check if collection already exists | ||||
|             if collection_name in self.collections: | ||||
|                 start_response('409 Conflict', [('Content-Type', 'application/json')]) | ||||
|                 return [json.dumps({'error': f'Collection "{collection_name}" already exists'}).encode('utf-8')] | ||||
|  | ||||
|             # Create collection directory | ||||
|             collection_path = Path(f'./collections/{collection_name}') | ||||
|             collection_path.mkdir(parents=True, exist_ok=True) | ||||
|  | ||||
|             # Create images subdirectory | ||||
|             images_path = collection_path / 'images' | ||||
|             images_path.mkdir(exist_ok=True) | ||||
|  | ||||
|             # Add to collections dict | ||||
|             self.collections[collection_name] = { | ||||
|                 'path': str(collection_path), | ||||
|                 'description': f'User-created collection: {collection_name}' | ||||
|             } | ||||
|  | ||||
|             # Update config file | ||||
|             self.save_config() | ||||
|  | ||||
|             # Add to WebDAV provider mapping | ||||
|             from wsgidav.fs_dav_provider import FilesystemProvider | ||||
|             provider_path = os.path.abspath(str(collection_path)) | ||||
|             provider_key = f'/fs/{collection_name}' | ||||
|  | ||||
|             # Use the add_provider method if available, otherwise add directly to provider_map | ||||
|             provider = FilesystemProvider(provider_path) | ||||
|             if hasattr(self.webdav_app, 'add_provider'): | ||||
|                 self.webdav_app.add_provider(provider_key, provider) | ||||
|                 print(f"Added provider using add_provider(): {provider_key}") | ||||
|             else: | ||||
|                 self.webdav_app.provider_map[provider_key] = provider | ||||
|                 print(f"Added provider to provider_map: {provider_key}") | ||||
|  | ||||
|             # Also update sorted_share_list if it exists | ||||
|             if hasattr(self.webdav_app, 'sorted_share_list'): | ||||
|                 if provider_key not in self.webdav_app.sorted_share_list: | ||||
|                     self.webdav_app.sorted_share_list.append(provider_key) | ||||
|                     self.webdav_app.sorted_share_list.sort(reverse=True) | ||||
|                     print(f"Updated sorted_share_list") | ||||
|  | ||||
|             print(f"Created collection '{collection_name}' at {provider_path}") | ||||
|  | ||||
|             response_body = json.dumps({'success': True, 'name': collection_name}).encode('utf-8') | ||||
|             start_response('201 Created', [ | ||||
|                 ('Content-Type', 'application/json'), | ||||
|                 ('Content-Length', str(len(response_body))), | ||||
|                 ('Access-Control-Allow-Origin', '*') | ||||
|             ]) | ||||
|  | ||||
|             return [response_body] | ||||
|  | ||||
|         except Exception as e: | ||||
|             print(f"Error creating collection: {e}") | ||||
|             start_response('500 Internal Server Error', [('Content-Type', 'application/json')]) | ||||
|             return [json.dumps({'error': str(e)}).encode('utf-8')] | ||||
|      | ||||
|     def handle_static(self, environ, start_response): | ||||
|         """Serve static files""" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user