mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-18 01:36:08 +08:00
core: fix deletion of referenced files
This commit is contained in:
1 file changed
+30
-14
@@ -4,6 +4,7 @@ import moment from 'moment-timezone';
|
||||
import { nanoid } from 'nanoid';
|
||||
import type { Readable } from 'stream';
|
||||
import { Context } from '../context';
|
||||
import { FileNode } from '../interface';
|
||||
import mime from '../lib/mime';
|
||||
import db from '../service/db';
|
||||
import storage from '../service/storage';
|
||||
@@ -49,25 +50,40 @@ export class StorageModel {
|
||||
);
|
||||
}
|
||||
|
||||
private static async _swapId(fileA: FileNode, fileB: FileNode) {
|
||||
// try to swap the two file with same content to make sure the first file is no longer being referenced
|
||||
// Example
|
||||
// _id: A, path: C, meta: R
|
||||
// _id: B, path: D, link: A, meta: P
|
||||
// and we want to delete path=B, the result should be
|
||||
// _id: A, path: D, meta: P
|
||||
// _id: B, path: C, link: A, meta: R
|
||||
await Promise.all([
|
||||
StorageModel.coll.updateOne({ _id: fileA._id }, { $set: omit(fileB, ['_id', 'link']) }),
|
||||
StorageModel.coll.updateOne({ _id: fileB._id }, { $set: omit(fileA, ['_id', 'link']) }),
|
||||
]);
|
||||
}
|
||||
|
||||
static async del(path: string[], operator = 1) {
|
||||
if (!path.length) return;
|
||||
const affected = await StorageModel.coll.find({ path: { $in: path } }).toArray();
|
||||
if (!affected.length) return;
|
||||
const linked = await StorageModel.coll.find({ link: { $in: affected.map((i) => i._id) }, path: { $nin: path } }).toArray();
|
||||
const processedIds = [];
|
||||
for (const i of linked || []) {
|
||||
if (processedIds.includes(i.link)) continue;
|
||||
const current = affected.find((t) => t._id === i.link); // to be deleted
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Promise.all([
|
||||
StorageModel.coll.updateOne({ _id: current._id }, { $set: omit(i, ['_id']) }),
|
||||
StorageModel.coll.updateOne({ _id: i._id }, { $set: omit(current, ['_id']), $unset: { link: '' } }),
|
||||
]);
|
||||
processedIds.push(i.link);
|
||||
// files pending to be deleted
|
||||
const pendingDelete = await StorageModel.coll.find({ path: { $in: path }, autoDelete: null }).toArray();
|
||||
if (!pendingDelete.length) return;
|
||||
// all files not going to be deleted but affected (referencing to the files to be deleted)
|
||||
const linked = await StorageModel.coll.find({ link: { $in: pendingDelete.map((i) => i._id) }, path: { $nin: path } }).toArray();
|
||||
const fileIds = [];
|
||||
for (const i of pendingDelete) {
|
||||
const affected = linked.filter((t) => t.link === i._id);
|
||||
if (!affected.length) {
|
||||
fileIds.push(i._id);
|
||||
continue;
|
||||
}
|
||||
await StorageModel._swapId(i, affected[0]); // eslint-disable-line no-await-in-loop
|
||||
fileIds.push(affected[0]._id); // we already swapped the two files, so we need to delete the other one
|
||||
}
|
||||
const autoDelete = moment().add(7, 'day').toDate();
|
||||
await StorageModel.coll.updateMany(
|
||||
{ path: { $in: path }, autoDelete: null },
|
||||
{ _id: { $in: fileIds } },
|
||||
{ $set: { autoDelete }, $push: { operator } },
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user