Skip to content

Commit

Permalink
chore: topics/k1ch/admin-get-personas/simplify filter logic
Browse files Browse the repository at this point in the history
  • Loading branch information
k1ch committed Feb 15, 2024
1 parent 456bf43 commit e839810
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 46 deletions.
14 changes: 9 additions & 5 deletions database/layer/admin-persona.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,18 @@ const deletePersonaByKey = async (personaKey) => {
const getPersonas = async (filterQuery = {}, sort = 'key', order = 'asc') => {
try {
const tenantNameKey = 'tenantname'
if (tenantNameKey in filterQuery) {
filterQuery.name = filterQuery[tenantNameKey]
delete filterQuery[tenantNameKey]
}
const filters = Object.entries(filterQuery).reduce((acc, [key, val]) => {
if (key === tenantNameKey) {
acc.name = filterQuery[tenantNameKey]
} else {
acc[`personas.${key}`] = val
}
return acc
}, {})
return await usherDb('personas')
.select('personas.*', `tenants.name as ${tenantNameKey}`)
.join('tenants', 'personas.tenantkey', 'tenants.key')
.where(filterQuery)
.where(filters)
.orderBy(sort, order)
} catch (err) {
throw pgErrorHandler(err)
Expand Down
14 changes: 11 additions & 3 deletions server/src/api_endpoints/personas/persona.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const createError = require('http-errors')
const dbAdminPersona = require('database/layer/admin-persona')
const { checkPersonaExists, getFilterObjectFromFilterQueryString } = require('./utils')
const { checkPersonaExists } = require('./utils')

/**
* HTTP Request handler
Expand Down Expand Up @@ -52,8 +52,16 @@ const deletePersona = async (req, res, next) => {
*/
const getPersonas = async (req, res, next) => {
try {
const { filter, sort, order } = req.query
const personas = await dbAdminPersona.getPersonas(getFilterObjectFromFilterQueryString(filter), sort, order)
const { sort, order } = req.query
const allowedFilterParameters = ['key', 'tenantkey', 'tenantname', 'sub_claim', 'user_context']
const filters = allowedFilterParameters.reduce((acc, filter) => {
const filterValue = req.query[filter]
if (filterValue) {
acc[filter] = filterValue
}
return acc
}, {})
const personas = await dbAdminPersona.getPersonas(filters, sort, order)
res.status(200).send(personas);
} catch ({ httpStatusCode = 500, message }) {
return next(createError(httpStatusCode, { message }))
Expand Down
25 changes: 0 additions & 25 deletions server/src/api_endpoints/personas/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,35 +70,10 @@ const checkRoleExists = async (roleKey) => {
}
}

/**
* Converts a filter query string into a filter object
*
* @param {string} filterQuery - The filter query string (E.g. 'tenantname:value1, sub_claim:value2')
* @returns {Object} - The generated filter object
* @throws {Object} - Error object with HTTP status code and message if the filter query is invalid
*/
const getFilterObjectFromFilterQueryString = (filterQuery) => {
try {
return filterQuery ? filterQuery.split(',').reduce((acc, filter) => {
const [field, value] = filter.split(':').map((v) => {
return v.trim()
})
acc[field] = value
return acc
}, {}) : {}
} catch {
throw {
httpStatusCode: 400,
message: 'Invalid filter query!'
}
}
}

module.exports = {
checkPersonaExists,
checkPermissionExists,
checkPersonaRolesValidity,
checkPersonaPermissionsValidity,
checkRoleExists,
getFilterObjectFromFilterQueryString,
}
23 changes: 15 additions & 8 deletions server/test/endpoint_admin_personas.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ describe('Admin Personas', () => {
* GET /personas
* HTTP request to retrieve a list of personas
*
* @param {string} query - The query params to be added to the URL (E.g. ?filter=tenantname:value1,sub_claim:value2&sort=sub_claim&order=desc)
* @param {string} query - The query params to be added to the URL (E.g. ?tenantname=value1&sub_claim=value2&sort=sub_claim&order=desc)
* @param {Object} header - The request headers
* @returns {Promise<fetch.response>} - A Promise which resolves to fetch.response
*/
Expand All @@ -154,15 +154,26 @@ describe('Admin Personas', () => {
it('should return 200, return all the personas for a tenant', async () => {
const { name: validTenantName, key: tenantkey } = await usherDb('tenants').select('*').first()
const { count: totalCount } = await usherDb('personas').where({ tenantkey }).count('*').first()
const response = await getPersonas(`?filter=tenantname:${validTenantName}`)
const response = await getPersonas(`?tenantname=${validTenantName}`)
assert.equal(response.status, 200)
const personas = await response.json()
assert.equal(personas.length, Number(totalCount))
assert.equal(personas[0]['tenantname'], validTenantName)
})

it('should return 200, return a persona with two filter parameters', async () => {
const validPersona = await usherDb('personas').select('*').first()
const { tenantkey, sub_claim } = validPersona
const response = await getPersonas(`?tennatkey=${tenantkey}&sub_claim=${sub_claim}`)
assert.equal(response.status, 200)
const personas = await response.json()
assert.equal(personas.length, 1)
assert.equal(personas[0]['tenantkey'], tenantkey)
assert.equal(personas[0]['sub_claim'], sub_claim)
})

it('should return 200, return empty array for invalid tennatname', async () => {
const response = await getPersonas('?filter=tenantname:invalid')
const response = await getPersonas('?tenantname=invalid')
assert.equal(response.status, 200)
const personas = await response.json()
assert.equal(personas.length, 0)
Expand All @@ -181,11 +192,7 @@ describe('Admin Personas', () => {
it('should return 400, due to invalid query params', async () => {
const responses = await Promise.all(
[
getPersonas('?filter='),
getPersonas('?filter=tenant'),
getPersonas('?filter=tenantname:'),
getPersonas('?filter=tenantname:test,'),
getPersonas('?filter=tenantname:test&sort=invalidField'),
getPersonas('?key=NaN'),
getPersonas('?sort=key,'),
getPersonas('?sort=key&order'),
getPersonas('?sort=key&order=not_asc_desc'),
Expand Down
41 changes: 36 additions & 5 deletions server/the-usher-openapi-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -434,20 +434,51 @@ paths:
operationId: getPersonas
summary: Retrieve a list of personas
parameters:
- name: filter
- name: key
in: query
description: Filter by a field value
description: Filter by key (exact match)
schema:
type: number
example: 10
- name: tenantkey
in: query
description: Filter by tenantkey (exact match)
schema:
type: number
example: 10
- name: tenantname
in: query
description: Filter by tenantname (exact match)
schema:
type: string
example: DMGT
- name: sub_claim
in: query
description: Filter by sub_claim (exact match)
schema:
type: string
example: auth0|test-persona
- name: user_context
in: query
description: Filter by user_context (exact match)
schema:
type: string
example: tenantname:value1,sub_claim:value2
pattern: ^((?:key|tenantkey|sub_claim|user_context|created_at|updated_at|tenantname)\s*:\s*([^,]+)(?:,(?!$))*)+$
- name: sort
in: query
description: Sort the results by a field
schema:
type: string
example: sub_claim
pattern: ^(key|tenantkey|sub_claim|user_context|created_at|updated_at|tenantname)$
enum:
[
key,
tenantkey,
tenantname,
sub_claim,
user_context,
created_at,
updated_at,
]
- name: order
in: query
description: Specify the sort order (asc or desc)
Expand Down

0 comments on commit e839810

Please sign in to comment.