From 10a7c4151f74385078763021dbf7719188d9ac33 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Fri, 27 Nov 2020 23:49:42 +0800 Subject: [PATCH 01/26] validate skills before create/update jobs --- src/common/helper.js | 1 + src/services/JobService.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/common/helper.js b/src/common/helper.js index 4df5766b..dd8a20a9 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -406,6 +406,7 @@ module.exports = { isConnectMember, getESClient, getUserId, + getM2Mtoken, postEvent, getBusApiClient, isDocumentMissingException, diff --git a/src/services/JobService.js b/src/services/JobService.js index f4953782..6970db49 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 @@ -91,6 +120,7 @@ getJob.schema = Joi.object().keys({ * @returns {Object} the created job */ async function createJob (currentUser, job) { + await _validateSkills(job.skills) if (!currentUser.isBookingManager) { const connect = await helper.isConnectMember(job.projectId, currentUser.jwtToken) if (!connect) { @@ -130,6 +160,9 @@ createJob.schema = Joi.object().keys({ * @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 connect = await helper.isConnectMember(job.dataValues.projectId, currentUser.jwtToken) From e3dea7814cd81426345422f50071fbfc766d09f4 Mon Sep 17 00:00:00 2001 From: Caizheng Peng Date: Tue, 1 Dec 2020 10:29:34 +0800 Subject: [PATCH 02/26] make sure user exist in both v3 api and v5 api (#19) --- config/default.js | 2 + package-lock.json | 173 ++++++++++++++++++++++++++-- package.json | 2 +- src/common/helper.js | 70 +++++++++++ src/services/JobCandidateService.js | 30 ++++- 5 files changed, 266 insertions(+), 11 deletions(-) diff --git a/config/default.js b/config/default.js index 333d5f55..b2678ce5 100644 --- a/config/default.js +++ b/config/default.js @@ -17,6 +17,8 @@ module.exports = { TC_API: process.env.TC_API || 'https://api.topcoder-dev.com/v5', ORG_ID: process.env.ORG_ID || '36ed815b-3da1-49f1-a043-aaed0a4e81ad', + TOPCODER_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/package-lock.json b/package-lock.json index 6f940aa0..a95efc87 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", @@ -1812,6 +1876,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 +2862,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 +3444,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 +3644,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 +5772,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 +5941,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 +6152,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 +6274,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 +6429,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..7eed4400 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,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/src/common/helper.js b/src/common/helper.js index dd8a20a9..2f51e986 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -23,6 +23,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 /** @@ -202,6 +207,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 @@ -307,6 +320,27 @@ async function getProjects (token) { }) } +/** + * 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 +} + /** * Function to get users * @param {String} token the user request token @@ -323,6 +357,39 @@ async function getUserById (token, userId) { return _.pick(res.body, ['id', 'handle', 'firstName', 'lastName']) } +/** + * 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)}` }) +} + /** * Function to get members * @param {String} token the user request token @@ -411,7 +478,10 @@ module.exports = { getBusApiClient, isDocumentMissingException, getProjects, + getTopcoderUserById, getUserById, + createUbhanUser, + createUserExternalProfile, getMembers, getProjectById, getSkillById, diff --git a/src/services/JobCandidateService.js b/src/services/JobCandidateService.js index d768cf84..36fca156 100644 --- a/src/services/JobCandidateService.js +++ b/src/services/JobCandidateService.js @@ -15,6 +15,29 @@ const models = require('../models') const JobCandidate = models.JobCandidate const esClient = helper.getESClient() +/** + * 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 {undefined} + */ +async function _ensureUbhanUserId (currentUser) { + try { + return await helper.getUserId(currentUser.userId) + } catch (err) { + if (!(err instanceof errors.NotFoundError)) { + throw err + } + const topcoderUser = await helper.getTopcoderUserById(currentUser.userId) + const user = await helper.createUbhanUser(_.pick(topcoderUser, ['handle', 'firstName', 'lastName'])) + await helper.createUserExternalProfile(user.id, { organizationId: config.ORG_ID, externalId: currentUser.userId }) + return user.id + } +} + /** * Get jobCandidate by id * @param {String} id the jobCandidate id @@ -56,7 +79,7 @@ getJobCandidate.schema = Joi.object().keys({ async function createJobCandidate (currentUser, jobCandidate) { jobCandidate.id = uuid() jobCandidate.createdAt = new Date() - jobCandidate.createdBy = await helper.getUserId(currentUser.userId) + jobCandidate.createdBy = await _ensureUbhanUserId(currentUser) jobCandidate.status = 'open' const created = await JobCandidate.create(jobCandidate) @@ -82,16 +105,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) + const userId = await _ensureUbhanUserId(currentUser) if (projectId && !currentUser.isBookingManager) { 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 }) From 31c82ee28a232b1520175307477cae3e915ef52b Mon Sep 17 00:00:00 2001 From: Caizheng Peng Date: Tue, 1 Dec 2020 10:30:17 +0800 Subject: [PATCH 03/26] fix weekly count (#20) --- src/services/TeamService.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 0f5c2b89..79c0113a 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -71,6 +71,8 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { const firstDay = new Date(curr.setDate(first)) const lastDay = new Date(curr.setDate(last)) + lastDay.setHours(23, 59, 59, 59) // the end of the day + logger.debug({ component: 'TeamService', context: 'getTeamDetail', message: `week started: ${firstDay}, week ended: ${lastDay}` }) const result = [] for (const project of projects) { @@ -104,8 +106,9 @@ 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))) { + // 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.weeklyCount += item.customerRate } } From f85cb458fa386ecaf2ad71b521d1001db4e870fe Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Wed, 2 Dec 2020 03:21:22 +0800 Subject: [PATCH 04/26] allow normal topcoder members to create jobs and update/delete the jobs --- ...coder-bookings-api.postman_collection.json | 202 +++++++++++++++--- ...topcoder-bookings.postman_environment.json | 11 +- src/common/helper.js | 29 ++- src/services/JobCandidateService.js | 27 +-- src/services/JobService.js | 26 +-- 5 files changed, 220 insertions(+), 75 deletions(-) diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index df9b154b..045872ca 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": "35048a3f-8fc2-448a-a76b-84018421c548", "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": "e9fa0faf-a74f-4773-9062-ec0beb5282ad", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -59,7 +59,7 @@ { "listen": "test", "script": { - "id": "5d118bcb-ea69-4f92-b267-7a807deef522", + "id": "5e70de3f-213c-4b45-9a0d-6c8466edc158", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -99,14 +99,15 @@ "response": [] }, { - "name": "create job with member", + "name": "create job with member success", "event": [ { "listen": "test", "script": { - "id": "cb499304-14a4-4c9e-a43f-4a3356f917aa", + "id": "aa97c213-e7d7-4583-a148-d6a06413403f", "exec": [ - "" + "var data = JSON.parse(responseBody);", + "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" ], "type": "text/javascript" } @@ -123,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 \"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 \"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 +149,7 @@ { "listen": "test", "script": { - "id": "c0f62918-f916-468a-9e81-5151f1869f9f", + "id": "f1f4f692-9df3-42ab-939a-40fae57dfd75", "exec": [ "" ], @@ -192,7 +193,7 @@ { "listen": "test", "script": { - "id": "ab099735-7af0-4f99-b274-a9be3f70ffd3", + "id": "3cd48952-dd0a-4893-958e-2dd53d504b91", "exec": [ "" ], @@ -320,13 +321,13 @@ } ], "url": { - "raw": "{{URL}}/jobs/{{jobId}}", + "raw": "{{URL}}/jobs/{{jobIdCreatedByMember}}", "host": [ "{{URL}}" ], "path": [ "jobs", - "{{jobId}}" + "{{jobIdCreatedByMember}}" ] } }, @@ -779,7 +780,21 @@ "response": [] }, { - "name": "put job with member", + "name": "put job with member 403", + "event": [ + { + "listen": "test", + "script": { + "id": "cf9e7a1f-dcbd-4971-bf72-ff1ccfce8f3c", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PUT", "header": [ @@ -791,7 +806,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 \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\r\n", "options": { "raw": { "language": "json" @@ -811,6 +826,39 @@ }, "response": [] }, + { + "name": "put job with member success", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "body": { + "mode": "raw", + "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 \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByMember}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByMember}}" + ] + } + }, + "response": [] + }, { "name": "put job with member with user id not exist", "request": { @@ -944,7 +992,21 @@ "response": [] }, { - "name": "patch job with member", + "name": "patch job with member 403", + "event": [ + { + "listen": "test", + "script": { + "id": "07133dc2-316e-4404-98b6-c3f8056557fe", + "exec": [ + "pm.test(\"Status code is 403\", function () {", + " pm.response.to.have.status(403);", + "});" + ], + "type": "text/javascript" + } + } + ], "request": { "method": "PATCH", "header": [ @@ -956,7 +1018,7 @@ ], "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 \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\r\n", "options": { "raw": { "language": "json" @@ -976,6 +1038,39 @@ }, "response": [] }, + { + "name": "patch job with member success", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_member}}" + } + ], + "body": { + "mode": "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 \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByMember}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByMember}}" + ] + } + }, + "response": [] + }, { "name": "patch job with user id not exist", "request": { @@ -1043,14 +1138,14 @@ "response": [] }, { - "name": "delete job with menber", + "name": "delete job with booking manager", "request": { "method": "DELETE", "header": [ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "value": "Bearer {{token_bookingManager}}" } ], "body": { @@ -1109,14 +1204,28 @@ "response": [] }, { - "name": "delete job with booking manager", + "name": "delete job with member 403", + "event": [ + { + "listen": "test", + "script": { + "id": "70634304-5c18-4817-b450-75fbe96c2b0f", + "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_bookingManager}}" + "value": "Bearer {{token_member}}" } ], "body": { @@ -1141,6 +1250,39 @@ }, "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": { @@ -1186,7 +1328,7 @@ { "listen": "test", "script": { - "id": "6b168a78-7f6b-4000-bd44-3b9c76f0277e", + "id": "f255609a-48fe-45db-8716-ec44966516a4", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1231,7 +1373,7 @@ { "listen": "test", "script": { - "id": "bc965016-a5d4-4f08-9994-3f4865915125", + "id": "acf51116-1650-4887-99ed-d096ac604e92", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1276,7 +1418,7 @@ { "listen": "test", "script": { - "id": "751ec141-ef8d-4893-8802-d814006c8304", + "id": "3d949037-a5f6-4070-8230-f344497bbf94", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1321,7 +1463,7 @@ { "listen": "test", "script": { - "id": "0fbba452-0387-494b-b09d-4efc7805a273", + "id": "752e75ca-207c-4ebb-b5fd-5a1d7b88e00c", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1366,7 +1508,7 @@ { "listen": "test", "script": { - "id": "c7ad1e24-852b-4f35-9131-81e0470f82be", + "id": "309180a1-03e5-4c79-a92b-665aaa764783", "exec": [ "" ], @@ -2183,7 +2325,7 @@ { "listen": "test", "script": { - "id": "84511971-c664-4334-b3de-2d5e3642ce95", + "id": "a012d801-2727-4a42-bd3c-0a6f59a06892", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2228,7 +2370,7 @@ { "listen": "test", "script": { - "id": "fde28c86-d477-4214-8441-f74d99f4b654", + "id": "abf51d77-d171-4574-812d-5c9eb15b277e", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2273,7 +2415,7 @@ { "listen": "test", "script": { - "id": "7e928dd2-24be-4349-9e7c-6e8ccec4d6e7", + "id": "86177859-f04f-4499-9673-1a5d5a2a97ff", "exec": [ "" ], @@ -2317,7 +2459,7 @@ { "listen": "test", "script": { - "id": "25e3434c-0935-4aed-ab5f-7dc240acf95e", + "id": "2e8bc196-31b8-4be5-9486-df03eaa53d3f", "exec": [ "" ], @@ -2361,7 +2503,7 @@ { "listen": "test", "script": { - "id": "ce94fcb6-b450-4cb6-bf65-18ab34a168ec", + "id": "98f57ace-31f1-478a-b3a4-a78013198f66", "exec": [ "" ], @@ -3328,4 +3470,4 @@ } ], "protocolProfileBehavior": {} -} \ No newline at end of file +} diff --git a/docs/topcoder-bookings.postman_environment.json b/docs/topcoder-bookings.postman_environment.json index f87f1fe1..2b9a3aa4 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": "190c1a31-b774-40f1-aa5c-b24cbdab67fc", "name": "topcoder-bookings", "values": [ { @@ -46,9 +46,14 @@ "key": "projectId", "value": "111", "enabled": true + }, + { + "key": "jobIdCreatedByMember", + "value": "", + "enabled": true } ], "_postman_variable_scope": "environment", - "_postman_exported_at": "2020-11-19T12:26:05.800Z", + "_postman_exported_at": "2020-12-01T18:44:10.102Z", "_postman_exported_using": "Postman/7.29.0" -} +} \ No newline at end of file diff --git a/src/common/helper.js b/src/common/helper.js index 2f51e986..ca714eef 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -466,22 +466,43 @@ 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 + } +} + module.exports = { autoWrapExpress, setResHeaders, clearObject, isConnectMember, getESClient, - getUserId, + getUserId: (userId) => ensureUbhanUserId({ userId }), getM2Mtoken, postEvent, getBusApiClient, isDocumentMissingException, getProjects, - getTopcoderUserById, getUserById, - createUbhanUser, - createUserExternalProfile, getMembers, getProjectById, getSkillById, diff --git a/src/services/JobCandidateService.js b/src/services/JobCandidateService.js index 36fca156..dd369b60 100644 --- a/src/services/JobCandidateService.js +++ b/src/services/JobCandidateService.js @@ -15,29 +15,6 @@ const models = require('../models') const JobCandidate = models.JobCandidate const esClient = helper.getESClient() -/** - * 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 {undefined} - */ -async function _ensureUbhanUserId (currentUser) { - try { - return await helper.getUserId(currentUser.userId) - } catch (err) { - if (!(err instanceof errors.NotFoundError)) { - throw err - } - const topcoderUser = await helper.getTopcoderUserById(currentUser.userId) - const user = await helper.createUbhanUser(_.pick(topcoderUser, ['handle', 'firstName', 'lastName'])) - await helper.createUserExternalProfile(user.id, { organizationId: config.ORG_ID, externalId: currentUser.userId }) - return user.id - } -} - /** * Get jobCandidate by id * @param {String} id the jobCandidate id @@ -79,7 +56,7 @@ getJobCandidate.schema = Joi.object().keys({ async function createJobCandidate (currentUser, jobCandidate) { jobCandidate.id = uuid() jobCandidate.createdAt = new Date() - jobCandidate.createdBy = await _ensureUbhanUserId(currentUser) + jobCandidate.createdBy = await helper.getUserId(currentUser.userId) jobCandidate.status = 'open' const created = await JobCandidate.create(jobCandidate) @@ -105,7 +82,7 @@ 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) - const userId = await _ensureUbhanUserId(currentUser) + const userId = await helper.getUserId(currentUser.userId) if (projectId && !currentUser.isBookingManager) { const connect = await helper.isConnectMember(projectId, currentUser.jwtToken) if (!connect) { diff --git a/src/services/JobService.js b/src/services/JobService.js index 6970db49..e02093d8 100644 --- a/src/services/JobService.js +++ b/src/services/JobService.js @@ -114,19 +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) { await _validateSkills(job.skills) - 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!') - } - } job.id = uuid() job.createdAt = new Date() job.createdBy = await helper.getUserId(currentUser.userId) @@ -153,7 +147,7 @@ createJob.schema = Joi.object().keys({ }).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 @@ -164,15 +158,18 @@ async function updateJob (currentUser, id, data) { await _validateSkills(data.skills) } let job = await Job.findById(id) + const ubhanUserId = await helper.getUserId(currentUser.userId) if (!currentUser.isBookingManager) { 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 }) @@ -236,16 +233,19 @@ fullyUpdateJob.schema = Joi.object().keys({ }).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) { + const job = await Job.findById(id) if (!currentUser.isBookingManager) { - throw new errors.ForbiddenError('You are not allowed to perform this action!') + 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 }) } From ca0876fcf9c3985680f1aa502bd22fa6ddaedb36 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Wed, 2 Dec 2020 18:30:29 +0800 Subject: [PATCH 05/26] update access rules for /jobs endpoints in Swagger --- docs/swagger.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 8cc73679..2547abe3 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: @@ -231,7 +231,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 +290,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 +340,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: From 4a7221ffebc000518d6197ea056bd370cd68c779 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Thu, 3 Dec 2020 00:13:46 +0800 Subject: [PATCH 06/26] fix calculation of last week day --- package-lock.json | 5 +++++ package.json | 1 + src/services/TeamService.js | 9 +++------ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index a95efc87..8f11bdb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1594,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", diff --git a/package.json b/package.json index 7eed4400..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", diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 79c0113a..e262b633 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -4,6 +4,7 @@ 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') @@ -65,13 +66,9 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { // 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)) - lastDay.setHours(23, 59, 59, 59) // the end of the day logger.debug({ component: 'TeamService', context: 'getTeamDetail', message: `week started: ${firstDay}, week ended: ${lastDay}` }) const result = [] From 1e5069740c6088e8390cda3b50ff51f201ed8d20 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Thu, 3 Dec 2020 03:56:59 +0800 Subject: [PATCH 07/26] add workload field to Job model --- ...coder-bookings-api.postman_collection.json | 90 +++++++++---------- docs/swagger.yaml | 19 ++++ scripts/createIndex.js | 1 + src/bootstrap.js | 1 + src/models/Job.js | 5 ++ src/services/JobService.js | 28 +++++- 6 files changed, 97 insertions(+), 47 deletions(-) diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 045872ca..39156ec7 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "35048a3f-8fc2-448a-a76b-84018421c548", + "_postman_id": "418b385c-5ce1-4810-b357-cddf05adf271", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,7 @@ { "listen": "test", "script": { - "id": "e9fa0faf-a74f-4773-9062-ec0beb5282ad", + "id": "ff119e52-58f4-4501-8193-dd8c75f9ba4a", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -34,7 +34,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}\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" @@ -59,7 +59,7 @@ { "listen": "test", "script": { - "id": "5e70de3f-213c-4b45-9a0d-6c8466edc158", + "id": "66169f57-ba0e-4a88-85c3-e27ee380c332", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -79,7 +79,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" @@ -104,7 +104,7 @@ { "listen": "test", "script": { - "id": "aa97c213-e7d7-4583-a148-d6a06413403f", + "id": "31016a7d-5de6-4802-92f8-b1c7a9afcc4a", "exec": [ "var data = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" @@ -124,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}\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" @@ -149,7 +149,7 @@ { "listen": "test", "script": { - "id": "f1f4f692-9df3-42ab-939a-40fae57dfd75", + "id": "0b96c49d-6fb7-49ab-bfe1-4623ffe1be10", "exec": [ "" ], @@ -168,7 +168,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" @@ -193,7 +193,7 @@ { "listen": "test", "script": { - "id": "3cd48952-dd0a-4893-958e-2dd53d504b91", + "id": "bce80082-b100-466d-a196-73e9c38e2b9d", "exec": [ "" ], @@ -212,7 +212,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" @@ -419,8 +419,8 @@ "disabled": true }, { - "key": "", - "value": "", + "key": "workload", + "value": "full-time", "disabled": true } ] @@ -514,8 +514,8 @@ "disabled": true }, { - "key": "", - "value": "", + "key": "workload", + "value": "full-time", "disabled": true } ] @@ -609,8 +609,8 @@ "disabled": true }, { - "key": "", - "value": "", + "key": "workload", + "value": "fractional", "disabled": true } ] @@ -704,8 +704,8 @@ "disabled": true }, { - "key": "", - "value": "", + "key": "workload", + "value": "full-time", "disabled": true } ] @@ -726,7 +726,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" @@ -759,7 +759,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" @@ -785,7 +785,7 @@ { "listen": "test", "script": { - "id": "cf9e7a1f-dcbd-4971-bf72-ff1ccfce8f3c", + "id": "40f37d6f-508f-47ba-bbd4-41e1e0c3a4a2", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -806,7 +806,7 @@ ], "body": { "mode": "raw", - "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 \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\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" @@ -839,7 +839,7 @@ ], "body": { "mode": "raw", - "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 \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\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" @@ -872,7 +872,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" @@ -905,7 +905,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" @@ -938,7 +938,7 @@ ], "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" @@ -971,7 +971,7 @@ ], "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" @@ -997,7 +997,7 @@ { "listen": "test", "script": { - "id": "07133dc2-316e-4404-98b6-c3f8056557fe", + "id": "5d25999b-14ec-432c-bf11-028ec73a7140", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1018,7 +1018,7 @@ ], "body": { "mode": "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 \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\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" @@ -1051,7 +1051,7 @@ ], "body": { "mode": "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 \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\"\r\n ]\r\n}\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" @@ -1084,7 +1084,7 @@ ], "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" @@ -1117,7 +1117,7 @@ ], "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" @@ -1209,7 +1209,7 @@ { "listen": "test", "script": { - "id": "70634304-5c18-4817-b450-75fbe96c2b0f", + "id": "5f89405c-6907-41c8-8630-ccb5d5d640e6", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1328,7 +1328,7 @@ { "listen": "test", "script": { - "id": "f255609a-48fe-45db-8716-ec44966516a4", + "id": "865f0f13-444b-4247-902d-b3e6cdb1898e", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1373,7 +1373,7 @@ { "listen": "test", "script": { - "id": "acf51116-1650-4887-99ed-d096ac604e92", + "id": "37973c93-a13f-448d-8f02-af7f18818df2", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1418,7 +1418,7 @@ { "listen": "test", "script": { - "id": "3d949037-a5f6-4070-8230-f344497bbf94", + "id": "79490454-9392-42f1-8f07-7ab1950318df", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1463,7 +1463,7 @@ { "listen": "test", "script": { - "id": "752e75ca-207c-4ebb-b5fd-5a1d7b88e00c", + "id": "99a176e1-645b-47ca-91b4-940fbebc65f6", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1508,7 +1508,7 @@ { "listen": "test", "script": { - "id": "309180a1-03e5-4c79-a92b-665aaa764783", + "id": "92b01e89-a317-4663-95f0-ecb861fceefb", "exec": [ "" ], @@ -2325,7 +2325,7 @@ { "listen": "test", "script": { - "id": "a012d801-2727-4a42-bd3c-0a6f59a06892", + "id": "d8fcb38d-6699-4710-9db2-13fb3c814dff", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2370,7 +2370,7 @@ { "listen": "test", "script": { - "id": "abf51d77-d171-4574-812d-5c9eb15b277e", + "id": "45daab6c-adbd-4083-84e9-0e64640e6d95", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2415,7 +2415,7 @@ { "listen": "test", "script": { - "id": "86177859-f04f-4499-9673-1a5d5a2a97ff", + "id": "daa443f9-6ba1-48b0-9c59-b7e7e4192244", "exec": [ "" ], @@ -2459,7 +2459,7 @@ { "listen": "test", "script": { - "id": "2e8bc196-31b8-4be5-9486-df03eaa53d3f", + "id": "693dffa5-7de5-4940-8e1b-3053cb6a5684", "exec": [ "" ], @@ -2503,7 +2503,7 @@ { "listen": "test", "script": { - "id": "98f57ace-31f1-478a-b3a4-a78013198f66", + "id": "dba6c30b-b9c8-4750-8f97-e98bb21aa436", "exec": [ "" ], @@ -3470,4 +3470,4 @@ } ], "protocolProfileBehavior": {} -} +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 2547abe3..0ce3b6cf 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -145,6 +145,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 @@ -1479,6 +1486,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 +1568,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 +1669,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/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..7a191878 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -5,6 +5,7 @@ const logger = require('./common/logger') 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/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/services/JobService.js b/src/services/JobService.js index e02093d8..5022f7ed 100644 --- a/src/services/JobService.js +++ b/src/services/JobService.js @@ -142,6 +142,7 @@ 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() @@ -200,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() @@ -227,6 +229,7 @@ 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() @@ -286,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 = { @@ -347,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) { @@ -403,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() From e192960abae4473304a1b5cd92820d36578c3de5 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Thu, 3 Dec 2020 20:49:59 +0800 Subject: [PATCH 08/26] populate jobIds in resources for GET /taas-teams/:id and populate skills for GET /taas-teams/:id/jobs/:jobId --- src/services/TeamService.js | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/services/TeamService.js b/src/services/TeamService.js index e262b633..814e9603 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -111,7 +111,19 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { } const usersPromises = [] - _.map(rbs, (rb) => { usersPromises.push(helper.getUserById(currentUser.jwtToken, rb.userId)) }) + _.map(rbs, (rb) => { + usersPromises.push( + helper.getUserById(currentUser.jwtToken, rb.userId) + .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 +137,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 - } - } - } - } } } } @@ -236,7 +233,8 @@ async function getTeamJob (currentUser, id, jobId) { } const result = { id: job.id, - description: job.description + description: job.description, + skills: job.skills } const jobSkills = job.skills From 1517cb1dcb7f896e106807440f750b43f607faf6 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Thu, 3 Dec 2020 21:34:39 +0800 Subject: [PATCH 09/26] return skills instead of skillids for GET /taas-teams/:id/jobs/:jobId --- src/services/TeamService.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 814e9603..09a5411a 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -233,8 +233,13 @@ async function getTeamJob (currentUser, id, jobId) { } const result = { id: job.id, - description: job.description, - skills: job.skills + description: job.description + } + + if (job.skills) { + result.skills = await Promise.all( + _.map(job.skills, (skillId) => helper.getSkillById(currentUser.jwtToken, skillId)) + ) } const jobSkills = job.skills From 38787ddeff55757f6ba959f8a3ed486dc060c1fe Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Fri, 4 Dec 2020 21:25:00 +0800 Subject: [PATCH 10/26] allow m2m users to access the API --- README.md | 3 + app-constants.js | 26 +- app-routes.js | 20 +- config/default.js | 5 + ...coder-bookings-api.postman_collection.json | 871 +++++++++++++++++- ...topcoder-bookings.postman_environment.json | 99 +- src/common/helper.js | 42 +- src/routes/JobCandidateRoutes.js | 19 +- src/routes/JobRoutes.js | 19 +- src/routes/ResourceBookingRoutes.js | 19 +- src/routes/TeamRoutes.js | 10 +- src/services/JobCandidateService.js | 4 +- src/services/JobService.js | 4 +- src/services/ResourceBookingService.js | 8 +- src/services/TeamService.js | 20 +- 15 files changed, 1102 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 88bca715..f94f0802 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ The following parameters can be set in config files or in env variables: - `AUTH0_CLIENT_SECRET`: Auth0 client secret, used to get TC M2M token - `AUTH0_PROXY_SERVER_URL`: Proxy Auth0 URL, used to get TC M2M token +- `m2m.M2M_AUDIT_USER_ID`: default value is `00000000-0000-0000-0000-000000000000` +- `m2m.M2M_AUDIT_HANDLE`: default value is `TopcoderService` + - `DATABASE_URL`: PostgreSQL database url. - `DB_SCHEMA_NAME`: string - PostgreSQL database target schema - `PROJECT_API_URL`: the project service url diff --git a/app-constants.js b/app-constants.js index e2ffaa14..bf1a43b7 100644 --- a/app-constants.js +++ b/app-constants.js @@ -6,6 +6,30 @@ const UserRoles = { BookingManager: 'bookingmanager' } +const Scopes = { + // job + READ_JOB: 'read:taas-jobs', + CREATE_JOB: 'create:taas-jobs', + UPDATE_JOB: 'update:taas-jobs', + DELETE_JOB: 'delete:taas-jobs', + ALL_JOB: 'all:taas-jobs', + // job candidate + READ_JOB_CANDIDATE: 'read:taas-jobCandidates', + CREATE_JOB_CANDIDATE: 'create:taas-jobCandidates', + UPDATE_JOB_CANDIDATE: 'update:taas-jobCandidates', + DELETE_JOB_CANDIDATE: 'delete:taas-jobCandidates', + ALL_JOB_CANDIDATE: 'all:taas-jobCandidates', + // resource booking + READ_RESOURCE_BOOKING: 'read:taas-resourceBookings', + CREATE_RESOURCE_BOOKING: 'create:taas-resourceBookings', + UPDATE_RESOURCE_BOOKING: 'update:taas-resourceBookings', + DELETE_RESOURCE_BOOKING: 'delete:taas-resourceBookings', + ALL_RESOURCE_BOOKING: 'all:taas-resourceBookings', + // taas-team + READ_TAAS_TEAM: 'read:taas-teams' +} + module.exports = { - UserRoles + UserRoles, + Scopes } diff --git a/app-routes.js b/app-routes.js index 66413aee..023dda0a 100644 --- a/app-routes.js +++ b/app-routes.js @@ -6,6 +6,7 @@ const _ = require('lodash') const config = require('config') const HttpStatus = require('http-status-codes') const helper = require('./src/common/helper') +const errors = require('./src/common/errors') const routes = require('./src/routes') const constants = require('./app-constants') const authenticator = require('tc-core-library-js').middleware.jwtAuthenticator @@ -37,11 +38,22 @@ module.exports = (app) => { }) actions.push((req, res, next) => { - req.authUser.jwtToken = req.headers.authorization - if (_.includes(req.authUser.roles, constants.UserRoles.BookingManager)) { - req.authUser.isBookingManager = true + if (req.authUser.isMachine) { + // M2M + if (!req.authUser.scopes || !helper.checkIfExists(def.scopes, req.authUser.scopes)) { + next(new errors.ForbiddenError('You are not allowed to perform this action!')) + } else { + req.authUser.userId = config.m2m.M2M_AUDIT_USER_ID + req.authUser.handle = config.m2m.M2M_AUDIT_HANDLE + next() + } + } else { + req.authUser.jwtToken = req.headers.authorization + if (_.includes(req.authUser.roles, constants.UserRoles.BookingManager)) { + req.authUser.isBookingManager = true + } + next() } - next() }) } diff --git a/config/default.js b/config/default.js index b2678ce5..cccdf99c 100644 --- a/config/default.js +++ b/config/default.js @@ -14,6 +14,11 @@ module.exports = { AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET, AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL, + m2m: { + M2M_AUDIT_USER_ID: process.env.M2M_AUDIT_USER_ID || '00000000-0000-0000-0000-000000000000', + M2M_AUDIT_HANDLE: process.env.M2M_AUDIT_HANDLE || 'TopcoderService' + }, + TC_API: process.env.TC_API || 'https://api.topcoder-dev.com/v5', ORG_ID: process.env.ORG_ID || '36ed815b-3da1-49f1-a043-aaed0a4e81ad', diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 39156ec7..fbcc275f 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "418b385c-5ce1-4810-b357-cddf05adf271", + "_postman_id": "f4cd931d-2cfb-4d3a-b31e-4a6a02317cb2", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,7 @@ { "listen": "test", "script": { - "id": "ff119e52-58f4-4501-8193-dd8c75f9ba4a", + "id": "72230770-0780-406e-b740-12fba4aac339", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -53,13 +53,58 @@ }, "response": [] }, + { + "name": "create job with m2m create", + "event": [ + { + "listen": "test", + "script": { + "id": "a36bec2a-bf3d-4d1f-bf83-32c99676695c", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"jobIdCreatedByM2M\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer {{token_m2m_create_job}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"1212\",\r\n \"description\": \"Dummy Description\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 13,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"hourly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": [\r\n \"23e00d92-207a-4b5b-b3c9-4c5662644941\",\r\n \"7d076384-ccf6-4e43-a45d-1b24b1e624aa\",\r\n \"cbac57a3-7180-4316-8769-73af64893158\",\r\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ] + } + }, + "response": [] + }, { "name": "create job with connect user", "event": [ { "listen": "test", "script": { - "id": "66169f57-ba0e-4a88-85c3-e27ee380c332", + "id": "aa345d54-a75a-4702-9079-edf37f05fc28", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -104,7 +149,7 @@ { "listen": "test", "script": { - "id": "31016a7d-5de6-4802-92f8-b1c7a9afcc4a", + "id": "0351c210-4a5a-4514-8fe9-d6debb1c1bbb", "exec": [ "var data = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" @@ -149,7 +194,7 @@ { "listen": "test", "script": { - "id": "0b96c49d-6fb7-49ab-bfe1-4623ffe1be10", + "id": "bb2df571-ae1e-43d5-a3d1-fdd21cc85882", "exec": [ "" ], @@ -193,7 +238,7 @@ { "listen": "test", "script": { - "id": "bce80082-b100-466d-a196-73e9c38e2b9d", + "id": "8e8187ba-302f-43a4-b1e8-5116232dec57", "exec": [ "" ], @@ -255,6 +300,30 @@ }, "response": [] }, + { + "name": "get job with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_job}}" + } + ], + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "get job with booking manager from db", "request": { @@ -428,6 +497,101 @@ }, "response": [] }, + { + "name": "search jobs with with m2m all", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_all_job}}" + } + ], + "url": { + "raw": "{{URL}}/jobs", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs" + ], + "query": [ + { + "key": "page", + "value": "0", + "disabled": true + }, + { + "key": "perPage", + "value": "3", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "asc", + "disabled": true + }, + { + "key": "projectId", + "value": "21", + "disabled": true + }, + { + "key": "externalId", + "value": "1212", + "disabled": true + }, + { + "key": "description", + "value": "Dummy", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "endDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "resourceType", + "value": "Dummy Resource Type", + "disabled": true + }, + { + "key": "skill", + "value": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "sourcing", + "disabled": true + }, + { + "key": "workload", + "value": "full-time", + "disabled": true + } + ] + } + }, + "response": [] + }, { "name": "search jobs with connect user", "request": { @@ -746,6 +910,39 @@ }, "response": [] }, + { + "name": "put job with m2m update", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_job}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"1212\",\r\n \"description\": \"Dummy Description\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 13,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"hourly\",\r\n \"workload\": \"fractional\",\r\n \"skills\": [\r\n \"cbac57a3-7180-4316-8769-73af64893158\",\r\n \"a2b4bc11-c641-4a19-9eb7-33980378f82e\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "put job with connect user", "request": { @@ -785,7 +982,7 @@ { "listen": "test", "script": { - "id": "40f37d6f-508f-47ba-bbd4-41e1e0c3a4a2", + "id": "9c04dea6-d12d-4287-84e4-068ca7025e2a", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -958,6 +1155,39 @@ }, "response": [] }, + { + "name": "patch job with m2m update", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_job}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"description\": \"Dummy Description\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"numPositions\": 13,\r\n \"resourceType\": \"Dummy Resource Type\",\r\n \"rateType\": \"hourly\",\r\n \"workload\": \"fractional\",\r\n \"skills\": [\r\n \"cbac57a3-7180-4316-8769-73af64893158\"\r\n ],\r\n \"status\": \"sourcing\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "patch job with connect user", "request": { @@ -997,7 +1227,7 @@ { "listen": "test", "script": { - "id": "5d25999b-14ec-432c-bf11-028ec73a7140", + "id": "a4e3f5a6-cc9b-419d-aa56-73aab3046d4b", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1170,6 +1400,39 @@ }, "response": [] }, + { + "name": "delete job with m2m delete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_delete_job}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobs/{{jobIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobs", + "{{jobIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "delete job with connect user", "request": { @@ -1209,7 +1472,7 @@ { "listen": "test", "script": { - "id": "5f89405c-6907-41c8-8630-ccb5d5d640e6", + "id": "bb287666-8bd5-411b-85a2-1739d1c43a5d", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1328,7 +1591,7 @@ { "listen": "test", "script": { - "id": "865f0f13-444b-4247-902d-b3e6cdb1898e", + "id": "a4164751-2a2a-477e-82c7-897f71de1272", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1368,15 +1631,15 @@ "response": [] }, { - "name": "create job candidate with connect user", + "name": "create job candidate with m2m create", "event": [ { "listen": "test", "script": { - "id": "37973c93-a13f-448d-8f02-af7f18818df2", + "id": "c9c1b298-f7f9-456b-bffe-77b5ba83f38c", "exec": [ "var data = JSON.parse(responseBody);\r", - "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" + "postman.setEnvironmentVariable(\"jobCandidateIdCreatedByM2M\",data.id);" ], "type": "text/javascript" } @@ -1388,12 +1651,12 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_connectUser}}" + "value": "Bearer {{token_m2m_create_job_candidate}}" } ], "body": { "mode": "raw", - "raw": "{\r\n \"jobId\": \"{{jobId}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\"\r\n}", + "raw": "{\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\"\r\n}", "options": { "raw": { "language": "json" @@ -1413,12 +1676,12 @@ "response": [] }, { - "name": "create job candidate with member", + "name": "create job candidate with connect user", "event": [ { "listen": "test", "script": { - "id": "79490454-9392-42f1-8f07-7ab1950318df", + "id": "107c325f-d111-418e-8d2f-84709e317a0e", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1433,7 +1696,7 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_member}}" + "value": "Bearer {{token_connectUser}}" } ], "body": { @@ -1458,12 +1721,12 @@ "response": [] }, { - "name": "create job candidate with user id not exist", + "name": "create job candidate with member", "event": [ { "listen": "test", "script": { - "id": "99a176e1-645b-47ca-91b4-940fbebc65f6", + "id": "ed118309-1cee-4795-8586-a6e4f3555ce2", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1478,7 +1741,7 @@ { "key": "Authorization", "type": "text", - "value": "Bearer {{token_userId_not_exist}}" + "value": "Bearer {{token_member}}" } ], "body": { @@ -1503,14 +1766,59 @@ "response": [] }, { - "name": "create job candidate with invalid token", + "name": "create job candidate with user id not exist", "event": [ { "listen": "test", "script": { - "id": "92b01e89-a317-4663-95f0-ecb861fceefb", + "id": "7622898d-a47c-4631-8a82-da52b2de72cc", "exec": [ - "" + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_userId_not_exist}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{jobId}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ] + } + }, + "response": [] + }, + { + "name": "create job candidate with invalid token", + "event": [ + { + "listen": "test", + "script": { + "id": "a034038a-b2ec-49d9-afd4-e08625802057", + "exec": [ + "" ], "type": "text/javascript" } @@ -1570,6 +1878,30 @@ }, "response": [] }, + { + "name": "get job candidate with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_job_candidate}}" + } + ], + "url": { + "raw": "{{URL}}/jobCandidates/{{jobCandidateIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{jobCandidateIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "get job candidate with booking manager from db", "request": { @@ -1708,6 +2040,66 @@ }, "response": [] }, + { + "name": "search job candidates with m2m all", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_all_job_candidate}}" + } + ], + "url": { + "raw": "{{URL}}/jobCandidates", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "1", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "asc", + "disabled": true + }, + { + "key": "jobId", + "value": "46225f4c-c2a3-4603-a141-0277e96fabfa", + "disabled": true + }, + { + "key": "userId", + "value": "a55fe1bc-1754-45fa-9adc-cf3d6d7c377a", + "disabled": true + }, + { + "key": "status", + "value": "shortlist", + "disabled": true + } + ] + } + }, + "response": [] + }, { "name": "search job candidates with connect user", "request": { @@ -1917,6 +2309,39 @@ }, "response": [] }, + { + "name": "put job candidate with m2m update", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_job_candidate}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"status\": \"selected\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{jobCandidateIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{jobCandidateIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "put job candidate with connect user", "request": { @@ -2082,6 +2507,39 @@ }, "response": [] }, + { + "name": "patch job candidate with m2m update", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_job_candidate}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"shortlist\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{jobCandidateIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{jobCandidateIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "patch job candidate with connect user", "request": { @@ -2312,6 +2770,39 @@ } }, "response": [] + }, + { + "name": "delete job candidate with m2m delete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_delete_job_candidate}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/jobCandidates/{{jobCandidateIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "jobCandidates", + "{{jobCandidateIdCreatedByM2M}}" + ] + } + }, + "response": [] } ], "protocolProfileBehavior": {} @@ -2325,7 +2816,7 @@ { "listen": "test", "script": { - "id": "d8fcb38d-6699-4710-9db2-13fb3c814dff", + "id": "b6c5a8bf-da7a-4062-90c0-d53fa0920df5", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2364,13 +2855,58 @@ }, "response": [] }, + { + "name": "create resource booking with m2m create", + "event": [ + { + "listen": "test", + "script": { + "id": "5423120e-887d-4789-96c2-553bb7e2118c", + "exec": [ + "var data = JSON.parse(responseBody);\r", + "postman.setEnvironmentVariable(\"resourceBookingIdCreatedByM2M\",data.id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_create_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ] + } + }, + "response": [] + }, { "name": "create resource booking with connect user", "event": [ { "listen": "test", "script": { - "id": "45daab6c-adbd-4083-84e9-0e64640e6d95", + "id": "46874c20-fb80-4c00-abae-1dc16871b3b4", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2415,7 +2951,7 @@ { "listen": "test", "script": { - "id": "daa443f9-6ba1-48b0-9c59-b7e7e4192244", + "id": "d6142f6d-92e3-4e99-9f67-bd19072103fa", "exec": [ "" ], @@ -2459,7 +2995,7 @@ { "listen": "test", "script": { - "id": "693dffa5-7de5-4940-8e1b-3053cb6a5684", + "id": "cb7bff90-167a-441e-960a-29bffc5bd01d", "exec": [ "" ], @@ -2503,7 +3039,7 @@ { "listen": "test", "script": { - "id": "dba6c30b-b9c8-4750-8f97-e98bb21aa436", + "id": "54827c9d-36fe-4b1d-95a9-7546cf174820", "exec": [ "" ], @@ -2565,6 +3101,30 @@ }, "response": [] }, + { + "name": "get resource booking with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_resource_booking}}" + } + ], + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "get resource booking with booking manager from db", "request": { @@ -2708,6 +3268,71 @@ }, "response": [] }, + { + "name": "search resource bookings with m2m all", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_all_resource_booking}}" + } + ], + "url": { + "raw": "{{URL}}/resourceBookings", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings" + ], + "query": [ + { + "key": "page", + "value": "1", + "disabled": true + }, + { + "key": "perPage", + "value": "5", + "disabled": true + }, + { + "key": "sortBy", + "value": "id", + "disabled": true + }, + { + "key": "sortOrder", + "value": "desc", + "disabled": true + }, + { + "key": "startDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "endDate", + "value": "2020-09-27T04:17:23.131Z", + "disabled": true + }, + { + "key": "rateType", + "value": "hourly", + "disabled": true + }, + { + "key": "status", + "value": "sourcing", + "disabled": true + } + ] + } + }, + "response": [] + }, { "name": "search resource bookings with connect user", "request": { @@ -2918,6 +3543,39 @@ }, "response": [] }, + { + "name": "put resource booking with m2m update", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"a55fe1bc-1754-45fa-9adc-cf3d6d7c377a\",\r\n \"jobId\": \"{{jobIdCreatedByM2M}}\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\",\r\n \"status\": \"assigned\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "put resource booking with connect user", "request": { @@ -3083,6 +3741,39 @@ }, "response": [] }, + { + "name": "patch resource booking with m2m update", + "request": { + "method": "PATCH", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_update_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"status\": \"assigned\",\r\n \"startDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"endDate\": \"2020-09-27T04:17:23.131Z\",\r\n \"memberRate\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "patch resource booking with connect user", "request": { @@ -3314,6 +4005,39 @@ }, "response": [] }, + { + "name": "delete resource booking with m2m delete", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_delete_resource_booking}}" + } + ], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{URL}}/resourceBookings/{{resourceBookingIdCreatedByM2M}}", + "host": [ + "{{URL}}" + ], + "path": [ + "resourceBookings", + "{{resourceBookingIdCreatedByM2M}}" + ] + } + }, + "response": [] + }, { "name": "delete resource booking with invalid token", "request": { @@ -3376,6 +4100,29 @@ }, "response": [] }, + { + "name": "GET /taas-teams with m2m read", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer {{token_m2m_read_taas_team}}" + } + ], + "url": { + "raw": "{{URL}}/taas-teams", + "host": [ + "{{URL}}" + ], + "path": [ + "taas-teams" + ] + } + }, + "response": [] + }, { "name": "GET /taas-teams/:id", "request": { @@ -3406,6 +4153,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": { @@ -3441,6 +4218,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": {} diff --git a/docs/topcoder-bookings.postman_environment.json b/docs/topcoder-bookings.postman_environment.json index 2b9a3aa4..a97d2383 100644 --- a/docs/topcoder-bookings.postman_environment.json +++ b/docs/topcoder-bookings.postman_environment.json @@ -1,5 +1,5 @@ { - "id": "190c1a31-b774-40f1-aa5c-b24cbdab67fc", + "id": "a7cb1c6e-c710-49c3-ad58-db7536c85944", "name": "topcoder-bookings", "values": [ { @@ -51,9 +51,104 @@ "key": "jobIdCreatedByMember", "value": "", "enabled": true + }, + { + "key": "token_m2m_read_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtam9icyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.l4fH_SGhhbP8kcQoOJhhQW0eRGwC3wIwuj0_7XGj7Ac", + "enabled": true + }, + { + "key": "token_m2m_create_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.m-tHt9ABFj5KqzWYbLNxufVL4QvNw_y4j7w-Pj9l5_E", + "enabled": true + }, + { + "key": "token_m2m_update_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.AM9C6kPZmtQVN-6GtbKeMIiQIZqRk5nOcPuciClZKdY", + "enabled": true + }, + { + "key": "token_m2m_delete_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJkZWxldGU6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.j5YIG2xpirJaXyDRMPoGa8Y_vTCiwxi1qRQfhF2MQpA", + "enabled": true + }, + { + "key": "token_m2m_all_job", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy1qb2JzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.YqhP6JHGu1L4yQ_uAH8_Am29MaZ5fUvZgCk9GjqRDl8", + "enabled": true + }, + { + "key": "token_m2m_read_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtam9iQ2FuZGlkYXRlcyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.N-5rUvF8gKHqs3rSCjlbsa6GJ9SPgJ66ZQlGYuImQXQ", + "enabled": true + }, + { + "key": "token_m2m_create_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.SXQY7145ceuDQd8YPAv4ePyaF1JRnHtVGy1kIhzCfPk", + "enabled": true + }, + { + "key": "token_m2m_update_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.5UXD6hTkx2Iz-LRvz2uGkA85lLJfWeyBksxCpO7Zj-0", + "enabled": true + }, + { + "key": "token_m2m_delete_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJkZWxldGU6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.BquDCL94jRFceLlwEAIGm7oHiVG3GPE-xdNbVh7lX9Y", + "enabled": true + }, + { + "key": "token_m2m_all_job_candidate", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy1qb2JDYW5kaWRhdGVzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.b1ScJHn574-WqhAyFXkc5-bSp3xiZuVzPGm0W1dOVlM", + "enabled": true + }, + { + "key": "token_m2m_read_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtcmVzb3VyY2VCb29raW5ncyIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.tQEMwMS7z7S1q_9vyVCvhlKKRInZ4U21KdE1lQIenjo", + "enabled": true + }, + { + "key": "token_m2m_create_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJjcmVhdGU6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.mE4x9DtPvjVKCib3S9qykmwAr1NsloT0ozQVOPcSdMU", + "enabled": true + }, + { + "key": "token_m2m_update_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJ1cGRhdGU6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.OPN89qGvuvRv2A8CAWPEx_pVCWw0MXlkUuKFbaqnF2I", + "enabled": true + }, + { + "key": "token_m2m_delete_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJkZWxldGU6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.mzQw4hYQKQGu6Q1UIN202pk_aHYEy4DioLbrm37eG48", + "enabled": true + }, + { + "key": "token_m2m_all_resource_booking", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6dGFhcy1yZXNvdXJjZUJvb2tpbmdzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.ErIUp7EQejnNRLUj8we7rRiZg7KVqxaFSW9WboPmt5w", + "enabled": true + }, + { + "key": "token_m2m_read_taas_team", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUwOTA2Mzg4LCJleHAiOjIxNDc0ODM2NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJyZWFkOnRhYXMtdGVhbXMiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.LKd9krhA2ErAMPqLR6dEeWPG0u0JedsysrkZwvAVSMs", + "enabled": true + }, + { + "key": "jobIdCreatedByM2M", + "value": "47430794-8d89-42a4-947b-341b3fe75031", + "enabled": true + }, + { + "key": "jobCandidateIdCreatedByM2M", + "value": "bdc13c45-40a2-4597-9b21-4b572a1faf25", + "enabled": true + }, + { + "key": "resourceBookingIdCreatedByM2M", + "value": "083ddc0e-710e-45f3-b4d3-1f70bf3d8713", + "enabled": true } ], "_postman_variable_scope": "environment", - "_postman_exported_at": "2020-12-01T18:44:10.102Z", + "_postman_exported_at": "2020-12-04T12:09:30.809Z", "_postman_exported_using": "Postman/7.29.0" } \ No newline at end of file diff --git a/src/common/helper.js b/src/common/helper.js index ca714eef..a93f8de4 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -49,6 +49,38 @@ function getBusApiClient () { // ES Client mapping const esClients = {} +/** + * Check if exists. + * + * @param {Array} source the array in which to search for the term + * @param {Array | String} term the term to search + */ +function checkIfExists (source, term) { + let terms + + if (!_.isArray(source)) { + throw new Error('Source argument should be an array') + } + + source = source.map(s => s.toLowerCase()) + + if (_.isString(term)) { + terms = term.toLowerCase().split(' ') + } else if (_.isArray(term)) { + terms = term.map(t => t.toLowerCase()) + } else { + throw new Error('Term argument should be either a string or an array') + } + + for (let i = 0; i < terms.length; i++) { + if (source.includes(terms[i])) { + return true + } + } + + return false +} + /** * Wrap async function to standard express function * @param {Function} fn the async function @@ -491,13 +523,21 @@ async function ensureUbhanUserId (currentUser) { } module.exports = { + checkIfExists, autoWrapExpress, setResHeaders, clearObject, isConnectMember, getESClient, - getUserId: (userId) => ensureUbhanUserId({ userId }), + getUserId: async (userId) => { + // check m2m user id + if (userId === config.m2m.M2M_AUDIT_USER_ID) { + return config.m2m.M2M_AUDIT_USER_ID + } + return ensureUbhanUserId({ userId }) + }, getM2Mtoken, + getTopcoderM2MToken, postEvent, getBusApiClient, isDocumentMissingException, diff --git a/src/routes/JobCandidateRoutes.js b/src/routes/JobCandidateRoutes.js index 8f7ad8f8..7c1dac24 100644 --- a/src/routes/JobCandidateRoutes.js +++ b/src/routes/JobCandidateRoutes.js @@ -1,40 +1,47 @@ /** * Contains jobCandidate routes */ +const constants = require('../../app-constants') module.exports = { '/jobCandidates': { post: { controller: 'JobCandidateController', method: 'createJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.CREATE_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] }, get: { controller: 'JobCandidateController', method: 'searchJobCandidates', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] } }, '/jobCandidates/:id': { get: { controller: 'JobCandidateController', method: 'getJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] }, put: { controller: 'JobCandidateController', method: 'fullyUpdateJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] }, patch: { controller: 'JobCandidateController', method: 'partiallyUpdateJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] }, delete: { controller: 'JobCandidateController', method: 'deleteJobCandidate', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.DELETE_JOB_CANDIDATE, constants.Scopes.ALL_JOB_CANDIDATE] } } } diff --git a/src/routes/JobRoutes.js b/src/routes/JobRoutes.js index 9d57fa8f..5764f9c7 100644 --- a/src/routes/JobRoutes.js +++ b/src/routes/JobRoutes.js @@ -1,40 +1,47 @@ /** * Contains job routes */ +const constants = require('../../app-constants') module.exports = { '/jobs': { post: { controller: 'JobController', method: 'createJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.CREATE_JOB, constants.Scopes.ALL_JOB] }, get: { controller: 'JobController', method: 'searchJobs', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_JOB, constants.Scopes.ALL_JOB] } }, '/jobs/:id': { get: { controller: 'JobController', method: 'getJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_JOB, constants.Scopes.ALL_JOB] }, put: { controller: 'JobController', method: 'fullyUpdateJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_JOB, constants.Scopes.ALL_JOB] }, patch: { controller: 'JobController', method: 'partiallyUpdateJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_JOB, constants.Scopes.ALL_JOB] }, delete: { controller: 'JobController', method: 'deleteJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.DELETE_JOB, constants.Scopes.ALL_JOB] } } } diff --git a/src/routes/ResourceBookingRoutes.js b/src/routes/ResourceBookingRoutes.js index 91983c1d..eb152165 100644 --- a/src/routes/ResourceBookingRoutes.js +++ b/src/routes/ResourceBookingRoutes.js @@ -1,40 +1,47 @@ /** * Contains resourceBooking routes */ +const constants = require('../../app-constants') module.exports = { '/resourceBookings': { post: { controller: 'ResourceBookingController', method: 'createResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.CREATE_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] }, get: { controller: 'ResourceBookingController', method: 'searchResourceBookings', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] } }, '/resourceBookings/:id': { get: { controller: 'ResourceBookingController', method: 'getResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] }, put: { controller: 'ResourceBookingController', method: 'fullyUpdateResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] }, patch: { controller: 'ResourceBookingController', method: 'partiallyUpdateResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.UPDATE_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] }, delete: { controller: 'ResourceBookingController', method: 'deleteResourceBooking', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.DELETE_RESOURCE_BOOKING, constants.Scopes.ALL_RESOURCE_BOOKING] } } } diff --git a/src/routes/TeamRoutes.js b/src/routes/TeamRoutes.js index 30dd5bc1..43a9a261 100644 --- a/src/routes/TeamRoutes.js +++ b/src/routes/TeamRoutes.js @@ -1,27 +1,31 @@ /** * Contains taas team routes */ +const constants = require('../../app-constants') module.exports = { '/taas-teams': { get: { controller: 'TeamController', method: 'searchTeams', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_TAAS_TEAM] } }, '/taas-teams/:id': { get: { controller: 'TeamController', method: 'getTeam', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_TAAS_TEAM] } }, '/taas-teams/:id/jobs/:jobId': { get: { controller: 'TeamController', method: 'getTeamJob', - auth: 'jwt' + auth: 'jwt', + scopes: [constants.Scopes.READ_TAAS_TEAM] } } } diff --git a/src/services/JobCandidateService.js b/src/services/JobCandidateService.js index dd369b60..3e49f78d 100644 --- a/src/services/JobCandidateService.js +++ b/src/services/JobCandidateService.js @@ -83,7 +83,7 @@ async function updateJobCandidate (currentUser, id, data) { const jobCandidate = await JobCandidate.findById(id) const projectId = await JobCandidate.getProjectId(jobCandidate.dataValues.jobId) const userId = await helper.getUserId(currentUser.userId) - if (projectId && !currentUser.isBookingManager) { + if (projectId && !currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(projectId, currentUser.jwtToken) if (!connect) { if (jobCandidate.dataValues.userId !== userId) { @@ -146,7 +146,7 @@ fullyUpdateJobCandidate.schema = Joi.object().keys({ * @params {String} id the jobCandidate id */ async function deleteJobCandidate (currentUser, id) { - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { throw new errors.ForbiddenError('You are not allowed to perform this action!') } diff --git a/src/services/JobService.js b/src/services/JobService.js index 5022f7ed..febffc81 100644 --- a/src/services/JobService.js +++ b/src/services/JobService.js @@ -160,7 +160,7 @@ async function updateJob (currentUser, id, data) { } let job = await Job.findById(id) const ubhanUserId = await helper.getUserId(currentUser.userId) - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(job.dataValues.projectId, currentUser.jwtToken) if (!connect) { if (ubhanUserId !== job.createdBy) { @@ -242,7 +242,7 @@ fullyUpdateJob.schema = Joi.object().keys({ */ async function deleteJob (currentUser, id) { const job = await Job.findById(id) - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { const ubhanUserId = await helper.getUserId(currentUser.userId) if (ubhanUserId !== job.createdBy) { throw new errors.ForbiddenError('You are not allowed to perform this action!') diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index fc234402..d8011d6e 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -22,7 +22,7 @@ const esClient = helper.getESClient() * @returns {Object} the resourceBooking */ async function _getResourceBookingFilteringFields (currentUser, resourceBooking) { - if (currentUser.isBookingManager) { + if (currentUser.isBookingManager || currentUser.isMachine) { return helper.clearObject(resourceBooking) } else if (await helper.isConnectMember(resourceBooking.projectId, currentUser.jwtToken)) { return _.omit(helper.clearObject(resourceBooking), 'memberRate') @@ -72,7 +72,7 @@ getResourceBooking.schema = Joi.object().keys({ * @returns {Object} the created resourceBooking */ async function createResourceBooking (currentUser, resourceBooking) { - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(resourceBooking.projectId, currentUser.jwtToken) if (!connect) { throw new errors.ForbiddenError('You are not allowed to perform this action!') @@ -111,7 +111,7 @@ createResourceBooking.schema = Joi.object().keys({ */ async function updateResourceBooking (currentUser, id, data) { const resourceBooking = await ResourceBooking.findById(id) - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { const connect = await helper.isConnectMember(resourceBooking.dataValues.projectId, currentUser.jwtToken) if (!connect) { throw new errors.ForbiddenError('You are not allowed to perform this action!') @@ -183,7 +183,7 @@ fullyUpdateResourceBooking.schema = Joi.object().keys({ * @params {String} id the resourceBooking id */ async function deleteResourceBooking (currentUser, id) { - if (!currentUser.isBookingManager) { + if (!currentUser.isBookingManager && !currentUser.isMachine) { throw new errors.ForbiddenError('You are not allowed to perform this action!') } diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 09a5411a..df08804a 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -40,6 +40,10 @@ async function _getJobsByProjectIds (projectIds) { * @returns {Object} the search result, contain total/page/perPage and result array */ async function searchTeams (currentUser) { + if (currentUser.isMachine) { + const m2mToken = await helper.getM2Mtoken() + currentUser.jwtToken = `Bearer ${m2mToken}` + } // Get projects from /v5/projects const projects = await helper.getProjects(currentUser.jwtToken) @@ -168,6 +172,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) @@ -223,6 +231,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 }) @@ -252,7 +264,13 @@ async function getTeamJob (currentUser, id, jobId) { const userHandles = _.map(candidates, 'handle') if (userHandles && userHandles.length > 0) { // Get user photo from /v5/members - const members = await helper.getMembers(currentUser.jwtToken, userHandles) + let members + if (currentUser.isMachine) { + const m2mToken = await helper.getTopcoderM2MToken() + members = await helper.getMembers(`Bearer ${m2mToken}`, userHandles) + } else { + members = await helper.getMembers(currentUser.jwtToken, userHandles) + } for (const item of candidates) { item.resumeLink = null From ef79f763ad5a9a75bc195c1f7507fa970418f150 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Sat, 5 Dec 2020 03:34:42 +0800 Subject: [PATCH 11/26] GET /taas-teams supports `perPage`, `page`, `sortBy`, `sortOrder`, and `name` params --- app.js | 5 +- ...coder-bookings-api.postman_collection.json | 65 ++++++++++++------ docs/swagger.yaml | 67 +++++++++++++++++++ src/bootstrap.js | 2 + src/common/helper.js | 20 +++--- src/controllers/TeamController.js | 5 +- src/services/TeamService.js | 40 +++++++++-- 7 files changed, 166 insertions(+), 38 deletions(-) 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/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 39156ec7..46f07ebf 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "418b385c-5ce1-4810-b357-cddf05adf271", + "_postman_id": "282e8342-2d5a-4566-8509-f2f240a594a0", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,7 @@ { "listen": "test", "script": { - "id": "ff119e52-58f4-4501-8193-dd8c75f9ba4a", + "id": "a2236151-22f2-46c7-869a-858eb7da1ab8", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -59,7 +59,7 @@ { "listen": "test", "script": { - "id": "66169f57-ba0e-4a88-85c3-e27ee380c332", + "id": "91236482-d7b2-4acd-a47d-e9f9ac833bad", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -104,7 +104,7 @@ { "listen": "test", "script": { - "id": "31016a7d-5de6-4802-92f8-b1c7a9afcc4a", + "id": "1e5b5bdf-6ff0-4d96-8018-8698bc359674", "exec": [ "var data = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" @@ -149,7 +149,7 @@ { "listen": "test", "script": { - "id": "0b96c49d-6fb7-49ab-bfe1-4623ffe1be10", + "id": "0b469a8d-8119-4907-ac37-a69a1766754d", "exec": [ "" ], @@ -193,7 +193,7 @@ { "listen": "test", "script": { - "id": "bce80082-b100-466d-a196-73e9c38e2b9d", + "id": "fec863ef-1db6-4008-8a9d-ef616e3cac4d", "exec": [ "" ], @@ -785,7 +785,7 @@ { "listen": "test", "script": { - "id": "40f37d6f-508f-47ba-bbd4-41e1e0c3a4a2", + "id": "28720714-8006-4fd5-b3b8-0c588266bb5e", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -997,7 +997,7 @@ { "listen": "test", "script": { - "id": "5d25999b-14ec-432c-bf11-028ec73a7140", + "id": "aa7fa1f8-cca2-4323-8266-ff4e770dae10", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1209,7 +1209,7 @@ { "listen": "test", "script": { - "id": "5f89405c-6907-41c8-8630-ccb5d5d640e6", + "id": "8299d83c-e5c3-4639-8c4a-bf783f178fb2", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1328,7 +1328,7 @@ { "listen": "test", "script": { - "id": "865f0f13-444b-4247-902d-b3e6cdb1898e", + "id": "cbee0ff6-5824-447c-915d-466bfd5242bc", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1373,7 +1373,7 @@ { "listen": "test", "script": { - "id": "37973c93-a13f-448d-8f02-af7f18818df2", + "id": "6a1b4404-55ef-40e8-981a-3cb9e960d6ea", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1418,7 +1418,7 @@ { "listen": "test", "script": { - "id": "79490454-9392-42f1-8f07-7ab1950318df", + "id": "a42f6045-fdb2-4d61-8dd4-a919573f5d24", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1463,7 +1463,7 @@ { "listen": "test", "script": { - "id": "99a176e1-645b-47ca-91b4-940fbebc65f6", + "id": "b133db18-fa52-4a59-9e35-5e7d340b7f1d", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1508,7 +1508,7 @@ { "listen": "test", "script": { - "id": "92b01e89-a317-4663-95f0-ecb861fceefb", + "id": "6cd47ee8-4139-4309-8cb1-ceb74d2d06eb", "exec": [ "" ], @@ -2325,7 +2325,7 @@ { "listen": "test", "script": { - "id": "d8fcb38d-6699-4710-9db2-13fb3c814dff", + "id": "2722fecc-08fa-4d6e-9895-e7ed844f21c9", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2370,7 +2370,7 @@ { "listen": "test", "script": { - "id": "45daab6c-adbd-4083-84e9-0e64640e6d95", + "id": "86edd7ff-eef6-4976-ae59-101fbe154e2c", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2415,7 +2415,7 @@ { "listen": "test", "script": { - "id": "daa443f9-6ba1-48b0-9c59-b7e7e4192244", + "id": "10be7afd-f528-4abf-a524-a9642678c436", "exec": [ "" ], @@ -2459,7 +2459,7 @@ { "listen": "test", "script": { - "id": "693dffa5-7de5-4940-8e1b-3053cb6a5684", + "id": "ad50f131-aff8-4e32-acda-d647889d4dc3", "exec": [ "" ], @@ -2503,7 +2503,7 @@ { "listen": "test", "script": { - "id": "dba6c30b-b9c8-4750-8f97-e98bb21aa436", + "id": "ebe085f5-b1ce-455b-b147-c4c6f4cd4283", "exec": [ "" ], @@ -3365,12 +3365,37 @@ } ], "url": { - "raw": "{{URL}}/taas-teams", + "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" + } ] } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 0ce3b6cf..380c4c14 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1278,6 +1278,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: @@ -1289,6 +1327,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: diff --git a/src/bootstrap.js b/src/bootstrap.js index 7a191878..a35212e0 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -3,6 +3,8 @@ 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') diff --git a/src/common/helper.js b/src/common/helper.js index ca714eef..441d7f25 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -124,14 +124,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) } /** @@ -305,19 +297,27 @@ 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) { +async function getProjects (token, criteria = {}) { const url = `${config.TC_API}/projects?type=talent-as-a-service` const res = await request .get(url) + .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 => { + 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 + } } /** diff --git a/src/controllers/TeamController.js b/src/controllers/TeamController.js index f29e11e1..b7dfe5d8 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.result }) } /** diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 09a5411a..3d08b956 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -37,17 +37,45 @@ 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) { + let sort = `${criteria.sortBy}` + if (criteria.sortOrder) { + 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('createdAt'), + 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() /** From bf56071790fb4d7e29281731e582978e96067787 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Sat, 5 Dec 2020 03:58:59 +0800 Subject: [PATCH 12/26] remove unnecessary code --- src/services/TeamService.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 3d08b956..e6f75278 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -41,10 +41,7 @@ async function _getJobsByProjectIds (projectIds) { * @returns {Object} the search result, contain total/page/perPage and result array */ async function searchTeams (currentUser, criteria) { - let sort = `${criteria.sortBy}` - if (criteria.sortOrder) { - sort = `${criteria.sortBy} ${criteria.sortOrder}` - } + 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, From a1ad5c0a5635c26c1f7f8a903d710cea86b7e65d Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Sat, 5 Dec 2020 05:50:45 +0800 Subject: [PATCH 13/26] update status of candidate when the candidate is booked --- src/services/ResourceBookingService.js | 29 +++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index fc234402..007d463d 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() @@ -120,8 +121,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 (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 } From f3328f79158b327cc22a1d26fdee807a5b21e068 Mon Sep 17 00:00:00 2001 From: maxceem Date: Mon, 7 Dec 2020 13:10:59 +0200 Subject: [PATCH 14/26] fix: return arrays of records without "result" --- src/controllers/JobCandidateController.js | 2 +- src/controllers/JobController.js | 2 +- src/controllers/ResourceBookingController.js | 2 +- src/controllers/TeamController.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 b7dfe5d8..9e1f7946 100644 --- a/src/controllers/TeamController.js +++ b/src/controllers/TeamController.js @@ -12,7 +12,7 @@ const helper = require('../common/helper') async function searchTeams (req, res) { const result = await service.searchTeams(req.authUser, req.query) helper.setResHeaders(req, res, result) - res.send({ result: result.result }) + res.send(result.result) } /** From 672e7e68892c08be3232801b5784f0173ade7869 Mon Sep 17 00:00:00 2001 From: maxceem Date: Mon, 7 Dec 2020 13:19:53 +0200 Subject: [PATCH 15/26] improve: sort teams by "lastActivityAt" by default --- src/services/TeamService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/TeamService.js b/src/services/TeamService.js index e6f75278..80a35e56 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -65,7 +65,7 @@ searchTeams.schema = Joi.object().keys({ criteria: Joi.object().keys({ page: Joi.page(), perPage: Joi.perPage(), - sortBy: Joi.string().valid('createdAt', 'updatedAt', 'lastActivityAt', 'id', 'status', 'name', 'type', 'best match').default('createdAt'), + 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`)'), From 73936d7c0a41a16257cf185d37564c06e28131d3 Mon Sep 17 00:00:00 2001 From: maxceem Date: Mon, 7 Dec 2020 15:54:30 +0200 Subject: [PATCH 16/26] fix: remove "result" in swagger --- .gitignore | 5 ++++- docs/swagger.yaml | 30 ++++++++++++------------------ 2 files changed, 16 insertions(+), 19 deletions(-) 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/docs/swagger.yaml b/docs/swagger.yaml index 380c4c14..a35dc19b 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -172,12 +172,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: @@ -573,12 +571,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: @@ -982,12 +978,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: From 44a26d2725ce355f8aa0971e69860db3b04fbf36 Mon Sep 17 00:00:00 2001 From: maxceem Date: Tue, 8 Dec 2020 12:16:31 +0200 Subject: [PATCH 17/26] fix: rename "weeklyCount" to "weeklyCost" ref issue #47 --- src/services/TeamService.js | 4 ++-- test/unit/TeamService.test.js | 2 +- test/unit/common/testData.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/services/TeamService.js b/src/services/TeamService.js index 80a35e56..bc0c499a 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -100,7 +100,7 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { 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) { @@ -131,7 +131,7 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { // 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.weeklyCount += item.customerRate + res.weeklyCost += item.customerRate } } 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', From bed2699b08e51e9f4ddf0e301be5d3fd180e1115 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Tue, 8 Dec 2020 19:05:48 +0800 Subject: [PATCH 18/26] check if status being changed before updating candidates --- src/services/ResourceBookingService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index 007d463d..25d62ed6 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -112,6 +112,7 @@ createResourceBooking.schema = Joi.object().keys({ */ async function updateResourceBooking (currentUser, id, data) { const resourceBooking = await ResourceBooking.findById(id) + const isDiffStatus = resourceBooking.status !== data.status if (!currentUser.isBookingManager) { const connect = await helper.isConnectMember(resourceBooking.dataValues.projectId, currentUser.jwtToken) if (!connect) { @@ -126,7 +127,7 @@ async function updateResourceBooking (currentUser, 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 (data.status === 'assigned') { + if (isDiffStatus && data.status === 'assigned') { const candidates = await models.JobCandidate.findAll({ where: { jobId: updatedResourceBooking.jobId, From 74c3b3651241253110d26ef1b0b155e983513387 Mon Sep 17 00:00:00 2001 From: maxceem Date: Tue, 8 Dec 2020 21:07:59 +0200 Subject: [PATCH 19/26] tests: postman for creating demo data --- ...coder-bookings-api.postman_collection.json | 2591 ++++++++++++++++- 1 file changed, 2568 insertions(+), 23 deletions(-) diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 2f51d42c..1d5fa236 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "f4cd931d-2cfb-4d3a-b31e-4a6a02317cb2", + "_postman_id": "8a85ef5b-c835-427b-ab3c-27a1a99ba290", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,7 @@ { "listen": "test", "script": { - "id": "72230770-0780-406e-b740-12fba4aac339", + "id": "a174d4ac-8b78-416a-a3cc-f14f66205e2f", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -59,7 +59,7 @@ { "listen": "test", "script": { - "id": "a36bec2a-bf3d-4d1f-bf83-32c99676695c", + "id": "002ddcbb-ce9e-4be5-ab41-5a4f91fff9a0", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobIdCreatedByM2M\",data.id);" @@ -104,7 +104,7 @@ { "listen": "test", "script": { - "id": "aa345d54-a75a-4702-9079-edf37f05fc28", + "id": "b06555c1-081b-4116-835d-151a1b2f63db", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -149,7 +149,7 @@ { "listen": "test", "script": { - "id": "0351c210-4a5a-4514-8fe9-d6debb1c1bbb", + "id": "0e4d2512-c12e-4688-ba62-e203de36def3", "exec": [ "var data = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" @@ -194,7 +194,7 @@ { "listen": "test", "script": { - "id": "bb2df571-ae1e-43d5-a3d1-fdd21cc85882", + "id": "76617d98-f3f2-4ae6-85e9-bbe6a9ebf646", "exec": [ "" ], @@ -238,7 +238,7 @@ { "listen": "test", "script": { - "id": "8e8187ba-302f-43a4-b1e8-5116232dec57", + "id": "b3154f8d-54da-46e4-b3fd-440dca435329", "exec": [ "" ], @@ -982,7 +982,7 @@ { "listen": "test", "script": { - "id": "9c04dea6-d12d-4287-84e4-068ca7025e2a", + "id": "60c1b84d-0e09-41e8-96ab-a1ea4c40e158", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1227,7 +1227,7 @@ { "listen": "test", "script": { - "id": "a4e3f5a6-cc9b-419d-aa56-73aab3046d4b", + "id": "908ef69d-1da9-46b0-bbb2-4b783459d40b", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1472,7 +1472,7 @@ { "listen": "test", "script": { - "id": "bb287666-8bd5-411b-85a2-1739d1c43a5d", + "id": "9f3a84e8-9374-455e-8bdb-294b1615fd67", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1591,7 +1591,7 @@ { "listen": "test", "script": { - "id": "a4164751-2a2a-477e-82c7-897f71de1272", + "id": "9a3b174a-b59b-440d-be00-e9789133327e", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1636,7 +1636,7 @@ { "listen": "test", "script": { - "id": "c9c1b298-f7f9-456b-bffe-77b5ba83f38c", + "id": "1c40e1a1-b3be-4463-b0c3-896a999d2bae", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateIdCreatedByM2M\",data.id);" @@ -1681,7 +1681,7 @@ { "listen": "test", "script": { - "id": "107c325f-d111-418e-8d2f-84709e317a0e", + "id": "04adbcc4-af7e-48aa-a16e-c6c259274c6e", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1726,7 +1726,7 @@ { "listen": "test", "script": { - "id": "ed118309-1cee-4795-8586-a6e4f3555ce2", + "id": "7868dace-3232-428d-aa73-803ed4993b0a", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1771,7 +1771,7 @@ { "listen": "test", "script": { - "id": "7622898d-a47c-4631-8a82-da52b2de72cc", + "id": "a2e2bf97-2ef0-4c66-a485-c8640f8e1a43", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1816,7 +1816,7 @@ { "listen": "test", "script": { - "id": "a034038a-b2ec-49d9-afd4-e08625802057", + "id": "6f6d5a0c-77e2-40f5-ab77-d3f1057d4880", "exec": [ "" ], @@ -2816,7 +2816,7 @@ { "listen": "test", "script": { - "id": "b6c5a8bf-da7a-4062-90c0-d53fa0920df5", + "id": "41049db0-7673-4f58-964b-9890c1fb20b7", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2861,7 +2861,7 @@ { "listen": "test", "script": { - "id": "5423120e-887d-4789-96c2-553bb7e2118c", + "id": "e119a03a-c75d-4e6e-8feb-8f295719124c", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingIdCreatedByM2M\",data.id);" @@ -2906,7 +2906,7 @@ { "listen": "test", "script": { - "id": "46874c20-fb80-4c00-abae-1dc16871b3b4", + "id": "bdc6338a-79fb-4da0-a4fb-d512e10a0013", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2951,7 +2951,7 @@ { "listen": "test", "script": { - "id": "d6142f6d-92e3-4e99-9f67-bd19072103fa", + "id": "eb3ab1d2-c077-407d-bb27-4a726b8060f4", "exec": [ "" ], @@ -2995,7 +2995,7 @@ { "listen": "test", "script": { - "id": "cb7bff90-167a-441e-960a-29bffc5bd01d", + "id": "15628973-b3cc-40a9-bcc8-949bc69d5b23", "exec": [ "" ], @@ -3039,7 +3039,7 @@ { "listen": "test", "script": { - "id": "54827c9d-36fe-4b1d-95a9-7546cf174820", + "id": "19f15ea4-efd9-40d9-ad83-0695e8cb2bc0", "exec": [ "" ], @@ -4305,7 +4305,2552 @@ } ], "protocolProfileBehavior": {} + }, + { + "name": "Create Demo Data For Team", + "item": [ + { + "name": "Get Users", + "item": [ + { + "name": "Get Users", + "event": [ + { + "listen": "test", + "script": { + "id": "f05e4a3b-0212-4fcd-99c6-3a5ea7735250", + "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": "aa7b3bf1-d744-4190-8e80-707b532bdfb1", + "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\": \"Designer #1\",\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 \"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": "7dd20ad6-cdef-4729-930f-c60cd08916b1", + "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\": \"Front-End Developer #2\",\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\": \"hourly\",\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": "0de7c3ec-f9bd-439a-a48b-536571e8299e", + "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": "1c12c1ce-9c9c-43ef-bbdb-afd2b51b0dd4", + "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": "4fa51760-a365-4539-b482-9983bcf7f02c", + "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": "7bfe4379-84a7-43c9-a3d0-34d7b9ae7d01", + "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": "b59ce584-58f3-47c9-a909-fa6778f418f5", + "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": "6d0807c5-edfc-480e-bd2b-2c94c2ec8f07", + "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": "7f9ca91a-c2ae-4616-a8e2-0d41b39a4559", + "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": "d4122d98-02c3-4152-b3a2-6a9f12d2aca4", + "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": "32b361aa-0011-49a1-9a18-4796e1660bdc", + "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": "baa0558e-c74a-4667-979c-d3e6fa3ea2aa", + "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": "466003be-222a-4800-b490-e7c7498a1eb7", + "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": "e53cea2d-d0f4-42cb-ac73-39e6b324b7c1", + "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": "86bb9e58-8770-4afe-928d-95b9922224e6", + "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": "5b507df6-d85a-43dc-a32a-8c6988cfb492", + "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\": \"Back-End Developer #3\",\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\": \"hourly\",\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": "fc6d08e5-03b5-4edc-9cec-d39b70930c19", + "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": "718d4b34-b642-4132-af76-3c7e338c8edc", + "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": "7498ab0a-d6a2-4581-bc57-203c3614e59e", + "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": "8d350c13-b63c-4122-8420-590109723f23", + "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": "4b52d98d-3236-46f1-8a62-ec71bfa17db3", + "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": "9aa8a01a-ebee-4641-bd59-e31a89e41002", + "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": "b8df1a4f-4bd8-425b-8a50-8a31042b3fa7", + "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": "aebacb9d-9e2b-419d-9f83-16fb8fac80d0", + "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": "2db8e8e3-3f73-49e2-8c7b-203593ecd257", + "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": "eef44eaa-a541-454f-8e35-029e256719f4", + "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": "3eddf21c-d9b1-4248-8baf-9185df59931a", + "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" + } + } + ], + "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\": \"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 job 3 resource booking 12", + "event": [ + { + "listen": "test", + "script": { + "id": "f5bc861f-dae5-49b6-b0e5-2fab8900f348", + "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" + } + } + ], + "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\": \"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 job 3 resource booking 13", + "event": [ + { + "listen": "test", + "script": { + "id": "746bedf6-a9c4-40e0-811b-7d940757c87f", + "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" + } + } + ], + "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\": \"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 job 3 resource booking 14", + "event": [ + { + "listen": "test", + "script": { + "id": "ffe14de5-ec63-4c1b-b8c8-9d3713283e67", + "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" + } + } + ], + "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\": \"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 job 3 resource booking 15", + "event": [ + { + "listen": "test", + "script": { + "id": "3bf5bac7-ebb8-40b2-a326-e2d3da8c0a3b", + "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" + } + } + ], + "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\": \"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 job 3 resource booking 16", + "event": [ + { + "listen": "test", + "script": { + "id": "d5222da2-57f9-4a63-b3ba-8cf949628ad2", + "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" + } + } + ], + "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\": \"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 job 3 resource booking 17", + "event": [ + { + "listen": "test", + "script": { + "id": "26035f48-5dcc-4879-b5cc-cff68282ca07", + "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" + } + } + ], + "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\": \"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 job 3 resource booking 18", + "event": [ + { + "listen": "test", + "script": { + "id": "f3c58ef3-dc1a-402b-a496-49255284b270", + "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" + } + } + ], + "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\": \"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 job 3 resource booking 19", + "event": [ + { + "listen": "test", + "script": { + "id": "6f0a8185-58ec-47f3-8c96-d2a88ff4a5bb", + "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\": \"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 job 3 resource booking 20", + "event": [ + { + "listen": "test", + "script": { + "id": "e09b2898-7ee6-4abf-8dd7-95964a05ac19", + "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" + } + } + ], + "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\": 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": "update job 3 resource booking 11 status to \"assigned\"", + "event": [ + { + "listen": "test", + "script": { + "id": "19db0df8-46b3-4642-9c57-a3593bc9e011", + "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": "6aa34685-b1fa-430f-9242-c6700a17422b", + "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": "3e8cfe28-fe2d-4db1-8e6b-3621c84fedea", + "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": "d80f6e76-7a0c-466d-90d5-a7c9a0049a5e", + "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": "9f2100e6-4e66-48d0-b0fe-247979d63ad1", + "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": "7ce25ebd-d9be-4a01-adbf-19387db61f75", + "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": "453678c7-9ebc-4599-b0b3-223b89cc5e26", + "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": "427d92c9-d68b-4da2-84c2-546cec1ef34e", + "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": "128712e4-9d75-42f3-8a3f-68afc2cdfc7d", + "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": "54199830-cf4f-4cb4-bc21-12c5e6c144cc", + "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": "226ceac8-1870-44f1-bde8-4664640cf511", + "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": "295d310b-76e9-4fc2-8fde-cb3267dc5e14", + "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\": \"QA #4\",\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\": \"hourly\",\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": "b0c2fd5b-7d45-4b48-a8f7-181897c4be85", + "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": "a728bdb2-1fa0-4075-ba1f-af3e7fbf96a9", + "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\": \"Data-Scientist #5\",\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\": \"hourly\",\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": "caedca49-bc10-457c-9aa9-106cfa1e8625", + "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": {} -} +} \ No newline at end of file From 1998370272ed2d8bbbb9d65ee0d06cb68d224826 Mon Sep 17 00:00:00 2001 From: maxceem Date: Wed, 9 Dec 2020 16:00:01 +0200 Subject: [PATCH 20/26] fix: load user skills fast for teams --- src/common/helper.js | 13 ++++++++++--- src/services/TeamService.js | 17 +++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/common/helper.js b/src/common/helper.js index 48b19e46..be8aae35 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -379,14 +379,21 @@ async function getTopcoderUserById (userId) { * @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 } /** diff --git a/src/services/TeamService.js b/src/services/TeamService.js index de0b5a73..a4cebb1b 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -142,7 +142,7 @@ async function getTeamDetail (currentUser, projects, isSearch = true) { const usersPromises = [] _.map(rbs, (rb) => { usersPromises.push( - helper.getUserById(currentUser.jwtToken, rb.userId) + helper.getUserById(currentUser.jwtToken, rb.userId, true) .then(user => { // If call function is not search, add jobId field if (!isSearch) { @@ -224,13 +224,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 @@ -308,14 +305,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 From 91c98df98d28b04ba3d658c9f8a2dfbba1f2dba9 Mon Sep 17 00:00:00 2001 From: maxceem Date: Wed, 9 Dec 2020 16:06:08 +0200 Subject: [PATCH 21/26] fix: return skills for job candidates --- src/services/TeamService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/TeamService.js b/src/services/TeamService.js index a4cebb1b..64a3aad5 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -280,7 +280,7 @@ async function getTeamJob (currentUser, id, jobId) { 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') From 2034ddc51ddf21183a5075876a9672b84b33eef3 Mon Sep 17 00:00:00 2001 From: maxceem Date: Wed, 9 Dec 2020 18:14:13 +0200 Subject: [PATCH 22/26] docs: rename demo jobs in postman --- ...coder-bookings-api.postman_collection.json | 158 +++++++++--------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 1d5fa236..113b823a 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "8a85ef5b-c835-427b-ab3c-27a1a99ba290", + "_postman_id": "5d74e7a7-d744-4176-994a-62a8ac68efef", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,7 @@ { "listen": "test", "script": { - "id": "a174d4ac-8b78-416a-a3cc-f14f66205e2f", + "id": "eede316e-3a6b-456a-aa23-18a058e9ea49", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -59,7 +59,7 @@ { "listen": "test", "script": { - "id": "002ddcbb-ce9e-4be5-ab41-5a4f91fff9a0", + "id": "e400497c-7e5c-43e1-8402-d21e8dd5a903", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobIdCreatedByM2M\",data.id);" @@ -104,7 +104,7 @@ { "listen": "test", "script": { - "id": "b06555c1-081b-4116-835d-151a1b2f63db", + "id": "d835a72e-cebb-4a22-8186-838c6a427a6c", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -149,7 +149,7 @@ { "listen": "test", "script": { - "id": "0e4d2512-c12e-4688-ba62-e203de36def3", + "id": "f9889f54-be41-49cf-94d4-a4f39043ee41", "exec": [ "var data = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" @@ -194,7 +194,7 @@ { "listen": "test", "script": { - "id": "76617d98-f3f2-4ae6-85e9-bbe6a9ebf646", + "id": "a79f30e7-6491-483d-b016-a6ff9a0cd0b3", "exec": [ "" ], @@ -238,7 +238,7 @@ { "listen": "test", "script": { - "id": "b3154f8d-54da-46e4-b3fd-440dca435329", + "id": "d0a3307a-ad6a-4123-a1ec-dd0a30fc8b6c", "exec": [ "" ], @@ -982,7 +982,7 @@ { "listen": "test", "script": { - "id": "60c1b84d-0e09-41e8-96ab-a1ea4c40e158", + "id": "1cd415d8-f6e3-43d9-812d-68fe3dc5a707", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1227,7 +1227,7 @@ { "listen": "test", "script": { - "id": "908ef69d-1da9-46b0-bbb2-4b783459d40b", + "id": "809d595d-b657-4527-90fa-c9396cf9a0ce", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1472,7 +1472,7 @@ { "listen": "test", "script": { - "id": "9f3a84e8-9374-455e-8bdb-294b1615fd67", + "id": "578a12d8-13d7-4557-9e7b-8958ba75191e", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1591,7 +1591,7 @@ { "listen": "test", "script": { - "id": "9a3b174a-b59b-440d-be00-e9789133327e", + "id": "df26ced2-6c95-4833-9c2e-db07ccb43d90", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1636,7 +1636,7 @@ { "listen": "test", "script": { - "id": "1c40e1a1-b3be-4463-b0c3-896a999d2bae", + "id": "51ac0814-9cbb-4b5a-81fc-9fa9e8f82131", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateIdCreatedByM2M\",data.id);" @@ -1681,7 +1681,7 @@ { "listen": "test", "script": { - "id": "04adbcc4-af7e-48aa-a16e-c6c259274c6e", + "id": "e2482a20-1719-4791-ae49-7c2f052510c5", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1726,7 +1726,7 @@ { "listen": "test", "script": { - "id": "7868dace-3232-428d-aa73-803ed4993b0a", + "id": "7cb7e30a-5afa-469d-bb58-6eec4f51d1c4", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1771,7 +1771,7 @@ { "listen": "test", "script": { - "id": "a2e2bf97-2ef0-4c66-a485-c8640f8e1a43", + "id": "373fb1e4-2f3c-4182-9f8f-342e62be61a9", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1816,7 +1816,7 @@ { "listen": "test", "script": { - "id": "6f6d5a0c-77e2-40f5-ab77-d3f1057d4880", + "id": "a79dc990-c63d-442a-9b33-9c2fd70d8391", "exec": [ "" ], @@ -2816,7 +2816,7 @@ { "listen": "test", "script": { - "id": "41049db0-7673-4f58-964b-9890c1fb20b7", + "id": "936361be-5be1-47b1-b2e8-453e67302af3", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2861,7 +2861,7 @@ { "listen": "test", "script": { - "id": "e119a03a-c75d-4e6e-8feb-8f295719124c", + "id": "eb606efa-595d-466f-b41d-8a6d14f5f160", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingIdCreatedByM2M\",data.id);" @@ -2906,7 +2906,7 @@ { "listen": "test", "script": { - "id": "bdc6338a-79fb-4da0-a4fb-d512e10a0013", + "id": "177053c5-325e-4663-9918-afba02fd09f3", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2951,7 +2951,7 @@ { "listen": "test", "script": { - "id": "eb3ab1d2-c077-407d-bb27-4a726b8060f4", + "id": "5a42e489-1d61-486a-b5ac-4cfd24950338", "exec": [ "" ], @@ -2995,7 +2995,7 @@ { "listen": "test", "script": { - "id": "15628973-b3cc-40a9-bcc8-949bc69d5b23", + "id": "25fd464b-ef8b-45b7-ad51-9350469d7e8e", "exec": [ "" ], @@ -3039,7 +3039,7 @@ { "listen": "test", "script": { - "id": "19f15ea4-efd9-40d9-ad83-0695e8cb2bc0", + "id": "73138739-2706-4dfa-8ded-7e74de85962e", "exec": [ "" ], @@ -4318,7 +4318,7 @@ { "listen": "test", "script": { - "id": "f05e4a3b-0212-4fcd-99c6-3a5ea7735250", + "id": "2066b7ec-8e67-4dee-b6bf-d39e780af162", "exec": [ "var data = JSON.parse(responseBody);", "", @@ -4392,7 +4392,7 @@ { "listen": "test", "script": { - "id": "aa7b3bf1-d744-4190-8e80-707b532bdfb1", + "id": "b580af07-2ac9-4166-b695-a0acc28f047a", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4417,7 +4417,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"Designer #1\",\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 \"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", + "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\": \"hourly\",\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" @@ -4449,7 +4449,7 @@ { "listen": "test", "script": { - "id": "7dd20ad6-cdef-4729-930f-c60cd08916b1", + "id": "7600ff0d-60a9-4eac-b962-783d12ec6528", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4474,7 +4474,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"Front-End Developer #2\",\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\": \"hourly\",\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", + "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\": \"hourly\",\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" @@ -4499,7 +4499,7 @@ { "listen": "test", "script": { - "id": "0de7c3ec-f9bd-439a-a48b-536571e8299e", + "id": "d4c844ea-c78b-4cad-b8d0-f91d1ef19bd6", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4549,7 +4549,7 @@ { "listen": "test", "script": { - "id": "1c12c1ce-9c9c-43ef-bbdb-afd2b51b0dd4", + "id": "25cd6303-d5b8-4c78-b793-fbe85768d68e", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4599,7 +4599,7 @@ { "listen": "test", "script": { - "id": "4fa51760-a365-4539-b482-9983bcf7f02c", + "id": "6736cab7-df48-4af5-87be-0aee6416d75d", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4645,7 +4645,7 @@ { "listen": "test", "script": { - "id": "7bfe4379-84a7-43c9-a3d0-34d7b9ae7d01", + "id": "4b912181-560a-4187-b230-440de69d4a74", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4691,7 +4691,7 @@ { "listen": "test", "script": { - "id": "b59ce584-58f3-47c9-a909-fa6778f418f5", + "id": "a7d5916a-6984-466a-a72c-59d767d1fb1d", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4737,7 +4737,7 @@ { "listen": "test", "script": { - "id": "6d0807c5-edfc-480e-bd2b-2c94c2ec8f07", + "id": "26560e50-5fc7-47fc-a9dc-88052e65b04e", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4783,7 +4783,7 @@ { "listen": "test", "script": { - "id": "7f9ca91a-c2ae-4616-a8e2-0d41b39a4559", + "id": "e22ffd91-332d-47f8-a1ae-add1b8e528f4", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4829,7 +4829,7 @@ { "listen": "test", "script": { - "id": "d4122d98-02c3-4152-b3a2-6a9f12d2aca4", + "id": "0e54787d-a531-4784-a3e9-15253ac203e0", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4875,7 +4875,7 @@ { "listen": "test", "script": { - "id": "32b361aa-0011-49a1-9a18-4796e1660bdc", + "id": "9ca4c42f-aa60-43c0-8865-3759642e775e", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4921,7 +4921,7 @@ { "listen": "test", "script": { - "id": "baa0558e-c74a-4667-979c-d3e6fa3ea2aa", + "id": "6f75c0bb-c0b1-4eab-8949-c191ec1b304b", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4967,7 +4967,7 @@ { "listen": "test", "script": { - "id": "466003be-222a-4800-b490-e7c7498a1eb7", + "id": "95c4b4a8-c260-4675-a7ff-b8a35348ad80", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5014,7 +5014,7 @@ { "listen": "test", "script": { - "id": "e53cea2d-d0f4-42cb-ac73-39e6b324b7c1", + "id": "6f7cc660-bb1a-4c43-a29a-11f12fbfb5c9", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5061,7 +5061,7 @@ { "listen": "test", "script": { - "id": "86bb9e58-8770-4afe-928d-95b9922224e6", + "id": "bfe73179-6098-41cf-bebc-d7385d57d478", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5115,7 +5115,7 @@ { "listen": "test", "script": { - "id": "5b507df6-d85a-43dc-a32a-8c6988cfb492", + "id": "41e6556a-11e4-40bb-be17-41d2b286881e", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5140,7 +5140,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"Back-End Developer #3\",\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\": \"hourly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": []\r\n}\r\n", + "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\": \"hourly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": []\r\n}\r\n", "options": { "raw": { "language": "json" @@ -5165,7 +5165,7 @@ { "listen": "test", "script": { - "id": "fc6d08e5-03b5-4edc-9cec-d39b70930c19", + "id": "ea9cc291-3382-46bc-b30d-16d19e334776", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5211,7 +5211,7 @@ { "listen": "test", "script": { - "id": "718d4b34-b642-4132-af76-3c7e338c8edc", + "id": "bf84527d-be67-4aba-a24b-4669d75c8644", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5257,7 +5257,7 @@ { "listen": "test", "script": { - "id": "7498ab0a-d6a2-4581-bc57-203c3614e59e", + "id": "d3c18fa5-01a3-42d6-b84c-a97a31c1ceca", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5303,7 +5303,7 @@ { "listen": "test", "script": { - "id": "8d350c13-b63c-4122-8420-590109723f23", + "id": "76ebfb97-90a6-45f6-a0d4-402cbe77a5a8", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5349,7 +5349,7 @@ { "listen": "test", "script": { - "id": "4b52d98d-3236-46f1-8a62-ec71bfa17db3", + "id": "23c32a83-f20c-4a70-a33d-94eb49468d70", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5395,7 +5395,7 @@ { "listen": "test", "script": { - "id": "9aa8a01a-ebee-4641-bd59-e31a89e41002", + "id": "02c6f86d-e2a6-4b32-85d8-753c2ce40ecf", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5441,7 +5441,7 @@ { "listen": "test", "script": { - "id": "b8df1a4f-4bd8-425b-8a50-8a31042b3fa7", + "id": "95933381-82e4-40ec-bbc3-0f888863793c", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5487,7 +5487,7 @@ { "listen": "test", "script": { - "id": "aebacb9d-9e2b-419d-9f83-16fb8fac80d0", + "id": "17e1204b-7282-47d6-9e5c-f3efa268d69d", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5533,7 +5533,7 @@ { "listen": "test", "script": { - "id": "2db8e8e3-3f73-49e2-8c7b-203593ecd257", + "id": "1fb3860d-bfd3-42fe-b1cb-e3aec43a7068", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5579,7 +5579,7 @@ { "listen": "test", "script": { - "id": "eef44eaa-a541-454f-8e35-029e256719f4", + "id": "65e40a53-7ab1-4295-b55b-67913c66c642", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5625,7 +5625,7 @@ { "listen": "test", "script": { - "id": "3eddf21c-d9b1-4248-8baf-9185df59931a", + "id": "5f2d37dd-94a5-4ff0-b6dd-ba285f820a62", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5675,7 +5675,7 @@ { "listen": "test", "script": { - "id": "f5bc861f-dae5-49b6-b0e5-2fab8900f348", + "id": "012da7ca-70b0-474c-9478-7d5f0896c5ee", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5725,7 +5725,7 @@ { "listen": "test", "script": { - "id": "746bedf6-a9c4-40e0-811b-7d940757c87f", + "id": "a802d37f-e1e3-4c28-98f8-f065dcc91c12", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5775,7 +5775,7 @@ { "listen": "test", "script": { - "id": "ffe14de5-ec63-4c1b-b8c8-9d3713283e67", + "id": "23c93c49-59af-4193-bd24-ed7730ac801d", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5825,7 +5825,7 @@ { "listen": "test", "script": { - "id": "3bf5bac7-ebb8-40b2-a326-e2d3da8c0a3b", + "id": "955cc007-f31f-4ed4-93a7-54c0efd1e0cb", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5875,7 +5875,7 @@ { "listen": "test", "script": { - "id": "d5222da2-57f9-4a63-b3ba-8cf949628ad2", + "id": "496e1faf-3ecf-47db-8b9a-56b08958164d", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5925,7 +5925,7 @@ { "listen": "test", "script": { - "id": "26035f48-5dcc-4879-b5cc-cff68282ca07", + "id": "5696cc95-b1f3-4ef0-88d4-cd2b6f46a7ec", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5975,7 +5975,7 @@ { "listen": "test", "script": { - "id": "f3c58ef3-dc1a-402b-a496-49255284b270", + "id": "85b2f034-a66b-45bb-b6c9-db95e77a08f8", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6025,7 +6025,7 @@ { "listen": "test", "script": { - "id": "6f0a8185-58ec-47f3-8c96-d2a88ff4a5bb", + "id": "dcae5aff-6734-4192-9abd-59b91c62f78b", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6075,7 +6075,7 @@ { "listen": "test", "script": { - "id": "e09b2898-7ee6-4abf-8dd7-95964a05ac19", + "id": "002e4a7e-4d0f-48f6-95ee-e3daf81431aa", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6125,7 +6125,7 @@ { "listen": "test", "script": { - "id": "19db0df8-46b3-4642-9c57-a3593bc9e011", + "id": "7791a3df-da95-440e-8b59-91dc7918fb9e", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6172,7 +6172,7 @@ { "listen": "test", "script": { - "id": "6aa34685-b1fa-430f-9242-c6700a17422b", + "id": "2c44579b-d9d3-405b-b265-ea73c35128ed", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6219,7 +6219,7 @@ { "listen": "test", "script": { - "id": "3e8cfe28-fe2d-4db1-8e6b-3621c84fedea", + "id": "49ab91cd-f5d4-44a9-823c-7980d8d8e896", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6266,7 +6266,7 @@ { "listen": "test", "script": { - "id": "d80f6e76-7a0c-466d-90d5-a7c9a0049a5e", + "id": "ba45ce14-076d-4bc6-8e95-4bd7db32a9bc", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6313,7 +6313,7 @@ { "listen": "test", "script": { - "id": "9f2100e6-4e66-48d0-b0fe-247979d63ad1", + "id": "3a57e69b-a02c-4cca-b225-11d7fa4e780d", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6360,7 +6360,7 @@ { "listen": "test", "script": { - "id": "7ce25ebd-d9be-4a01-adbf-19387db61f75", + "id": "da3d9d7d-fd9a-41de-9378-840e34f01d8d", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6407,7 +6407,7 @@ { "listen": "test", "script": { - "id": "453678c7-9ebc-4599-b0b3-223b89cc5e26", + "id": "67d7211b-2d23-47e0-8fad-b9725221c17e", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6454,7 +6454,7 @@ { "listen": "test", "script": { - "id": "427d92c9-d68b-4da2-84c2-546cec1ef34e", + "id": "124fe3ee-0314-4da3-b564-da848d11d1a6", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6501,7 +6501,7 @@ { "listen": "test", "script": { - "id": "128712e4-9d75-42f3-8a3f-68afc2cdfc7d", + "id": "fd8103a8-3369-429d-8ba0-a46c3b7b1f04", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6548,7 +6548,7 @@ { "listen": "test", "script": { - "id": "54199830-cf4f-4cb4-bc21-12c5e6c144cc", + "id": "cbc8fa49-6f36-461b-b1a9-70dd3b82572e", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6595,7 +6595,7 @@ { "listen": "test", "script": { - "id": "226ceac8-1870-44f1-bde8-4664640cf511", + "id": "ace9e189-c5f8-4eab-931b-3714f9e37260", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6649,7 +6649,7 @@ { "listen": "test", "script": { - "id": "295d310b-76e9-4fc2-8fde-cb3267dc5e14", + "id": "c7fb7228-ca43-4cef-804a-23c25e9df21e", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6674,7 +6674,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"QA #4\",\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\": \"hourly\",\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", + "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\": \"hourly\",\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" @@ -6699,7 +6699,7 @@ { "listen": "test", "script": { - "id": "b0c2fd5b-7d45-4b48-a8f7-181897c4be85", + "id": "67892217-b9e9-4b20-947d-df49d8a0f855", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6753,7 +6753,7 @@ { "listen": "test", "script": { - "id": "a728bdb2-1fa0-4075-ba1f-af3e7fbf96a9", + "id": "db632f9d-a83b-42f7-861b-da3ded160f45", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6778,7 +6778,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"externalId\": \"0\",\r\n \"description\": \"Data-Scientist #5\",\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\": \"hourly\",\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", + "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\": \"hourly\",\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" @@ -6803,7 +6803,7 @@ { "listen": "test", "script": { - "id": "caedca49-bc10-457c-9aa9-106cfa1e8625", + "id": "73d2a47b-47d8-4681-b9dc-905d987b4ca9", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", From 931896128a834aa45756dfbf5448ae4c3fb31b85 Mon Sep 17 00:00:00 2001 From: maxceem Date: Thu, 10 Dec 2020 12:24:32 +0200 Subject: [PATCH 23/26] chore: deploy only "dev" branch to DEV env --- .circleci/config.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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. From df59e389b4c0fd34468bc724e626694b2b39588e Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Tue, 15 Dec 2020 00:18:26 +0800 Subject: [PATCH 24/26] add input checks of jobId and userId --- docs/swagger.yaml | 12 ++++++++ src/common/helper.js | 40 +++++++++++++++++++++++++- src/services/JobCandidateService.js | 5 ++++ src/services/ResourceBookingService.js | 9 ++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/docs/swagger.yaml b/docs/swagger.yaml index a35dc19b..0ccbaa43 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -499,6 +499,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: @@ -898,6 +904,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: diff --git a/src/common/helper.js b/src/common/helper.js index be8aae35..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 = { @@ -529,6 +531,40 @@ async function ensureUbhanUserId (currentUser) { } } +/** + * 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, @@ -553,5 +589,7 @@ module.exports = { getMembers, getProjectById, getSkillById, - getUserSkill + getUserSkill, + ensureJobById, + ensureUserById } diff --git a/src/services/JobCandidateService.js b/src/services/JobCandidateService.js index 3e49f78d..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) @@ -127,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) } diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index cf6a74f9..0554ab56 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -73,6 +73,11 @@ getResourceBooking.schema = Joi.object().keys({ * @returns {Object} the created resourceBooking */ async function createResourceBooking (currentUser, resourceBooking) { + 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) { @@ -186,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) } From 799ab707e507a7419673ec88ae73d672196794e6 Mon Sep 17 00:00:00 2001 From: imcaizheng Date: Tue, 15 Dec 2020 07:02:46 +0800 Subject: [PATCH 25/26] fix function `_getAssignedResourceBooking()` --- ...coder-bookings-api.postman_collection.json | 153 +++++++++--------- docs/swagger.yaml | 6 + src/services/ResourceBookingService.js | 46 +++++- src/services/TeamService.js | 19 +-- 4 files changed, 135 insertions(+), 89 deletions(-) diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 113b823a..445f1789 100644 --- a/docs/Topcoder-bookings-api.postman_collection.json +++ b/docs/Topcoder-bookings-api.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "5d74e7a7-d744-4176-994a-62a8ac68efef", + "_postman_id": "37d3b6c4-bd34-4219-bd39-d56264e3a3b8", "name": "Topcoder-bookings-api", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, @@ -14,7 +14,7 @@ { "listen": "test", "script": { - "id": "eede316e-3a6b-456a-aa23-18a058e9ea49", + "id": "1b2e6f1f-825c-4bd0-b7d9-cb6b300fe3a7", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -59,7 +59,7 @@ { "listen": "test", "script": { - "id": "e400497c-7e5c-43e1-8402-d21e8dd5a903", + "id": "762aaf85-cd76-4c2d-ace8-abe2d11cc03c", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobIdCreatedByM2M\",data.id);" @@ -104,7 +104,7 @@ { "listen": "test", "script": { - "id": "d835a72e-cebb-4a22-8186-838c6a427a6c", + "id": "d2480c94-19e2-4f9d-81d7-4ea8f5af6ded", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -149,7 +149,7 @@ { "listen": "test", "script": { - "id": "f9889f54-be41-49cf-94d4-a4f39043ee41", + "id": "c1832f81-34c7-4d37-960e-69a15e2d5689", "exec": [ "var data = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" @@ -194,7 +194,7 @@ { "listen": "test", "script": { - "id": "a79f30e7-6491-483d-b016-a6ff9a0cd0b3", + "id": "5950c660-27ba-4594-913e-cf520be9f698", "exec": [ "" ], @@ -238,7 +238,7 @@ { "listen": "test", "script": { - "id": "d0a3307a-ad6a-4123-a1ec-dd0a30fc8b6c", + "id": "927a494c-9a6c-475f-85da-ab902bb754eb", "exec": [ "" ], @@ -982,7 +982,7 @@ { "listen": "test", "script": { - "id": "1cd415d8-f6e3-43d9-812d-68fe3dc5a707", + "id": "55200ddd-727e-40e0-bf14-4bdc71a1b308", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1227,7 +1227,7 @@ { "listen": "test", "script": { - "id": "809d595d-b657-4527-90fa-c9396cf9a0ce", + "id": "79d4bdd7-a294-4302-a253-14de0f1cb5ef", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1472,7 +1472,7 @@ { "listen": "test", "script": { - "id": "578a12d8-13d7-4557-9e7b-8958ba75191e", + "id": "87ae5a1d-6a2d-4d54-8b15-0b655b26397f", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1591,7 +1591,7 @@ { "listen": "test", "script": { - "id": "df26ced2-6c95-4833-9c2e-db07ccb43d90", + "id": "9341ed82-6439-4b25-b3ee-6e68b686d56a", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1636,7 +1636,7 @@ { "listen": "test", "script": { - "id": "51ac0814-9cbb-4b5a-81fc-9fa9e8f82131", + "id": "415d5b9c-4670-4bb7-9741-e4e0edeb5938", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateIdCreatedByM2M\",data.id);" @@ -1681,7 +1681,7 @@ { "listen": "test", "script": { - "id": "e2482a20-1719-4791-ae49-7c2f052510c5", + "id": "f9c06c94-e853-4023-88ec-631853ff4ac5", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1726,7 +1726,7 @@ { "listen": "test", "script": { - "id": "7cb7e30a-5afa-469d-bb58-6eec4f51d1c4", + "id": "2cfc4c43-d085-4bfd-9cdb-230c178de1da", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1771,7 +1771,7 @@ { "listen": "test", "script": { - "id": "373fb1e4-2f3c-4182-9f8f-342e62be61a9", + "id": "995492fd-7ced-4e2d-bc7c-00cf2a59bd0b", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1816,7 +1816,7 @@ { "listen": "test", "script": { - "id": "a79dc990-c63d-442a-9b33-9c2fd70d8391", + "id": "49d67b90-a9d6-49bc-b7c6-29abcade6542", "exec": [ "" ], @@ -2816,7 +2816,7 @@ { "listen": "test", "script": { - "id": "936361be-5be1-47b1-b2e8-453e67302af3", + "id": "94a35722-0d8d-47c2-a784-97efc41bf533", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2861,7 +2861,7 @@ { "listen": "test", "script": { - "id": "eb606efa-595d-466f-b41d-8a6d14f5f160", + "id": "7fbc1bd8-fb7f-408a-9c19-1e77233307cc", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingIdCreatedByM2M\",data.id);" @@ -2906,7 +2906,7 @@ { "listen": "test", "script": { - "id": "177053c5-325e-4663-9918-afba02fd09f3", + "id": "c9823d26-249e-486e-985f-8d301690f846", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2951,7 +2951,7 @@ { "listen": "test", "script": { - "id": "5a42e489-1d61-486a-b5ac-4cfd24950338", + "id": "8a9130a3-990b-4b2e-a62b-a632d5a23c1a", "exec": [ "" ], @@ -2995,7 +2995,7 @@ { "listen": "test", "script": { - "id": "25fd464b-ef8b-45b7-ad51-9350469d7e8e", + "id": "b7d9fde8-cfbf-4ec8-a79e-d4729c081054", "exec": [ "" ], @@ -3039,7 +3039,7 @@ { "listen": "test", "script": { - "id": "73138739-2706-4dfa-8ded-7e74de85962e", + "id": "53b7c5a6-b445-45ab-a1a8-95a65b4c6ff6", "exec": [ "" ], @@ -3262,6 +3262,11 @@ "key": "status", "value": "sourcing", "disabled": true + }, + { + "key": "projectIds", + "value": "111, 16705", + "disabled": true } ] } @@ -4318,7 +4323,7 @@ { "listen": "test", "script": { - "id": "2066b7ec-8e67-4dee-b6bf-d39e780af162", + "id": "95ff39b1-a4af-467c-a4db-f6e3bae20ac6", "exec": [ "var data = JSON.parse(responseBody);", "", @@ -4392,7 +4397,7 @@ { "listen": "test", "script": { - "id": "b580af07-2ac9-4166-b695-a0acc28f047a", + "id": "d940642d-4fe5-4163-af08-c1af0f6f6a62", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4449,7 +4454,7 @@ { "listen": "test", "script": { - "id": "7600ff0d-60a9-4eac-b962-783d12ec6528", + "id": "85f2c365-809d-4a18-92a8-e75c3b585065", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4499,7 +4504,7 @@ { "listen": "test", "script": { - "id": "d4c844ea-c78b-4cad-b8d0-f91d1ef19bd6", + "id": "934eb335-db8f-46de-ac7f-28e9c18ba17b", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4549,7 +4554,7 @@ { "listen": "test", "script": { - "id": "25cd6303-d5b8-4c78-b793-fbe85768d68e", + "id": "61a79684-6850-4462-8bcc-919e5d5a4ddc", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4599,7 +4604,7 @@ { "listen": "test", "script": { - "id": "6736cab7-df48-4af5-87be-0aee6416d75d", + "id": "895608f9-7c90-451b-8a11-e62d878a35be", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4645,7 +4650,7 @@ { "listen": "test", "script": { - "id": "4b912181-560a-4187-b230-440de69d4a74", + "id": "fa39e460-2720-40a6-85e8-17f33c9f59c4", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4691,7 +4696,7 @@ { "listen": "test", "script": { - "id": "a7d5916a-6984-466a-a72c-59d767d1fb1d", + "id": "1f9b6a06-15f4-4c02-be41-96e0a6a621d8", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4737,7 +4742,7 @@ { "listen": "test", "script": { - "id": "26560e50-5fc7-47fc-a9dc-88052e65b04e", + "id": "f7e96a2d-2237-4c44-81aa-7ee6e5d70f57", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4783,7 +4788,7 @@ { "listen": "test", "script": { - "id": "e22ffd91-332d-47f8-a1ae-add1b8e528f4", + "id": "d5317050-01e8-4ae7-b42e-875b99e549ec", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4829,7 +4834,7 @@ { "listen": "test", "script": { - "id": "0e54787d-a531-4784-a3e9-15253ac203e0", + "id": "5a1b32ba-240e-4b04-bdd7-5918cf78828b", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4875,7 +4880,7 @@ { "listen": "test", "script": { - "id": "9ca4c42f-aa60-43c0-8865-3759642e775e", + "id": "1c8b58dd-c509-46f8-875e-0b4a3fcc8061", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4921,7 +4926,7 @@ { "listen": "test", "script": { - "id": "6f75c0bb-c0b1-4eab-8949-c191ec1b304b", + "id": "aa6cf8f8-f245-4c3c-9be1-9ea45bc26e55", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4967,7 +4972,7 @@ { "listen": "test", "script": { - "id": "95c4b4a8-c260-4675-a7ff-b8a35348ad80", + "id": "9638d278-99a1-4ee4-b4d0-6685a9cc74fe", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5014,7 +5019,7 @@ { "listen": "test", "script": { - "id": "6f7cc660-bb1a-4c43-a29a-11f12fbfb5c9", + "id": "873472f5-05bf-43b4-9b07-f4af0c6d4915", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5061,7 +5066,7 @@ { "listen": "test", "script": { - "id": "bfe73179-6098-41cf-bebc-d7385d57d478", + "id": "771e8bea-6fa4-4fa0-90f1-2ca234828350", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5115,7 +5120,7 @@ { "listen": "test", "script": { - "id": "41e6556a-11e4-40bb-be17-41d2b286881e", + "id": "a78e2dc4-5d7f-4924-839c-e8091aad22ec", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5165,7 +5170,7 @@ { "listen": "test", "script": { - "id": "ea9cc291-3382-46bc-b30d-16d19e334776", + "id": "eae48594-813b-4503-abba-070e364a80ba", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5211,7 +5216,7 @@ { "listen": "test", "script": { - "id": "bf84527d-be67-4aba-a24b-4669d75c8644", + "id": "16fcc254-17da-49a5-80a3-ce31102bf706", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5257,7 +5262,7 @@ { "listen": "test", "script": { - "id": "d3c18fa5-01a3-42d6-b84c-a97a31c1ceca", + "id": "6cb0885a-d738-4ac7-854e-21bd41f44842", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5303,7 +5308,7 @@ { "listen": "test", "script": { - "id": "76ebfb97-90a6-45f6-a0d4-402cbe77a5a8", + "id": "ac5fb0d6-21ef-4738-befd-9d2f6e66e584", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5349,7 +5354,7 @@ { "listen": "test", "script": { - "id": "23c32a83-f20c-4a70-a33d-94eb49468d70", + "id": "2ef7ac60-3a4b-4942-b375-2b88650f7c96", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5395,7 +5400,7 @@ { "listen": "test", "script": { - "id": "02c6f86d-e2a6-4b32-85d8-753c2ce40ecf", + "id": "8a711f51-b4bb-4887-9fcf-b801a04c6c91", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5441,7 +5446,7 @@ { "listen": "test", "script": { - "id": "95933381-82e4-40ec-bbc3-0f888863793c", + "id": "37c04066-59c3-47af-ad7a-1e36c9094fa3", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5487,7 +5492,7 @@ { "listen": "test", "script": { - "id": "17e1204b-7282-47d6-9e5c-f3efa268d69d", + "id": "0afd9ed3-96c2-4f23-9d92-1b32c3e1755c", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5533,7 +5538,7 @@ { "listen": "test", "script": { - "id": "1fb3860d-bfd3-42fe-b1cb-e3aec43a7068", + "id": "5da6b28e-4b56-435d-a210-0017cc7be308", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5579,7 +5584,7 @@ { "listen": "test", "script": { - "id": "65e40a53-7ab1-4295-b55b-67913c66c642", + "id": "46dee70b-402b-4357-9ff7-3df818187e37", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5625,7 +5630,7 @@ { "listen": "test", "script": { - "id": "5f2d37dd-94a5-4ff0-b6dd-ba285f820a62", + "id": "87de944c-a2b2-4d85-a22e-3c8547925d58", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5675,7 +5680,7 @@ { "listen": "test", "script": { - "id": "012da7ca-70b0-474c-9478-7d5f0896c5ee", + "id": "f86cf427-6864-47a5-85c1-bbd9ccd3f05d", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5725,7 +5730,7 @@ { "listen": "test", "script": { - "id": "a802d37f-e1e3-4c28-98f8-f065dcc91c12", + "id": "9e5dbc13-7177-49f3-bee5-5edfa6707682", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5775,7 +5780,7 @@ { "listen": "test", "script": { - "id": "23c93c49-59af-4193-bd24-ed7730ac801d", + "id": "59db9e12-5d7a-4696-8ea2-3814a1f7628f", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5825,7 +5830,7 @@ { "listen": "test", "script": { - "id": "955cc007-f31f-4ed4-93a7-54c0efd1e0cb", + "id": "964d6667-4ee7-4c7d-a160-193763e75efa", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5875,7 +5880,7 @@ { "listen": "test", "script": { - "id": "496e1faf-3ecf-47db-8b9a-56b08958164d", + "id": "1471ca31-c834-486a-b6b5-ebfbd6cff01e", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5925,7 +5930,7 @@ { "listen": "test", "script": { - "id": "5696cc95-b1f3-4ef0-88d4-cd2b6f46a7ec", + "id": "7d90244e-0b28-4cc7-bcbb-a0aa6112f203", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5975,7 +5980,7 @@ { "listen": "test", "script": { - "id": "85b2f034-a66b-45bb-b6c9-db95e77a08f8", + "id": "28348059-186e-4c7b-ac40-b966999907af", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6025,7 +6030,7 @@ { "listen": "test", "script": { - "id": "dcae5aff-6734-4192-9abd-59b91c62f78b", + "id": "e0b243ca-1b31-4619-836f-9d5c8896d8cf", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6075,7 +6080,7 @@ { "listen": "test", "script": { - "id": "002e4a7e-4d0f-48f6-95ee-e3daf81431aa", + "id": "9d5d7c9e-3c85-4c68-8906-22200b1e653a", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6125,7 +6130,7 @@ { "listen": "test", "script": { - "id": "7791a3df-da95-440e-8b59-91dc7918fb9e", + "id": "e7b2b625-81ff-4c21-9a41-0db5ab0d102c", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6172,7 +6177,7 @@ { "listen": "test", "script": { - "id": "2c44579b-d9d3-405b-b265-ea73c35128ed", + "id": "29389fdd-08e2-4a69-be29-4c0346401322", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6219,7 +6224,7 @@ { "listen": "test", "script": { - "id": "49ab91cd-f5d4-44a9-823c-7980d8d8e896", + "id": "cdf1871e-ecea-4148-814b-dc585578fa77", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6266,7 +6271,7 @@ { "listen": "test", "script": { - "id": "ba45ce14-076d-4bc6-8e95-4bd7db32a9bc", + "id": "69154f22-4c76-4e74-ba9d-5738fc77701c", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6313,7 +6318,7 @@ { "listen": "test", "script": { - "id": "3a57e69b-a02c-4cca-b225-11d7fa4e780d", + "id": "6959f008-3278-4a5f-9751-ca5fa95d6611", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6360,7 +6365,7 @@ { "listen": "test", "script": { - "id": "da3d9d7d-fd9a-41de-9378-840e34f01d8d", + "id": "3201f89a-6383-4beb-8952-e81307a735cd", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6407,7 +6412,7 @@ { "listen": "test", "script": { - "id": "67d7211b-2d23-47e0-8fad-b9725221c17e", + "id": "1aea95ac-5586-44f7-a8ba-4c5cb5db96cd", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6454,7 +6459,7 @@ { "listen": "test", "script": { - "id": "124fe3ee-0314-4da3-b564-da848d11d1a6", + "id": "58fe8e95-7c6c-46c8-b851-5ef2cce629c0", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6501,7 +6506,7 @@ { "listen": "test", "script": { - "id": "fd8103a8-3369-429d-8ba0-a46c3b7b1f04", + "id": "a345e774-d2b6-4073-95f7-7f64aba91940", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6548,7 +6553,7 @@ { "listen": "test", "script": { - "id": "cbc8fa49-6f36-461b-b1a9-70dd3b82572e", + "id": "456b01cd-71a4-4106-97f8-031071cbd30e", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6595,7 +6600,7 @@ { "listen": "test", "script": { - "id": "ace9e189-c5f8-4eab-931b-3714f9e37260", + "id": "1ef3d1a5-d223-492a-bce1-b6a56686b63a", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6649,7 +6654,7 @@ { "listen": "test", "script": { - "id": "c7fb7228-ca43-4cef-804a-23c25e9df21e", + "id": "8e8310d3-9d9f-4740-9fcc-b0453639f618", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6699,7 +6704,7 @@ { "listen": "test", "script": { - "id": "67892217-b9e9-4b20-947d-df49d8a0f855", + "id": "7d530291-663e-4066-bc2e-1ba7d75932ce", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6753,7 +6758,7 @@ { "listen": "test", "script": { - "id": "db632f9d-a83b-42f7-861b-da3ded160f45", + "id": "cc1f0be0-698f-46e1-a704-54905c9dbd24", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6803,7 +6808,7 @@ { "listen": "test", "script": { - "id": "73d2a47b-47d8-4681-b9dc-905d987b4ca9", + "id": "43846e9f-cc3f-4922-9d90-ca6b4f9de0ad", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index a35dc19b..a1a28533 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -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 diff --git a/src/services/ResourceBookingService.js b/src/services/ResourceBookingService.js index cf6a74f9..95556dab 100644 --- a/src/services/ResourceBookingService.js +++ b/src/services/ResourceBookingService.js @@ -228,11 +228,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' @@ -266,6 +288,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) @@ -290,6 +320,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: { @@ -318,8 +351,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 64a3aad5..4fd3ab6a 100644 --- a/src/services/TeamService.js +++ b/src/services/TeamService.js @@ -11,16 +11,13 @@ 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 } @@ -88,9 +85,9 @@ 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 From 2f30696cfad2d17fd7f1899e65fe73184be66c94 Mon Sep 17 00:00:00 2001 From: maxceem Date: Tue, 15 Dec 2020 19:03:34 +0200 Subject: [PATCH 26/26] docs: improve demo data script --- ...coder-bookings-api.postman_collection.json | 324 +++++++++++++----- 1 file changed, 235 insertions(+), 89 deletions(-) diff --git a/docs/Topcoder-bookings-api.postman_collection.json b/docs/Topcoder-bookings-api.postman_collection.json index 445f1789..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": "37d3b6c4-bd34-4219-bd39-d56264e3a3b8", + "_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": "1b2e6f1f-825c-4bd0-b7d9-cb6b300fe3a7", + "id": "6e8082d1-0726-4ba9-b125-25618640ad00", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -59,7 +59,7 @@ { "listen": "test", "script": { - "id": "762aaf85-cd76-4c2d-ace8-abe2d11cc03c", + "id": "01d9b0de-698f-415a-ae3e-078ce7e4acc2", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobIdCreatedByM2M\",data.id);" @@ -104,7 +104,7 @@ { "listen": "test", "script": { - "id": "d2480c94-19e2-4f9d-81d7-4ea8f5af6ded", + "id": "cff233a7-6b62-4c99-994f-94bc4a6bfae6", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobId\",data.id);" @@ -149,7 +149,7 @@ { "listen": "test", "script": { - "id": "c1832f81-34c7-4d37-960e-69a15e2d5689", + "id": "93f5a652-d342-41ff-a43e-d63c3e6946a6", "exec": [ "var data = JSON.parse(responseBody);", "postman.setEnvironmentVariable(\"jobIdCreatedByMember\",data.id);" @@ -194,7 +194,7 @@ { "listen": "test", "script": { - "id": "5950c660-27ba-4594-913e-cf520be9f698", + "id": "33f7a08c-8368-45f8-900e-d28197f696ef", "exec": [ "" ], @@ -238,7 +238,7 @@ { "listen": "test", "script": { - "id": "927a494c-9a6c-475f-85da-ab902bb754eb", + "id": "f1956483-7e8f-4b29-b126-d2e86283edff", "exec": [ "" ], @@ -982,7 +982,7 @@ { "listen": "test", "script": { - "id": "55200ddd-727e-40e0-bf14-4bdc71a1b308", + "id": "7ce5a41a-da32-41be-b59e-547d7bc6f848", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1227,7 +1227,7 @@ { "listen": "test", "script": { - "id": "79d4bdd7-a294-4302-a253-14de0f1cb5ef", + "id": "df192d97-0f1d-4f56-9c60-fbb86fe1d694", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1472,7 +1472,7 @@ { "listen": "test", "script": { - "id": "87ae5a1d-6a2d-4d54-8b15-0b655b26397f", + "id": "840f8941-f568-41fb-ab30-e5263cf75c88", "exec": [ "pm.test(\"Status code is 403\", function () {", " pm.response.to.have.status(403);", @@ -1591,7 +1591,7 @@ { "listen": "test", "script": { - "id": "9341ed82-6439-4b25-b3ee-6e68b686d56a", + "id": "39076747-dd0e-4e63-99da-ca6caad846bc", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1636,7 +1636,7 @@ { "listen": "test", "script": { - "id": "415d5b9c-4670-4bb7-9741-e4e0edeb5938", + "id": "ef36a884-10a1-469d-8b29-ddc5a12e1b68", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateIdCreatedByM2M\",data.id);" @@ -1681,7 +1681,7 @@ { "listen": "test", "script": { - "id": "f9c06c94-e853-4023-88ec-631853ff4ac5", + "id": "11a00ab6-c16d-424c-a60a-33ecd365767e", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1726,7 +1726,7 @@ { "listen": "test", "script": { - "id": "2cfc4c43-d085-4bfd-9cdb-230c178de1da", + "id": "30e0500f-87b0-4a38-a6ea-5cb049a5091c", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1771,7 +1771,7 @@ { "listen": "test", "script": { - "id": "995492fd-7ced-4e2d-bc7c-00cf2a59bd0b", + "id": "26b82a3d-6818-4874-9ecb-7fdd70ecedb0", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"jobCandidateId\",data.id);" @@ -1816,7 +1816,7 @@ { "listen": "test", "script": { - "id": "49d67b90-a9d6-49bc-b7c6-29abcade6542", + "id": "e314f53d-cf06-49cd-a85c-566d1c38468f", "exec": [ "" ], @@ -2816,7 +2816,7 @@ { "listen": "test", "script": { - "id": "94a35722-0d8d-47c2-a784-97efc41bf533", + "id": "d852601c-f07c-45b9-a518-73b9bb54a3ba", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2861,7 +2861,7 @@ { "listen": "test", "script": { - "id": "7fbc1bd8-fb7f-408a-9c19-1e77233307cc", + "id": "b37a6e7c-2b7c-4d8b-b6dc-c06dcacb7819", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingIdCreatedByM2M\",data.id);" @@ -2906,7 +2906,7 @@ { "listen": "test", "script": { - "id": "c9823d26-249e-486e-985f-8d301690f846", + "id": "ea33fc97-6745-4f57-9084-ec03f8e45ba2", "exec": [ "var data = JSON.parse(responseBody);\r", "postman.setEnvironmentVariable(\"resourceBookingId\",data.id);" @@ -2951,7 +2951,7 @@ { "listen": "test", "script": { - "id": "8a9130a3-990b-4b2e-a62b-a632d5a23c1a", + "id": "eac01ab8-fd22-49a7-a4c4-67aae1d65c4e", "exec": [ "" ], @@ -2995,7 +2995,7 @@ { "listen": "test", "script": { - "id": "b7d9fde8-cfbf-4ec8-a79e-d4729c081054", + "id": "dccb2b70-08eb-4966-a631-6c3c53e51fd2", "exec": [ "" ], @@ -3039,7 +3039,7 @@ { "listen": "test", "script": { - "id": "53b7c5a6-b445-45ab-a1a8-95a65b4c6ff6", + "id": "81e5ed58-7cc8-49cb-8eed-d9094bd383d3", "exec": [ "" ], @@ -4323,7 +4323,7 @@ { "listen": "test", "script": { - "id": "95ff39b1-a4af-467c-a4db-f6e3bae20ac6", + "id": "e14b539f-7286-41df-9044-c2fd866fe89a", "exec": [ "var data = JSON.parse(responseBody);", "", @@ -4397,7 +4397,7 @@ { "listen": "test", "script": { - "id": "d940642d-4fe5-4163-af08-c1af0f6f6a62", + "id": "7ed1f685-3178-43f2-b4cc-92f3bdb26aab", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4422,7 +4422,7 @@ ], "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\": \"hourly\",\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", + "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" @@ -4454,7 +4454,7 @@ { "listen": "test", "script": { - "id": "85f2c365-809d-4a18-92a8-e75c3b585065", + "id": "55d76433-8a0b-4cb7-aed6-3a1f1a8a0c8d", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4479,7 +4479,7 @@ ], "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\": \"hourly\",\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", + "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" @@ -4504,7 +4504,7 @@ { "listen": "test", "script": { - "id": "934eb335-db8f-46de-ac7f-28e9c18ba17b", + "id": "066c4353-64b8-448f-aa72-1554e08b5afd", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4554,7 +4554,7 @@ { "listen": "test", "script": { - "id": "61a79684-6850-4462-8bcc-919e5d5a4ddc", + "id": "ba07a220-18ea-4b98-9ff5-4f2ef2a6f938", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -4604,7 +4604,7 @@ { "listen": "test", "script": { - "id": "895608f9-7c90-451b-8a11-e62d878a35be", + "id": "5d7758c9-3921-460c-9a07-cc42cef409c1", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4650,7 +4650,7 @@ { "listen": "test", "script": { - "id": "fa39e460-2720-40a6-85e8-17f33c9f59c4", + "id": "d8ea4ecb-0cb1-4573-92ae-d98374e27b9e", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4696,7 +4696,7 @@ { "listen": "test", "script": { - "id": "1f9b6a06-15f4-4c02-be41-96e0a6a621d8", + "id": "e0a12c48-cf1f-4c31-a021-4aca890c18bc", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4742,7 +4742,7 @@ { "listen": "test", "script": { - "id": "f7e96a2d-2237-4c44-81aa-7ee6e5d70f57", + "id": "5d865acc-250f-42b0-a4a2-7f8a07f0b9d4", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4788,7 +4788,7 @@ { "listen": "test", "script": { - "id": "d5317050-01e8-4ae7-b42e-875b99e549ec", + "id": "3c43394d-244c-47b1-9e2f-1e625cf7e420", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4834,7 +4834,7 @@ { "listen": "test", "script": { - "id": "5a1b32ba-240e-4b04-bdd7-5918cf78828b", + "id": "3d34dc24-9498-496f-a52b-ef788a1d66e7", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4880,7 +4880,7 @@ { "listen": "test", "script": { - "id": "1c8b58dd-c509-46f8-875e-0b4a3fcc8061", + "id": "22bff7e4-8927-444f-9a45-91494087a297", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4926,7 +4926,7 @@ { "listen": "test", "script": { - "id": "aa6cf8f8-f245-4c3c-9be1-9ea45bc26e55", + "id": "75b39c48-4aed-4100-9612-6db632b0da6c", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -4972,7 +4972,7 @@ { "listen": "test", "script": { - "id": "9638d278-99a1-4ee4-b4d0-6685a9cc74fe", + "id": "b3e10a61-151e-47d6-a4b0-47fde62c1142", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5019,7 +5019,7 @@ { "listen": "test", "script": { - "id": "873472f5-05bf-43b4-9b07-f4af0c6d4915", + "id": "87621008-82a1-48dd-b4ef-7c72e2a9c4c6", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5066,7 +5066,7 @@ { "listen": "test", "script": { - "id": "771e8bea-6fa4-4fa0-90f1-2ca234828350", + "id": "cffe697d-21b8-452d-be0f-f5fb7c9a5f95", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5120,7 +5120,7 @@ { "listen": "test", "script": { - "id": "a78e2dc4-5d7f-4924-839c-e8091aad22ec", + "id": "848a04c5-b3ae-4808-8993-e45ad2732827", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5145,7 +5145,7 @@ ], "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\": \"hourly\",\r\n \"workload\": \"full-time\",\r\n \"skills\": []\r\n}\r\n", + "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" @@ -5170,7 +5170,7 @@ { "listen": "test", "script": { - "id": "eae48594-813b-4503-abba-070e364a80ba", + "id": "e5cb331e-bef5-404d-8c10-3b418392b976", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5216,7 +5216,7 @@ { "listen": "test", "script": { - "id": "16fcc254-17da-49a5-80a3-ce31102bf706", + "id": "e0970502-16d8-401a-b68d-b4c93317303e", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5262,7 +5262,7 @@ { "listen": "test", "script": { - "id": "6cb0885a-d738-4ac7-854e-21bd41f44842", + "id": "d5096ca6-daaa-42dc-befd-743efd45c68a", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5308,7 +5308,7 @@ { "listen": "test", "script": { - "id": "ac5fb0d6-21ef-4738-befd-9d2f6e66e584", + "id": "d4c0f029-ef26-4674-a879-185a38f1a840", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5354,7 +5354,7 @@ { "listen": "test", "script": { - "id": "2ef7ac60-3a4b-4942-b375-2b88650f7c96", + "id": "a82c5644-ab0b-49c2-9630-778abd537e9d", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5400,7 +5400,7 @@ { "listen": "test", "script": { - "id": "8a711f51-b4bb-4887-9fcf-b801a04c6c91", + "id": "c033b550-5dc5-4a05-afb3-5ee5d65c7ebf", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5446,7 +5446,7 @@ { "listen": "test", "script": { - "id": "37c04066-59c3-47af-ad7a-1e36c9094fa3", + "id": "d791b733-89a7-432d-947f-8ec4bf3b187b", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5492,7 +5492,7 @@ { "listen": "test", "script": { - "id": "0afd9ed3-96c2-4f23-9d92-1b32c3e1755c", + "id": "d62edda6-69ff-4451-ae1a-9501c227c9ae", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5538,7 +5538,7 @@ { "listen": "test", "script": { - "id": "5da6b28e-4b56-435d-a210-0017cc7be308", + "id": "7aafa77e-41a1-416e-8a5e-31a0a2034fa7", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5584,7 +5584,7 @@ { "listen": "test", "script": { - "id": "46dee70b-402b-4357-9ff7-3df818187e37", + "id": "aaadf3af-06ab-49c3-9897-6f630c24429e", "exec": [ "pm.test(\"Successful POST request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -5630,7 +5630,7 @@ { "listen": "test", "script": { - "id": "87de944c-a2b2-4d85-a22e-3c8547925d58", + "id": "b92b7cab-0a20-446a-8f94-0a9b1185ffce", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5642,6 +5642,23 @@ ], "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": { @@ -5655,7 +5672,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId11}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -5680,7 +5697,7 @@ { "listen": "test", "script": { - "id": "f86cf427-6864-47a5-85c1-bbd9ccd3f05d", + "id": "4e6a7e74-6a2b-4b3e-8a7d-ad8d7a18fa3c", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5692,6 +5709,23 @@ ], "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": { @@ -5705,7 +5739,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId12}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -5730,7 +5764,7 @@ { "listen": "test", "script": { - "id": "9e5dbc13-7177-49f3-bee5-5edfa6707682", + "id": "cb63048c-f0ac-414b-802c-e7df4719b445", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5742,6 +5776,23 @@ ], "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": { @@ -5755,7 +5806,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId13}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -5780,7 +5831,7 @@ { "listen": "test", "script": { - "id": "59db9e12-5d7a-4696-8ea2-3814a1f7628f", + "id": "121a11f0-3efa-4b07-b515-be3fb414cd85", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5792,6 +5843,23 @@ ], "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": { @@ -5805,7 +5873,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId14}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -5830,7 +5898,7 @@ { "listen": "test", "script": { - "id": "964d6667-4ee7-4c7d-a160-193763e75efa", + "id": "92f5ab04-6878-448d-b89f-543b785f9829", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5842,6 +5910,23 @@ ], "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": { @@ -5855,7 +5940,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId15}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -5880,7 +5965,7 @@ { "listen": "test", "script": { - "id": "1471ca31-c834-486a-b6b5-ebfbd6cff01e", + "id": "d3d0593e-682c-4b76-acae-9d32dd134b7c", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5892,6 +5977,23 @@ ], "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": { @@ -5905,7 +6007,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId16}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -5930,7 +6032,7 @@ { "listen": "test", "script": { - "id": "7d90244e-0b28-4cc7-bcbb-a0aa6112f203", + "id": "738c34a4-3aa9-477b-a604-88e1edc2cb62", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5942,6 +6044,23 @@ ], "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": { @@ -5955,7 +6074,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId17}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -5980,7 +6099,7 @@ { "listen": "test", "script": { - "id": "28348059-186e-4c7b-ac40-b966999907af", + "id": "64f57590-1dc5-400d-888f-7efe71ea3dfd", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -5992,6 +6111,16 @@ ], "type": "text/javascript" } + }, + { + "listen": "prerequest", + "script": { + "id": "52dac9d1-adb8-4c2d-93f6-a5a7fb1a6d08", + "exec": [ + "" + ], + "type": "text/javascript" + } } ], "request": { @@ -6005,7 +6134,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId18}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -6030,7 +6159,7 @@ { "listen": "test", "script": { - "id": "e0b243ca-1b31-4619-836f-9d5c8896d8cf", + "id": "fc175290-c583-49e5-9ba8-5d94af9d9ea2", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6055,7 +6184,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"projectId\": {{projectId}},\r\n \"userId\": \"{{demoUserId19}}\",\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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -6080,7 +6209,7 @@ { "listen": "test", "script": { - "id": "9d5d7c9e-3c85-4c68-8906-22200b1e653a", + "id": "c056d309-c9da-4aad-8d84-32cb4d5659bf", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6092,6 +6221,23 @@ ], "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": { @@ -6105,7 +6251,7 @@ ], "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\": 13.23,\r\n \"customerRate\": 13,\r\n \"rateType\": \"hourly\"\r\n}", + "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" @@ -6130,7 +6276,7 @@ { "listen": "test", "script": { - "id": "e7b2b625-81ff-4c21-9a41-0db5ab0d102c", + "id": "9226322c-9ad3-4d0a-9e2d-cf2263bf355d", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6177,7 +6323,7 @@ { "listen": "test", "script": { - "id": "29389fdd-08e2-4a69-be29-4c0346401322", + "id": "2e39a592-6f51-4c96-8163-8c7987e1bb03", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6224,7 +6370,7 @@ { "listen": "test", "script": { - "id": "cdf1871e-ecea-4148-814b-dc585578fa77", + "id": "8ce1c231-81f5-401f-b016-7deea2b2c76b", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6271,7 +6417,7 @@ { "listen": "test", "script": { - "id": "69154f22-4c76-4e74-ba9d-5738fc77701c", + "id": "92eee318-1f47-49f5-86ae-e9bbe986c8e6", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6318,7 +6464,7 @@ { "listen": "test", "script": { - "id": "6959f008-3278-4a5f-9751-ca5fa95d6611", + "id": "08882fb4-35b0-4a75-a821-dc59a53a9d2b", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6365,7 +6511,7 @@ { "listen": "test", "script": { - "id": "3201f89a-6383-4beb-8952-e81307a735cd", + "id": "8e04c98e-59a5-4377-a35d-8b8521cf236b", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6412,7 +6558,7 @@ { "listen": "test", "script": { - "id": "1aea95ac-5586-44f7-a8ba-4c5cb5db96cd", + "id": "4ee12efc-0349-46ab-9a79-4f66aa551061", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6459,7 +6605,7 @@ { "listen": "test", "script": { - "id": "58fe8e95-7c6c-46c8-b851-5ef2cce629c0", + "id": "091ef060-7048-4b9c-996a-c8b6fe3e5705", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6506,7 +6652,7 @@ { "listen": "test", "script": { - "id": "a345e774-d2b6-4073-95f7-7f64aba91940", + "id": "85cc5231-9f1e-4dff-8a89-e4537aeaef8e", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6553,7 +6699,7 @@ { "listen": "test", "script": { - "id": "456b01cd-71a4-4106-97f8-031071cbd30e", + "id": "ff761b56-eacc-40d7-8ae5-52fb59aa5df0", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6600,7 +6746,7 @@ { "listen": "test", "script": { - "id": "1ef3d1a5-d223-492a-bce1-b6a56686b63a", + "id": "8a657df4-bc76-4afa-8464-0e03439e5fd5", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6654,7 +6800,7 @@ { "listen": "test", "script": { - "id": "8e8310d3-9d9f-4740-9fcc-b0453639f618", + "id": "6fea605c-e45d-4b74-8984-e026d800883c", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6679,7 +6825,7 @@ ], "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\": \"hourly\",\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", + "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" @@ -6704,7 +6850,7 @@ { "listen": "test", "script": { - "id": "7d530291-663e-4066-bc2e-1ba7d75932ce", + "id": "dea1c56f-d9f8-40dd-9137-7f2619ee96a0", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);", @@ -6758,7 +6904,7 @@ { "listen": "test", "script": { - "id": "cc1f0be0-698f-46e1-a704-54905c9dbd24", + "id": "66889f4d-32cf-40a7-8524-85e5e2ad5f67", "exec": [ "var data = JSON.parse(responseBody);\r", "\r", @@ -6783,7 +6929,7 @@ ], "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\": \"hourly\",\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", + "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" @@ -6808,7 +6954,7 @@ { "listen": "test", "script": { - "id": "43846e9f-cc3f-4922-9d90-ca6b4f9de0ad", + "id": "34e50784-298e-44ce-949a-380a3c015d3a", "exec": [ "pm.test(\"Successful PATCH request\", function () {", " pm.expect(pm.response.code).to.be.oneOf([200, 201, 202]);",