fix(#104): enforce storage quota on uploads & fix usage tracking
Backend: - Add QuotaExceeded error kind mapped to HTTP 507 Insufficient Storage - Add check_storage_quota() and get_user_storage_info() to StorageUsagePort - Enforce quota in upload_file_with_cache, upload_file_with_thumbnails (AuthUser extractor) - Enforce quota in chunked upload create_upload handler - Add update_user_storage_usage_by_username() for username-based lookup - Fix extract_username_from_path() to handle subfolders (take first segment only) - Fix maybe_update_storage_usage() to use username-based lookup instead of passing username to get_user_by_id (which always failed silently) Frontend: - Parse and display quota error messages on upload failure (507 / QuotaExceeded) - Stop remaining uploads when quota is exceeded - Call refreshUserData() after uploads to update storage usage display - Bump service worker cache to v9
This commit is contained in:
@@ -128,7 +128,15 @@ const fileOps = {
|
||||
fileRowElements.icon.innerHTML = '<i class="fas fa-exclamation-circle"></i>';
|
||||
fileRowElements.icon.classList.add('error');
|
||||
}
|
||||
resolve({ ok: false });
|
||||
// Parse error body for quota-exceeded or other messages
|
||||
let errorMsg = null;
|
||||
let isQuotaError = false;
|
||||
try {
|
||||
const errBody = JSON.parse(xhr.responseText);
|
||||
errorMsg = errBody.error || null;
|
||||
isQuotaError = errBody.error_type === 'QuotaExceeded' || xhr.status === 507;
|
||||
} catch (_) {}
|
||||
resolve({ ok: false, errorMsg, isQuotaError });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -208,7 +216,14 @@ const fileOps = {
|
||||
console.log(`Successfully uploaded ${file.name}`, result.data);
|
||||
} else {
|
||||
console.error(`Upload error for ${file.name}`);
|
||||
window.ui.showNotification('Error', `Error uploading file: ${file.name}`);
|
||||
if (result.isQuotaError) {
|
||||
const msg = result.errorMsg || window.i18n?.t('storage_quota_exceeded') || 'Storage quota exceeded';
|
||||
window.ui.showNotification('Error', `${file.name}: ${msg}`);
|
||||
// Stop uploading remaining files — quota is full
|
||||
break;
|
||||
} else {
|
||||
window.ui.showNotification('Error', `Error uploading file: ${file.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +233,11 @@ const fileOps = {
|
||||
// Wait for backend to persist, then reload
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
|
||||
// Refresh storage usage display
|
||||
if (typeof window.refreshUserData === 'function') {
|
||||
try { await window.refreshUserData(); } catch (_) {}
|
||||
}
|
||||
|
||||
try {
|
||||
await window.loadFiles({ forceRefresh: true });
|
||||
} catch (reloadError) {
|
||||
@@ -330,6 +350,11 @@ const fileOps = {
|
||||
console.log(`Uploaded: ${file.webkitRelativePath}`);
|
||||
} else {
|
||||
console.error(`Error uploading ${file.webkitRelativePath}`);
|
||||
if (result.isQuotaError) {
|
||||
const msg = result.errorMsg || window.i18n?.t('storage_quota_exceeded') || 'Storage quota exceeded';
|
||||
window.ui.showNotification('Error', `${file.name}: ${msg}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,6 +362,11 @@ const fileOps = {
|
||||
this._finishUploadToast(successCount, totalFiles);
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 800));
|
||||
|
||||
// Refresh storage usage display
|
||||
if (typeof window.refreshUserData === 'function') {
|
||||
try { await window.refreshUserData(); } catch (_) {}
|
||||
}
|
||||
|
||||
try {
|
||||
await window.loadFiles({ forceRefresh: true });
|
||||
|
||||
Reference in New Issue
Block a user