Skip to content

Commit 0040e20

Browse files
authored
Create travel api (#639)
* Create travel model * Create travel service and begin implementing travel router * Create controller for travel * Implement POST /travel/ endpoint * Implement PATCH /travel/status/:id and PATCH /travel/offer/:id endpoints * Implement GET /travel/:id and GET /travel/email/:email endpoints * Fix bugs in travel endpoints * Load request from travel * Bind Hacker.application.accommondaton.travel to Travel.request * Get travel api working * Fix typos * Update changelog and fix merge conflicts * Ensure travel is uniquely associated with accounts * Add support for travel policy agreement travel state
1 parent 050ba0f commit 0040e20

File tree

16 files changed

+866
-7
lines changed

16 files changed

+866
-7
lines changed

.github/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## Unreleased
9+
10+
- Added travel model
11+
- Added route to create travel
12+
- Added routes to look up travel by id, email or self
13+
- Added routes to status or offer of an existing travel
14+
815
## [2.2.0](https://github.com/hackmcgill/hackerapi/tree/2.2.0) - 2020-01-12
916

1017
### Added

app.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const accountRouter = require("./routes/api/account");
2525
const authRouter = require("./routes/api/auth");
2626
const hackerRouter = require("./routes/api/hacker");
2727
const teamRouter = require("./routes/api/team");
28+
const travelRouter = require("./routes/api/travel");
2829
const sponsorRouter = require("./routes/api/sponsor");
2930
const searchRouter = require("./routes/api/search");
3031
const settingsRouter = require("./routes/api/settings");
@@ -87,6 +88,8 @@ hackerRouter.activate(apiRouter);
8788
Services.log.info("Hacker router activated");
8889
teamRouter.activate(apiRouter);
8990
Services.log.info("Team router activated");
91+
travelRouter.activate(apiRouter);
92+
Services.log.info("Travel router activated")
9093
sponsorRouter.activate(apiRouter);
9194
Services.log.info("Sponsor router activated");
9295
volunteerRouter.activate(apiRouter);

constants/error.constant.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const RESUME_404_MESSAGE = "Resume not found";
77
const SPONSOR_404_MESSAGE = "Sponsor not found";
88
const VOLUNTEER_404_MESSAGE = "Volunteer not found";
99
const SETTINGS_404_MESSAGE = "Settings not found";
10+
const TRAVEL_404_MESSAGE = "Travel not found";
1011

1112
const ACCOUNT_TYPE_409_MESSAGE = "Wrong account type";
1213
const ACCOUNT_EMAIL_409_MESSAGE = "Email already in use";
@@ -44,6 +45,7 @@ const EMAIL_500_MESSAGE = "Error while generating email";
4445
const GENERIC_500_MESSAGE = "Internal error";
4546
const LOGIN_500_MESSAGE = "Error while logging in";
4647
const ROLE_CREATE_500_MESSAGE = "Error while creating role";
48+
const TRAVEL_CREATE_500_MESSAGE = "Error while creating travel";
4749

4850
module.exports = {
4951
ACCOUNT_404_MESSAGE: ACCOUNT_404_MESSAGE,
@@ -83,5 +85,7 @@ module.exports = {
8385
TEAM_READ_500_MESSAGE: TEAM_READ_500_MESSAGE,
8486
VOLUNTEER_404_MESSAGE: VOLUNTEER_404_MESSAGE,
8587
SPONSOR_UPDATE_500_MESSAGE: SPONSOR_UPDATE_500_MESSAGE,
86-
SETTINGS_404_MESSAGE: SETTINGS_404_MESSAGE
88+
SETTINGS_404_MESSAGE: SETTINGS_404_MESSAGE,
89+
TRAVEL_404_MESSAGE: TRAVEL_404_MESSAGE,
90+
TRAVEL_CREATE_500_MESSAGE: TRAVEL_CREATE_500_MESSAGE
8791
};

constants/general.constant.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@ const HACKER_STATUSES = [
2828
// This date is Jan 6, 2020 00:00:00 GMT -0500
2929
const APPLICATION_CLOSE_TIME = 1578286800000;
3030

31+
const TRAVEL_STATUS_NONE = "None"; // Hacker has not been offered compensation for travelling
32+
const TRAVEL_STATUS_BUS = "Bus"; // Hacker is taking bus to hackathon
33+
const TRAVEL_STATUS_POLICY = "Policy"; // Hacker has been offer some reimbursement, but we are waiting for hacker to accept travel policy first
34+
const TRAVEL_STATUS_OFFERED = "Offered"; // Hacker has been offered some amount of compensation for travelling, but we have not verified their reciepts yet
35+
const TRAVEL_STATUS_VALID = "Valid"; // Hacker has been offered some amount of compensation for travelling and have uploaded reciepts which we have confirmed to be an approprate amount
36+
const TRAVEL_STATUS_INVALID = "Invalid"; // Hacker has been offered some amount of compensation for travelling but have uploaded reciepts which we have confirmed to be an inapproprate amount
37+
const TRAVEL_STATUS_CLAIMED = "Claimed"; // Hacker has been offered some amount of compensation and has recieved such the funds
38+
const TRAVEL_STATUSES = [
39+
TRAVEL_STATUS_NONE,
40+
TRAVEL_STATUS_BUS,
41+
TRAVEL_STATUS_POLICY,
42+
TRAVEL_STATUS_OFFERED,
43+
TRAVEL_STATUS_VALID,
44+
TRAVEL_STATUS_INVALID,
45+
TRAVEL_STATUS_CLAIMED
46+
];
47+
3148
const SAMPLE_DIET_RESTRICTIONS = [
3249
"None",
3350
"Vegan",
@@ -160,6 +177,14 @@ module.exports = {
160177
HACKER_STATUS_WITHDRAWN: HACKER_STATUS_WITHDRAWN,
161178
HACKER_STATUS_CHECKED_IN: HACKER_STATUS_CHECKED_IN,
162179
HACKER_STATUSES: HACKER_STATUSES,
180+
TRAVEL_STATUS_NONE: TRAVEL_STATUS_NONE,
181+
TRAVEL_STATUS_BUS: TRAVEL_STATUS_BUS,
182+
TRAVEL_STATUS_POLICY: TRAVEL_STATUS_POLICY,
183+
TRAVEL_STATUS_OFFERED: TRAVEL_STATUS_OFFERED,
184+
TRAVEL_STATUS_VALID: TRAVEL_STATUS_VALID,
185+
TRAVEL_STATUS_INVALID: TRAVEL_STATUS_INVALID,
186+
TRAVEL_STATUS_CLAIMED: TRAVEL_STATUS_CLAIMED,
187+
TRAVEL_STATUSES: TRAVEL_STATUSES,
163188
APPLICATION_CLOSE_TIME: APPLICATION_CLOSE_TIME,
164189
REQUEST_TYPES: REQUEST_TYPES,
165190
JOB_INTERESTS: JOB_INTERESTS,

constants/role.constant.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ const hackerRole = {
3838
Constants.Routes.hackerRoutes.patchSelfConfirmationById,
3939
Constants.Routes.hackerRoutes.getSelf,
4040

41+
Constants.Routes.travelRoutes.getSelf,
42+
Constants.Routes.travelRoutes.getSelfById,
43+
Constants.Routes.travelRoutes.getAnyById,
44+
Constants.Routes.travelRoutes.getSelfByEmail,
45+
Constants.Routes.travelRoutes.getAnyByEmail,
46+
Constants.Routes.travelRoutes.patchAnyStatusById,
47+
Constants.Routes.travelRoutes.patchAnyOfferById,
48+
4149
Constants.Routes.teamRoutes.join,
4250
Constants.Routes.teamRoutes.patchSelfById,
4351
Constants.Routes.teamRoutes.post,

constants/routes.constant.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,41 @@ const hackerRoutes = {
150150
}
151151
};
152152

153+
const travelRoutes = {
154+
getSelf: {
155+
requestType: Constants.REQUEST_TYPES.GET,
156+
uri: "/api/travel/self/"
157+
},
158+
getSelfById: {
159+
requestType: Constants.REQUEST_TYPES.GET,
160+
uri: "/api/travel/" + Constants.ROLE_CATEGORIES.SELF
161+
},
162+
getAnyById: {
163+
requestType: Constants.REQUEST_TYPES.GET,
164+
uri: "/api/travel/" + Constants.ROLE_CATEGORIES.ALL
165+
},
166+
getSelfByEmail: {
167+
requestType: Constants.REQUEST_TYPES.GET,
168+
uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.SELF
169+
},
170+
getAnyByEmail: {
171+
requestType: Constants.REQUEST_TYPES.GET,
172+
uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.ALL
173+
},
174+
post: {
175+
requestType: Constants.REQUEST_TYPES.POST,
176+
uri: "/api/travel/"
177+
},
178+
patchAnyStatusById: {
179+
requestType: Constants.REQUEST_TYPES.PATCH,
180+
uri: "/api/travel/status/" + Constants.ROLE_CATEGORIES.ALL
181+
},
182+
patchAnyOfferById: {
183+
requestType: Constants.REQUEST_TYPES.PATCH,
184+
uri: "/api/travel/offer/" + Constants.ROLE_CATEGORIES.ALL
185+
}
186+
}
187+
153188
const sponsorRoutes = {
154189
getSelf: {
155190
requestType: Constants.REQUEST_TYPES.GET,
@@ -263,6 +298,7 @@ const allRoutes = {
263298
Auth: authRoutes,
264299
Account: accountRoutes,
265300
Hacker: hackerRoutes,
301+
Travel: travelRoutes,
266302
Sponsor: sponsorRoutes,
267303
Team: teamRoutes,
268304
Volunteer: volunteerRoutes,
@@ -302,6 +338,7 @@ module.exports = {
302338
authRoutes: authRoutes,
303339
accountRoutes: accountRoutes,
304340
hackerRoutes: hackerRoutes,
341+
travelRoutes: travelRoutes,
305342
sponsorRoutes: sponsorRoutes,
306343
teamRoutes: teamRoutes,
307344
volunteerRoutes: volunteerRoutes,

constants/success.constant.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ const HACKER_SENT_DAY_OF = "Hacker day-of email sent.";
2727
const RESUME_UPLOAD = "Resume upload successful.";
2828
const RESUME_DOWNLOAD = "Resume download successful.";
2929

30+
const TRAVEL_READ = "Travel retrieval successful.";
31+
const TRAVEL_CREATE = "Travel creation successful.";
32+
const TRAVEL_UPDATE = "Travel update successful.";
33+
3034
const ROLE_CREATE = "Role creation successful.";
3135

3236
const SEARCH_QUERY = "Query search successful. Returning results.";
@@ -78,6 +82,10 @@ module.exports = {
7882
RESUME_UPLOAD: RESUME_UPLOAD,
7983
RESUME_DOWNLOAD: RESUME_DOWNLOAD,
8084

85+
TRAVEL_READ: TRAVEL_READ,
86+
TRAVEL_CREATE: TRAVEL_CREATE,
87+
TRAVE_UPDATE: TRAVEL_UPDATE,
88+
8189
ROLE_CREATE: ROLE_CREATE,
8290

8391
SEARCH_QUERY: SEARCH_QUERY,

controllers/travel.controller.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"use strict";
2+
const Constants = {
3+
Success: require("../constants/success.constant"),
4+
Error: require("../constants/error.constant")
5+
};
6+
7+
function okay(req, res) {
8+
return res.status(200).json({
9+
message: "good"
10+
});
11+
}
12+
13+
/**
14+
* @function showTravel
15+
* @param {{body: {travel: Object}}} req
16+
* @param {*} res
17+
* @return {JSON} Success status and travel object
18+
* @description Returns the JSON of travel object located in req.body.travel
19+
*/
20+
function showTravel(req, res) {
21+
return res.status(200).json({
22+
message: Constants.Success.TRAVEL_READ,
23+
data: req.body.travel.toJSON()
24+
});
25+
}
26+
27+
/**
28+
* @function createTravel
29+
* @param {{body: {travel: {_id: ObjectId, accountId: ObjectId, hackerId: objectId, status: string, request: number, offer: number}}}} req
30+
* @param {*} res
31+
* @return {JSON} Success status
32+
* @description
33+
* Create a travel's record based off information stored in req.body.travel
34+
* Returns a 200 status for the created travel.
35+
*/
36+
function createdTravel(req, res) {
37+
return res.status(200).json({
38+
message: Constants.Success.TRAVEL_CREATE,
39+
data: req.body.travel.toJSON()
40+
});
41+
}
42+
43+
/**
44+
* @function updatedTravel
45+
* @param {{params: {id: ObjectId}, body: {Object}}} req
46+
* @param {*} res
47+
* @return {JSON} Success or error status
48+
* @description
49+
* Change a travel's information based on the trave;'s mongoID specified in req.params.id.
50+
* The id is moved to req.body.id from req.params.id by validation.
51+
* Returns a 200 status for an updated travel.
52+
* The new information is located in req.body.
53+
*/
54+
function updatedTravel(req, res) {
55+
return res.status(200).json({
56+
message: Constants.Success.TRAVEL_UPDATE,
57+
data: req.body
58+
});
59+
}
60+
61+
module.exports = {
62+
okay: okay,
63+
showTravel: showTravel,
64+
updatedTravel: updatedTravel,
65+
createdTravel: createdTravel
66+
};

middlewares/hacker.middleware.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const Services = {
77
Storage: require("../services/storage.service"),
88
Email: require("../services/email.service"),
99
Account: require("../services/account.service"),
10+
Travel: require("../services/travel.service"),
1011
Env: require("../services/env.service")
1112
};
1213
const Middleware = {
@@ -158,9 +159,9 @@ async function validateConfirmedStatusFromHackerId(req, res, next) {
158159
const hacker = await Services.Hacker.findById(req.params.id);
159160
if (hacker == null) {
160161
return next({
161-
status: 404,
162-
message: Constants.Error.HACKER_404_MESSAGE,
163-
data: req.body.hackerId
162+
status: 404,
163+
message: Constants.Error.HACKER_404_MESSAGE,
164+
data: req.body.hackerId
164165
});
165166
}
166167
const account = await Services.Account.findById(hacker.accountId);
@@ -235,7 +236,7 @@ function ensureAccountLinkedToHacker(req, res, next) {
235236
hacker &&
236237
req.user &&
237238
String.toString(hacker.accountId) ===
238-
String.toString(req.user.id)
239+
String.toString(req.user.id)
239240
) {
240241
return next();
241242
} else {
@@ -545,6 +546,12 @@ async function updateHacker(req, res, next) {
545546
});
546547
}
547548
req.email = acct.email;
549+
550+
// If this hacker has a travel account associated with it, then update request to reflect amount wanted for travel
551+
const travel = await Services.Travel.findByHackerId(hacker.id);
552+
if (travel) {
553+
await Services.Travel.updateOne(travel.id, { "request": hacker.application.accommodation.travel });
554+
}
548555
return next();
549556
} else {
550557
return next({
@@ -617,7 +624,7 @@ function parseAcceptEmail(req, res, next) {
617624

618625

619626
/**
620-
* @function createhacker
627+
* @function createHacker
621628
* @param {{body: {hackerDetails: object}}} req
622629
* @param {*} res
623630
* @param {(err?)=>void} next

0 commit comments

Comments
 (0)