Skip to content

Commit 375b0a8

Browse files
authored
Get User Meeting Settings Endpoint (topcoder-platform#16)
* Get User Meeting Settings Endpoint Fixes topcoder-platform#9 Signed-off-by: Alessandro De Blasis <[email protected]> * Get User Meeting Settings Endpoint Fixes topcoder-platform#9 Signed-off-by: Alessandro De Blasis <[email protected]>
1 parent 5867e0e commit 375b0a8

14 files changed

+303
-44
lines changed

app-constants.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,13 @@ const Scopes = {
5858
CREATE_ROLE: 'create:taas-roles',
5959
UPDATE_ROLE: 'update:taas-roles',
6060
DELETE_ROLE: 'delete:taas-roles',
61-
ALL_ROLE: 'all:taas-roles'
61+
ALL_ROLE: 'all:taas-roles',
62+
// userMeetingSettings
63+
READ_USER_MEETING_SETTINGS: 'read:taas-userMeetingsSettings',
64+
CREATE_USER_MEETING_SETTINGS: 'create:taas-userMeetingsSettings',
65+
UPDATE_USER_MEETING_SETTINGS: 'update:taas-userMeetingsSettings',
66+
ALL_USER_MEETING_SETTINGS: 'all:taas-userMeetingsSettings'
67+
6268
}
6369

6470
// Interview related constants

config/default.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ module.exports = {
8282
ES_INDEX_RESOURCE_BOOKING: process.env.ES_INDEX_RESOURCE_BOOKING || 'resource_booking',
8383
// the role index
8484
ES_INDEX_ROLE: process.env.ES_INDEX_ROLE || 'role',
85+
// the userMeetingSettings index
86+
ES_INDEX_USER_MEETING_SETTINGS: process.env.ES_INDEX_USER_MEETING_SETTINGS || 'user_meeting_settings',
8587

8688
// the max bulk size in MB for ES indexing
8789
MAX_BULK_REQUEST_SIZE_MB: process.env.MAX_BULK_REQUEST_SIZE_MB || 20,

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"index:jobs": "node scripts/es/reIndexJobs.js",
1717
"index:job-candidates": "node scripts/es/reIndexJobCandidates.js",
1818
"index:resource-bookings": "node scripts/es/reIndexResourceBookings.js",
19+
"index:user-meeting-settings": "node scripts/es/reIndexUserMeetingSettings.js",
1920
"index:roles": "node scripts/es/reIndexRoles.js",
2021
"data:export": "node scripts/data/exportData.js",
2122
"data:import": "node scripts/data/importData.js",

scripts/es/createIndex.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ const indices = [
99
config.get('esConfig.ES_INDEX_JOB'),
1010
config.get('esConfig.ES_INDEX_JOB_CANDIDATE'),
1111
config.get('esConfig.ES_INDEX_RESOURCE_BOOKING'),
12-
config.get('esConfig.ES_INDEX_ROLE')
12+
config.get('esConfig.ES_INDEX_ROLE'),
13+
config.get('esConfig.ES_INDEX_USER_MEETING_SETTINGS')
1314
]
1415
const userPrompt = `WARNING: Are you sure want to create the following elasticsearch indices: ${indices}?`
1516

scripts/es/deleteIndex.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ const indices = [
99
config.get('esConfig.ES_INDEX_JOB'),
1010
config.get('esConfig.ES_INDEX_JOB_CANDIDATE'),
1111
config.get('esConfig.ES_INDEX_RESOURCE_BOOKING'),
12-
config.get('esConfig.ES_INDEX_ROLE')
12+
config.get('esConfig.ES_INDEX_ROLE'),
13+
config.get('esConfig.ES_INDEX_USER_MEETING_SETTINGS')
1314
]
1415
const userPrompt = `WARNING: this would remove existent data! Are you sure want to delete the following eleasticsearch indices: ${indices}?`
1516

scripts/es/reIndexAll.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ async function indexAll () {
3535
await helper.indexBulkDataToES(jobCandidateModelOpts, config.get('esConfig.ES_INDEX_JOB_CANDIDATE'), logger)
3636
await helper.indexBulkDataToES(resourceBookingModelOpts, config.get('esConfig.ES_INDEX_RESOURCE_BOOKING'), logger)
3737
await helper.indexBulkDataToES('Role', config.get('esConfig.ES_INDEX_ROLE'), logger)
38+
await helper.indexBulkDataToES('UserMeetingSettings', config.get('esConfig.ES_INDEX_USER_MEETING_SETTINGS'), logger)
3839
process.exit(0)
3940
} catch (err) {
4041
logger.logFullError(err, { component: 'indexAll' })
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Reindex UserMeetingSettings data in Elasticsearch using data from database
3+
*/
4+
const config = require('config')
5+
const logger = require('../../src/common/logger')
6+
const helper = require('../../src/common/helper')
7+
8+
const userId = helper.getParamFromCliArgs()
9+
const index = config.get('esConfig.ES_INDEX_USER_MEETING_SETTINGS')
10+
const reIndexAllUserMeetingSettingsPrompt = `WARNING: this would remove existent data! Are you sure you want to reindex the index ${index}?`
11+
const reIndexUserMeetingSettingPrompt = `WARNING: this would remove existent data! Are you sure you want to reindex the document with id ${userId} in index ${index}?`
12+
13+
const userMeetingSettingModelOpts = {
14+
modelName: 'UserMeetingSettings'
15+
}
16+
17+
async function reIndexUserMeetingSettings () {
18+
if (userId === null) {
19+
await helper.promptUser(reIndexAllUserMeetingSettingsPrompt, async () => {
20+
try {
21+
await helper.indexBulkDataToES(userMeetingSettingModelOpts, index, logger)
22+
process.exit(0)
23+
} catch (err) {
24+
logger.logFullError(err, { component: 'reIndexUserMeetingSettings' })
25+
process.exit(1)
26+
}
27+
})
28+
} else {
29+
await helper.promptUser(reIndexUserMeetingSettingPrompt, async () => {
30+
try {
31+
await helper.indexDataToEsById(userId, userMeetingSettingModelOpts, index, logger)
32+
process.exit(0)
33+
} catch (err) {
34+
logger.logFullError(err, { component: 'reIndexUserMeetingSettings' })
35+
process.exit(1)
36+
}
37+
})
38+
}
39+
}
40+
41+
reIndexUserMeetingSettings()

src/common/helper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ async function getUserEmailByUserUUID (userUUID) {
11511151

11521152
const handleQuery = `handleLower:${user.handle.toLowerCase()}`
11531153
const userIdQuery = `userId:${user.userId}`
1154-
1154+
// eslint-disable-next-line
11551155
const query = _.concat(handleQuery, userIdQuery).join(URI.encodeQuery(' OR ', 'utf8'))
11561156
try {
11571157
const searchResult = await searchUsersByQuery(query)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Controller for UserMeetingSettings endpoints
3+
*/
4+
const service = require('../services/UserMeetingSettingsService')
5+
const helper = require('../common/helper')
6+
7+
/**
8+
* Get UserMeetingSettings for the provided userId
9+
* @param req the request
10+
* @param res the response
11+
*/
12+
async function getUserMeetingSettingsByUserId (req, res) {
13+
const result = await service.getUserMeetingSettingsByUserId(req.authUser, req.params.userId, req.query.fromDb)
14+
helper.setResHeaders(req, res, result)
15+
res.send(result.result)
16+
}
17+
18+
module.exports = { getUserMeetingSettingsByUserId }
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* UserMeetingSettings Processor
3+
*/
4+
5+
const config = require('config')
6+
const helper = require('../common/helper')
7+
8+
const esClient = helper.getESClient()
9+
10+
/**
11+
* Process create entity
12+
* @param {Object} entity entity object
13+
*/
14+
async function processCreate (entity) {
15+
await esClient.create({
16+
index: config.get('esConfig.ES_INDEX_USER_MEETING_SETTINGS'),
17+
id: entity.userId,
18+
body: entity,
19+
refresh: 'wait_for'
20+
})
21+
}
22+
23+
/**
24+
* Process update entity
25+
* @param {Object} entity entity object
26+
*/
27+
async function processUpdate (entity) {
28+
await esClient.update({
29+
index: config.get('esConfig.ES_INDEX_USER_MEETING_SETTINGS'),
30+
id: entity.userId,
31+
body: {
32+
doc: entity
33+
},
34+
refresh: 'wait_for'
35+
})
36+
}
37+
38+
/**
39+
* Process delete entity
40+
* @param {Object} entity entity object
41+
*/
42+
async function processDelete (entity) {
43+
await esClient.delete({
44+
index: config.get('esConfig.ES_INDEX_USER_MEETING_SETTINGS'),
45+
id: entity.userId,
46+
refresh: 'wait_for'
47+
})
48+
}
49+
50+
module.exports = {
51+
processCreate,
52+
processUpdate,
53+
processDelete
54+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Contains taas routes
3+
*/
4+
const constants = require('../../app-constants')
5+
6+
module.exports = {
7+
'/taas/user-meeting-settings/:userId': {
8+
get: {
9+
controller: 'UserMeetingSettingsController',
10+
method: 'getUserMeetingSettingsByUserId',
11+
auth: 'jwt',
12+
scopes: [constants.Scopes.READ_USER_MEETING_SETTINGS, constants.Scopes.ALL_USER_MEETING_SETTINGS]
13+
}
14+
}
15+
}

src/services/InterviewService.js

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const {
1818
processUpdateInterview,
1919
processBulkUpdateInterviews
2020
} = require('../esProcessors/InterviewProcessor')
21+
2122
const {
2223
processUpdate: jobCandidateProcessUpdate
2324
} = require('../esProcessors/JobCandidateProcessor')
@@ -26,6 +27,7 @@ const Interview = models.Interview
2627
const UserMeetingSettings = models.UserMeetingSettings
2728
const esClient = helper.getESClient()
2829
const NylasService = require('./NylasService')
30+
const UserMeetingSettingsService = require('./UserMeetingSettingsService')
2931
/**
3032
* Ensures user is permitted for the operation.
3133
*
@@ -41,7 +43,7 @@ async function ensureUserIsPermitted (currentUser, jobCandidateId, allowCandidat
4143
try {
4244
await helper.checkIsMemberOfProject(currentUser.userId, job.projectId)
4345
} catch (error) {
44-
if (e instanceof errors.UnauthorizedError && allowCandidate === true) {
46+
if (error instanceof errors.UnauthorizedError && allowCandidate === true) {
4547
const userId = await helper.getUserId(currentUser.userId)
4648
if (userId !== jobCandidate.userId) {
4749
throw error
@@ -80,7 +82,7 @@ function handleSequelizeError (err, jobCandidateId) {
8082
*/
8183
async function getInterviewByRound (currentUser, jobCandidateId, round, fromDb = false) {
8284
// check permission
83-
await ensureUserIsPermitted(currentUser, jobCandidateIdm, true)
85+
await ensureUserIsPermitted(currentUser, jobCandidateId, true)
8486
if (!fromDb) {
8587
try {
8688
// get job candidate from ES
@@ -306,23 +308,10 @@ async function requestInterview (currentUser, jobCandidateId, interview) {
306308
interview.nylasPageSlug = schedulingPage.slug
307309
interview.nylasCalendarId = calendar.id
308310

311+
await UserMeetingSettingsService.createUserMeetingSettings(interview.hostUserId, calendar, schedulingPage, t)
312+
309313
// create the interview
310314
const created = await Interview.create(interview, { transaction: t })
311-
312-
// create the userMeetingSettings
313-
await UserMeetingSettings.create({
314-
userId: interview.hostUserId,
315-
defaultAvailableTime: NylasService.getAvailableTimeFromSchedulingPage(schedulingPage),
316-
defaultTimezone: NylasService.getTimezoneFromSchedulingPage(schedulingPage),
317-
nylasCalendars: [].concat({
318-
accessToken: calendar.accessToken,
319-
accountId: calendar.accountId,
320-
accountProvider: 'nylas', // TODO 🤔
321-
id: calendar.id,
322-
isPrimary: calendar.is_primary
323-
})
324-
}, { transaction: t })
325-
326315
entity = created.toJSON()
327316
await processRequestInterview(entity)
328317
// update jobCandidate.status to Interview
@@ -358,7 +347,14 @@ requestInterview.schema = Joi.object().keys({
358347
expireTimestamp: Joi.date(),
359348
availableTime: Joi.array().items(
360349
Joi.object({
361-
days: Joi.array().items(Joi.string().valid(InterviewConstants.Nylas.Days.Monday, InterviewConstants.Nylas.Days.Tuesday, InterviewConstants.Nylas.Days.Wednesday, InterviewConstants.Nylas.Days.Thursday, InterviewConstants.Nylas.Days.Friday, InterviewConstants.Nylas.Days.Saturday, InterviewConstants.Nylas.Days.Sunday)).required(),
350+
days: Joi.array().items(Joi.string().valid(
351+
InterviewConstants.Nylas.Days.Monday,
352+
InterviewConstants.Nylas.Days.Tuesday,
353+
InterviewConstants.Nylas.Days.Wednesday,
354+
InterviewConstants.Nylas.Days.Thursday,
355+
InterviewConstants.Nylas.Days.Friday,
356+
InterviewConstants.Nylas.Days.Saturday,
357+
InterviewConstants.Nylas.Days.Sunday)).required(),
362358
end: Joi.string().regex(InterviewConstants.Nylas.StartEndRegex).required(),
363359
start: Joi.string().regex(InterviewConstants.Nylas.StartEndRegex).required()
364360
})

src/services/NylasService.js

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,28 +65,6 @@ async function _getAccessToken (code) {
6565
return { accountId, accessToken }
6666
}
6767

68-
// Step 3
69-
async function getExistingCalendars (accessToken) {
70-
const res = await axios.get('https://api.nylas.com/calendars', {
71-
headers: {
72-
Authorization: `Bearer ${accessToken}`
73-
}
74-
})
75-
76-
return res.data
77-
}
78-
79-
// Step 5
80-
async function getSchedulingPages (accessToken) {
81-
const res = await axios.get('https://api.schedule.nylas.com/manage/pages', {
82-
headers: {
83-
Authorization: `Bearer ${accessToken}`
84-
}
85-
})
86-
87-
return res.data
88-
}
89-
9068
function getAvailableTimeFromSchedulingPage (page) {
9169
return page.config.booking.opening_hours
9270
}

0 commit comments

Comments
 (0)