From ab74ed6dc2377bc20e3ad1f1195df96f6e681f1a Mon Sep 17 00:00:00 2001 From: ekzyis Date: Fri, 20 Oct 2023 00:41:32 +0200 Subject: [PATCH] Also delete objects in S3 --- api/resolvers/item.js | 11 +++++++---- api/resolvers/upload.js | 29 +++-------------------------- api/s3/index.js | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 api/s3/index.js diff --git a/api/resolvers/item.js b/api/resolvers/item.js index 19e8abee6..a326c2a91 100644 --- a/api/resolvers/item.js +++ b/api/resolvers/item.js @@ -16,6 +16,7 @@ import { advSchema, amountSchema, bountySchema, commentSchema, discussionSchema, import { sendUserNotification } from '../webPush' import { defaultCommentSort } from '../../lib/item' import { notifyItemParents, notifyUserSubscribers, notifyZapped } from '../../lib/push-notifications' +import { deleteObject } from '../s3' export async function commentFilterClause (me, models) { let clause = ` AND ("Item"."weightedVotes" - "Item"."weightedDownVotes" > -${ITEM_FILTER_THRESHOLD}` @@ -757,13 +758,15 @@ export default { throw new GraphQLError('you must be logged in', { extensions: { code: 'FORBIDDEN' } }) } - id = Number(id) - - const img = await models.upload.findUnique({ where: { id } }) + const img = await models.upload.findUnique({ where: { id: Number(id) } }) if (img.userId !== me.id) { throw new GraphQLError('not your image', { extensions: { code: 'FORBIDDEN' } }) } - await models.upload.delete({ where: { id } }) + if (img.itemId) { + throw new GraphQLError('image already included in an item', { extensions: { code: 'BAD_INPUT' } }) + } + await models.upload.delete({ where: { id: Number(id) } }) + await deleteObject(id) return id } diff --git a/api/resolvers/upload.js b/api/resolvers/upload.js index b8bd1e937..34e86c172 100644 --- a/api/resolvers/upload.js +++ b/api/resolvers/upload.js @@ -1,12 +1,6 @@ import { GraphQLError } from 'graphql' -import AWS from 'aws-sdk' import { IMAGE_PIXELS_MAX, UPLOAD_SIZE_MAX, UPLOAD_TYPES_ALLOW } from '../../lib/constants' - -const bucketRegion = 'us-east-1' - -AWS.config.update({ - region: bucketRegion -}) +import { createPresignedPost } from '../s3' export default { Mutation: { @@ -38,25 +32,8 @@ export default { } }) - // get presigned POST ur - const s3 = new AWS.S3({ apiVersion: '2006-03-01' }) - const res = await new Promise((resolve, reject) => { - s3.createPresignedPost({ - Bucket: process.env.NEXT_PUBLIC_AWS_UPLOAD_BUCKET, - Fields: { - key: String(upload.id) - }, - Expires: 300, - Conditions: [ - { 'Content-Type': type }, - { 'Cache-Control': 'max-age=31536000' }, - { acl: 'public-read' }, - ['content-length-range', size, size] - ] - }, (err, preSigned) => { if (err) { reject(err) } else { resolve(preSigned) } }) - }) - - return res + // get presigned POST url + return createPresignedPost({ key: String(upload.id), type, size }) } } } diff --git a/api/s3/index.js b/api/s3/index.js new file mode 100644 index 000000000..bcaf23316 --- /dev/null +++ b/api/s3/index.js @@ -0,0 +1,35 @@ +import AWS from 'aws-sdk' + +const bucketRegion = 'us-east-1' +const Bucket = process.env.NEXT_PUBLIC_AWS_UPLOAD_BUCKET + +AWS.config.update({ + region: bucketRegion +}) + +export function createPresignedPost ({ key, type, size }) { + const s3 = new AWS.S3({ apiVersion: '2006-03-01' }) + return new Promise((resolve, reject) => { + s3.createPresignedPost({ + Bucket, + Fields: { key }, + Expires: 300, + Conditions: [ + { 'Content-Type': type }, + { 'Cache-Control': 'max-age=31536000' }, + { acl: 'public-read' }, + ['content-length-range', size, size] + ] + }, (err, preSigned) => { err ? reject(err) : resolve(preSigned) }) + }) +} + +export function deleteObject (key) { + const s3 = new AWS.S3({ apiVersion: '2006-03-01' }) + return new Promise((resolve, reject) => { + s3.deleteObject({ + Bucket, + Key: key + }, (err, data) => { err ? reject(err) : resolve(key) }) + }) +}