feat: folder ownership scoping, batch operations integration, frontend audit fixes
Backend: - Add owner_id to Folder entity + FolderDto (DB user_id column) - Add list_folders_by_owner to FolderRepository trait + PG impl - Add list_folders_for_owner to FolderUseCase + FolderService - Rewrite FolderHandler: all endpoints now scope by AuthUser - Remove dead handler methods (list_folders_inner, list_folders_for_user, is_user_home_folder, folder_belongs_to_user) - Add ownership check in get_folder (returns 404 on mismatch) Batch operations: - Add trash_service + zip_service to BatchOperationService - New methods: trash_files, trash_folders, move_folders, download_zip - New handlers: trash_batch, move_folders_batch, download_batch - New routes: POST /api/batch/trash, /api/batch/folders/move, /api/batch/download Frontend: - Replace findUserHomeFolder (~130 lines) with resolveHomeFolder (~35 lines) - Remove client-side folder filtering in loadFiles (backend now scopes) - Rewrite batchDelete: N requests -> 1 POST /api/batch/trash - Rewrite batchMove: N requests -> 2 POST max (files + folders) - Rewrite batchDownload: N requests -> 1 POST /api/batch/download (ZIP) - Search moved to backend, share system uses backend API - Dark mode fixes, frontend audit improvements
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>OxiCloud - Shared Resources</title>
|
||||
<!-- Apply saved theme immediately to prevent flash of light mode -->
|
||||
<script>if(localStorage.getItem('oxicloud_theme')==='dark')document.documentElement.setAttribute('data-theme','dark');</script>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||
@@ -74,6 +76,13 @@
|
||||
<span class="user-email" id="user-menu-email">admin@oxicloud.local</span>
|
||||
</div>
|
||||
<div class="user-menu-divider"></div>
|
||||
<div class="user-menu-item" id="menu-theme">
|
||||
<i class="fas fa-moon"></i>
|
||||
<span data-i18n="user_menu.appearance">Appearance</span>
|
||||
<div class="theme-toggle-pill" id="theme-toggle-pill">
|
||||
<div class="theme-toggle-knob"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-menu-item" id="menu-logout">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
<span data-i18n="actions.logout">Log out</span>
|
||||
@@ -284,6 +293,21 @@
|
||||
window.location.href = '/login';
|
||||
});
|
||||
}
|
||||
|
||||
// Theme toggle (dark mode)
|
||||
const themeBtn = document.getElementById('menu-theme');
|
||||
const pill = document.getElementById('theme-toggle-pill');
|
||||
if (themeBtn && pill) {
|
||||
const isDark = localStorage.getItem('oxicloud_theme') === 'dark';
|
||||
if (isDark) pill.classList.add('active');
|
||||
themeBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
pill.classList.toggle('active');
|
||||
const dark = pill.classList.contains('active');
|
||||
localStorage.setItem('oxicloud_theme', dark ? 'dark' : 'light');
|
||||
document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script src="/js/shared.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user