Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

My Gigs > Release of Profile Integration #140

Merged
merged 42 commits into from
Jun 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
1fde08a
refine the profile Update
Jun 21, 2021
ac43db4
fix profile API
Jun 22, 2021
505adcb
output from challenge: 30191400
Jun 22, 2021
7007b51
integration profile
Jun 22, 2021
faf08d0
remove dummy data finished
Jun 22, 2021
34a27ed
合并integration into integration-b
Jun 23, 2021
f4b46ec
enable update profile btn
Jun 23, 2021
64c9a50
Merge branch 'integration' into integration-b
Jun 23, 2021
bc9761b
ci:deploying profile integration
Jun 23, 2021
447d6bd
ci:fixing 122
Jun 23, 2021
cb31d3c
ci:redeploying
Jun 23, 2021
4c7657c
ci:fixing 129
Jun 24, 2021
7fe0f90
ci:availability change
Jun 24, 2021
b049aa4
fix lint
Jun 24, 2021
185a2dd
ci:fix130
Jun 25, 2021
2bced58
ci:issue-130
Jun 25, 2021
f25527e
ci:fix130
Jun 25, 2021
21e9acc
fix: issue 131
Jun 25, 2021
8fb9930
default empty for zip and stateCode
Jun 25, 2021
cffff54
Merge branch 'issues-130' into issues-131
Jun 25, 2021
6fe7884
ci:130-131deploying
Jun 25, 2021
04edc57
ci:fix130
Jun 25, 2021
7f59ff7
ci: fixing128
Jun 25, 2021
a6f684c
ci:fixing 134
Jun 25, 2021
3be1b3e
fix phone validation
Jun 26, 2021
bf6f5c0
fix trait add
Jun 26, 2021
bb7e21d
ci:post city data to rcrm
Jun 26, 2021
83b44cc
ci:fixing countryCodes
Jun 26, 2021
c131182
"ci:lint error"
Jun 26, 2021
cf61433
ci:fixing codes error
Jun 26, 2021
546ca74
ci:optional resume
Jun 26, 2021
02368bd
ci:fix 128
Jun 26, 2021
2b1b80f
ci:fixing minor
Jun 26, 2021
163cc63
ci:fixing all bugs
Jun 26, 2021
5d0bd35
clean up
Jun 27, 2021
692a38e
ci:merge with dev
Jun 27, 2021
4c4e0ac
clean up
Jun 27, 2021
79f2926
ci:resolving headers
Jun 27, 2021
3d8a0d7
ci:final deploy
Jun 27, 2021
4a3fe33
Merge pull request #139 from topcoder-platform/integration-b
sushilshinde Jun 28, 2021
4943ad8
ci: deploy on dev
sushilshinde Jun 28, 2021
1987028
Merge branch 'master' into dev
Jun 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ workflows:
branches:
only:
- dev
- fix-m2m-env-var

# Production builds are exectuted only on tagged commits to the
# master branch.
Expand Down
2 changes: 1 addition & 1 deletion config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
COMMUNITY_APP: "https://community-app.topcoder-dev.com",
PLATFORM_WEBSITE_URL: "https://platform.topcoder-dev.com",
},
RECRUIT_API: process.env.RECRUIT_API,
RECRUIT_API: "https://www.topcoder-dev.com",
// the server api base path
API_BASE_PATH: process.env.API_BASE_PATH || "/earn-app/api/my-gigs",
// the log level, default is 'debug'
Expand Down
1 change: 1 addition & 0 deletions config/development.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ module.exports = {
COMMUNITY_APP: "https://community-app.topcoder-dev.com",
PLATFORM_WEBSITE_URL: "https://platform.topcoder-dev.com",
},
RECRUIT_API: "https://www.topcoder-dev.com",
};
1 change: 1 addition & 0 deletions config/production.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ module.exports = {
COMMUNITY_APP: "https://community-app.topcoder.com",
PLATFORM_WEBSITE_URL: "https://platform.topcoder.com",
},
RECRUIT_API: "https://www.topcoder.com",
};
28 changes: 25 additions & 3 deletions src/actions/lookup.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,35 @@ async function checkIsLoggedIn() {
return service.checkIsLoggedIn();
}

async function getGigStatuses() {
return service.getGigStatuses();
/**
* Gets all the countries.
* @returns {Array} Array containing all countries
*/
async function getAllCountries() {
// fetch the first page to see how many more fetches are necessary to get all
const countries = await service.getPaginatedCountries();
const {
meta: { totalPages },
} = countries;

const pagesMissing = totalPages - 1;

// fetch the other pages.
const allPageResults = await Promise.all(
[...Array(pagesMissing > 0 ? pagesMissing : 0)].map((_, index) => {
const newPage = index + 2;

return service.getPaginatedCountries(newPage);
})
);

const newCountries = allPageResults.map((data) => data).flat();
return [...countries, ...newCountries];
}

export default createActions({
GET_TAGS: getTags,
GET_COMMUNITY_LIST: getCommunityList,
CHECK_IS_LOGGED_IN: checkIsLoggedIn,
GET_GIG_STATUSES: getGigStatuses,
GET_ALL_COUNTRIES: getAllCountries,
});
14 changes: 13 additions & 1 deletion src/api/app-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,19 @@ const authenticator = require("tc-core-library-js").middleware.jwtAuthenticator;
*/
module.exports = (app) => {
app.use(express.json());
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(
fileUpload({
limits: {
Expand Down
79 changes: 69 additions & 10 deletions src/api/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,26 @@ async function getMember(handle, query) {
return res.body;
}

/**
* Get member traits info
* @param {string} handle the handle of the user
* @param {string} query the query criteria
* @returns the object of member traitsdetails
*/
async function getMemberTraits(handle, query) {
const token = await getM2MToken();
const url = `${config.API.V5}/members/${handle}/traits`;
const res = await request
.get(url)
.query(query)
.set("Authorization", `Bearer ${token}`)
.set("Accept", "application/json");
localLogger.debug({
context: "getMemberTraits",
message: `response body: ${JSON.stringify(res.body)}`,
});
return res.body;
}
/**
* Update member details
* @param {string} handle the handle of the user
Expand All @@ -357,6 +377,28 @@ async function updateMember(currentUser, data) {
return res.body;
}

/**
* Update member traits
* @param {string} handle the handle of the user
* @param {object} data the data to be updated
* @return {object} the object of updated member details
*/
async function updateMemberTraits(currentUser, data) {
const token = currentUser.jwtToken;
const url = `${config.API.V5}/members/${currentUser.handle}/traits`;
const res = await request
.put(url)
.set("Authorization", token)
.set("Content-Type", "application/json")
.set("Accept", "application/json")
.send(data);
localLogger.debug({
context: "updateMemberTraits",
message: `response body: ${JSON.stringify(res.body)}`,
});
return res.body;
}

/**
* Get Recruit CRM profile details
* @param {object} currentUser the user who performs the operation
Expand All @@ -379,21 +421,36 @@ async function getRCRMProfile(currentUser) {
/**
* Update Recruit CRM profile details
* @param {object} currentUser the user who performs the operation
* @param {object} file the resume file
* @param {object} data the data to be updated
* @param {object} file the resume file
* @return {object} the returned object
*/
async function updateRCRMProfile(currentUser, file, data) {
async function updateRCRMProfile(currentUser, data, file) {
const token = currentUser.jwtToken;
const url = `${config.RECRUIT_API}/api/recruit/profile`;
const res = await request
.post(url)
.set("Authorization", token)
.set("Content-Type", "multipart/form-data")
.set("Accept", "application/json")
.field("phone", data.phone)
.field("availability", data.availability)
.attach("resume", file.data, file.name);
let res = null;
if (file) {
res = await request
.post(url)
.set("Authorization", token)
.set("Content-Type", "multipart/form-data")
.set("Accept", "application/json")
.field("phone", data.phone)
.field("availability", data.availability)
.field("city", data.city)
.field("countryName", data.countryName)
.attach("resume", file.data, file.name);
} else {
res = await request
.post(url)
.set("Authorization", token)
.set("Content-Type", "multipart/form-data")
.set("Accept", "application/json")
.field("phone", data.phone)
.field("availability", data.availability)
.field("city", data.city)
.field("countryName", data.countryName);
}
localLogger.debug({
context: "updateRCRMProfile",
message: `response body: ${JSON.stringify(res.body)}`,
Expand All @@ -412,7 +469,9 @@ module.exports = {
getJobCandidates,
getJobs,
getMember,
getMemberTraits,
updateMember,
updateMemberTraits,
getRCRMProfile,
updateRCRMProfile,
};
2 changes: 1 addition & 1 deletion src/api/controllers/ProfileController.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async function getMyProfile(req, res) {
* @param res the response
*/
async function updateMyProfile(req, res) {
await service.updateMyProfile(req.authUser, req.files, req.body);
await service.updateMyProfile(req.authUser, req.body, req.files);
res.status(204).end();
}

Expand Down
3 changes: 2 additions & 1 deletion src/api/mock-api/mock-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ app.use((req, res, next) => {

app.get("/api/recruit/profile", (req, res) => {
const result = {
hasProfile: false,
phone: "555-555-55-55",
resume: "https://resume.topcoder.com/1234567",
availibility: true,
availability: true,
};
res.status(200).json(result);
});
Expand Down
93 changes: 67 additions & 26 deletions src/api/services/ProfileService.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ async function getMyProfile(currentUser) {
email: _.get(member, "email", null),
city: _.get(member, "addresses[0].city", null),
country: _.get(member, "competitionCountryCode", null),
hasProfile: _.get(recruitProfile, "hasProfile", false),
phone: _.get(recruitProfile, "phone", null),
resume: _.get(recruitProfile, "resume", null),
availability: _.get(recruitProfile, "availibility", true),
availability: _.get(recruitProfile, "availability", true),
};
}

Expand All @@ -48,13 +49,13 @@ getMyProfile.schema = Joi.object()
* @param {object} currentUser the user who perform this operation.
* @param {object} data the data to be updated
*/
async function updateMyProfile(currentUser, files, data) {
async function updateMyProfile(currentUser, data, files) {
// we expect logged-in users
if (currentUser.isMachine) {
return;
}
// check if file was truncated
if (files.resume.truncated) {
if (files && files.resume.truncated) {
throw new errors.BadRequestError(
`Maximum allowed file size is ${config.MAX_ALLOWED_FILE_SIZE_MB} MB`
);
Expand All @@ -64,7 +65,7 @@ async function updateMyProfile(currentUser, files, data) {
`^.*\.(${_.join(config.ALLOWED_FILE_TYPES, "|")})$`,
"i"
);
if (!regex.test(files.resume.name)) {
if (files && !regex.test(files.resume.name)) {
throw new errors.BadRequestError(
`Allowed file types are: ${_.join(config.ALLOWED_FILE_TYPES, ",")}`
);
Expand All @@ -75,56 +76,96 @@ async function updateMyProfile(currentUser, files, data) {
"fields=addresses,competitionCountryCode,homeCountryCode"
);
const update = {};
let shouldUpdateTrait = false;
// update member data if city is different from existing one
if (_.get(member, "addresses[0].city") !== data.city) {
update.addresses = _.cloneDeep(member.addresses);
if (!_.isEmpty(update.addresses)) {
update.addresses[0].city = data.city;
delete update.addresses[0].createdAt;
delete update.addresses[0].updatedAt;
delete update.addresses[0].createdBy;
delete update.addresses[0].updatedBy;
update.addresses[0].streetAddr1 = update.addresses[0].streetAddr1
? update.addresses[0].streetAddr1
: " ";
update.addresses[0].streetAddr2 = update.addresses[0].streetAddr2
? update.addresses[0].streetAddr2
: " ";
update.addresses[0].type = update.addresses[0].type
? update.addresses[0].type
: "HOME";
update.addresses[0].stateCode = update.addresses[0].stateCode
? update.addresses[0].stateCode
: " ";
update.addresses[0].zip = update.addresses[0].zip
? update.addresses[0].zip
: " ";
} else {
update.addresses = [
{
city: data.city,
type: "HOME",
stateCode: " ",
zip: " ",
streetAddr1: " ",
streetAddr2: " ",
},
];
}
}
// update member data if competitionCountryCode is different from existing one
if (_.get(member, "competitionCountryCode") !== data.country) {
update.competitionCountryCode = data.country;
shouldUpdateTrait = true;
}
if (_.get(member, "homeCountryCode") !== data.country) {
update.homeCountryCode = data.country;
shouldUpdateTrait = true;
}
// avoid unnecessary api calls
if (!_.isEmpty(update)) {
await helper.updateMember(currentUser, update);
}
await helper.updateRCRMProfile(currentUser, files.resume, {
phone: data.phone,
availability: data.availability,
});
if (shouldUpdateTrait) {
const memberTraits = await helper.getMemberTraits(
currentUser.handle,
`traitIds=basic_info`
);
if (memberTraits && memberTraits.length) {
memberTraits[0]["traits"].data[0].country = data.countryName;
delete memberTraits[0].createdAt;
delete memberTraits[0].createdBy;
delete memberTraits[0].updatedAt;
delete memberTraits[0].updatedBy;
delete memberTraits[0].userId;
await helper.updateMemberTraits(currentUser, memberTraits);
}
}
await helper.updateRCRMProfile(
currentUser,
{
phone: data.phone,
availability: data.availability,
city: data.city,
countryName: data.countryName,
},
files && files.resume
);
}

updateMyProfile.schema = Joi.object()
.keys({
currentUser: Joi.object().required(),
files: Joi.object()
.keys({
resume: Joi.object().required(),
})
.required(),
data: Joi.object()
.keys({
city: Joi.string().required(),
country: Joi.string().required(),
phone: Joi.string().required(),
availability: Joi.boolean().required(),
})
.required(),
})
.required();
updateMyProfile.schema = Joi.object({
currentUser: Joi.object().required(),
data: Joi.object()
.keys({
city: Joi.string().required(),
country: Joi.string().required(),
countryName: Joi.string().required(),
phone: Joi.string().required(),
availability: Joi.boolean().required(),
})
.required(),
}).unknown();

module.exports = {
getMyProfile,
Expand Down
Loading