From be275c8953a8f6bcf804a4230ae0ca16f3268b8e Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Wed, 23 Dec 2020 09:01:50 +0800 Subject: [PATCH] implement taas-teams skills endpoint --- README.md | 1 + config/default.js | 1 + ...coder-bookings-api.postman_collection.json | 39 ++++++ docs/swagger.yaml | 126 ++++++++++++++++++ src/common/helper.js | 33 +++++ src/controllers/SkillController.js | 20 +++ src/routes/TeamRoutes.js | 8 ++ src/services/SkillService.js | 26 ++++ 8 files changed, 254 insertions(+) create mode 100644 src/controllers/SkillController.js create mode 100644 src/services/SkillService.js diff --git a/README.md b/README.md index f94f0802..14625a85 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ The following parameters can be set in config files or in env variables: - `PROJECT_API_URL`: the project service url - `TC_API`: the Topcoder v5 url - `ORG_ID`: the organization id +- `TOPCODER_SKILL_PROVIDER_ID`: the referenced skill provider id - `esConfig.HOST`: the elasticsearch host - `esConfig.ES_INDEX_JOB`: the job index diff --git a/config/default.js b/config/default.js index cccdf99c..7a6a2a62 100644 --- a/config/default.js +++ b/config/default.js @@ -21,6 +21,7 @@ module.exports = { TC_API: process.env.TC_API || 'https://api.topcoder-dev.com/v5', ORG_ID: process.env.ORG_ID || '36ed815b-3da1-49f1-a043-aaed0a4e81ad', + TOPCODER_SKILL_PROVIDER_ID: process.env.TOPCODER_SKILL_PROVIDER_ID, TOPCODER_USERS_API: process.env.TOPCODER_USERS_API || 'https://api.topcoder-dev.com/v3/users', diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 67804f49..f3068fbd 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -4366,6 +4366,45 @@ } }, "response": [] + }, + { + "name": "GET /taas-teams/skills", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_member}}", + "type": "text" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/skills?perPage=10&page=1&orderBy=name", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + "skills" + ], + "query": [ + { + "key": "perPage", + "value": "10" + }, + { + "key": "page", + "value": "1" + }, + { + "key": "orderBy", + "value": "name", + "description": "possible values are defined by /v5/skills" + } + ] + } + }, + "response": [] } ], "protocolProfileBehavior": {} diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e5d52f0a..f532914e 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1491,6 +1491,96 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /taas-teams/skills: + get: + tags: + - Teams + description: | + Serves as a proxy endpoint for /v5/skills, allowing to be accessed by any topcoder user. + parameters: + - in: query + name: page + required: false + schema: + type: integer + default: 1 + description: The page number. + - in: query + name: perPage + required: false + schema: + type: integer + default: 20 + description: The number of items to list per page. + - name: orderBy + in: query + schema: + type: string + description: "Specify by which field to sort by. Sorts in ascending order only" + security: + - bearerAuth: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UbahnSkill' + headers: + X-Next-Page: + schema: + type: integer + description: The index of the next page + X-Page: + schema: + type: integer + description: The index of the current page (starting at 1) + X-Per-Page: + schema: + type: integer + description: The number of items to list per page + X-Prev-Page: + schema: + type: integer + description: The index of the previous page + X-Total: + schema: + type: integer + description: The total number of items + X-Total-Pages: + schema: + type: integer + description: The total number of pages + Link: + schema: + type: string + description: Pagination link header. + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /health: get: tags: @@ -2056,6 +2146,42 @@ components: type: string example: 'React' description: The skill name. + UbahnSkill: + type: object + properties: + id: + type: "string" + format: "UUID" + description: "The skill id" + skillProviderId: + type: "string" + format: "UUID" + description: "The referenced skill provider id" + name: + type: "string" + description: "The name of the skill" + externalId: + type: "string" + description: "The external id for the skill" + uri: + type: "string" + description: "The uri for the skill" + created: + type: "string" + format: "date-time" + description: "When the entity was created." + updated: + type: "string" + format: "date-time" + description: "When the entity was updated." + createdBy: + type: "string" + format: "UUID" + description: "Creator of the entity." + updatedBy: + type: "string" + format: "UUID" + description: "User that last updated the entity." JobForTeam: properties: id: diff --git a/src/common/helper.js b/src/common/helper.js index 715d9981..f80fc173 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -493,6 +493,38 @@ async function getProjectById (currentUser, id) { } } +/** + * Function to search skills from v5/skills + * @param {Object} criteria the search criteria + * @returns the request result + */ +async function getSkills (criteria) { + const token = await getM2Mtoken() + try { + const res = await request + .get(`${config.TC_API}/skills`) + .query({ + skillProviderId: config.TOPCODER_SKILL_PROVIDER_ID, + ...criteria + }) + .set('Authorization', `Bearer ${token}`) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + localLogger.debug({ context: 'getSkills', message: `response body: ${JSON.stringify(res.body)}` }) + return { + total: Number(_.get(res.headers, 'x-total')), + page: Number(_.get(res.headers, 'x-page')), + perPage: Number(_.get(res.headers, 'x-per-page')), + result: res.body + } + } catch (err) { + if (err.status === HttpStatus.BAD_REQUEST) { + throw new errors.BadRequestError(err.response.body.message) + } + throw err + } +} + /** * Function to get skill by id * @param {String} skillId the skill Id @@ -612,6 +644,7 @@ module.exports = { getUserById, getMembers, getProjectById, + getSkills, getSkillById, getUserSkill, ensureJobById, diff --git a/src/controllers/SkillController.js b/src/controllers/SkillController.js new file mode 100644 index 00000000..0dd13ea7 --- /dev/null +++ b/src/controllers/SkillController.js @@ -0,0 +1,20 @@ +/** + * Controller for skills endpoints + */ +const service = require('../services/SkillService') +const helper = require('../common/helper') + +/** + * Search skills + * @param req the request + * @param res the response + */ +async function searchSkills (req, res) { + const result = await service.searchSkills(req.query) + helper.setResHeaders(req, res, result) + res.send(result.result) +} + +module.exports = { + searchSkills +} diff --git a/src/routes/TeamRoutes.js b/src/routes/TeamRoutes.js index 43a9a261..7cfff792 100644 --- a/src/routes/TeamRoutes.js +++ b/src/routes/TeamRoutes.js @@ -12,6 +12,14 @@ module.exports = { scopes: [constants.Scopes.READ_TAAS_TEAM] } }, + '/taas-teams/skills': { + get: { + controller: 'SkillController', + method: 'searchSkills', + auth: 'jwt', + scopes: [constants.Scopes.READ_TAAS_TEAM] + } + }, '/taas-teams/:id': { get: { controller: 'TeamController', diff --git a/src/services/SkillService.js b/src/services/SkillService.js new file mode 100644 index 00000000..071e502c --- /dev/null +++ b/src/services/SkillService.js @@ -0,0 +1,26 @@ +/** + * This service provides operations of Skill. + */ +const Joi = require('joi') +const helper = require('../common/helper') + +/** + * Search skills + * @param {Object} criteria the search criteria + * @returns {Object} the search result, contain total/page/perPage and result array + */ +async function searchSkills (criteria) { + return helper.getSkills(criteria) +} + +searchSkills.schema = Joi.object().keys({ + criteria: Joi.object().keys({ + page: Joi.page(), + perPage: Joi.perPage(), + orderBy: Joi.string() + }).required() +}).required() + +module.exports = { + searchSkills +}