add: more things

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-07-04 03:35:09 +08:00
parent a572c1e25f
commit 3c13bb9821
36 changed files with 896 additions and 928 deletions
+77
View File
@@ -660,6 +660,83 @@ exports.restoreAssets = async (req, res) => {
}
};
// ─── PERMANENT DELETE (single) ─────────────────────────────────────────────────
exports.permanentlyDeleteAsset = async (req, res) => {
try {
const { assetId } = req.params;
const asset = await Asset.findOne({ where: { asset_id: assetId }, paranoid: false });
if (!asset) return R.error(res, "Asset not found.", 404);
if (!asset.deletedAt) return R.error(res, "Asset must be archived before it can be permanently deleted.", 400);
const { storage_provider, storage_key, thumbnail_storage_key } = asset;
await asset.destroy({ force: true });
const svc = getProvider(storage_provider);
if (svc) {
if (storage_key) {
try { await svc.deleteFile(storage_key); }
catch (err) { console.warn(`[ASSET][PERMANENT DELETE] File cleanup failed for "${storage_key}":`, err.message); }
}
if (thumbnail_storage_key) {
try { await svc.deleteFile(thumbnail_storage_key); }
catch (err) { console.warn(`[ASSET][PERMANENT DELETE] Thumbnail cleanup failed for "${thumbnail_storage_key}":`, err.message); }
}
}
invalidateListCache();
logActivity(req.user?.user_id, 'permanently_delete_asset', { entityType: 'asset', entityId: Number(assetId) });
return R.success(res, "Asset permanently deleted.");
} catch (err) {
console.error("[ASSET][PERMANENT DELETE]", err);
return R.error(res, "Internal server error.", 500);
}
};
// ─── PERMANENT DELETE (bulk) ───────────────────────────────────────────────────
exports.permanentlyDeleteAssets = async (req, res) => {
try {
const { ids } = req.body;
if (!Array.isArray(ids) || !ids.length) return R.error(res, "ids must be a non-empty array.", 400);
const assets = await Asset.findAll({ where: { asset_id: { [Op.in]: ids } }, paranoid: false });
if (!assets.length) return R.error(res, "No assets found.", 404);
const archivedAssets = assets.filter((a) => a.deletedAt);
if (!archivedAssets.length) return R.error(res, "All selected assets must be archived before they can be permanently deleted.", 400);
const archivedIds = archivedAssets.map((a) => a.asset_id);
await Asset.destroy({ where: { asset_id: { [Op.in]: archivedIds } }, force: true });
for (const asset of archivedAssets) {
const svc = getProvider(asset.storage_provider);
if (!svc) continue;
if (asset.storage_key) {
try { await svc.deleteFile(asset.storage_key); }
catch (err) { console.warn(`[ASSET][PERMANENT DELETE] File cleanup failed for "${asset.storage_key}":`, err.message); }
}
if (asset.thumbnail_storage_key) {
try { await svc.deleteFile(asset.thumbnail_storage_key); }
catch (err) { console.warn(`[ASSET][PERMANENT DELETE] Thumbnail cleanup failed for "${asset.thumbnail_storage_key}":`, err.message); }
}
}
invalidateListCache();
logActivity(req.user?.user_id, 'bulk_permanently_delete_assets', { entityType: 'asset', details: { ids: archivedIds, count: archivedIds.length } });
return R.success(res, `${archivedIds.length} asset(s) permanently deleted.`, {
deleted_ids: archivedIds,
skipped_ids: ids.filter((id) => !archivedIds.includes(id)),
});
} catch (err) {
console.error("[ASSET][BULK PERMANENT DELETE]", err);
return R.error(res, "Internal server error.", 500);
}
};
// ─── ARCHIVED LIST ────────────────────────────────────────────────────────────
exports.getArchivedAssets = async (req, res) => {