diff --git a/app/src/controllers/object.js b/app/src/controllers/object.js index dddd851a..3b83c83e 100644 --- a/app/src/controllers/object.js +++ b/app/src/controllers/object.js @@ -929,14 +929,20 @@ const controller = { public: isTruthy(req.query.public), active: isTruthy(req.query.active), deleteMarker: isTruthy(req.query.deleteMarker), - latest: isTruthy(req.query.latest) + latest: isTruthy(req.query.latest), + page: req.query.page, + limit: req.query.limit, + sort: req.query.sort, + order: req.query.order, + permissions: isTruthy(req.query.permissions) }; // if scoping to current user permissions on objects if (config.has('server.privacyMask')) { params.userId = await userService.getCurrentUserId(getCurrentIdentity(req.currentUser, SYSTEM_USER)); } const response = await objectService.searchObjects(params); - res.status(200).json(response); + res.setHeader('X-Total-Rows', response.total); + res.status(200).json(response.data); } catch (error) { next(error); } diff --git a/app/src/db/models/tables/objectModel.js b/app/src/db/models/tables/objectModel.js index e391d203..81df5254 100644 --- a/app/src/db/models/tables/objectModel.js +++ b/app/src/db/models/tables/objectModel.js @@ -176,6 +176,12 @@ class ObjectModel extends Timestamps(Model) { }); }); } + }, + pagination(query, page, limit){ + if( page && limit) query.page(page - 1, limit); + }, + sortOrder(query, column, order='asc'){ + if(column) query.orderBy(column, order); } }; } diff --git a/app/src/docs/v1.api-spec.yaml b/app/src/docs/v1.api-spec.yaml index c888ce95..53de0999 100644 --- a/app/src/docs/v1.api-spec.yaml +++ b/app/src/docs/v1.api-spec.yaml @@ -401,6 +401,11 @@ paths: - $ref: "#/components/parameters/Query-Public" - $ref: "#/components/parameters/Query-MimeType" - $ref: "#/components/parameters/Query-Name" + - $ref: "#/components/parameters/Query-Permissions" + - $ref: "#/components/parameters/Query-Page" + - $ref: "#/components/parameters/Query-Limit" + - $ref: "#/components/parameters/Query-Sort" + - $ref: "#/components/parameters/Query-Order" - $ref: "#/components/parameters/Query-TagSet" responses: "200": @@ -1738,6 +1743,41 @@ components: schema: type: boolean example: true + Query-Permissions: + in: query + name: permissions + description: >- + Boolean representing whether or not to include matching permissions + schema: + type: boolean + example: true + Query-Page: + in: query + name: page + description: >- + The index of the page to return. The index of first page is 1. + Must specify limit when defined. + schema: + type: number + example: 1 + Query-Limit: + in: query + name: limit + description: >- + The page size, number of objects in a page. + Must specify page number when defined. + schema: + type: number + example: 5 + Query-Sort: + in: query + name: Sort + description: >- + The page size, number of objects in a page. + Must specify page number when defined. + schema: + type: number + example: 5 Query-Path: in: query name: path diff --git a/app/src/services/object.js b/app/src/services/object.js index 736bb20b..073b8361 100644 --- a/app/src/services/object.js +++ b/app/src/services/object.js @@ -117,11 +117,13 @@ const service = { */ searchObjects: async (params, etrx = undefined) => { let trx; + let response = []; try { trx = etrx ? etrx : await ObjectModel.startTransaction(); - const response = await ObjectModel.query(trx) - .allowGraph('version') + response.data = await ObjectModel.query(trx) + .allowGraph('objectPermission') + .withGraphFetched('objectPermission') .modify('filterIds', params.id) .modify('filterBucketIds', params.bucketId) .modify('filterName', params.name) @@ -136,12 +138,27 @@ const service = { tag: params.tag }) .modify('hasPermission', params.userId, 'READ') - // format result + .modify('pagination', params.page, params.limit) + .modify('sortOrder', params.sort, params.order) .then(result => { - // just return object table records - const res = result.map(row => { + let resultObject = []; + if (Object.hasOwn(result, 'results')) { + resultObject = result.results; + response.total = result.total; + } else { + resultObject = result; + response.total = result.length; + } + + const res = resultObject.map(row => { // eslint-disable-next-line no-unused-vars const { objectPermission, bucketPermission, version, ...object } = row; + if (params.permissions) { + object.objectPermissions = []; + objectPermission.map(o => { + object.objectPermissions.push(o.permCode); + }); + } return object; }); // remove duplicates diff --git a/app/src/validators/common.js b/app/src/validators/common.js index d4c2c174..d0fcb341 100644 --- a/app/src/validators/common.js +++ b/app/src/validators/common.js @@ -81,7 +81,12 @@ const scheme = { guid: oneOrMany(type.uuidv4), string: oneOrMany(Joi.string().max(255)), - + pagination: { + page: Joi.number().min(1), + limit: Joi.number(), + sort: Joi.string(), + order: Joi.string().valid('asc', 'desc'), + }, permCode: oneOrMany(Joi.string().valid(...Object.values(Permissions))) }; diff --git a/app/src/validators/object.js b/app/src/validators/object.js index bfd66caa..48a1a4a0 100644 --- a/app/src/validators/object.js +++ b/app/src/validators/object.js @@ -137,7 +137,9 @@ const schema = { public: type.truthy, active: type.truthy, deleteMarker: type.truthy, - latest: type.truthy + latest: type.truthy, + permissions: type.truthy, + ...scheme.pagination, }) }, diff --git a/app/tests/unit/services/object.spec.js b/app/tests/unit/services/object.spec.js index efdedeb3..b3b1f9de 100644 --- a/app/tests/unit/services/object.spec.js +++ b/app/tests/unit/services/object.spec.js @@ -134,6 +134,8 @@ describe('searchObjects', () => { tag: params.tag }); expect(ObjectModel.modify).toHaveBeenNthCalledWith(11, 'hasPermission', params.userId, 'READ'); + expect(ObjectModel.modify).toHaveBeenNthCalledWith(12, 'pagination', params.page, params.limit); + expect(ObjectModel.modify).toHaveBeenNthCalledWith(13, 'sortOrder', params.sort, params.order); expect(ObjectModel.then).toHaveBeenCalledTimes(1); expect(objectModelTrx.commit).toHaveBeenCalledTimes(1); }); diff --git a/app/tests/unit/validators/object.spec.js b/app/tests/unit/validators/object.spec.js index 61d62c3e..3e156cc9 100644 --- a/app/tests/unit/validators/object.spec.js +++ b/app/tests/unit/validators/object.spec.js @@ -512,6 +512,47 @@ describe('searchObjects', () => { expect(active).toEqual(type.truthy.describe()); }); }); + + describe('page', () => { + const page = query.keys.page; + + it('is a number', () => { + expect(page.type).toEqual('number'); + }); + }); + + describe('limit', () => { + const limit = query.keys.limit; + + it('is a number', () => { + expect(limit.type).toEqual('number'); + }); + }); + + describe('sort', () => { + const sort = query.keys.sort; + + it('is a string', () => { + expect(sort.type).toEqual('string'); + }); + }); + + describe('order', () => { + const order = query.keys.order; + + it('is a string', () => { + expect(order.type).toEqual('string'); + }); + }); + + describe('permissions', () => { + const permissions = query.keys.permissions; + + it('is the expected schema', () => { + expect(permissions).toEqual(type.truthy.describe()); + }); + }); + }); });