diff --git a/README.md b/README.md index 88bca715..f94f0802 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ The following parameters can be set in config files or in env variables: - `AUTH0_CLIENT_SECRET`: Auth0 client secret, used to get TC M2M token - `AUTH0_PROXY_SERVER_URL`: Proxy Auth0 URL, used to get TC M2M token +- `m2m.M2M_AUDIT_USER_ID`: default value is `00000000-0000-0000-0000-000000000000` +- `m2m.M2M_AUDIT_HANDLE`: default value is `TopcoderService` + - `DATABASE_URL`: PostgreSQL database url. - `DB_SCHEMA_NAME`: string - PostgreSQL database target schema - `PROJECT_API_URL`: the project service url diff --git a/app-constants.js b/app-constants.js index e2ffaa14..bf1a43b7 100644 --- a/app-constants.js +++ b/app-constants.js @@ -6,6 +6,30 @@ const UserRoles = { BookingManager: 'bookingmanager' } +const Scopes = { + // job + READ_JOB: 'read:taas-jobs', + CREATE_JOB: 'create:taas-jobs', + UPDATE_JOB: 'update:taas-jobs', + DELETE_JOB: 'delete:taas-jobs', + ALL_JOB: 'all:taas-jobs', + // job candidate + READ_JOB_CANDIDATE: 'read:taas-jobCandidates', + CREATE_JOB_CANDIDATE: 'create:taas-jobCandidates', + UPDATE_JOB_CANDIDATE: 'update:taas-jobCandidates', + DELETE_JOB_CANDIDATE: 'delete:taas-jobCandidates', + ALL_JOB_CANDIDATE: 'all:taas-jobCandidates', + // resource booking + READ_RESOURCE_BOOKING: 'read:taas-resourceBookings', + CREATE_RESOURCE_BOOKING: 'create:taas-resourceBookings', + UPDATE_RESOURCE_BOOKING: 'update:taas-resourceBookings', + DELETE_RESOURCE_BOOKING: 'delete:taas-resourceBookings', + ALL_RESOURCE_BOOKING: 'all:taas-resourceBookings', + // taas-team + READ_TAAS_TEAM: 'read:taas-teams' +} + module.exports = { - UserRoles + UserRoles, + Scopes } diff --git a/app-routes.js b/app-routes.js index 66413aee..023dda0a 100644 --- a/app-routes.js +++ b/app-routes.js @@ -6,6 +6,7 @@ const _ = require('lodash') const config = require('config') const HttpStatus = require('http-status-codes') const helper = require('./src/common/helper') +const errors = require('./src/common/errors') const routes = require('./src/routes') const constants = require('./app-constants') const authenticator = require('tc-core-library-js').middleware.jwtAuthenticator @@ -37,11 +38,22 @@ module.exports = (app) => { }) actions.push((req, res, next) => { - req.authUser.jwtToken = req.headers.authorization - if (_.includes(req.authUser.roles, constants.UserRoles.BookingManager)) { - req.authUser.isBookingManager = true + if (req.authUser.isMachine) { + // M2M + if (!req.authUser.scopes || !helper.checkIfExists(def.scopes, req.authUser.scopes)) { + next(new errors.ForbiddenError('You are not allowed to perform this action!')) + } else { + req.authUser.userId = config.m2m.M2M_AUDIT_USER_ID + req.authUser.handle = config.m2m.M2M_AUDIT_HANDLE + next() + } + } else { + req.authUser.jwtToken = req.headers.authorization + if (_.includes(req.authUser.roles, constants.UserRoles.BookingManager)) { + req.authUser.isBookingManager = true + } + next() } - next() }) } diff --git a/config/default.js b/config/default.js index b2678ce5..cccdf99c 100644 --- a/config/default.js +++ b/config/default.js @@ -14,6 +14,11 @@ module.exports = { AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET, AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL, + m2m: { + M2M_AUDIT_USER_ID: process.env.M2M_AUDIT_USER_ID || '00000000-0000-0000-0000-000000000000', + M2M_AUDIT_HANDLE: process.env.M2M_AUDIT_HANDLE || 'TopcoderService' + }, + TC_API: process.env.TC_API || 'https://api.topcoder-dev.com/v5', ORG_ID: process.env.ORG_ID || '36ed815b-3da1-49f1-a043-aaed0a4e81ad', diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 46f07ebf..2f51d42c 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "282e8342-2d5a-4566-8509-f2f240a594a0", + "_postman_id": "f4cd931d-2cfb-4d3a-b31e-4a6a02317cb2", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,7 @@ { "listen": "test", "script": { - "id": "a2236151-22f2-46c7-869a-858eb7da1ab8", + "id": "72230770-0780-406e-b740-12fba4aac339", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -53,13 +53,58 @@ }, "response": [] }, + { + "name": "create job with m2m create", + "event": [ + { + "listen": "test", + "script": { + "id": "a36bec2a-bf3d-4d1f-bf83-32c99676695c", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"jobIdCreatedByM2M\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_m2m_create_job}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"1212\",\r\n \"description\": \"Dummy Description\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 13,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"hourly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\",\r\n \"7d076384-ccf6-4e43-a45d-1b24b1e624aa\",\r\n \"cbac57a3-7180-4316-8769-73af64893158\",\r\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + }, { "name": "create job with connect user", "event": [ { "listen": "test", "script": { - "id": "91236482-d7b2-4acd-a47d-e9f9ac833bad", + "id": "aa345d54-a75a-4702-9079-edf37f05fc28", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -104,7 +149,7 @@ { "listen": "test", "script": { - "id": "1e5b5bdf-6ff0-4d96-8018-8698bc359674", + "id": "0351c210-4a5a-4514-8fe9-d6debb1c1bbb", "exec": [ "var data = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" @@ -149,7 +194,7 @@ { "listen": "test", "script": { - "id": "0b469a8d-8119-4907-ac37-a69a1766754d", + "id": "bb2df571-ae1e-43d5-a3d1-fdd21cc85882", "exec": [ "" ], @@ -193,7 +238,7 @@ { "listen": "test", "script": { - "id": "fec863ef-1db6-4008-8a9d-ef616e3cac4d", + "id": "8e8187ba-302f-43a4-b1e8-5116232dec57", "exec": [ "" ], @@ -255,6 +300,30 @@ }, "response": [] }, + { + "name": "get job with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_job}}" + } + ], + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "get job with booking manager from db", "request": { @@ -428,6 +497,101 @@ }, "response": [] }, + { + "name": "search jobs with with m2m all", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_all_job}}" + } + ], + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ], + "query": [ + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "perPage", + "value": "3", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "asc", + "disabled": true + }, + { + "key": "projectId", + "value": "21", + "disabled": true + }, + { + "key": "externalId", + "value": "1212", + "disabled": true + }, + { + "key": "description", + "value": "Dummy", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "endDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "resourceType", + "value": "Dummy Resource Type", + "disabled": true + }, + { + "key": "skill", + "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "sourcing", + "disabled": true + }, + { + "key": "workload", + "value": "full-time", + "disabled": true + } + ] + } + }, + "response": [] + }, { "name": "search jobs with connect user", "request": { @@ -746,6 +910,39 @@ }, "response": [] }, + { + "name": "put job with m2m update", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_job}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"1212\",\r\n \"description\": \"Dummy Description\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 13,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"hourly\",\r\n \"workload\": \"fractional\",\r\n \"skills\": [\r\n \"cbac57a3-7180-4316-8769-73af64893158\",\r\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "put job with connect user", "request": { @@ -785,7 +982,7 @@ { "listen": "test", "script": { - "id": "28720714-8006-4fd5-b3b8-0c588266bb5e", + "id": "9c04dea6-d12d-4287-84e4-068ca7025e2a", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -958,6 +1155,39 @@ }, "response": [] }, + { + "name": "patch job with m2m update", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_job}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"description\": \"Dummy Description\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 13,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"hourly\",\r\n \"workload\": \"fractional\",\r\n \"skills\": [\r\n \"cbac57a3-7180-4316-8769-73af64893158\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "patch job with connect user", "request": { @@ -997,7 +1227,7 @@ { "listen": "test", "script": { - "id": "aa7fa1f8-cca2-4323-8266-ff4e770dae10", + "id": "a4e3f5a6-cc9b-419d-aa56-73aab3046d4b", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1170,6 +1400,39 @@ }, "response": [] }, + { + "name": "delete job with m2m delete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_delete_job}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "delete job with connect user", "request": { @@ -1209,7 +1472,7 @@ { "listen": "test", "script": { - "id": "8299d83c-e5c3-4639-8c4a-bf783f178fb2", + "id": "bb287666-8bd5-411b-85a2-1739d1c43a5d", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1328,7 +1591,7 @@ { "listen": "test", "script": { - "id": "cbee0ff6-5824-447c-915d-466bfd5242bc", + "id": "a4164751-2a2a-477e-82c7-897f71de1272", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1368,15 +1631,15 @@ "response": [] }, { - "name": "create job candidate with connect user", + "name": "create job candidate with m2m create", "event": [ { "listen": "test", "script": { - "id": "6a1b4404-55ef-40e8-981a-3cb9e960d6ea", + "id": "c9c1b298-f7f9-456b-bffe-77b5ba83f38c", "exec": [ "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" + "postman.setEnvironmentVariable(\"jobCandidateIdCreatedByM2M\",data.id);" ], "type": "text/javascript" } @@ -1388,12 +1651,12 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_m2m_create_job_candidate}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{jobId}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\"\r\n}", + "raw": "{\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\"\r\n}", "options": { "raw": { "language": "json" @@ -1413,12 +1676,12 @@ "response": [] }, { - "name": "create job candidate with member", + "name": "create job candidate with connect user", "event": [ { "listen": "test", "script": { - "id": "a42f6045-fdb2-4d61-8dd4-a919573f5d24", + "id": "107c325f-d111-418e-8d2f-84709e317a0e", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1433,7 +1696,7 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "value": "Bearer {{token_connectUser}}" } ], "body": { @@ -1458,12 +1721,12 @@ "response": [] }, { - "name": "create job candidate with user id not exist", + "name": "create job candidate with member", "event": [ { "listen": "test", "script": { - "id": "b133db18-fa52-4a59-9e35-5e7d340b7f1d", + "id": "ed118309-1cee-4795-8586-a6e4f3555ce2", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1478,7 +1741,7 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_userId_not_exist}}" + "value": "Bearer {{token_member}}" } ], "body": { @@ -1503,14 +1766,59 @@ "response": [] }, { - "name": "create job candidate with invalid token", + "name": "create job candidate with user id not exist", "event": [ { "listen": "test", "script": { - "id": "6cd47ee8-4139-4309-8cb1-ceb74d2d06eb", + "id": "7622898d-a47c-4631-8a82-da52b2de72cc", "exec": [ - "" + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_userId_not_exist}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{jobId}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job candidate with invalid token", + "event": [ + { + "listen": "test", + "script": { + "id": "a034038a-b2ec-49d9-afd4-e08625802057", + "exec": [ + "" ], "type": "text/javascript" } @@ -1570,6 +1878,30 @@ }, "response": [] }, + { + "name": "get job candidate with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_job_candidate}}" + } + ], + "url": { + "raw": "{{URL}}/jobCandidates/{{jobCandidateIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{jobCandidateIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "get job candidate with booking manager from db", "request": { @@ -1708,6 +2040,66 @@ }, "response": [] }, + { + "name": "search job candidates with m2m all", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_all_job_candidate}}" + } + ], + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "1", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "asc", + "disabled": true + }, + { + "key": "jobId", + "value": "46225f4c-c2a3-4603-a141-0277e96fabfa", + "disabled": true + }, + { + "key": "userId", + "value": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", + "disabled": true + }, + { + "key": "status", + "value": "shortlist", + "disabled": true + } + ] + } + }, + "response": [] + }, { "name": "search job candidates with connect user", "request": { @@ -1917,6 +2309,39 @@ }, "response": [] }, + { + "name": "put job candidate with m2m update", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_job_candidate}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"status\": \"selected\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{jobCandidateIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{jobCandidateIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "put job candidate with connect user", "request": { @@ -2082,6 +2507,39 @@ }, "response": [] }, + { + "name": "patch job candidate with m2m update", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_job_candidate}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{jobCandidateIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{jobCandidateIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "patch job candidate with connect user", "request": { @@ -2312,6 +2770,39 @@ } }, "response": [] + }, + { + "name": "delete job candidate with m2m delete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_delete_job_candidate}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{jobCandidateIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{jobCandidateIdCreatedByM2M}}" + ] + } + }, + "response": [] } ], "protocolProfileBehavior": {} @@ -2325,7 +2816,7 @@ { "listen": "test", "script": { - "id": "2722fecc-08fa-4d6e-9895-e7ed844f21c9", + "id": "b6c5a8bf-da7a-4062-90c0-d53fa0920df5", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2364,13 +2855,58 @@ }, "response": [] }, + { + "name": "create resource booking with m2m create", + "event": [ + { + "listen": "test", + "script": { + "id": "5423120e-887d-4789-96c2-553bb7e2118c", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"resourceBookingIdCreatedByM2M\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_create_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, { "name": "create resource booking with connect user", "event": [ { "listen": "test", "script": { - "id": "86edd7ff-eef6-4976-ae59-101fbe154e2c", + "id": "46874c20-fb80-4c00-abae-1dc16871b3b4", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2415,7 +2951,7 @@ { "listen": "test", "script": { - "id": "10be7afd-f528-4abf-a524-a9642678c436", + "id": "d6142f6d-92e3-4e99-9f67-bd19072103fa", "exec": [ "" ], @@ -2459,7 +2995,7 @@ { "listen": "test", "script": { - "id": "ad50f131-aff8-4e32-acda-d647889d4dc3", + "id": "cb7bff90-167a-441e-960a-29bffc5bd01d", "exec": [ "" ], @@ -2503,7 +3039,7 @@ { "listen": "test", "script": { - "id": "ebe085f5-b1ce-455b-b147-c4c6f4cd4283", + "id": "54827c9d-36fe-4b1d-95a9-7546cf174820", "exec": [ "" ], @@ -2565,6 +3101,30 @@ }, "response": [] }, + { + "name": "get resource booking with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_resource_booking}}" + } + ], + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "get resource booking with booking manager from db", "request": { @@ -2708,6 +3268,71 @@ }, "response": [] }, + { + "name": "search resource bookings with m2m all", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_all_resource_booking}}" + } + ], + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "5", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "endDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "sourcing", + "disabled": true + } + ] + } + }, + "response": [] + }, { "name": "search resource bookings with connect user", "request": { @@ -2918,6 +3543,39 @@ }, "response": [] }, + { + "name": "put resource booking with m2m update", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "put resource booking with connect user", "request": { @@ -3083,6 +3741,39 @@ }, "response": [] }, + { + "name": "patch resource booking with m2m update", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "patch resource booking with connect user", "request": { @@ -3314,6 +4005,39 @@ }, "response": [] }, + { + "name": "delete resource booking with m2m delete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_delete_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "delete resource booking with invalid token", "request": { @@ -3401,6 +4125,29 @@ }, "response": [] }, + { + "name": "GET /taas-teams with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_taas_team}}" + } + ], + "url": { + "raw": "{{URL}}/taas-teams", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams" + ] + } + }, + "response": [] + }, { "name": "GET /taas-teams/:id", "request": { @@ -3431,6 +4178,36 @@ }, "response": [] }, + { + "name": "GET /taas-teams/:id with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_taas_team}}" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/:projectId", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + ":projectId" + ], + "variable": [ + { + "key": "projectId", + "value": "16705" + } + ] + } + }, + "response": [] + }, { "name": "GET /taas-teams/:id/jobs/:jobId", "request": { @@ -3466,6 +4243,42 @@ } }, "response": [] + }, + { + "name": "GET /taas-teams/:id/jobs/:jobId with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_taas_team}}" + } + ], + "url": { + "raw": "{{URL}}/taas-teams/:projectId/jobs/:jobId", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams", + ":projectId", + "jobs", + ":jobId" + ], + "variable": [ + { + "key": "projectId", + "value": "16705" + }, + { + "key": "jobId", + "value": "948a25a6-086f-4a96-aad5-9ccd2d3e87b2" + } + ] + } + }, + "response": [] } ], "protocolProfileBehavior": {} @@ -3495,4 +4308,4 @@ } ], "protocolProfileBehavior": {} -} \ No newline at end of file +} diff --git a/docs/topcoder-bookings.postman_environment.json b/docs/topcoder-bookings.postman_environment.json index 2b9a3aa4..a97d2383 100644 --- a/docs/topcoder-bookings.postman_environment.json +++ b/docs/topcoder-bookings.postman_environment.json @@ -1,5 +1,5 @@ { - "id": "190c1a31-b774-40f1-aa5c-b24cbdab67fc", + "id": "a7cb1c6e-c710-49c3-ad58-db7536c85944", "name": "topcoder-bookings", "values": [ { @@ -51,9 +51,104 @@ "key": "jobIdCreatedByMember", "value": "", "enabled": true + }, + { + "key": "token_m2m_read_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtam9icyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.l4fH_SGhhbP8kcQoOJhhQW0eRGwC3wIwuj0_7XGj7Ac", + "enabled": true + }, + { + "key": "token_m2m_create_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.m-tHt9ABFj5KqzWYbLNxufVL4QvNw_y4j7w-Pj9l5_E", + "enabled": true + }, + { + "key": "token_m2m_update_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.AM9C6kPZmtQVN-6GtbKeMIiQIZqRk5nOcPuciClZKdY", + "enabled": true + }, + { + "key": "token_m2m_delete_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJkZWxldGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.j5YIG2xpirJaXyDRMPoGa8Y_vTCiwxi1qRQfhF2MQpA", + "enabled": true + }, + { + "key": "token_m2m_all_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.YqhP6JHGu1L4yQ_uAH8_Am29MaZ5fUvZgCk9GjqRDl8", + "enabled": true + }, + { + "key": "token_m2m_read_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtam9iQ2FuZGlkYXRlcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.N-5rUvF8gKHqs3rSCjlbsa6GJ9SPgJ66ZQlGYuImQXQ", + "enabled": true + }, + { + "key": "token_m2m_create_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.SXQY7145ceuDQd8YPAv4ePyaF1JRnHtVGy1kIhzCfPk", + "enabled": true + }, + { + "key": "token_m2m_update_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.5UXD6hTkx2Iz-LRvz2uGkA85lLJfWeyBksxCpO7Zj-0", + "enabled": true + }, + { + "key": "token_m2m_delete_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJkZWxldGU6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.BquDCL94jRFceLlwEAIGm7oHiVG3GPE-xdNbVh7lX9Y", + "enabled": true + }, + { + "key": "token_m2m_all_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.b1ScJHn574-WqhAyFXkc5-bSp3xiZuVzPGm0W1dOVlM", + "enabled": true + }, + { + "key": "token_m2m_read_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtcmVzb3VyY2VCb29raW5ncyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.tQEMwMS7z7S1q_9vyVCvhlKKRInZ4U21KdE1lQIenjo", + "enabled": true + }, + { + "key": "token_m2m_create_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.mE4x9DtPvjVKCib3S9qykmwAr1NsloT0ozQVOPcSdMU", + "enabled": true + }, + { + "key": "token_m2m_update_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.OPN89qGvuvRv2A8CAWPEx_pVCWw0MXlkUuKFbaqnF2I", + "enabled": true + }, + { + "key": "token_m2m_delete_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJkZWxldGU6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.mzQw4hYQKQGu6Q1UIN202pk_aHYEy4DioLbrm37eG48", + "enabled": true + }, + { + "key": "token_m2m_all_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.ErIUp7EQejnNRLUj8we7rRiZg7KVqxaFSW9WboPmt5w", + "enabled": true + }, + { + "key": "token_m2m_read_taas_team", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtdGVhbXMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.LKd9krhA2ErAMPqLR6dEeWPG0u0JedsysrkZwvAVSMs", + "enabled": true + }, + { + "key": "jobIdCreatedByM2M", + "value": "47430794-8d89-42a4-947b-341b3fe75031", + "enabled": true + }, + { + "key": "jobCandidateIdCreatedByM2M", + "value": "bdc13c45-40a2-4597-9b21-4b572a1faf25", + "enabled": true + }, + { + "key": "resourceBookingIdCreatedByM2M", + "value": "083ddc0e-710e-45f3-b4d3-1f70bf3d8713", + "enabled": true } ], "_postman_variable_scope": "environment", - "_postman_exported_at": "2020-12-01T18:44:10.102Z", + "_postman_exported_at": "2020-12-04T12:09:30.809Z", "_postman_exported_using": "Postman/7.29.0" } \ No newline at end of file diff --git a/src/common/helper.js b/src/common/helper.js index 441d7f25..48b19e46 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -49,6 +49,38 @@ function getBusApiClient () { // ES Client mapping const esClients = {} +/** + * Check if exists. + * + * @param {Array} source the array in which to search for the term + * @param {Array | String} term the term to search + */ +function checkIfExists (source, term) { + let terms + + if (!_.isArray(source)) { + throw new Error('Source argument should be an array') + } + + source = source.map(s => s.toLowerCase()) + + if (_.isString(term)) { + terms = term.toLowerCase().split(' ') + } else if (_.isArray(term)) { + terms = term.map(t => t.toLowerCase()) + } else { + throw new Error('Term argument should be either a string or an array') + } + + for (let i = 0; i < terms.length; i++) { + if (source.includes(terms[i])) { + return true + } + } + + return false +} + /** * Wrap async function to standard express function * @param {Function} fn the async function @@ -491,13 +523,21 @@ async function ensureUbhanUserId (currentUser) { } module.exports = { + checkIfExists, autoWrapExpress, setResHeaders, clearObject, isConnectMember, getESClient, - getUserId: (userId) => ensureUbhanUserId({ userId }), + getUserId: async (userId) => { + // check m2m user id + if (userId === config.m2m.M2M_AUDIT_USER_ID) { + return config.m2m.M2M_AUDIT_USER_ID + } + return ensureUbhanUserId({ userId }) + }, getM2Mtoken, + getTopcoderM2MToken, postEvent, getBusApiClient, isDocumentMissingException, diff --git a/src/routes/JobCandidateRoutes.js b/src/routes/JobCandidateRoutes.js index 8f7ad8f8..7c1dac24 100644 --- a/src/routes/JobCandidateRoutes.js +++ b/src/routes/JobCandidateRoutes.js @@ -1,40 +1,47 @@ /** * Contains jobCandidate routes */ +const constants = require('../../app-constants') module.exports = { '/jobCandidates': { post: { controller: 'JobCandidateController', method: 'createJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.CREATE_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] }, get: { controller: 'JobCandidateController', method: 'searchJobCandidates', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] } }, '/jobCandidates/:id': { get: { controller: 'JobCandidateController', method: 'getJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] }, put: { controller: 'JobCandidateController', method: 'fullyUpdateJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] }, patch: { controller: 'JobCandidateController', method: 'partiallyUpdateJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] }, delete: { controller: 'JobCandidateController', method: 'deleteJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.DELETE_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] } } } diff --git a/src/routes/JobRoutes.js b/src/routes/JobRoutes.js index 9d57fa8f..5764f9c7 100644 --- a/src/routes/JobRoutes.js +++ b/src/routes/JobRoutes.js @@ -1,40 +1,47 @@ /** * Contains job routes */ +const constants = require('../../app-constants') module.exports = { '/jobs': { post: { controller: 'JobController', method: 'createJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.CREATE_JOB, constants.Scopes.ALL_JOB] }, get: { controller: 'JobController', method: 'searchJobs', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_JOB, constants.Scopes.ALL_JOB] } }, '/jobs/:id': { get: { controller: 'JobController', method: 'getJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_JOB, constants.Scopes.ALL_JOB] }, put: { controller: 'JobController', method: 'fullyUpdateJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_JOB, constants.Scopes.ALL_JOB] }, patch: { controller: 'JobController', method: 'partiallyUpdateJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_JOB, constants.Scopes.ALL_JOB] }, delete: { controller: 'JobController', method: 'deleteJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.DELETE_JOB, constants.Scopes.ALL_JOB] } } } diff --git a/src/routes/ResourceBookingRoutes.js b/src/routes/ResourceBookingRoutes.js index 91983c1d..eb152165 100644 --- a/src/routes/ResourceBookingRoutes.js +++ b/src/routes/ResourceBookingRoutes.js @@ -1,40 +1,47 @@ /** * Contains resourceBooking routes */ +const constants = require('../../app-constants') module.exports = { '/resourceBookings': { post: { controller: 'ResourceBookingController', method: 'createResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.CREATE_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] }, get: { controller: 'ResourceBookingController', method: 'searchResourceBookings', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] } }, '/resourceBookings/:id': { get: { controller: 'ResourceBookingController', method: 'getResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] }, put: { controller: 'ResourceBookingController', method: 'fullyUpdateResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] }, patch: { controller: 'ResourceBookingController', method: 'partiallyUpdateResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] }, delete: { controller: 'ResourceBookingController', method: 'deleteResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.DELETE_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] } } } diff --git a/src/routes/TeamRoutes.js b/src/routes/TeamRoutes.js index 30dd5bc1..43a9a261 100644 --- a/src/routes/TeamRoutes.js +++ b/src/routes/TeamRoutes.js @@ -1,27 +1,31 @@ /** * Contains taas team routes */ +const constants = require('../../app-constants') module.exports = { '/taas-teams': { get: { controller: 'TeamController', method: 'searchTeams', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_TAAS_TEAM] } }, '/taas-teams/:id': { get: { controller: 'TeamController', method: 'getTeam', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_TAAS_TEAM] } }, '/taas-teams/:id/jobs/:jobId': { get: { controller: 'TeamController', method: 'getTeamJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_TAAS_TEAM] } } } diff --git a/src/services/JobCandidateService.js b/src/services/JobCandidateService.js index dd369b60..3e49f78d 100644 --- a/src/services/JobCandidateService.js +++ b/src/services/JobCandidateService.js @@ -83,7 +83,7 @@ async function updateJobCandidate (currentUser, id, data) { const jobCandidate = await JobCandidate.findById(id) const projectId = await JobCandidate.getProjectId(jobCandidate.dataValues.jobId) const userId = await helper.getUserId(currentUser.userId) - if (projectId && !currentUser.isBookingManager) { + if (projectId && !currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(projectId, currentUser.jwtToken) if (!connect) { if (jobCandidate.dataValues.userId !== userId) { @@ -146,7 +146,7 @@ fullyUpdateJobCandidate.schema = Joi.object().keys({ * @params {String} id the jobCandidate id */ async function deleteJobCandidate (currentUser, id) { - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { throw new errors.ForbiddenError('You are not allowed to perform this action!') } diff --git a/src/services/JobService.js b/src/services/JobService.js index 5022f7ed..febffc81 100644 --- a/src/services/JobService.js +++ b/src/services/JobService.js @@ -160,7 +160,7 @@ async function updateJob (currentUser, id, data) { } let job = await Job.findById(id) const ubhanUserId = await helper.getUserId(currentUser.userId) - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(job.dataValues.projectId, currentUser.jwtToken) if (!connect) { if (ubhanUserId !== job.createdBy) { @@ -242,7 +242,7 @@ fullyUpdateJob.schema = Joi.object().keys({ */ async function deleteJob (currentUser, id) { const job = await Job.findById(id) - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { const ubhanUserId = await helper.getUserId(currentUser.userId) if (ubhanUserId !== job.createdBy) { throw new errors.ForbiddenError('You are not allowed to perform this action!') diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index fc234402..d8011d6e 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -22,7 +22,7 @@ const esClient = helper.getESClient() * @returns {Object} the resourceBooking */ async function _getResourceBookingFilteringFields (currentUser, resourceBooking) { - if (currentUser.isBookingManager) { + if (currentUser.isBookingManager || currentUser.isMachine) { return helper.clearObject(resourceBooking) } else if (await helper.isConnectMember(resourceBooking.projectId, currentUser.jwtToken)) { return _.omit(helper.clearObject(resourceBooking), 'memberRate') @@ -72,7 +72,7 @@ getResourceBooking.schema = Joi.object().keys({ * @returns {Object} the created resourceBooking */ async function createResourceBooking (currentUser, resourceBooking) { - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(resourceBooking.projectId, currentUser.jwtToken) if (!connect) { throw new errors.ForbiddenError('You are not allowed to perform this action!') @@ -111,7 +111,7 @@ createResourceBooking.schema = Joi.object().keys({ */ async function updateResourceBooking (currentUser, id, data) { const resourceBooking = await ResourceBooking.findById(id) - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(resourceBooking.dataValues.projectId, currentUser.jwtToken) if (!connect) { throw new errors.ForbiddenError('You are not allowed to perform this action!') @@ -183,7 +183,7 @@ fullyUpdateResourceBooking.schema = Joi.object().keys({ * @params {String} id the resourceBooking id */ async function deleteResourceBooking (currentUser, id) { - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { throw new errors.ForbiddenError('You are not allowed to perform this action!') } diff --git a/src/services/TeamService.js b/src/services/TeamService.js index bc0c499a..de0b5a73 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -41,6 +41,10 @@ async function _getJobsByProjectIds (projectIds) { * @returns {Object} the search result, contain total/page/perPage and result array */ async function searchTeams (currentUser, criteria) { + if (currentUser.isMachine) { + const m2mToken = await helper.getM2Mtoken() + currentUser.jwtToken = `Bearer ${m2mToken}` + } const sort = `${criteria.sortBy} ${criteria.sortOrder}` // Get projects from /v5/projects with searching criteria const { total, page, perPage, result: projects } = await helper.getProjects( @@ -193,6 +197,10 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { * @returns {Object} the team */ async function getTeam (currentUser, id) { + if (currentUser.isMachine) { + const m2mToken = await helper.getM2Mtoken() + currentUser.jwtToken = `Bearer ${m2mToken}` + } // Get users from /v5/projects const project = await helper.getProjectById(currentUser.jwtToken, id) @@ -248,6 +256,10 @@ getTeam.schema = Joi.object().keys({ * @returns the team job */ async function getTeamJob (currentUser, id, jobId) { + if (currentUser.isMachine) { + const m2mToken = await helper.getM2Mtoken() + currentUser.jwtToken = `Bearer ${m2mToken}` + } // Get jobs from taas api const jobs = await _getJobsByProjectIds([id]) const job = _.find(jobs, { id: jobId }) @@ -277,7 +289,13 @@ async function getTeamJob (currentUser, id, jobId) { const userHandles = _.map(candidates, 'handle') if (userHandles && userHandles.length > 0) { // Get user photo from /v5/members - const members = await helper.getMembers(currentUser.jwtToken, userHandles) + let members + if (currentUser.isMachine) { + const m2mToken = await helper.getTopcoderM2MToken() + members = await helper.getMembers(`Bearer ${m2mToken}`, userHandles) + } else { + members = await helper.getMembers(currentUser.jwtToken, userHandles) + } for (const item of candidates) { item.resumeLink = null