diff --git a/app/src/docs/v1.api-spec.yaml b/app/src/docs/v1.api-spec.yaml index 6b8bdbc3..3ba9df27 100644 --- a/app/src/docs/v1.api-spec.yaml +++ b/app/src/docs/v1.api-spec.yaml @@ -417,6 +417,12 @@ paths: type: array items: $ref: "#/components/schemas/DB-Object" + headers: + X-Total-Rows: + schema: + type: integer + description: Total number of objects matching the search query independent of pagination scope + required: true "401": $ref: "#/components/responses/Unauthorized" "403": @@ -2057,6 +2063,13 @@ components: type: string description: The filename of the original file uploaded example: foobar.txt + permissions: + type: array + items: + type: string + description: An array of explicit permCodes the current user has. Empty array if authenticated via Basic auth or if user lacks explicit permissions for the object. Attribute only appears if request contains permissions query parameter + example: + - READ - $ref: "#/components/schemas/DB-TimestampUserData" DB-ObjectPermission: title: DB Object Permission diff --git a/app/src/validators/common.js b/app/src/validators/common.js index 84dbb40d..20282835 100644 --- a/app/src/validators/common.js +++ b/app/src/validators/common.js @@ -83,8 +83,30 @@ const scheme = { string: oneOrMany(Joi.string().max(255)), pagination: (sortList) => ({ - page: Joi.number().min(1), - limit: Joi.number().min(0), + page: Joi.alternatives() + .conditional('limit', { + not: true, + then: Joi + .number() + .min(1) + .required() + .messages({ + 'any.required': '`Must specify page number`', + }), + otherwise: Joi.number().min(1) + }), + limit: Joi.alternatives() + .conditional('page', { + not: true, + then: Joi + .number() + .min(1) + .required() + .messages({ + 'any.required': '`Must specify page limit`', + }), + otherwise: Joi.number().min(1) + }), sort: Joi.string().valid(...sortList), order: Joi.string().valid(...Object.values(SortOrder)), }), diff --git a/app/tests/unit/validators/object.spec.js b/app/tests/unit/validators/object.spec.js index d461800e..5b4f6074 100644 --- a/app/tests/unit/validators/object.spec.js +++ b/app/tests/unit/validators/object.spec.js @@ -517,7 +517,8 @@ describe('searchObjects', () => { const page = query.keys.page; it('is a number', () => { - expect(page.type).toEqual('number'); + expect(page.type).toEqual('alternatives'); + expect(page.matches).toBeTruthy(); }); it('enforces min value 1', () => { @@ -534,8 +535,10 @@ describe('searchObjects', () => { const limit = query.keys.limit; it('is a number', () => { - expect(limit.type).toEqual('number'); + expect(limit.type).toEqual('alternatives'); + expect(limit.matches).toBeTruthy(); }); + it('enforces min value 0', () => { expect.objectContaining({ name: 'min', @@ -544,14 +547,29 @@ describe('searchObjects', () => { }) }); }); + + it('limit is provided and greater then or equal to 0', () => { + const limitObject = schema.searchObjects.query; + const result = limitObject.validate({ + limit: 0 + }); + expect(result.value.limit).toBeGreaterThanOrEqual(0); + }); }); describe('sort', () => { const sort = query.keys.sort; + const sortName = ['id', 'path', 'public', 'active', 'createdBy', 'updatedBy', 'updatedAt', 'bucketId', 'name']; it('is a string', () => { expect(sort.type).toEqual('string'); }); + + it('must be one of ' + sortName, () => { + expect(sort.allow).toEqual( + expect.arrayContaining(sortName) + ); + }); }); describe('order', () => {