From 93fea83a2e5a7d83c64c4c2fef5c20bc3eebd1a3 Mon Sep 17 00:00:00 2001 From: Andrei Cioromila <andrei.cioromila@thinslices.com> Date: Fri, 26 Oct 2018 10:01:20 +0300 Subject: [PATCH] feature(collections): Add custom delete route to clear all linked resources --- .../src/Collections.js | 6 ++ .../src/routes/collections/delete.js | 81 +++++++++++++++++++ .../src/PackageManager.js | 21 +++++ 3 files changed, 108 insertions(+) create mode 100644 packages/component-manuscript-manager/src/routes/collections/delete.js diff --git a/packages/component-manuscript-manager/src/Collections.js b/packages/component-manuscript-manager/src/Collections.js index 8ce7c7977..178ca4dbc 100644 --- a/packages/component-manuscript-manager/src/Collections.js +++ b/packages/component-manuscript-manager/src/Collections.js @@ -36,6 +36,12 @@ const Collections = app => { authBearer, require(`${routePath}/get`)(app.locals.models), ) + + app.delete( + '/api/collections/:collectionId', + authBearer, + require(`${routePath}/delete`)(app.locals.models), + ) } module.exports = Collections diff --git a/packages/component-manuscript-manager/src/routes/collections/delete.js b/packages/component-manuscript-manager/src/routes/collections/delete.js new file mode 100644 index 000000000..b2a85a1b0 --- /dev/null +++ b/packages/component-manuscript-manager/src/routes/collections/delete.js @@ -0,0 +1,81 @@ +const { get, remove, concat } = require('lodash') +const config = require('config') + +const { + Team, + services, + authsome: authsomeHelper, +} = require('pubsweet-component-helper-service') + +const { + deleteFilesS3, +} = require('pubsweet-component-mts-package/src/PackageManager') + +const s3Config = get(config, 'pubsweet-component-aws-s3', {}) + +module.exports = models => async (req, res) => { + const { collectionId } = req.params + let collection, fragment + try { + collection = await models.Collection.find(collectionId) + + const fragmentId = collection.fragments[0] + if (!collection.fragments.includes(fragmentId)) + return res.status(400).json({ + error: `Collection and fragment do not match.`, + }) + + fragment = await models.Fragment.find(fragmentId) + + const authsome = authsomeHelper.getAuthsome(models) + + const canDelete = await authsome.can(req.user, 'DELETE', collection) + if (!canDelete) + return res.status(403).json({ + error: 'Unauthorized.', + }) + + const teamHelper = new Team({ + TeamModel: models.Team, + fragmentId, + collectionId, + }) + const team = await teamHelper.getTeam({ + role: 'author', + objectType: 'fragment', + }) + + await Promise.all( + team.members.map(async member => { + const user = await models.User.find(member) + + remove(user.teams, teamId => teamId === team.id) + + return user.save() + }), + ) + + await team.delete() + + const fileKeys = concat( + fragment.files.manuscripts, + fragment.files.coverLetter, + fragment.files.supplementary, + ).map(file => `${fragment.id}/${file.id}`) + + if (fileKeys.length !== 0) { + await deleteFilesS3({ fileKeys, s3Config }) + } + + await fragment.delete() + + await collection.delete() + + return res.status(200).json() + } catch (e) { + const notFoundError = await services.handleNotFoundError(e, 'Item') + return res.status(notFoundError.status).json({ + error: notFoundError.message, + }) + } +} diff --git a/packages/component-mts-package/src/PackageManager.js b/packages/component-mts-package/src/PackageManager.js index b98dbf103..cb9b8ea4c 100644 --- a/packages/component-mts-package/src/PackageManager.js +++ b/packages/component-mts-package/src/PackageManager.js @@ -115,6 +115,26 @@ const uploadFiles = async ({ filename, s3Config, config }) => { .catch(fileError(filename)) } +const deleteFilesS3 = async ({ fileKeys, s3Config }) => { + AWS.config.update({ + secretAccessKey: s3Config.secretAccessKey, + accessKeyId: s3Config.accessKeyId, + region: s3Config.region, + }) + const s3 = new AWS.S3() + + const params = { + Bucket: s3Config.bucket, + Delete: { + Objects: fileKeys.map(file => ({ Key: file })), + }, + } + + const deleteObjectsS3 = promisify(s3.deleteObjects.bind(s3)) + + return deleteObjectsS3(params) +} + const deleteFile = filename => { fs.access(filename, fs.constants.F_OK, err => { if (!err) { @@ -138,4 +158,5 @@ const uploadFTP = ({ filename, config }) => { module.exports = { createFilesPackage, uploadFiles, + deleteFilesS3, } -- GitLab