Skip to content

Commit e6c8379

Browse files
committed
Add recursive option to bucket delete endpoint
1 parent 67f1d68 commit e6c8379

File tree

4 files changed

+38
-8
lines changed

4 files changed

+38
-8
lines changed

app/src/controllers/bucket.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const { UniqueViolationError } = require('objection');
33
const { NIL: SYSTEM_USER } = require('uuid');
44

55
const { DEFAULTREGION, Permissions } = require('../components/constants');
6+
const utils = require('../db/models/utils');
67
const errorToProblem = require('../components/errorToProblem');
78
const log = require('../components/log')(module.filename);
89
const {
@@ -215,7 +216,20 @@ const controller = {
215216
async deleteBucket(req, res, next) {
216217
try {
217218
const bucketId = addDashesToUuid(req.params.bucketId);
218-
await bucketService.delete(bucketId);
219+
const parentBucket = await bucketService.read(bucketId);
220+
let buckets = [parentBucket];
221+
// if doing recursive delete
222+
if (isTruthy(req.query.recursive)) {
223+
// get sub-folders
224+
const dbChildBuckets = await bucketService.searchChildBuckets(parentBucket);
225+
buckets = buckets.concat(dbChildBuckets);
226+
}
227+
// do delete
228+
await utils.trxWrapper(async (trx) => {
229+
return await Promise.all(
230+
buckets.map(bucket => bucketService.delete(bucket.bucketId, trx))
231+
);
232+
});
219233
res.status(204).end();
220234
} catch (e) {
221235
next(errorToProblem(SERVICE, e));

app/src/docs/v1.api-spec.yaml

+11-5
Original file line numberDiff line numberDiff line change
@@ -198,16 +198,19 @@ paths:
198198
delete:
199199
summary: Deletes a bucket
200200
description: >-
201-
Deletes the bucket record based on bucketId. This request does not
202-
dispatch an S3 operation to request the deletion of the associated
203-
bucket.
201+
Deletes the bucket record (and child objects) from the COMS database, based on bucketId.
202+
Providing the 'recursive' parameter will also delete all sub-folders.
203+
This request does not dispatch an S3 operation to request the deletion of the associated
204+
bucket(s) or delete any objects in object storage, it simply 'de-registers' knowledge of the bucket/folder
205+
and objects from the COMS system.
204206
operationId: deleteBucket
205207
tags:
206208
- Bucket
207209
parameters:
208210
- $ref: "#/components/parameters/Header-S3AccessMode-Bucket"
209211
- $ref: "#/components/parameters/Header-S3AccessMode-Endpoint"
210212
- $ref: "#/components/parameters/Path-BucketId"
213+
- $ref: "#/components/parameters/Query-Recursive"
211214
responses:
212215
"204":
213216
description: Returns no content success
@@ -285,11 +288,14 @@ paths:
285288
description: >-
286289
Synchronize the contents of an existing bucket with COMS so that it can
287290
track and manage the objects in it. This avoids the need to re-upload
288-
preexisting files through the COMS API. This endpoint does not guarantee
291+
pre-existing files through the COMS API. This endpoint does not guarantee
289292
immediately synchronized results. Synchronization latency will be
290293
affected by the remaining number of objects awaiting synchronization.
291294
This endpoint updates the last known successful synchronization request
292295
date when invoked.
296+
The `recursive` option will optionally sync sub-folders.
297+
Note: The current user (if using OIDC auth) will get the permissions they
298+
already have on the parent applied to any NEW sub-folders created in COMS
293299
tags:
294300
- Sync
295301
operationId: syncBucket
@@ -2051,7 +2057,7 @@ components:
20512057
in: query
20522058
name: recursive
20532059
description: >-
2054-
Whether or not to also sync sub-folders inside the provided bucket/folder
2060+
Whether or not to also run this operation for sub-folders inside the provided bucket/folder
20552061
schema:
20562062
type: boolean
20572063
default: false

app/src/validators/bucket.js

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const schema = {
4040
bucketId: type.uuidv4
4141
}),
4242
query: Joi.object({
43+
recursive: type.truthy,
4344
})
4445
},
4546

app/tests/unit/controllers/bucket.spec.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const { UniqueViolationError } = require('objection');
33
const { NIL: SYSTEM_USER } = require('uuid');
44

55
const controller = require('../../../src/controllers/bucket');
6+
const moduleUtils = require('../../../src/db/models/utils');
67
const {
78
bucketService,
89
storageService,
@@ -453,6 +454,8 @@ describe('createBucketChild', () => {
453454
describe('deleteBucket', () => {
454455
// mock service calls
455456
const addDashesToUuidSpy = jest.spyOn(utils, 'addDashesToUuid');
457+
const readSpy = jest.spyOn(bucketService, 'read');
458+
const trxWrapperSpy = jest.spyOn(moduleUtils, 'trxWrapper');
456459
const deleteSpy = jest.spyOn(bucketService, 'delete');
457460

458461
const next = jest.fn();
@@ -466,13 +469,16 @@ describe('deleteBucket', () => {
466469
};
467470

468471
addDashesToUuidSpy.mockReturnValue(REQUEST_BUCKET_ID);
472+
readSpy.mockReturnValue({ bucketId: REQUEST_BUCKET_ID });
473+
trxWrapperSpy.mockImplementation(callback => callback({}));
469474
deleteSpy.mockReturnValue(true);
470475

471476
await controller.deleteBucket(req, res, next);
472477

473478
expect(addDashesToUuidSpy).toHaveBeenCalledTimes(1);
474479
expect(addDashesToUuidSpy).toHaveBeenCalledWith(REQUEST_BUCKET_ID);
475-
expect(deleteSpy).toHaveBeenCalledWith(REQUEST_BUCKET_ID);
480+
expect(trxWrapperSpy).toHaveBeenCalledTimes(1);
481+
expect(deleteSpy).toHaveBeenCalledWith(REQUEST_BUCKET_ID, {});
476482

477483
expect(res.status).toHaveBeenCalledWith(204);
478484
});
@@ -486,6 +492,8 @@ describe('deleteBucket', () => {
486492
};
487493

488494
addDashesToUuidSpy.mockReturnValue(REQUEST_BUCKET_ID);
495+
readSpy.mockReturnValue({ bucketId: REQUEST_BUCKET_ID });
496+
trxWrapperSpy.mockImplementation(callback => callback({}));
489497
deleteSpy.mockImplementationOnce(() => {
490498
throw new Problem(502, 'Unknown BucketService Error');
491499
});
@@ -494,7 +502,8 @@ describe('deleteBucket', () => {
494502

495503
expect(addDashesToUuidSpy).toHaveBeenCalledTimes(1);
496504
expect(addDashesToUuidSpy).toHaveBeenCalledWith(REQUEST_BUCKET_ID);
497-
expect(deleteSpy).toHaveBeenCalledWith(REQUEST_BUCKET_ID);
505+
expect(trxWrapperSpy).toHaveBeenCalledTimes(1);
506+
expect(deleteSpy).toHaveBeenCalledWith(REQUEST_BUCKET_ID, {});
498507

499508
expect(next).toHaveBeenCalledTimes(1);
500509
expect(next).toHaveBeenCalledWith(

0 commit comments

Comments
 (0)