feat: Add button to empty trash (#6772)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import uniq from "lodash/uniq";
|
||||
import { QueryTypes } from "sequelize";
|
||||
import { Op, QueryTypes } from "sequelize";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import { Document, Attachment } from "@server/models";
|
||||
import DeleteAttachmentTask from "@server/queues/tasks/DeleteAttachmentTask";
|
||||
@@ -73,6 +73,21 @@ export default async function documentPermanentDeleter(documents: Document[]) {
|
||||
);
|
||||
}
|
||||
|
||||
const documentIds = documents.map((document) => document.id);
|
||||
await Document.update(
|
||||
{
|
||||
parentDocumentId: null,
|
||||
},
|
||||
{
|
||||
where: {
|
||||
parentDocumentId: {
|
||||
[Op.in]: documentIds,
|
||||
},
|
||||
},
|
||||
paranoid: false,
|
||||
}
|
||||
);
|
||||
|
||||
return Document.scope("withDrafts").destroy({
|
||||
where: {
|
||||
id: documents.map((document) => document.id),
|
||||
|
||||
@@ -18,6 +18,24 @@ exports[`#documents.delete should require authentication 1`] = `
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`#documents.empty_trash should not allow non-admin users 1`] = `
|
||||
{
|
||||
"error": "authorization_error",
|
||||
"message": "Admin role required",
|
||||
"ok": false,
|
||||
"status": 403,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`#documents.empty_trash should require authentication 1`] = `
|
||||
{
|
||||
"error": "authentication_required",
|
||||
"message": "Authentication required",
|
||||
"ok": false,
|
||||
"status": 401,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`#documents.list should require authentication 1`] = `
|
||||
{
|
||||
"error": "authentication_required",
|
||||
|
||||
@@ -4345,3 +4345,58 @@ describe("#documents.memberships", () => {
|
||||
expect(body.data.users[0].id).toEqual(members[1].id);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#documents.empty_trash", () => {
|
||||
it("should require authentication", async () => {
|
||||
const res = await server.post("/api/documents.empty_trash");
|
||||
const body = await res.json();
|
||||
expect(res.status).toEqual(401);
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
||||
it("should allow admin users", async () => {
|
||||
const user = await buildAdmin();
|
||||
const res = await server.post("/api/documents.empty_trash", {
|
||||
body: {
|
||||
token: user.getJwtToken(),
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
expect(res.status).toEqual(200);
|
||||
expect(body.success).toEqual(true);
|
||||
});
|
||||
it("should not allow non-admin users", async () => {
|
||||
const user = await buildUser();
|
||||
const res = await server.post("/api/documents.empty_trash", {
|
||||
body: {
|
||||
token: user.getJwtToken(),
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
expect(res.status).toEqual(403);
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
||||
it("should permanently delete documents", async () => {
|
||||
const user = await buildAdmin();
|
||||
const document = await buildDocument({
|
||||
userId: user.id,
|
||||
teamId: user.teamId,
|
||||
});
|
||||
await document.delete(user.id);
|
||||
|
||||
const res = await server.post("/api/documents.empty_trash", {
|
||||
body: {
|
||||
token: user.getJwtToken(),
|
||||
},
|
||||
});
|
||||
|
||||
const body = await res.json();
|
||||
expect(res.status).toEqual(200);
|
||||
expect(body.success).toEqual(true);
|
||||
|
||||
const deletedDoc = await Document.findByPk(document.id, {
|
||||
userId: user.id,
|
||||
paranoid: false,
|
||||
});
|
||||
expect(deletedDoc).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1213,17 +1213,6 @@ router.post(
|
||||
});
|
||||
authorize(user, "permanentDelete", document);
|
||||
|
||||
await Document.update(
|
||||
{
|
||||
parentDocumentId: null,
|
||||
},
|
||||
{
|
||||
where: {
|
||||
parentDocumentId: document.id,
|
||||
},
|
||||
paranoid: false,
|
||||
}
|
||||
);
|
||||
await documentPermanentDeleter([document]);
|
||||
await Event.create({
|
||||
name: "documents.permanent_delete",
|
||||
@@ -1701,4 +1690,55 @@ router.post(
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
"documents.empty_trash",
|
||||
auth({ role: UserRole.Admin }),
|
||||
async (ctx: APIContext) => {
|
||||
const { user } = ctx.state.auth;
|
||||
|
||||
const collectionIds = await user.collectionIds({
|
||||
paranoid: false,
|
||||
});
|
||||
const collectionScope: Readonly<ScopeOptions> = {
|
||||
method: ["withCollectionPermissions", user.id],
|
||||
};
|
||||
const documents = await Document.scope([
|
||||
collectionScope,
|
||||
"withDrafts",
|
||||
]).findAll({
|
||||
where: {
|
||||
deletedAt: {
|
||||
[Op.ne]: null,
|
||||
},
|
||||
[Op.or]: [
|
||||
{
|
||||
collectionId: {
|
||||
[Op.in]: collectionIds,
|
||||
},
|
||||
},
|
||||
{
|
||||
createdById: user.id,
|
||||
collectionId: {
|
||||
[Op.is]: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
paranoid: false,
|
||||
});
|
||||
|
||||
await documentPermanentDeleter(documents);
|
||||
await Event.create({
|
||||
name: "documents.empty_trash",
|
||||
teamId: user.teamId,
|
||||
actorId: user.id,
|
||||
ip: ctx.request.ip,
|
||||
});
|
||||
|
||||
ctx.body = {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user