mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +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 { nanoid } from 'nanoid';
|
||||||
import type { Readable } from 'stream';
|
import type { Readable } from 'stream';
|
||||||
import { Context } from '../context';
|
import { Context } from '../context';
|
||||||
|
import { FileNode } from '../interface';
|
||||||
import mime from '../lib/mime';
|
import mime from '../lib/mime';
|
||||||
import db from '../service/db';
|
import db from '../service/db';
|
||||||
import storage from '../service/storage';
|
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) {
|
static async del(path: string[], operator = 1) {
|
||||||
if (!path.length) return;
|
if (!path.length) return;
|
||||||
const affected = await StorageModel.coll.find({ path: { $in: path } }).toArray();
|
// files pending to be deleted
|
||||||
if (!affected.length) return;
|
const pendingDelete = await StorageModel.coll.find({ path: { $in: path }, autoDelete: null }).toArray();
|
||||||
const linked = await StorageModel.coll.find({ link: { $in: affected.map((i) => i._id) }, path: { $nin: path } }).toArray();
|
if (!pendingDelete.length) return;
|
||||||
const processedIds = [];
|
// all files not going to be deleted but affected (referencing to the files to be deleted)
|
||||||
for (const i of linked || []) {
|
const linked = await StorageModel.coll.find({ link: { $in: pendingDelete.map((i) => i._id) }, path: { $nin: path } }).toArray();
|
||||||
if (processedIds.includes(i.link)) continue;
|
const fileIds = [];
|
||||||
const current = affected.find((t) => t._id === i.link); // to be deleted
|
for (const i of pendingDelete) {
|
||||||
// eslint-disable-next-line no-await-in-loop
|
const affected = linked.filter((t) => t.link === i._id);
|
||||||
await Promise.all([
|
if (!affected.length) {
|
||||||
StorageModel.coll.updateOne({ _id: current._id }, { $set: omit(i, ['_id']) }),
|
fileIds.push(i._id);
|
||||||
StorageModel.coll.updateOne({ _id: i._id }, { $set: omit(current, ['_id']), $unset: { link: '' } }),
|
continue;
|
||||||
]);
|
}
|
||||||
processedIds.push(i.link);
|
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();
|
const autoDelete = moment().add(7, 'day').toDate();
|
||||||
await StorageModel.coll.updateMany(
|
await StorageModel.coll.updateMany(
|
||||||
{ path: { $in: path }, autoDelete: null },
|
{ _id: { $in: fileIds } },
|
||||||
{ $set: { autoDelete }, $push: { operator } },
|
{ $set: { autoDelete }, $push: { operator } },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user