fix: Cleanup S3 Attachments (#1217)
* fix: Server error if attempting to load an unknown attachment * fix: Migration should cascade delete to document attachments * fix: Delete S3 attachments along with documents
This commit is contained in:
@@ -3,7 +3,7 @@ import Router from 'koa-router';
|
||||
import auth from '../middlewares/authentication';
|
||||
import { Attachment, Document } from '../models';
|
||||
import { getSignedImageUrl } from '../utils/s3';
|
||||
|
||||
import { NotFoundError } from '../errors';
|
||||
import policy from '../policies';
|
||||
|
||||
const { authorize } = policy;
|
||||
@@ -15,6 +15,9 @@ router.post('attachments.redirect', auth(), async ctx => {
|
||||
|
||||
const user = ctx.state.user;
|
||||
const attachment = await Attachment.findByPk(id);
|
||||
if (!attachment) {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
|
||||
if (attachment.isPrivate) {
|
||||
if (attachment.documentId) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
publicS3Endpoint,
|
||||
makeCredential,
|
||||
} from '../utils/s3';
|
||||
import { Attachment, Event, User, Team } from '../models';
|
||||
import { Document, Attachment, Event, User, Team } from '../models';
|
||||
import auth from '../middlewares/authentication';
|
||||
import pagination from './middlewares/pagination';
|
||||
import userInviter from '../commands/userInviter';
|
||||
@@ -96,6 +96,11 @@ router.post('users.s3Upload', auth(), async ctx => {
|
||||
const endpoint = publicS3Endpoint();
|
||||
const url = `${endpoint}/${key}`;
|
||||
|
||||
if (documentId) {
|
||||
const document = await Document.findByPk(documentId, { userId: user.id });
|
||||
authorize(user, 'update', document);
|
||||
}
|
||||
|
||||
const attachment = await Attachment.create({
|
||||
key,
|
||||
acl,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// @flow
|
||||
import debug from 'debug';
|
||||
import Router from 'koa-router';
|
||||
import subDays from 'date-fns/sub_days';
|
||||
import { AuthenticationError } from '../errors';
|
||||
import { Document } from '../models';
|
||||
import { Document, Attachment } from '../models';
|
||||
import { Op } from '../sequelize';
|
||||
|
||||
const router = new Router();
|
||||
const log = debug('utils');
|
||||
|
||||
router.post('utils.gc', async ctx => {
|
||||
const { token } = ctx.body;
|
||||
@@ -14,15 +16,33 @@ router.post('utils.gc', async ctx => {
|
||||
throw new AuthenticationError('Invalid secret token');
|
||||
}
|
||||
|
||||
await Document.scope('withUnpublished').destroy({
|
||||
where: {
|
||||
deletedAt: {
|
||||
[Op.lt]: subDays(new Date(), 30),
|
||||
},
|
||||
log('Permanently deleting documents older than 30 days…');
|
||||
|
||||
const where = {
|
||||
deletedAt: {
|
||||
[Op.lt]: subDays(new Date(), 30),
|
||||
},
|
||||
};
|
||||
|
||||
const documents = await Document.scope('withUnpublished').findAll({
|
||||
attributes: ['id'],
|
||||
where,
|
||||
});
|
||||
const documentIds = documents.map(d => d.id);
|
||||
|
||||
await Attachment.destroy({
|
||||
where: {
|
||||
documentId: documentIds,
|
||||
},
|
||||
});
|
||||
|
||||
await Document.scope('withUnpublished').destroy({
|
||||
where,
|
||||
force: true,
|
||||
});
|
||||
|
||||
log(`Deleted ${documentIds.length} documents`);
|
||||
|
||||
ctx.body = {
|
||||
success: true,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user