diff --git a/.circleci/config.yml b/.circleci/config.yml index 78e4ffa1..e6268124 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -46,30 +46,28 @@ jobs: environment: DEPLOY_ENV: "DEV" LOGICAL_ENV: "dev" - APPNAME: "taas-apis" + APPNAME: "taas-apis" steps: *builddeploy_steps "build-prod": <<: *defaults environment: DEPLOY_ENV: "PROD" - LOGICAL_ENV: "prod" - APPNAME: "taas-apis" + LOGICAL_ENV: "prod" + APPNAME: "taas-apis" steps: *builddeploy_steps workflows: version: 2 build: jobs: - # Development builds are executed on "develop" branch only. + # Development builds are executed on "develop" branch only. - "build-dev": context : org-global filters: branches: only: - dev - - feature/es-segregation - - feature/integration-test-fix # Production builds are exectuted only on tagged commits to the # master branch. diff --git a/.gitignore b/.gitignore index d4e0230b..6ac5f84d 100644 --- a/.gitignore +++ b/.gitignore @@ -116,4 +116,7 @@ dist .pnp.* # api.env -api.env \ No newline at end of file +api.env + +# macOS files +.DS_Store 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/app.js b/app.js index a0a9e0e1..f60a0565 100644 --- a/app.js +++ b/app.js @@ -14,7 +14,10 @@ const logger = require('./src/common/logger') // setup express app const app = express() -app.use(cors()) +app.use(cors({ + // Allow browsers access pagination data in headers + exposedHeaders: ['X-Page', 'X-Per-Page', 'X-Total', 'X-Total-Pages', 'X-Prev-Page', 'X-Next-Page'] +})) app.use(express.json()) app.use(express.urlencoded({ extended: true })) app.set('port', config.PORT) diff --git a/config/default.js b/config/default.js index 333d5f55..cccdf99c 100644 --- a/config/default.js +++ b/config/default.js @@ -14,9 +14,16 @@ 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', + TOPCODER_USERS_API: process.env.TOPCODER_USERS_API || 'https://api.topcoder-dev.com/v3/users', + DATABASE_URL: process.env.DATABASE_URL || 'postgres://postgres:postgres@localhost:5432/postgres', DB_SCHEMA_NAME: process.env.DB_SCHEMA_NAME || 'bookings', PROJECT_API_URL: process.env.PROJECT_API_URL || 'https://api.topcoder-dev.com', diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index df9b154b..c99f8ab0 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "266c56d9-a96a-4f45-9220-95620f026041", + "_postman_id": "d2eee7f7-0fab-44f1-befa-4a6c8c901ddb", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,7 @@ { "listen": "test", "script": { - "id": "4f296739-8f36-4d76-be66-269aa4c6c34a", + "id": "6e8082d1-0726-4ba9-b125-25618640ad00", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -34,7 +34,52 @@ ], "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 \"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", + "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 m2m create", + "event": [ + { + "listen": "test", + "script": { + "id": "01d9b0de-698f-415a-ae3e-078ce7e4acc2", + "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" @@ -59,7 +104,7 @@ { "listen": "test", "script": { - "id": "5d118bcb-ea69-4f92-b267-7a807deef522", + "id": "cff233a7-6b62-4c99-994f-94bc4a6bfae6", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -79,7 +124,7 @@ ], "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 \"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}", + "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}", "options": { "raw": { "language": "json" @@ -99,14 +144,15 @@ "response": [] }, { - "name": "create job with member", + "name": "create job with member success", "event": [ { "listen": "test", "script": { - "id": "cb499304-14a4-4c9e-a43f-4a3356f917aa", + "id": "93f5a652-d342-41ff-a43e-d63c3e6946a6", "exec": [ - "" + "var data = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" ], "type": "text/javascript" } @@ -123,7 +169,7 @@ ], "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 \"skills\": [\r\n \"56fdc405-eccc-4189-9e83-c78abf844f50\",\r\n \"f91ae184-aba2-4485-a8cb-9336988c05ab\",\r\n \"edfc7b4f-636f-44bd-96fc-949ffc58e38b\",\r\n \"4ca63bb6-f515-4ab0-a6bc-c2d8531e084f\",\r\n \"ee03c041-d53b-4c08-b7d9-80d7461da3e4\"\r\n ]\r\n}", + "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" @@ -148,7 +194,7 @@ { "listen": "test", "script": { - "id": "c0f62918-f916-468a-9e81-5151f1869f9f", + "id": "33f7a08c-8368-45f8-900e-d28197f696ef", "exec": [ "" ], @@ -167,7 +213,7 @@ ], "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 \"skills\": [\r\n \"56fdc405-eccc-4189-9e83-c78abf844f50\",\r\n \"f91ae184-aba2-4485-a8cb-9336988c05ab\",\r\n \"edfc7b4f-636f-44bd-96fc-949ffc58e38b\",\r\n \"4ca63bb6-f515-4ab0-a6bc-c2d8531e084f\",\r\n \"ee03c041-d53b-4c08-b7d9-80d7461da3e4\"\r\n ]\r\n}", + "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 \"56fdc405-eccc-4189-9e83-c78abf844f50\",\r\n \"f91ae184-aba2-4485-a8cb-9336988c05ab\",\r\n \"edfc7b4f-636f-44bd-96fc-949ffc58e38b\",\r\n \"4ca63bb6-f515-4ab0-a6bc-c2d8531e084f\",\r\n \"ee03c041-d53b-4c08-b7d9-80d7461da3e4\"\r\n ]\r\n}", "options": { "raw": { "language": "json" @@ -192,7 +238,7 @@ { "listen": "test", "script": { - "id": "ab099735-7af0-4f99-b274-a9be3f70ffd3", + "id": "f1956483-7e8f-4b29-b126-d2e86283edff", "exec": [ "" ], @@ -211,7 +257,7 @@ ], "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 \"skills\": [\r\n \"56fdc405-eccc-4189-9e83-c78abf844f50\",\r\n \"f91ae184-aba2-4485-a8cb-9336988c05ab\",\r\n \"edfc7b4f-636f-44bd-96fc-949ffc58e38b\",\r\n \"4ca63bb6-f515-4ab0-a6bc-c2d8531e084f\",\r\n \"ee03c041-d53b-4c08-b7d9-80d7461da3e4\"\r\n ]\r\n}", + "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 \"56fdc405-eccc-4189-9e83-c78abf844f50\",\r\n \"f91ae184-aba2-4485-a8cb-9336988c05ab\",\r\n \"edfc7b4f-636f-44bd-96fc-949ffc58e38b\",\r\n \"4ca63bb6-f515-4ab0-a6bc-c2d8531e084f\",\r\n \"ee03c041-d53b-4c08-b7d9-80d7461da3e4\"\r\n ]\r\n}", "options": { "raw": { "language": "json" @@ -254,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": { @@ -320,13 +390,13 @@ } ], "url": { - "raw": "{{URL}}/jobs/{{jobId}}", + "raw": "{{URL}}/jobs/{{jobIdCreatedByMember}}", "host": [ "{{URL}}" ], "path": [ "jobs", - "{{jobId}}" + "{{jobIdCreatedByMember}}" ] } }, @@ -418,8 +488,103 @@ "disabled": true }, { - "key": "", - "value": "", + "key": "workload", + "value": "full-time", + "disabled": true + } + ] + } + }, + "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 } ] @@ -513,8 +678,8 @@ "disabled": true }, { - "key": "", - "value": "", + "key": "workload", + "value": "full-time", "disabled": true } ] @@ -608,8 +773,8 @@ "disabled": true }, { - "key": "", - "value": "", + "key": "workload", + "value": "fractional", "disabled": true } ] @@ -703,8 +868,8 @@ "disabled": true }, { - "key": "", - "value": "", + "key": "workload", + "value": "full-time", "disabled": true } ] @@ -725,7 +890,7 @@ ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\r\n \"cc41ddc4-cacc-4570-9bdb-1229c12b9784\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "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" @@ -745,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": { @@ -758,7 +956,7 @@ ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\r\n \"cc41ddc4-cacc-4570-9bdb-1229c12b9784\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "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 \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\r\n \"cc41ddc4-cacc-4570-9bdb-1229c12b9784\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", "options": { "raw": { "language": "json" @@ -779,7 +977,21 @@ "response": [] }, { - "name": "put job with member", + "name": "put job with member 403", + "event": [ + { + "listen": "test", + "script": { + "id": "7ce5a41a-da32-41be-b59e-547d7bc6f848", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PUT", "header": [ @@ -791,7 +1003,7 @@ ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\r\n \"cc41ddc4-cacc-4570-9bdb-1229c12b9784\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"1212\",\r\n \"description\": \"Dummy Description updated\",\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 \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\r\n", "options": { "raw": { "language": "json" @@ -812,19 +1024,19 @@ "response": [] }, { - "name": "put job with member with user id not exist", + "name": "put job with member success", "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_userId_not_exist}}" + "value": "Bearer {{token_member}}" } ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\r\n \"cc41ddc4-cacc-4570-9bdb-1229c12b9784\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"1212\",\r\n \"description\": \"Dummy Description updated\",\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 \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\r\n", "options": { "raw": { "language": "json" @@ -832,32 +1044,32 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{jobId}}", + "raw": "{{URL}}/jobs/{{jobIdCreatedByMember}}", "host": [ "{{URL}}" ], "path": [ "jobs", - "{{jobId}}" + "{{jobIdCreatedByMember}}" ] } }, "response": [] }, { - "name": "put job with invalid token", + "name": "put job with member with user id not exist", "request": { "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_userId_not_exist}}" } ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\r\n \"cc41ddc4-cacc-4570-9bdb-1229c12b9784\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "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 \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\r\n \"cc41ddc4-cacc-4570-9bdb-1229c12b9784\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", "options": { "raw": { "language": "json" @@ -878,19 +1090,19 @@ "response": [] }, { - "name": "patch job with booking manager", + "name": "put job with invalid token", "request": { - "method": "PATCH", + "method": "PUT", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer invalid_token" } ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "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 \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\r\n \"cc41ddc4-cacc-4570-9bdb-1229c12b9784\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", "options": { "raw": { "language": "json" @@ -911,19 +1123,19 @@ "response": [] }, { - "name": "patch job with connect user", + "name": "patch job with booking manager", "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_bookingManager}}" } ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "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" @@ -944,19 +1156,19 @@ "response": [] }, { - "name": "patch job with member", + "name": "patch job with m2m update", "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "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" @@ -964,32 +1176,32 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{jobId}}", + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", "host": [ "{{URL}}" ], "path": [ "jobs", - "{{jobId}}" + "{{jobIdCreatedByM2M}}" ] } }, "response": [] }, { - "name": "patch job with user id not exist", + "name": "patch job with connect user", "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_userId_not_exist}}" + "value": "Bearer {{token_connectUser}}" } ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "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 \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", "options": { "raw": { "language": "json" @@ -1010,19 +1222,33 @@ "response": [] }, { - "name": "patch job with invalid token", + "name": "patch job with member 403", + "event": [ + { + "listen": "test", + "script": { + "id": "df192d97-0f1d-4f56-9c60-fbb86fe1d694", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_member}}" } ], "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 \"skills\": [\r\n \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "raw": "{\r\n \"description\": \"Dummy Description updated 2\",\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 \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\r\n", "options": { "raw": { "language": "json" @@ -1043,9 +1269,9 @@ "response": [] }, { - "name": "delete job with menber", + "name": "patch job with member success", "request": { - "method": "DELETE", + "method": "PATCH", "header": [ { "key": "Authorization", @@ -1055,7 +1281,7 @@ ], "body": { "mode": "raw", - "raw": "", + "raw": "{\r\n \"description\": \"Dummy Description updated 2\",\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 \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\r\n", "options": { "raw": { "language": "json" @@ -1063,32 +1289,32 @@ } }, "url": { - "raw": "{{URL}}/jobs/{{jobId}}", + "raw": "{{URL}}/jobs/{{jobIdCreatedByMember}}", "host": [ "{{URL}}" ], "path": [ "jobs", - "{{jobId}}" + "{{jobIdCreatedByMember}}" ] } }, "response": [] }, { - "name": "delete job with connect user", + "name": "patch job with user id not exist", "request": { - "method": "DELETE", + "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_userId_not_exist}}" } ], "body": { "mode": "raw", - "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 \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", "options": { "raw": { "language": "json" @@ -1109,19 +1335,19 @@ "response": [] }, { - "name": "delete job with booking manager", + "name": "patch job with invalid token", "request": { - "method": "DELETE", + "method": "PATCH", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer invalid_token" } ], "body": { "mode": "raw", - "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 \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", "options": { "raw": { "language": "json" @@ -1142,14 +1368,14 @@ "response": [] }, { - "name": "delete job with invalid token", + "name": "delete job with booking manager", "request": { "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_bookingManager}}" } ], "body": { @@ -1173,8 +1399,187 @@ } }, "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": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_connectUser}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobId}}" + ] + } + }, + "response": [] + }, + { + "name": "delete job with member 403", + "event": [ + { + "listen": "test", + "script": { + "id": "840f8941-f568-41fb-ab30-e5263cf75c88", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobId}}" + ] + } + }, + "response": [] + }, + { + "name": "delete job with member success", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByMember}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByMember}}" + ] + } + }, + "response": [] + }, + { + "name": "delete job with invalid token", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer invalid_token" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobId}}" + ] + } + }, + "response": [] + } + ], "protocolProfileBehavior": {} }, { @@ -1186,7 +1591,7 @@ { "listen": "test", "script": { - "id": "6b168a78-7f6b-4000-bd44-3b9c76f0277e", + "id": "39076747-dd0e-4e63-99da-ca6caad846bc", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1225,13 +1630,58 @@ }, "response": [] }, + { + "name": "create job candidate with m2m create", + "event": [ + { + "listen": "test", + "script": { + "id": "ef36a884-10a1-469d-8b29-ddc5a12e1b68", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"jobCandidateIdCreatedByM2M\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_create_job_candidate}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\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 connect user", "event": [ { "listen": "test", "script": { - "id": "bc965016-a5d4-4f08-9994-3f4865915125", + "id": "11a00ab6-c16d-424c-a60a-33ecd365767e", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1276,7 +1726,7 @@ { "listen": "test", "script": { - "id": "751ec141-ef8d-4893-8802-d814006c8304", + "id": "30e0500f-87b0-4a38-a6ea-5cb049a5091c", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1321,7 +1771,7 @@ { "listen": "test", "script": { - "id": "0fbba452-0387-494b-b09d-4efc7805a273", + "id": "26b82a3d-6818-4874-9ecb-7fdd70ecedb0", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1366,7 +1816,7 @@ { "listen": "test", "script": { - "id": "c7ad1e24-852b-4f35-9131-81e0470f82be", + "id": "e314f53d-cf06-49cd-a85c-566d1c38468f", "exec": [ "" ], @@ -1428,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": { @@ -1567,14 +2041,14 @@ "response": [] }, { - "name": "search job candidates with connect user", + "name": "search job candidates with m2m all", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_m2m_all_job_candidate}}" } ], "url": { @@ -1627,18 +2101,18 @@ "response": [] }, { - "name": "search job candidates with member", + "name": "search job candidates with connect user", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "value": "Bearer {{token_connectUser}}" } ], "url": { - "raw": "{{URL}}/jobCandidates?sortBy=id&sortOrder=asc", + "raw": "{{URL}}/jobCandidates", "host": [ "{{URL}}" ], @@ -1658,11 +2132,13 @@ }, { "key": "sortBy", - "value": "id" + "value": "id", + "disabled": true }, { "key": "sortOrder", - "value": "asc" + "value": "asc", + "disabled": true }, { "key": "jobId", @@ -1685,14 +2161,14 @@ "response": [] }, { - "name": "search job candidates with invalid token", + "name": "search job candidates with member", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_member}}" } ], "url": { @@ -1743,19 +2219,77 @@ "response": [] }, { - "name": "put job candidate with booking manager", + "name": "search job candidates with invalid token", "request": { - "method": "PUT", + "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer invalid_token" } ], - "body": { - "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{jobId}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"status\": \"selected\"\r\n}", + "url": { + "raw": "{{URL}}/jobCandidates?sortBy=id&sortOrder=asc", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "1", + "disabled": true + }, + { + "key": "sortBy", + "value": "id" + }, + { + "key": "sortOrder", + "value": "asc" + }, + { + "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": "put job candidate with booking manager", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{jobId}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"status\": \"selected\"\r\n}", "options": { "raw": { "language": "json" @@ -1775,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": { @@ -1940,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": { @@ -2170,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": {} @@ -2183,7 +2816,7 @@ { "listen": "test", "script": { - "id": "84511971-c664-4334-b3de-2d5e3642ce95", + "id": "d852601c-f07c-45b9-a518-73b9bb54a3ba", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2222,13 +2855,58 @@ }, "response": [] }, + { + "name": "create resource booking with m2m create", + "event": [ + { + "listen": "test", + "script": { + "id": "b37a6e7c-2b7c-4d8b-b6dc-c06dcacb7819", + "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": "fde28c86-d477-4214-8441-f74d99f4b654", + "id": "ea33fc97-6745-4f57-9084-ec03f8e45ba2", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2273,7 +2951,7 @@ { "listen": "test", "script": { - "id": "7e928dd2-24be-4349-9e7c-6e8ccec4d6e7", + "id": "eac01ab8-fd22-49a7-a4c4-67aae1d65c4e", "exec": [ "" ], @@ -2317,7 +2995,7 @@ { "listen": "test", "script": { - "id": "25e3434c-0935-4aed-ab5f-7dc240acf95e", + "id": "dccb2b70-08eb-4966-a631-6c3c53e51fd2", "exec": [ "" ], @@ -2361,7 +3039,7 @@ { "listen": "test", "script": { - "id": "ce94fcb6-b450-4cb6-bf65-18ab34a168ec", + "id": "81e5ed58-7cc8-49cb-8eed-d9094bd383d3", "exec": [ "" ], @@ -2423,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": { @@ -2560,6 +3262,11 @@ "key": "status", "value": "sourcing", "disabled": true + }, + { + "key": "projectIds", + "value": "111, 16705", + "disabled": true } ] } @@ -2567,18 +3274,18 @@ "response": [] }, { - "name": "search resource bookings with connect user", + "name": "search resource bookings with m2m all", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_m2m_all_resource_booking}}" } ], "url": { - "raw": "{{URL}}/resourceBookings?sortOrder=desc", + "raw": "{{URL}}/resourceBookings", "host": [ "{{URL}}" ], @@ -2588,12 +3295,12 @@ "query": [ { "key": "page", - "value": "4", + "value": "1", "disabled": true }, { "key": "perPage", - "value": "3", + "value": "5", "disabled": true }, { @@ -2601,6 +3308,11 @@ "value": "id", "disabled": true }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, { "key": "startDate", "value": "2020-09-27T04:17:23.131Z", @@ -2617,8 +3329,9 @@ "disabled": true }, { - "key": "sortOrder", - "value": "desc" + "key": "status", + "value": "sourcing", + "disabled": true } ] } @@ -2626,14 +3339,14 @@ "response": [] }, { - "name": "search resource bookings with member", + "name": "search resource bookings with connect user", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "value": "Bearer {{token_connectUser}}" } ], "url": { @@ -2685,14 +3398,14 @@ "response": [] }, { - "name": "search resource bookings with invalid token", + "name": "search resource bookings with member", "request": { "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer invalid_token" + "value": "Bearer {{token_member}}" } ], "url": { @@ -2744,34 +3457,126 @@ "response": [] }, { - "name": "put resource booking with booking manager", + "name": "search resource bookings with invalid token", "request": { - "method": "PUT", + "method": "GET", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_bookingManager}}" + "value": "Bearer invalid_token" } ], - "body": { - "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\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/{{resourceBookingId}}", + "raw": "{{URL}}/resourceBookings?sortOrder=desc", "host": [ "{{URL}}" ], "path": [ - "resourceBookings", - "{{resourceBookingId}}" - ] + "resourceBookings" + ], + "query": [ + { + "key": "page", + "value": "4", + "disabled": true + }, + { + "key": "perPage", + "value": "3", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "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": "sortOrder", + "value": "desc" + } + ] + } + }, + "response": [] + }, + { + "name": "put resource booking with booking manager", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobId}}\",\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/{{resourceBookingId}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingId}}" + ] + } + }, + "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": [] @@ -2941,6 +3746,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": { @@ -3172,6 +4010,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": { @@ -3222,6 +4093,54 @@ "type": "text" } ], + "url": { + "raw": "{{URL}}/taas-teams?perPage=10&page=1&name=*taas*&sortBy=lastActivityAt&sortOrder=desc", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams" + ], + "query": [ + { + "key": "perPage", + "value": "10" + }, + { + "key": "page", + "value": "1" + }, + { + "key": "name", + "value": "*taas*", + "description": "case-insensitive; support wildcard match" + }, + { + "key": "sortBy", + "value": "lastActivityAt", + "description": "allows: createdAt, updatedAt, lastActivityAt, id, status, name, type, best match" + }, + { + "key": "sortOrder", + "value": "desc", + "description": "allows: asc, desc" + } + ] + } + }, + "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": [ @@ -3264,6 +4183,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": { @@ -3299,6 +4248,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": {} @@ -3325,6 +4310,2697 @@ } ], "protocolProfileBehavior": {} + }, + { + "name": "Create Demo Data For Team", + "item": [ + { + "name": "Get Users", + "item": [ + { + "name": "Get Users", + "event": [ + { + "listen": "test", + "script": { + "id": "e14b539f-7286-41df-9044-c2fd866fe89a", + "exec": [ + "var data = JSON.parse(responseBody);", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "var demoUsers = 20;", + "", + "pm.test('We need to have at least ' + demoUsers + ' demo userIds. Define them in {{demoUserIdN}} variables.', function () {", + " for (var i = 0; i < demoUsers; i++) {", + " var variableName = \"demoUserId\" + (i + 1);", + " var existentValue = pm.variables.get(variableName);", + " var user = data[i];", + "", + " pm.expect(!!user || !!existentValue).to.be.true;", + "", + " postman.setEnvironmentVariable(variableName, user.id);", + " }", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{token_bookingManager}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://api.topcoder-dev.com/v5/users?perPage=20", + "protocol": "https", + "host": [ + "api", + "topcoder-dev", + "com" + ], + "path": [ + "v5", + "users" + ], + "query": [ + { + "key": "perPage", + "value": "20" + } + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Create job #1 \"sourcing\"", + "item": [ + { + "name": "create job #1", + "event": [ + { + "listen": "test", + "script": { + "id": "7ed1f685-3178-43f2-b4cc-92f3bdb26aab", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId1\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"taas-demo-job1\",\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\": \"weekly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": [\r\n \"ee4c50c1-c8c3-475e-b6b6-edbd136a19d6\",\r\n \"89139c80-d0a2-47c2-aa16-14589d5afd10\",\r\n \"9f2d9127-6a2e-4506-ad76-c4ab63577b09\",\r\n \"9515e7ee-83b6-49d1-ba5c-6c59c5a8ef1b\",\r\n \"c854ab55-5922-4be1-8ecc-b3bc1f8629af\",\r\n \"8456002e-fa2d-44f0-b0e7-86b1c02b6e4c\",\r\n \"114b4ec8-805e-4c60-b351-14a955a991a9\",\r\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\r\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\r\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\r\n \"6388a632-c3ad-4525-9a73-66a527c03672\",\r\n \"23839f38-6f19-4de9-9d28-f020056bca73\",\r\n \"289e42a3-23e9-49be-88e1-6deb93cd8c31\",\r\n \"b403f209-63b5-42bc-9b5f-1564416640d8\"\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Create job #2 \"in-review\"", + "item": [ + { + "name": "create job #2", + "event": [ + { + "listen": "test", + "script": { + "id": "55d76433-8a0b-4cb7-aed6-3a1f1a8a0c8d", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId2\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"taas-demo-job2\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 7,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"weekly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": [\r\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\r\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\r\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\r\n \"6388a632-c3ad-4525-9a73-66a527c03672\",\r\n \"23839f38-6f19-4de9-9d28-f020056bca73\",\r\n \"289e42a3-23e9-49be-88e1-6deb93cd8c31\",\r\n \"b403f209-63b5-42bc-9b5f-1564416640d8\"\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 1", + "event": [ + { + "listen": "test", + "script": { + "id": "066c4353-64b8-448f-aa72-1554e08b5afd", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob1candidateId1\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId1}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 2", + "event": [ + { + "listen": "test", + "script": { + "id": "ba07a220-18ea-4b98-9ff5-4f2ef2a6f938", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob1candidateId2\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId2}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 3", + "event": [ + { + "listen": "test", + "script": { + "id": "5d7758c9-3921-460c-9a07-cc42cef409c1", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId3}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 4", + "event": [ + { + "listen": "test", + "script": { + "id": "d8ea4ecb-0cb1-4573-92ae-d98374e27b9e", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId4}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 5", + "event": [ + { + "listen": "test", + "script": { + "id": "e0a12c48-cf1f-4c31-a021-4aca890c18bc", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId5}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 6", + "event": [ + { + "listen": "test", + "script": { + "id": "5d865acc-250f-42b0-a4a2-7f8a07f0b9d4", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId6}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 7", + "event": [ + { + "listen": "test", + "script": { + "id": "3c43394d-244c-47b1-9e2f-1e625cf7e420", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId7}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 8", + "event": [ + { + "listen": "test", + "script": { + "id": "3d34dc24-9498-496f-a52b-ef788a1d66e7", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId8}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 9", + "event": [ + { + "listen": "test", + "script": { + "id": "22bff7e4-8927-444f-9a45-91494087a297", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId9}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #2 candidate 10", + "event": [ + { + "listen": "test", + "script": { + "id": "75b39c48-4aed-4100-9612-6db632b0da6c", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId2}}\",\r\n \"userId\": \"{{demoUserId10}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "update job #2 candidate 1 to \"shortlist\"", + "event": [ + { + "listen": "test", + "script": { + "id": "b3e10a61-151e-47d6-a4b0-47fde62c1142", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{demoJob1candidateId1}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{demoJob1candidateId1}}" + ] + } + }, + "response": [] + }, + { + "name": "update job #2 candidate 2 to \"rejected\"", + "event": [ + { + "listen": "test", + "script": { + "id": "87621008-82a1-48dd-b4ef-7c72e2a9c4c6", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"rejected\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{demoJob1candidateId2}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{demoJob1candidateId2}}" + ] + } + }, + "response": [] + }, + { + "name": "update job #2 status to \"in-review\"", + "event": [ + { + "listen": "test", + "script": { + "id": "cffe697d-21b8-452d-be0f-f5fb7c9a5f95", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"in-review\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{demoJobId2}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{demoJobId2}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Create job #3 \"assigned\"", + "item": [ + { + "name": "create job #3", + "event": [ + { + "listen": "test", + "script": { + "id": "848a04c5-b3ae-4808-8993-e45ad2732827", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId3\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"taas-demo-job3\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 7,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"weekly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": []\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 11", + "event": [ + { + "listen": "test", + "script": { + "id": "e5cb331e-bef5-404d-8c10-3b418392b976", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId11}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 12", + "event": [ + { + "listen": "test", + "script": { + "id": "e0970502-16d8-401a-b68d-b4c93317303e", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId12}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 13", + "event": [ + { + "listen": "test", + "script": { + "id": "d5096ca6-daaa-42dc-befd-743efd45c68a", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId13}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 14", + "event": [ + { + "listen": "test", + "script": { + "id": "d4c0f029-ef26-4674-a879-185a38f1a840", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId14}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 15", + "event": [ + { + "listen": "test", + "script": { + "id": "a82c5644-ab0b-49c2-9630-778abd537e9d", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId15}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 16", + "event": [ + { + "listen": "test", + "script": { + "id": "c033b550-5dc5-4a05-afb3-5ee5d65c7ebf", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId16}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 17", + "event": [ + { + "listen": "test", + "script": { + "id": "d791b733-89a7-432d-947f-8ec4bf3b187b", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId17}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 18", + "event": [ + { + "listen": "test", + "script": { + "id": "d62edda6-69ff-4451-ae1a-9501c227c9ae", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId18}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 19", + "event": [ + { + "listen": "test", + "script": { + "id": "7aafa77e-41a1-416e-8a5e-31a0a2034fa7", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId19}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job #3 candidate 20", + "event": [ + { + "listen": "test", + "script": { + "id": "aaadf3af-06ab-49c3-9897-6f630c24429e", + "exec": [ + "pm.test(\"Successful POST request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"userId\": \"{{demoUserId20}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 11", + "event": [ + { + "listen": "test", + "script": { + "id": "b92b7cab-0a20-446a-8f94-0a9b1185ffce", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId11\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "b6961c13-333b-44c6-8692-0d1ad9f69657", + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId11}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 12", + "event": [ + { + "listen": "test", + "script": { + "id": "4e6a7e74-6a2b-4b3e-8a7d-ad8d7a18fa3c", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId12\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "33183902-37c8-4901-8fa0-a6b5b3e0b8a0", + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId12}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 13", + "event": [ + { + "listen": "test", + "script": { + "id": "cb63048c-f0ac-414b-802c-e7df4719b445", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId13\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "9fb1ebfa-e8ec-4c23-a6e0-673fb9e50060", + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId13}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 14", + "event": [ + { + "listen": "test", + "script": { + "id": "121a11f0-3efa-4b07-b515-be3fb414cd85", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId14\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "2b513814-fb39-49e3-982e-9714a8a003ac", + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId14}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 15", + "event": [ + { + "listen": "test", + "script": { + "id": "92f5ab04-6878-448d-b89f-543b785f9829", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId15\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "6a556328-d533-4886-8e6b-d6d9e8b91764", + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId15}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 1000,\r\n \"customerRate\": 1200,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 16", + "event": [ + { + "listen": "test", + "script": { + "id": "d3d0593e-682c-4b76-acae-9d32dd134b7c", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId16\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "d3a77c20-a185-4992-bea0-a878f9a089a2", + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId16}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 800,\r\n \"customerRate\": 1000,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 17", + "event": [ + { + "listen": "test", + "script": { + "id": "738c34a4-3aa9-477b-a604-88e1edc2cb62", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId17\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "0065d3f9-141a-4054-b4b9-3d36d9432133", + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId17}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"{{resourceStartDate}}\",\r\n \"endDate\": \"{{resourceEndDate}}\",\r\n \"memberRate\": 2000,\r\n \"customerRate\": 2500,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 18", + "event": [ + { + "listen": "test", + "script": { + "id": "64f57590-1dc5-400d-888f-7efe71ea3dfd", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId18\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "52dac9d1-adb8-4c2d-93f6-a5a7fb1a6d08", + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId18}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2000-07-27T04:17:23.131Z\",\r\n \"endDate\": \"2000-09-27T04:17:23.131Z\",\r\n \"memberRate\": 3000,\r\n \"customerRate\": 3500,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 19", + "event": [ + { + "listen": "test", + "script": { + "id": "fc175290-c583-49e5-9ba8-5d94af9d9ea2", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId19\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId19}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2022-07-27T04:17:23.131Z\",\r\n \"endDate\": \"2022-09-27T04:17:23.131Z\",\r\n \"memberRate\": 1700,\r\n \"customerRate\": 1900,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "create job 3 resource booking 20", + "event": [ + { + "listen": "test", + "script": { + "id": "c056d309-c9da-4aad-8d84-32cb4d5659bf", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJob3resourceCandiateId20\",data.id);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "b024a20f-9c55-4af0-b978-012c6b3d885e", + "exec": [ + "const startDate = new Date()", + "startDate.setDate(startDate.getDate() - 3);", + "", + "const endDate = new Date()", + "endDate.setDate(endDate.getDate() + 3);", + "", + "postman.setEnvironmentVariable(\"resourceStartDate\", startDate.toUTCString());", + "postman.setEnvironmentVariable(\"resourceEndDate\", endDate.toUTCString());" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId20}}\",\r\n \"jobId\": \"{{demoJobId3}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 0,\r\n \"customerRate\": 0,\r\n \"rateType\": \"weekly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 11 status to \"assigned\"", + "event": [ + { + "listen": "test", + "script": { + "id": "9226322c-9ad3-4d0a-9e2d-cf2263bf355d", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId11}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId11}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 12 status to \"in-review\"", + "event": [ + { + "listen": "test", + "script": { + "id": "2e39a592-6f51-4c96-8163-8c7987e1bb03", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"in-review\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId12}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId12}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 13 status to \"closed\"", + "event": [ + { + "listen": "test", + "script": { + "id": "8ce1c231-81f5-401f-b016-7deea2b2c76b", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"closed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId13}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId13}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 14 status to \"cancelled\"", + "event": [ + { + "listen": "test", + "script": { + "id": "92eee318-1f47-49f5-86ae-e9bbe986c8e6", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId14}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId14}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 15 status to \"sourcing\"", + "event": [ + { + "listen": "test", + "script": { + "id": "08882fb4-35b0-4a75-a821-dc59a53a9d2b", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"sourcing\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId15}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId15}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 16 status to \"assigned\"", + "event": [ + { + "listen": "test", + "script": { + "id": "8e04c98e-59a5-4377-a35d-8b8521cf236b", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId16}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId16}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 17 status to \"assigned\"", + "event": [ + { + "listen": "test", + "script": { + "id": "4ee12efc-0349-46ab-9a79-4f66aa551061", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId17}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId17}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 18 status to \"assigned\"", + "event": [ + { + "listen": "test", + "script": { + "id": "091ef060-7048-4b9c-996a-c8b6fe3e5705", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId18}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId18}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 19 status to \"assigned\"", + "event": [ + { + "listen": "test", + "script": { + "id": "85cc5231-9f1e-4dff-8a89-e4537aeaef8e", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId19}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId19}}" + ] + } + }, + "response": [] + }, + { + "name": "update job 3 resource booking 20 status to \"assigned\"", + "event": [ + { + "listen": "test", + "script": { + "id": "ff761b56-eacc-40d7-8ae5-52fb59aa5df0", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{demoJob3resourceCandiateId20}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{demoJob3resourceCandiateId20}}" + ] + } + }, + "response": [] + }, + { + "name": "update job #3 status to \"assigned\"", + "event": [ + { + "listen": "test", + "script": { + "id": "8a657df4-bc76-4afa-8464-0e03439e5fd5", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{demoJobId3}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{demoJobId3}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Create job #4 \"closed\"", + "item": [ + { + "name": "create job #4", + "event": [ + { + "listen": "test", + "script": { + "id": "6fea605c-e45d-4b74-8984-e026d800883c", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId4\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"taas-demo-job4\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 7,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"weekly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": [\r\n \"8456002e-fa2d-44f0-b0e7-86b1c02b6e4c\",\r\n \"114b4ec8-805e-4c60-b351-14a955a991a9\",\r\n \"213408aa-f16f-46c8-bc57-9e569cee3f11\",\r\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\r\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\r\n \"6388a632-c3ad-4525-9a73-66a527c03672\"\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + }, + { + "name": "update job #4 status to \"closed\"", + "event": [ + { + "listen": "test", + "script": { + "id": "dea1c56f-d9f8-40dd-9137-7f2619ee96a0", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"closed\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{demoJobId4}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{demoJobId4}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Create job #5 \"cancelled\"", + "item": [ + { + "name": "create job #5", + "event": [ + { + "listen": "test", + "script": { + "id": "66889f4d-32cf-40a7-8524-85e5e2ad5f67", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "\r", + "pm.test(\"Successful POST request\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);\r", + "});\r", + "\r", + "postman.setEnvironmentVariable(\"demoJobId5\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"taas-demo-job5\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 7,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"weekly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": [\r\n \"b37a48db-f775-4e4e-b403-8ad1d234cdea\",\r\n \"99b930b5-1b91-4df1-8b17-d9307107bb51\",\r\n \"6388a632-c3ad-4525-9a73-66a527c03672\"\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + }, + { + "name": "update job #5 status to \"cancelled\"", + "event": [ + { + "listen": "test", + "script": { + "id": "34e50784-298e-44ce-949a-380a3c015d3a", + "exec": [ + "pm.test(\"Successful PATCH request\", function () {", + " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_bookingManager}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"cancelled\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{demoJobId5}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{demoJobId5}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + } + ], + "protocolProfileBehavior": {} } ], "protocolProfileBehavior": {} diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 8cc73679..50cdc8b0 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -22,7 +22,7 @@ paths: description: | Create job. - **Authorization** Topcoder token with write job scope is allowed + **Authorization** All topcoder members are allowed security: - bearerAuth: [] requestBody: @@ -67,7 +67,7 @@ paths: description: | Search jobs. - **Authorization** Topcoder token with read job scope is allowed + **Authorization** All topcoder members are allowed security: - bearerAuth: [] parameters: @@ -107,6 +107,12 @@ paths: schema: type: integer description: The project id. + - in: query + name: projectIds + required: false + schema: + type: string + description: The project ids, separated by commas. - in: query name: externalId required: false @@ -145,6 +151,13 @@ paths: schema: type: string description: The skill. + - in: query + name: workload + required: false + schema: + type: string + enum: ['full-time', 'fractional'] + description: The rate type. - in: query name: rateType required: false @@ -165,12 +178,10 @@ paths: content: application/json: schema: - type: object - properties: - result: - type: array - items: - $ref: '#/components/schemas/Job' + type: array + items: + $ref: '#/components/schemas/Job' + headers: X-Next-Page: schema: @@ -231,7 +242,7 @@ paths: description: | Get job information by id. - **Authorization** Topcoder token with read job scope is allowed + **Authorization** All topcoder members are allowed security: - bearerAuth: [] parameters: @@ -290,7 +301,7 @@ paths: description: | Delete the job. - **Authorization** Topcoder token with delete job scope is allowed + **Authorization** Every topcoder member can delete the job he/she created. bookingmanager can delete all jobs. security: - bearerAuth: [] parameters: @@ -340,7 +351,7 @@ paths: description: | Update the job. - **Authorization** Topcoder token with update job scope is allowed + **Authorization** Every topcoder member can update the job he/she created. bookingmanager and connectmember can update all jobs. security: - bearerAuth: [] parameters: @@ -494,6 +505,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: Internal Server Error content: @@ -566,12 +583,10 @@ paths: content: application/json: schema: - type: object - properties: - result: - type: array - items: - $ref: '#/components/schemas/JobCandidate' + type: array + items: + $ref: '#/components/schemas/JobCandidate' + headers: X-Next-Page: schema: @@ -895,6 +910,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '500': description: Internal Server Error content: @@ -975,12 +996,10 @@ paths: content: application/json: schema: - type: object - properties: - result: - type: array - items: - $ref: '#/components/schemas/ResourceBooking' + type: array + items: + $ref: '#/components/schemas/ResourceBooking' + headers: X-Next-Page: schema: @@ -1271,6 +1290,44 @@ paths: - Teams description: | Search my teams. Teams is project in topcoder with type=='talent-as-a-service' + 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. + - in: query + name: sortBy + required: false + schema: + type: string + default: createdAt + enum: ['createdAt', 'updatedAt', 'lastActivityAt', 'id', 'status', 'name', 'type', 'best match'] + description: The sort by column. + - in: query + name: sortOrder + required: false + schema: + type: string + default: desc + enum: ['desc','asc'] + description: The sort order. Not allowed when sortBy is `best match`. + - in: query + name: name + required: false + schema: + type: string + description: filter by name, case-insensitive; support wildcard match. + example: '*taas*' security: - bearerAuth: [] responses: @@ -1282,6 +1339,35 @@ paths: type: array items: $ref: '#/components/schemas/Team' + 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: @@ -1479,6 +1565,10 @@ components: type: string enum: ['hourly', 'daily', 'weekly', 'monthly'] description: "The rate type of the job." + workload: + type: string + enum: ['full-time', 'fractional'] + description: "The workload of the job." skills: type: array description: "The skills." @@ -1557,6 +1647,10 @@ components: type: string enum: ['hourly', 'daily', 'weekly', 'monthly'] description: "The rate type of the job." + workload: + type: string + enum: ['full-time', 'fractional'] + description: "The workload of the job." skills: type: array description: "The skills." @@ -1654,6 +1748,10 @@ components: type: string enum: ['hourly', 'daily', 'weekly', 'monthly'] description: "The rate type of the job." + workload: + type: string + enum: ['full-time', 'fractional'] + description: "The workload of the job." skills: type: array description: "The skills." diff --git a/docs/topcoder-bookings.postman_environment.json b/docs/topcoder-bookings.postman_environment.json index f87f1fe1..a97d2383 100644 --- a/docs/topcoder-bookings.postman_environment.json +++ b/docs/topcoder-bookings.postman_environment.json @@ -1,5 +1,5 @@ { - "id": "cc8450af-34ea-4981-8736-4cf27d947306", + "id": "a7cb1c6e-c710-49c3-ad58-db7536c85944", "name": "topcoder-bookings", "values": [ { @@ -46,9 +46,109 @@ "key": "projectId", "value": "111", "enabled": true + }, + { + "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-11-19T12:26:05.800Z", + "_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/package-lock.json b/package-lock.json index 6f940aa0..8f11bdb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -908,6 +908,65 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "auth0-js": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/auth0-js/-/auth0-js-9.14.0.tgz", + "integrity": "sha512-40gIBUejmYAYse06ck6sxdNO0KU0pX+KDIQsWAkcyFtI0HU6dY5aeHxZfVYkYjtbArKr5s13LuZFdKrUiGyCqQ==", + "requires": { + "base64-js": "^1.3.0", + "idtoken-verifier": "^2.0.3", + "js-cookie": "^2.2.0", + "qs": "^6.7.0", + "superagent": "^5.3.1", + "url-join": "^4.0.1", + "winchan": "^0.2.2" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "superagent": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.3.1.tgz", + "integrity": "sha512-wjJ/MoTid2/RuGCOFtlacyGNxN9QLMgcpYLDQlWFIhhdJ93kNscFonGvrpAHSCVjRVj++DGCglocF7Aej1KHvQ==", + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "dependencies": { + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + } + } + } + } + }, "available-typed-arrays": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", @@ -1516,6 +1575,11 @@ } } }, + "crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" + }, "crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -1530,6 +1594,11 @@ "assert-plus": "^1.0.0" } }, + "date-fns": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz", + "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1812,6 +1881,11 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, "escape-goat": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", @@ -2793,6 +2867,26 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "idtoken-verifier": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/idtoken-verifier/-/idtoken-verifier-2.1.0.tgz", + "integrity": "sha512-X0423UM4Rc5bFb39Ai0YHr35rcexlu4oakKdYzSGZxtoPy84P86hhAbzlpgbgomcLOFRgzgKRvhY7YjO5g8OPA==", + "requires": { + "base64-js": "^1.3.0", + "crypto-js": "^3.2.1", + "es6-promise": "^4.2.8", + "jsbn": "^1.1.0", + "unfetch": "^4.1.0", + "url-join": "^4.0.1" + }, + "dependencies": { + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA=" + } + } + }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", @@ -3355,6 +3449,11 @@ "@hapi/topo": "^5.0.0" } }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3550,6 +3649,31 @@ "package-json": "^6.3.0" } }, + "le_node": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/le_node/-/le_node-1.8.0.tgz", + "integrity": "sha512-NXzjxBskZ4QawTNwlGdRG05jYU0LhV2nxxmP3x7sRMHyROV0jPdyyikO9at+uYrWX3VFt0Y/am11oKITedx0iw==", + "requires": { + "babel-runtime": "6.6.1", + "codependency": "0.1.4", + "json-stringify-safe": "5.0.1", + "lodash": "4.17.11", + "reconnect-core": "1.3.0", + "semver": "5.1.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "semver": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.1.0.tgz", + "integrity": "sha1-hfLPhVBGXE3wAM99hvawVBBqueU=" + } + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -5653,6 +5777,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stream-consume": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", + "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==" + }, "string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", @@ -5817,17 +5946,37 @@ } }, "tc-core-library-js": { - "version": "github:appirio-tech/tc-core-library-js#081138e1f5eae76171abeff34b8f326b3fb2b504", - "from": "github:appirio-tech/tc-core-library-js#v2.6.5", + "version": "github:appirio-tech/tc-core-library-js#d16413db30b1eed21c0cf426e185bedb2329ddab", + "from": "github:appirio-tech/tc-core-library-js#v2.6", "requires": { - "axios": "^0.19.0", + "auth0-js": "^9.4.2", + "axios": "^0.12.0", "bunyan": "^1.8.12", - "jsonwebtoken": "^8.5.1", - "jwks-rsa": "^1.6.0", - "lodash": "^4.17.15", + "jsonwebtoken": "^8.3.0", + "jwks-rsa": "^1.3.0", + "le_node": "^1.3.1", + "lodash": "^4.17.10", "millisecond": "^0.1.2", - "r7insight_node": "^1.8.4", "request": "^2.88.0" + }, + "dependencies": { + "axios": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.12.0.tgz", + "integrity": "sha1-uQewIhzDTsHJ+sGOx/B935V4W6Q=", + "requires": { + "follow-redirects": "0.0.7" + } + }, + "follow-redirects": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", + "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", + "requires": { + "debug": "^2.2.0", + "stream-consume": "^0.1.0" + } + } } }, "term-size": { @@ -6008,6 +6157,11 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.11.0.tgz", "integrity": "sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw==" }, + "unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" + }, "uniq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", @@ -6125,6 +6279,11 @@ } } }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" + }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -6275,6 +6434,11 @@ "string-width": "^4.0.0" } }, + "winchan": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/winchan/-/winchan-0.2.2.tgz", + "integrity": "sha512-pvN+IFAbRP74n/6mc6phNyCH8oVkzXsto4KCHPJ2AScniAnA1AmeLI03I2BzjePpaClGSI4GUMowzsD3qz5PRQ==" + }, "winston": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", diff --git a/package.json b/package.json index bad6ecac..69b6012d 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "aws-sdk": "^2.787.0", "config": "^3.3.2", "cors": "^2.8.5", + "date-fns": "^2.16.1", "dotenv": "^8.2.0", "express": "^4.17.1", "express-interceptor": "^1.2.0", @@ -37,7 +38,7 @@ "rewire": "^5.0.0", "sequelize": "^6.3.5", "superagent": "^6.1.0", - "tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.5", + "tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6", "util": "^0.12.3", "uuid": "^8.3.1", "winston": "^3.3.3" diff --git a/scripts/createIndex.js b/scripts/createIndex.js index ad5fa2c0..4d39dea1 100644 --- a/scripts/createIndex.js +++ b/scripts/createIndex.js @@ -23,6 +23,7 @@ async function createIndex () { numPositions: { type: 'integer' }, resourceType: { type: 'keyword' }, rateType: { type: 'keyword' }, + workload: { type: 'keyword' }, skills: { type: 'keyword' }, status: { type: 'keyword' }, createdAt: { type: 'date' }, diff --git a/src/bootstrap.js b/src/bootstrap.js index 4e6d87f7..a35212e0 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -3,8 +3,11 @@ const Joi = require('joi') const path = require('path') const logger = require('./common/logger') +Joi.page = () => Joi.number().integer().min(1).default(1) +Joi.perPage = () => Joi.number().integer().min(1).default(20) Joi.rateType = () => Joi.string().valid('hourly', 'daily', 'weekly', 'monthly') Joi.jobStatus = () => Joi.string().valid('sourcing', 'in-review', 'assigned', 'closed', 'cancelled') +Joi.workload = () => Joi.string().valid('full-time', 'fractional') Joi.jobCandidateStatus = () => Joi.string().valid('open', 'selected', 'shortlist', 'rejected') function buildServices (dir) { diff --git a/src/common/helper.js b/src/common/helper.js index 7ab969f6..f2b775a9 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -5,11 +5,13 @@ const querystring = require('querystring') const AWS = require('aws-sdk') const config = require('config') +const HttpStatus = require('http-status-codes') const _ = require('lodash') const request = require('superagent') const elasticsearch = require('@elastic/elasticsearch') const errors = require('../common/errors') const logger = require('./logger') +const models = require('../models') const busApi = require('@topcoder-platform/topcoder-bus-api-wrapper') const localLogger = { @@ -23,6 +25,11 @@ const m2mAuth = require('tc-core-library-js').auth.m2m // const m2m = m2mAuth(_.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME', 'AUTH0_PROXY_SERVER_URL'])) const m2m = m2mAuth(_.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'AUTH0_PROXY_SERVER_URL'])) +const topcoderM2M = m2mAuth({ + AUTH0_AUDIENCE: config.AUTH0_AUDIENCE_FOR_BUS_API, + ..._.pick(config, ['AUTH0_URL', 'TOKEN_CACHE_TIME', 'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'AUTH0_PROXY_SERVER_URL']) +}) + let busApiClient /** @@ -44,6 +51,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 @@ -119,14 +158,6 @@ function setResHeaders (req, res, result) { } res.set('Link', link) } - - // Allow browsers access pagination data in headers - let accessControlExposeHeaders = res.get('Access-Control-Expose-Headers') || '' - accessControlExposeHeaders += accessControlExposeHeaders ? ', ' : '' - // append new values, to not override values set by someone else - accessControlExposeHeaders += 'X-Page, X-Per-Page, X-Total, X-Total-Pages, X-Prev-Page, X-Next-Page' - - res.set('Access-Control-Expose-Headers', accessControlExposeHeaders) } /** @@ -202,6 +233,14 @@ const getM2Mtoken = async () => { return await m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET) } +/* + * Function to get M2M token to access topcoder resources(e.g. /v3/users) + * @returns {Promise} + */ +const getTopcoderM2MToken = async () => { + return await topcoderM2M.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET) +} + /** * Function to encode query string * @param {Object} queryObj the query object @@ -292,46 +331,48 @@ function isDocumentMissingException (err) { /** * Function to get projects * @param {String} token the user request token + * @param {Object} criteria the search criteria * @returns the request result */ -async function getProjects (token) { -/* const url = `${config.TC_API}/projects?type=talent-as-a-service` +async function getProjects (token, criteria = {}) { + const url = `${config.TC_API}/projects?type=talent-as-a-service` const res = await request .get(url) - .query({ - memberOnly: true - }) + .query(criteria) .set('Authorization', token) .set('Content-Type', 'application/json') .set('Accept', 'application/json') localLogger.debug({ context: 'getProjects', message: `response body: ${JSON.stringify(res.body)}` }) - return _.map(res.body, item => { - return _.pick(item, ['id', 'name']) - })*/ - - const url = `${config.TC_API}/projects?type=talent-as-a-service` - let data = [] - let page = 1 - while (true) { - const res = await request - .get(url) - .query({ - page, - memberOnly: true - }) - .set('Authorization', token) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - localLogger.debug({ context: 'getProjects', message: `page ${page} - response body: ${JSON.stringify(res.body)}` }) - data = [...data, ...res.body] - page += 1 - if (!res.headers['x-next-page']) { - break - } - } - return _.map(data, item => { + const result = _.map(res.body, item => { return _.pick(item, ['id', 'name']) }) + return { + total: Number(_.get(res.headers, 'x-total')), + page: Number(_.get(res.headers, 'x-page')), + perPage: Number(_.get(res.headers, 'x-per-page')), + result + } +} + +/** + * Get topcoder user by id from /v3/users. + * + * @param {String} userId the legacy user id + * @returns {Object} the user + */ +async function getTopcoderUserById (userId) { + const token = await getTopcoderM2MToken() + const res = await request + .get(config.TOPCODER_USERS_API) + .query({ filter: `id=${userId}` }) + .set('Authorization', `Bearer ${token}`) + .set('Accept', 'application/json') + localLogger.debug({ context: 'getTopcoderUserById', message: `response body: ${JSON.stringify(res.body)}` }) + const user = _.get(res.body, 'result.content[0]') + if (!user) { + throw new errors.NotFoundError(`userId: ${userId} "user" not found from ${config.TOPCODER_USERS_API}`) + } + return user } /** @@ -340,14 +381,54 @@ async function getProjects (token) { * @param {String} userId the user id * @returns the request result */ -async function getUserById (token, userId) { +async function getUserById (token, userId, enrich) { const res = await request - .get(`${config.TC_API}/users/${userId}`) + .get(`${config.TC_API}/users/${userId}` + (enrich ? '?enrich=true' : '')) .set('Authorization', token) .set('Content-Type', 'application/json') .set('Accept', 'application/json') localLogger.debug({ context: 'getUserById', message: `response body: ${JSON.stringify(res.body)}` }) - return _.pick(res.body, ['id', 'handle', 'firstName', 'lastName']) + + const user = _.pick(res.body, ['id', 'handle', 'firstName', 'lastName']) + + if (enrich) { + user.skills = (res.body.skills || []).map((skillObj) => _.pick(skillObj.skill, ['id', 'name'])) + } + + return user +} + +/** + * Function to create user in ubhan + * @param {Object} data the user data + * @returns the request result + */ +async function createUbhanUser ({ handle, firstName, lastName }) { + const token = await getM2Mtoken() + const res = await request + .post(`${config.TC_API}/users`) + .set('Authorization', `Bearer ${token}`) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send({ handle, firstName, lastName }) + localLogger.debug({ context: 'createUbhanUser', message: `response body: ${JSON.stringify(res.body)}` }) + return _.pick(res.body, ['id']) +} + +/** + * Function to create external profile for a ubhan user + * @param {String} userId the user id(with uuid format) + * @param {Object} data the profile data + */ +async function createUserExternalProfile (userId, { organizationId, externalId }) { + const token = await getM2Mtoken() + const res = await request + .post(`${config.TC_API}/users/${userId}/externalProfiles`) + .set('Authorization', `Bearer ${token}`) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + .send({ organizationId, externalId: String(externalId) }) + localLogger.debug({ context: 'createUserExternalProfile', message: `response body: ${JSON.stringify(res.body)}` }) } /** @@ -357,7 +438,7 @@ async function getUserById (token, userId) { * @returns the request result */ async function getMembers (token, handles) { - /* const handlesStr = _.map(handles, handle => { + const handlesStr = _.map(handles, handle => { return '%22' + handle.toLowerCase() + '%22' }).join(',') const url = `${config.TC_API}/members?fields=userId,handleLower,photoURL&handlesLower=[${handlesStr}]` @@ -368,32 +449,7 @@ async function getMembers (token, handles) { .set('Content-Type', 'application/json') .set('Accept', 'application/json') localLogger.debug({ context: 'getMembers', message: `response body: ${JSON.stringify(res.body)}` }) - return res.body */ - - const handlesStr = _.map(handles, handle => { - return '%22' + handle.toLowerCase() + '%22' - }).join(',') - const url = `${config.TC_API}/members?fields=userId,handleLower,photoURL&handlesLower=[${handlesStr}]` - - let data = [] - let page = 1 - while (true) { - const res = await request - .get(url) - .query({ - page - }) - .set('Authorization', token) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - localLogger.debug({ context: 'getMembers', message: `page ${page} - response body: ${JSON.stringify(res.body)}` }) - data = [...data, ...res.body] - page += 1 - if (!res.headers['x-next-page']) { - break - } - } - return data + return res.body } /** @@ -451,13 +507,80 @@ async function getUserSkill (token, userId) { }) } +/** + * Encapsulate the getUserId function. + * Make sure a user exists in ubahn(/v5/users) and return the id of the user. + * + * In the case the user does not exist in /v5/users but can be found in /v3/users + * Fetch the user info from /v3/users and create a new user in /v5/users. + * + * @params {Object} currentUser the user who perform this operation + * @returns {String} the ubhan user id + */ +async function ensureUbhanUserId (currentUser) { + try { + return await getUserId(currentUser.userId) + } catch (err) { + if (!(err instanceof errors.NotFoundError)) { + throw err + } + const topcoderUser = await getTopcoderUserById(currentUser.userId) + const user = await createUbhanUser(_.pick(topcoderUser, ['handle', 'firstName', 'lastName'])) + await createUserExternalProfile(user.id, { organizationId: config.ORG_ID, externalId: currentUser.userId }) + return user.id + } +} + +/** + * Ensure job with specific id exists. + * + * @param {String} jobId the job id + * @returns {Object} the job data + */ +async function ensureJobById (jobId) { + return models.Job.findById(jobId) +} + +/** + * Ensure user with specific id exists. + * + * @param {String} jobId the user id + * @returns {Object} the user data + */ +async function ensureUserById (userId) { + const token = await getM2Mtoken() + try { + const res = await request + .get(`${config.TC_API}/users/${userId}`) + .set('Authorization', `Bearer ${token}`) + .set('Content-Type', 'application/json') + .set('Accept', 'application/json') + localLogger.debug({ context: 'ensureUserById', message: `response body: ${JSON.stringify(res.body)}` }) + return res.body + } catch (err) { + if (err.status === HttpStatus.NOT_FOUND) { + throw new errors.NotFoundError(`id: ${userId} "user" not found`) + } + throw err + } +} + module.exports = { + checkIfExists, autoWrapExpress, setResHeaders, clearObject, isConnectMember, getESClient, - getUserId, + 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, @@ -466,5 +589,7 @@ module.exports = { getMembers, getProjectById, getSkillById, - getUserSkill + getUserSkill, + ensureJobById, + ensureUserById } diff --git a/src/controllers/JobCandidateController.js b/src/controllers/JobCandidateController.js index 45810f39..1b1cf971 100644 --- a/src/controllers/JobCandidateController.js +++ b/src/controllers/JobCandidateController.js @@ -59,7 +59,7 @@ async function deleteJobCandidate (req, res) { async function searchJobCandidates (req, res) { const result = await service.searchJobCandidates(req.query) helper.setResHeaders(req, res, result) - res.send({ result: result.result }) + res.send(result.result) } module.exports = { diff --git a/src/controllers/JobController.js b/src/controllers/JobController.js index 6e71b108..f15f0a66 100644 --- a/src/controllers/JobController.js +++ b/src/controllers/JobController.js @@ -59,7 +59,7 @@ async function deleteJob (req, res) { async function searchJobs (req, res) { const result = await service.searchJobs(req.query) helper.setResHeaders(req, res, result) - res.send({ result: result.result }) + res.send(result.result) } module.exports = { diff --git a/src/controllers/ResourceBookingController.js b/src/controllers/ResourceBookingController.js index ed846a91..d222adc5 100644 --- a/src/controllers/ResourceBookingController.js +++ b/src/controllers/ResourceBookingController.js @@ -59,7 +59,7 @@ async function deleteResourceBooking (req, res) { async function searchResourceBookings (req, res) { const result = await service.searchResourceBookings(req.query) helper.setResHeaders(req, res, result) - res.send({ result: result.result }) + res.send(result.result) } module.exports = { diff --git a/src/controllers/TeamController.js b/src/controllers/TeamController.js index f29e11e1..9e1f7946 100644 --- a/src/controllers/TeamController.js +++ b/src/controllers/TeamController.js @@ -2,6 +2,7 @@ * Controller for TaaS teams endpoints */ const service = require('../services/TeamService') +const helper = require('../common/helper') /** * Search teams @@ -9,7 +10,9 @@ const service = require('../services/TeamService') * @param res the response */ async function searchTeams (req, res) { - res.send(await service.searchTeams(req.authUser)) + const result = await service.searchTeams(req.authUser, req.query) + helper.setResHeaders(req, res, result) + res.send(result.result) } /** diff --git a/src/models/Job.js b/src/models/Job.js index dcb11a3d..b8998198 100644 --- a/src/models/Job.js +++ b/src/models/Job.js @@ -98,6 +98,11 @@ module.exports = (sequelize) => { type: Sequelize.STRING, allowNull: false }, + workload: { + field: 'workload', + type: Sequelize.STRING, + allowNull: false + }, skills: { type: Sequelize.JSONB, allowNull: false 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 d768cf84..d48e409f 100644 --- a/src/services/JobCandidateService.js +++ b/src/services/JobCandidateService.js @@ -54,6 +54,9 @@ getJobCandidate.schema = Joi.object().keys({ * @returns {Object} the created jobCandidate */ async function createJobCandidate (currentUser, jobCandidate) { + await helper.ensureJobById(jobCandidate.jobId) // ensure job exists + await helper.ensureUserById(jobCandidate.userId) // ensure user exists + jobCandidate.id = uuid() jobCandidate.createdAt = new Date() jobCandidate.createdBy = await helper.getUserId(currentUser.userId) @@ -82,16 +85,17 @@ createJobCandidate.schema = Joi.object().keys({ async function updateJobCandidate (currentUser, id, data) { const jobCandidate = await JobCandidate.findById(id) const projectId = await JobCandidate.getProjectId(jobCandidate.dataValues.jobId) - if (projectId && !currentUser.isBookingManager) { + const userId = await helper.getUserId(currentUser.userId) + if (projectId && !currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(projectId, currentUser.jwtToken) if (!connect) { - if (jobCandidate.dataValues.userId !== await helper.getUserId(currentUser.userId)) { + if (jobCandidate.dataValues.userId !== userId) { throw new errors.ForbiddenError('You are not allowed to perform this action!') } } } data.updatedAt = new Date() - data.updatedBy = await helper.getUserId(currentUser.userId) + data.updatedBy = userId await jobCandidate.update(data) await helper.postEvent(config.TAAS_JOB_CANDIDATE_UPDATE_TOPIC, { id, ...data }) @@ -126,6 +130,8 @@ partiallyUpdateJobCandidate.schema = Joi.object().keys({ * @returns {Object} the updated jobCandidate */ async function fullyUpdateJobCandidate (currentUser, id, data) { + await helper.ensureJobById(data.jobId) // ensure job exists + await helper.ensureUserById(data.userId) // ensure user exists return updateJobCandidate(currentUser, id, data) } @@ -145,7 +151,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 f4953782..febffc81 100644 --- a/src/services/JobService.js +++ b/src/services/JobService.js @@ -5,6 +5,7 @@ const _ = require('lodash') const Joi = require('joi') const config = require('config') +const HttpStatus = require('http-status-codes') const { Op } = require('sequelize') const { v4: uuid } = require('uuid') const helper = require('../common/helper') @@ -46,6 +47,34 @@ async function _getJobCandidates (jobId) { return candidates } +/** + * Validate if all skills exist. + * + * @param {Array} skills the list of skills + * @returns {undefined} + */ +async function _validateSkills (skills) { + const m2mToken = await helper.getM2Mtoken() + const responses = await Promise.all( + skills.map( + skill => helper.getSkillById(`Bearer ${m2mToken}`, skill) + .then(() => { + return { found: true } + }) + .catch(err => { + if (err.status !== HttpStatus.NOT_FOUND) { + throw err + } + return { found: false, skill } + }) + ) + ) + const errResponses = responses.filter(res => !res.found) + if (errResponses.length) { + throw new errors.BadRequestError(`Invalid skills: [${errResponses.map(res => res.skill)}]`) + } +} + /** * Get job by id * @param {String} id the job id @@ -85,18 +114,13 @@ getJob.schema = Joi.object().keys({ }).required() /** - * Create job + * Create job. All member can create a job. * @params {Object} currentUser the user who perform this operation * @params {Object} job the job to be created * @returns {Object} the created job */ async function createJob (currentUser, job) { - if (!currentUser.isBookingManager) { - const connect = await helper.isConnectMember(job.projectId, currentUser.jwtToken) - if (!connect) { - throw new errors.ForbiddenError('You are not allowed to perform this action!') - } - } + await _validateSkills(job.skills) job.id = uuid() job.createdAt = new Date() job.createdBy = await helper.getUserId(currentUser.userId) @@ -118,28 +142,35 @@ createJob.schema = Joi.object().keys({ numPositions: Joi.number().integer().min(1).required(), resourceType: Joi.string().required(), rateType: Joi.rateType(), + workload: Joi.workload().default('full-time'), skills: Joi.array().items(Joi.string().uuid()).required() }).required() }).required() /** - * Update job + * Update job. Normal user can only update the job he/she created. * @params {Object} currentUser the user who perform this operation * @params {String} job id * @params {Object} data the data to be updated * @returns {Object} the updated job */ async function updateJob (currentUser, id, data) { + if (data.skills) { + await _validateSkills(data.skills) + } let job = await Job.findById(id) - if (!currentUser.isBookingManager) { + const ubhanUserId = await helper.getUserId(currentUser.userId) + if (!currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(job.dataValues.projectId, currentUser.jwtToken) if (!connect) { - throw new errors.ForbiddenError('You are not allowed to perform this action!') + if (ubhanUserId !== job.createdBy) { + throw new errors.ForbiddenError('You are not allowed to perform this action!') + } } } data.updatedAt = new Date() - data.updatedBy = await helper.getUserId(currentUser.userId) + data.updatedBy = ubhanUserId await job.update(data) await helper.postEvent(config.TAAS_JOB_UPDATE_TOPIC, { id, ...data }) @@ -170,6 +201,7 @@ partiallyUpdateJob.schema = Joi.object().keys({ numPositions: Joi.number().integer().min(1), resourceType: Joi.string(), rateType: Joi.rateType(), + workload: Joi.workload(), skills: Joi.array().items(Joi.string().uuid()) }).required() }).required() @@ -197,22 +229,26 @@ fullyUpdateJob.schema = Joi.object().keys({ numPositions: Joi.number().integer().min(1).required(), resourceType: Joi.string().required(), rateType: Joi.rateType().required(), + workload: Joi.workload().required(), skills: Joi.array().items(Joi.string().uuid()).required(), status: Joi.jobStatus() }).required() }).required() /** - * Delete job by id + * Delete job by id. Normal user can only delete the job he/she created. * @params {Object} currentUser the user who perform this operation * @params {String} id the job id */ async function deleteJob (currentUser, id) { - if (!currentUser.isBookingManager) { - throw new errors.ForbiddenError('You are not allowed to perform this action!') + const job = await Job.findById(id) + 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!') + } } - const job = await Job.findById(id) await job.update({ deletedAt: new Date() }) await helper.postEvent(config.TAAS_JOB_DELETE_TOPIC, { id }) } @@ -253,7 +289,18 @@ async function searchJobs (criteria) { } } - _.each(_.pick(criteria, ['projectId', 'externalId', 'description', 'startDate', 'endDate', 'resourceType', 'skill', 'rateType', 'status']), (value, key) => { + _.each(_.pick(criteria, [ + 'projectId', + 'externalId', + 'description', + 'startDate', + 'endDate', + 'resourceType', + 'skill', + 'rateType', + 'workload', + 'status' + ]), (value, key) => { let must if (key === 'description') { must = { @@ -314,7 +361,16 @@ async function searchJobs (criteria) { const filter = { [Op.and]: [{ deletedAt: null }] } - _.each(_.pick(criteria, ['projectId', 'externalId', 'startDate', 'endDate', 'resourceType', 'rateType', 'status']), (value, key) => { + _.each(_.pick(criteria, [ + 'projectId', + 'externalId', + 'startDate', + 'endDate', + 'resourceType', + 'rateType', + 'workload', + 'status' + ]), (value, key) => { filter[Op.and].push({ [key]: value }) }) if (criteria.description) { @@ -370,6 +426,7 @@ searchJobs.schema = Joi.object().keys({ resourceType: Joi.string(), skill: Joi.string().uuid(), rateType: Joi.rateType(), + workload: Joi.workload(), status: Joi.jobStatus(), projectIds: Joi.array().items(Joi.number().integer()).single() }).required() diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index fc234402..22285cbc 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -11,6 +11,7 @@ const helper = require('../common/helper') const logger = require('../common/logger') const errors = require('../common/errors') const models = require('../models') +const JobCandidateService = require('./JobCandidateService') const ResourceBooking = models.ResourceBooking const esClient = helper.getESClient() @@ -22,7 +23,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 +73,12 @@ getResourceBooking.schema = Joi.object().keys({ * @returns {Object} the created resourceBooking */ async function createResourceBooking (currentUser, resourceBooking) { - if (!currentUser.isBookingManager) { + if (resourceBooking.jobId) { + await helper.ensureJobById(resourceBooking.jobId) // ensure job exists + } + await helper.ensureUserById(resourceBooking.userId) // ensure user exists + + 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 +117,8 @@ createResourceBooking.schema = Joi.object().keys({ */ async function updateResourceBooking (currentUser, id, data) { const resourceBooking = await ResourceBooking.findById(id) - if (!currentUser.isBookingManager) { + const isDiffStatus = resourceBooking.status !== data.status + 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!') @@ -120,8 +127,34 @@ async function updateResourceBooking (currentUser, id, data) { data.updatedAt = new Date() data.updatedBy = await helper.getUserId(currentUser.userId) - await resourceBooking.update(data) + const updatedResourceBooking = await resourceBooking.update(data) await helper.postEvent(config.TAAS_RESOURCE_BOOKING_UPDATE_TOPIC, { id, ...data }) + // When we are updating the status of ResourceBooking to `assigned` + // the corresponding JobCandidate record (with the same userId and jobId) + // should be updated with the status `selected` + if (isDiffStatus && data.status === 'assigned') { + const candidates = await models.JobCandidate.findAll({ + where: { + jobId: updatedResourceBooking.jobId, + userId: updatedResourceBooking.userId, + status: { + [Op.not]: 'selected' + }, + deletedAt: null + } + }) + await Promise.all(candidates.map(candidate => JobCandidateService.partiallyUpdateJobCandidate( + currentUser, + candidate.id, + { status: 'selected' } + ).then(result => { + logger.debug({ + component: 'ResourceBookingService', + context: 'updatedResourceBooking', + message: `id: ${result.id} candidate got selected.` + }) + }))) + } const result = helper.clearObject(_.assign(resourceBooking.dataValues, data)) return result } @@ -158,6 +191,10 @@ partiallyUpdateResourceBooking.schema = Joi.object().keys({ * @returns {Object} the updated resourceBooking */ async function fullyUpdateResourceBooking (currentUser, id, data) { + if (data.jobId) { + await helper.ensureJobById(data.jobId) // ensure job exists + } + await helper.ensureUserById(data.userId) // ensure user exists return updateResourceBooking(currentUser, id, data) } @@ -183,7 +220,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!') } @@ -200,11 +237,33 @@ deleteResourceBooking.schema = Joi.object().keys({ /** * List resourceBookings * @params {Object} criteria the search criteria + * @params {Object} options the extra options to control the function * @returns {Object} the search result, contain total/page/perPage and result array */ -async function searchResourceBookings (criteria) { +async function searchResourceBookings (criteria, options = { returnAll: false }) { + if (criteria.projectIds) { + if ((typeof criteria.projectIds) === 'string') { + criteria.projectIds = criteria.projectIds.trim().split(',').map(projectIdRaw => { + const projectIdRawTrimed = projectIdRaw.trim() + const projectId = Number(projectIdRawTrimed) + if (_.isNaN(projectId)) { + throw new errors.BadRequestError(`projectId ${projectIdRawTrimed} is not a valid number`) + } + return projectId + }) + } + } const page = criteria.page > 0 ? criteria.page : 1 - const perPage = criteria.perPage > 0 ? criteria.perPage : 20 + let perPage + if (options.returnAll) { + // To simplify the logic we are use a very large number for perPage + // because in practice there could hardly be so many records to be returned.(also consider we are using filters in the meantime) + // the number is limited by `index.max_result_window`, its default value is 10000, see + // https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#index-max-result-window + perPage = 10000 + } else { + perPage = criteria.perPage > 0 ? criteria.perPage : 20 + } if (!criteria.sortBy) { criteria.sortBy = 'id' @@ -238,6 +297,14 @@ async function searchResourceBookings (criteria) { } }) }) + // if criteria contains projectIds, filter projectId with this value + if (criteria.projectIds) { + esQuery.body.query.bool.filter = [{ + terms: { + projectId: criteria.projectIds + } + }] + } logger.debug({ component: 'ResourceBookingService', context: 'searchResourceBookings', message: `Query: ${JSON.stringify(esQuery)}` }) const { body } = await esClient.search(esQuery) @@ -262,6 +329,9 @@ async function searchResourceBookings (criteria) { _.each(_.pick(criteria, ['status', 'startDate', 'endDate', 'rateType']), (value, key) => { filter[Op.and].push({ [key]: value }) }) + if (criteria.projectIds) { + filter[Op.and].push({ projectId: criteria.projectIds }) + } const resourceBookings = await ResourceBooking.findAll({ where: filter, attributes: { @@ -290,8 +360,13 @@ searchResourceBookings.schema = Joi.object().keys({ startDate: Joi.date(), endDate: Joi.date(), rateType: Joi.rateType(), - projectId: Joi.number().integer() - }).required() + projectId: Joi.number().integer(), + projectIds: Joi.alternatives( + Joi.string(), + Joi.array().items(Joi.number().integer()) + ) + }).required(), + options: Joi.object() }).required() module.exports = { diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 0f5c2b89..4fd3ab6a 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -4,22 +4,20 @@ const _ = require('lodash') const Joi = require('joi') +const dateFNS = require('date-fns') const helper = require('../common/helper') const logger = require('../common/logger') const JobService = require('./JobService') const ResourceBookingService = require('./ResourceBookingService') /** - * Function to get assigned resource booking - * @param {String} projectId project id + * Function to get assigned resource bookings with specific projectIds + * @param {Array} projectIds project ids * @returns the request result */ -async function _getAssignedResourceBooking (projectId) { - const criteria = { status: 'assigned' } - if (projectId) { - criteria.projectId = projectId - } - const { result } = await ResourceBookingService.searchResourceBookings(criteria) +async function _getAssignedResourceBookingsByProjectIds (projectIds) { + const criteria = { status: 'assigned', projectIds } + const { result } = await ResourceBookingService.searchResourceBookings(criteria, { returnAll: true }) return result } @@ -36,17 +34,46 @@ async function _getJobsByProjectIds (projectIds) { /** * List teams * @param {Object} currentUser the user who perform this operation + * @param {Object} criteria the search criteria * @returns {Object} the search result, contain total/page/perPage and result array */ -async function searchTeams (currentUser) { - // Get projects from /v5/projects - const projects = await helper.getProjects(currentUser.jwtToken) - - return await getTeamDetail(currentUser, projects) +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( + currentUser.jwtToken, + { + page: criteria.page, + perPage: criteria.perPage, + name: criteria.name, + sort + } + ) + return { + total, + page, + perPage, + result: await getTeamDetail(currentUser, projects) + } } searchTeams.schema = Joi.object().keys({ - currentUser: Joi.object().required() + currentUser: Joi.object().required(), + criteria: Joi.object().keys({ + page: Joi.page(), + perPage: Joi.perPage(), + sortBy: Joi.string().valid('createdAt', 'updatedAt', 'lastActivityAt', 'id', 'status', 'name', 'type', 'best match').default('lastActivityAt'), + sortOrder: Joi.when('sortBy', { + is: 'best match', + then: Joi.forbidden().label('sortOrder(with sortBy being `best match`)'), + otherwise: Joi.string().valid('asc', 'desc').default('desc') + }), + name: Joi.string() + }).required() }).required() /** @@ -58,25 +85,23 @@ searchTeams.schema = Joi.object().keys({ */ async function getTeamDetail (currentUser, projects, isSearch = true) { const projectIds = _.map(projects, 'id') - // Get resourceBookings from taas api - const resourceBookings = await _getAssignedResourceBooking() - // Get jobs from taas api + // Get all assigned resourceBookings filtered by projectIds + const resourceBookings = await _getAssignedResourceBookingsByProjectIds(projectIds) + // Get all jobs filtered by projectIds const jobs = await _getJobsByProjectIds(projectIds) // Get first week day and last week day const curr = new Date() - curr.setHours(0, 0, 0, 0) - const first = curr.getDate() - curr.getDay() - const last = first + 6 + const firstDay = dateFNS.startOfWeek(curr) + const lastDay = dateFNS.endOfWeek(curr) - const firstDay = new Date(curr.setDate(first)) - const lastDay = new Date(curr.setDate(last)) + logger.debug({ component: 'TeamService', context: 'getTeamDetail', message: `week started: ${firstDay}, week ended: ${lastDay}` }) const result = [] for (const project of projects) { const rbs = _.filter(resourceBookings, { projectId: project.id }) const res = _.clone(project) - res.weeklyCount = 0 + res.weeklyCost = 0 res.resources = [] if (rbs && rbs.length > 0) { @@ -104,14 +129,27 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { const startDate = new Date(item.startDate) const endDate = new Date(item.endDate) - if ((!item.startDate || (startDate <= firstDay && startDate < lastDay)) && - (!item.endDate || (endDate >= lastDay && endDate > firstDay))) { - res.weeklyCount += item.customerRate + // normally startDate is smaller than endDate for a resourceBooking so not check if startDate < endDate + if ((!item.startDate || startDate < lastDay) && + (!item.endDate || endDate > firstDay)) { + res.weeklyCost += item.customerRate } } const usersPromises = [] - _.map(rbs, (rb) => { usersPromises.push(helper.getUserById(currentUser.jwtToken, rb.userId)) }) + _.map(rbs, (rb) => { + usersPromises.push( + helper.getUserById(currentUser.jwtToken, rb.userId, true) + .then(user => { + // If call function is not search, add jobId field + if (!isSearch) { + user.jobId = rb.jobId + user.customerRate = rb.customerRate + } + return user + }) + ) + }) const userInfos = await Promise.all(usersPromises) if (userInfos && userInfos.length > 0) { res.resources = userInfos @@ -125,21 +163,6 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { if (findMember && findMember.photoURL) { item.photo_url = findMember.photoURL } - - if (!isSearch) { - // If call function is not search, add job field - const findRbs = _.find(rbs, { userId: item.id }) - if (findRbs) { - item.customerRate = findRbs.customerRate - const job = _.find(jobs, { id: findRbs.jobId }) - if (job) { - item.job = { - id: job.id, - name: job.description - } - } - } - } } } } @@ -171,6 +194,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) @@ -194,13 +221,10 @@ async function getTeam (currentUser, id) { // add resources skills for result if (teamDetail && teamDetail.resources) { for (const user of teamDetail.resources) { - const userSkills = await helper.getUserSkill(currentUser.jwtToken, user.id) - user.skills = userSkills - user.skillMatched = 0 - if (userSkills && userSkills.length > 0) { + if (user.skills && user.skills.length > 0) { for (const jobSkill of jobSkills) { - if (_.find(userSkills, userSkill => { + if (_.find(user.skills, userSkill => { return userSkill.id === jobSkill.id })) { user.skillMatched += 1 @@ -226,6 +250,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 }) @@ -239,17 +267,29 @@ async function getTeamJob (currentUser, id, jobId) { description: job.description } + if (job.skills) { + result.skills = await Promise.all( + _.map(job.skills, (skillId) => helper.getSkillById(currentUser.jwtToken, skillId)) + ) + } + const jobSkills = job.skills if (job && job.candidates && job.candidates.length > 0) { const usersPromises = [] - _.map(job.candidates, (candidate) => { usersPromises.push(helper.getUserById(currentUser.jwtToken, candidate.userId)) }) + _.map(job.candidates, (candidate) => { usersPromises.push(helper.getUserById(currentUser.jwtToken, candidate.userId, true)) }) const candidates = await Promise.all(usersPromises) 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 @@ -262,14 +302,10 @@ async function getTeamJob (currentUser, id, jobId) { item.photo_url = findMember.photoURL } - // Get user skill details from /v5/user/:id/skills - const userSkills = await helper.getUserSkill(currentUser.jwtToken, item.id) - item.skills = userSkills - item.skillMatched = 0 - if (userSkills && userSkills.length > 0) { + if (item.skills && item.skills.length > 0) { for (const jobSkillId of jobSkills) { - if (_.find(userSkills, userSkill => { + if (_.find(item.skills, userSkill => { return userSkill.id === jobSkillId })) { item.skillMatched += 1 diff --git a/test/unit/TeamService.test.js b/test/unit/TeamService.test.js index bbe81a00..01244d75 100644 --- a/test/unit/TeamService.test.js +++ b/test/unit/TeamService.test.js @@ -109,7 +109,7 @@ describe('Team service test', () => { expect(entity[0]).to.deep.eql({ id: 9050, name: 'sample', - weeklyCount: 0, + weeklyCost: 0, resources: [] }) expect(stubGetProjects.calledOnce).to.be.true diff --git a/test/unit/common/testData.js b/test/unit/common/testData.js index c7040d0b..dc607ba5 100644 --- a/test/unit/common/testData.js +++ b/test/unit/common/testData.js @@ -590,7 +590,7 @@ const jobsRequestBody = [ const taasTeamItem0ResponseBody = { id: 9050, name: 'sample', - weeklyCount: 29.7, + weeklyCost: 29.7, resources: [ { id: '1b88e433-828b-4e0d-9fb5-ef75b9dcca6e', @@ -620,7 +620,7 @@ const taasTeamItem0ResponseBody = { const taasTeam9050ResponseBody = { id: 9050, name: 'sample', - weeklyCount: 29.7, + weeklyCost: 29.7, resources: [ { id: '1b88e433-828b-4e0d-9fb5-ef75b9dcca6e',