diff --git a/constants/role.constant.js b/constants/role.constant.js index 9aa1a707..dfee5c3e 100644 --- a/constants/role.constant.js +++ b/constants/role.constant.js @@ -151,27 +151,26 @@ function createAllSingularRoles() { const allRoutes = Constants.Routes.allRoutes; let roles = []; - // i is unique integer so that objectId is constant - var i = 1000000; for (let routeGroupKey in allRoutes) { - if (!allRoutes.hasOwnProperty(routeGroupKey)) { + if (!Object.prototype.hasOwnProperty.call(allRoutes, routeGroupKey)) { continue; } const routeGroup = allRoutes[routeGroupKey]; for (let routeKey in routeGroup) { - if (!routeGroup.hasOwnProperty(routeKey)) { + // Iterating through the attributes in the routeGroup object + if (!Object.prototype.hasOwnProperty.call(routeGroup, routeKey)) { + // Avoid all prototype attributes continue; } let role = { - _id: mongoose.Types.ObjectId(i), + _id: routeGroup[routeKey]._id, name: routeKey + routeGroupKey, routes: routeGroup[routeKey] }; let roleName = role.name; roles[roleName] = role; - i -= 1; } } @@ -197,7 +196,7 @@ function createAllRoles() { const singularRoles = createAllSingularRoles(); for (let role in singularRoles) { - if (!singularRoles.hasOwnProperty(role)) { + if (!Object.prototype.hasOwnProperty.call(singularRoles, role)) { continue; } allRolesObject[role] = singularRoles[role]; diff --git a/constants/routes.constant.js b/constants/routes.constant.js index e9c21ed0..9a0dda56 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -1,296 +1,376 @@ "use strict"; + +/** + * ===***===***===***===***===***===***===***===***=== + * ===***=== PLEASE READ BEFORE EDITING ===***=== + * ===***===***===***===***===***===***===***===***=== + * + * If you are adding a route to this list, update this number + * next avaiable createFromTime value: 165 + * + * If you are deleting a route from this list, please add the ID to the list of 'reserved' IDs, + * so that we don't accidentally assign someone to a given ID. + * reserved createFromTime values: + */ + const Constants = require("./general.constant"); +const mongoose = require("mongoose"); const authRoutes = { login: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/auth/login" + uri: "/api/auth/login", + _id: mongoose.Types.ObjectId.createFromTime(100) }, logout: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/auth/logout" + uri: "/api/auth/logout", + _id: mongoose.Types.ObjectId.createFromTime(101) }, getSelfRoleBindindings: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(102) }, getAnyRoleBindings: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(103) }, changePassword: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/auth/password/change" + uri: "/api/auth/password/change", + _id: mongoose.Types.ObjectId.createFromTime(104) } }; const accountRoutes = { getSelf: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/account/self" + uri: "/api/account/self", + _id: mongoose.Types.ObjectId.createFromTime(105) }, getSelfById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/account/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/account/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(106) }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/account/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/account/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(107) }, post: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/account/" + uri: "/api/account/", + _id: mongoose.Types.ObjectId.createFromTime(108) }, patchSelfById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/account/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/account/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(109) }, patchAnyById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/account/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/account/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(110) }, inviteAccount: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/account/invite" + uri: "/api/account/invite", + _id: mongoose.Types.ObjectId.createFromTime(111) } }; const hackerRoutes = { getSelf: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/self/" + uri: "/api/hacker/self/", + _id: mongoose.Types.ObjectId.createFromTime(112) }, getSelfById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(113) }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(114) }, getSelfByEmail: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/email/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/email/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(115) }, getAnyByEmail: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/email/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/email/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(116) }, getSelfResumeById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(117) }, getAnyResumeById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(118) }, post: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/" + uri: "/api/hacker/", + _id: mongoose.Types.ObjectId.createFromTime(119) }, postSelfResumeById: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(120) }, postAnyResumeById: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(121) }, patchSelfById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(122) }, patchAnyById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(123) }, patchAnyStatusById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(124) }, patchSelfStatusById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(125) }, patchSelfCheckInById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(126) }, patchAnyCheckInById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(127) }, patchSelfConfirmationById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/confirmation/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/confirmation/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(128) }, patchAcceptHackerById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/accept/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(129) }, patchAcceptHackerByEmail: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/acceptEmail/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(130) }, postAnySendWeekOfEmail: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/email/weekOf/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/email/weekOf/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(131) }, postSelfSendWeekOfEmail: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/email/weekOf/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/email/weekOf/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(132) }, postAnySendDayOfEmail: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/email/dayOf/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/hacker/email/dayOf/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(133) }, postSelfSendDayOfEmail: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/email/dayOf/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/hacker/email/dayOf/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(134) } }; const travelRoutes = { getSelf: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/self/" + uri: "/api/travel/self/", + _id: mongoose.Types.ObjectId.createFromTime(135) }, getSelfById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/travel/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(136) }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/travel/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(137) }, getSelfByEmail: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(138) }, getAnyByEmail: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(139) }, post: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/travel/" + uri: "/api/travel/", + _id: mongoose.Types.ObjectId.createFromTime(140) }, patchAnyStatusById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/travel/status/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/travel/status/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(141) }, patchAnyOfferById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/travel/offer/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/travel/offer/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(142) } -} +}; const sponsorRoutes = { getSelf: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/sponsor/self/" + uri: "/api/sponsor/self/", + _id: mongoose.Types.ObjectId.createFromTime(143) }, getSelfById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(144) }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(145) }, post: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/sponsor/" + uri: "/api/sponsor/", + _id: mongoose.Types.ObjectId.createFromTime(146) }, patchSelfById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(147) }, patchAnyById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(148) } }; const teamRoutes = { get: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/team/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/team/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(149) }, post: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/team/" + uri: "/api/team/", + _id: mongoose.Types.ObjectId.createFromTime(150) }, join: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/team/join/" + uri: "/api/team/join/", + _id: mongoose.Types.ObjectId.createFromTime(151) }, patchSelfById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/team/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/team/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(152) }, patchAnyById: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/team/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/team/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(153) }, leave: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/team/leave/" + uri: "/api/team/leave/", + _id: mongoose.Types.ObjectId.createFromTime(154) } }; const volunteerRoutes = { getSelfById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/volunteer/" + Constants.ROLE_CATEGORIES.SELF + uri: "/api/volunteer/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(155) }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/volunteer/" + Constants.ROLE_CATEGORIES.ALL + uri: "/api/volunteer/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(156) }, post: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/volunteer/" + uri: "/api/volunteer/", + _id: mongoose.Types.ObjectId.createFromTime(157) } }; const roleRoutes = { post: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/role/" + uri: "/api/role/", + _id: mongoose.Types.ObjectId.createFromTime(158) } }; const searchRoutes = { get: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/search/" + uri: "/api/search/", + _id: mongoose.Types.ObjectId.createFromTime(159) } }; const staffRoutes = { hackerStats: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/stats" + uri: "/api/hacker/stats", + _id: mongoose.Types.ObjectId.createFromTime(160) }, postInvite: { requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/account/invite" + uri: "/api/account/invite", + _id: mongoose.Types.ObjectId.createFromTime(161) }, getInvite: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/account/invite" + uri: "/api/account/invite", + _id: mongoose.Types.ObjectId.createFromTime(162) } }; const settingsRoutes = { getSettings: { requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/settings" + uri: "/api/settings", + _id: mongoose.Types.ObjectId.createFromTime(163) }, patchSettings: { requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/settings" + uri: "/api/settings", + _id: mongoose.Types.ObjectId.createFromTime(164) } }; @@ -310,23 +390,29 @@ const allRoutes = { /** * returns all the routes as a list - * @return {{requestType: string, uri: string}[]} + * @param {boolean} includeId whether to include _id in the returned route object. + * @return {{requestType: string, uri: string, id?: ObjectId}[]} */ -function listAllRoutes() { +function listAllRoutes(includeId = true) { let routes = []; for (let routeGroupKey in allRoutes) { - if (!allRoutes.hasOwnProperty(routeGroupKey)) { + if (!Object.prototype.hasOwnProperty.call(allRoutes, routeGroupKey)) { continue; } const routeGroup = allRoutes[routeGroupKey]; for (let routeKey in routeGroup) { - if (!routeGroup.hasOwnProperty(routeKey)) { + if (!Object.prototype.hasOwnProperty.call(routeGroup, routeKey)) { continue; } - const route = routeGroup[routeKey]; + const route = {}; + // copy only over the attributes that we care about + route.requestType = routeGroup[routeKey].requestType; + route.uri = routeGroup[routeKey].uri; + if (includeId) route._id = routeGroup[routeKey]._id; + routes.push(route); } } diff --git a/docs/architecture.md b/docs/architecture.md index 952ee097..4cf2bbb2 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -28,12 +28,13 @@ We use a custom implementation for authorization, which relies heavily on the de #### `Route` -A `Route`, which is a component of a `Role`, is defined by its uri path, its query parameters in the uri path, and the HTTP verb used to access it: +A `Route`, which is a component of a `Role`, is defined by its uri path, its query parameters in the uri path, the HTTP verb used to access it, and and `_id`: ```json { "uri": "/api/sponsor/", "requestType": "POST", + "_id": "000000010000000000000000" } ``` @@ -53,6 +54,45 @@ A `Role` is a collection of `Routes`, and a unique name (such as `hacker`, or `s _Note here that the parameter `routes` is a list of `Route` objects described in the previous section._ +##### In our code-base, we have a auto-generated list of `single roles` and a custom list of `user roles` + +`single roles` are roles that give permissions for one specific URI and request type. Every route has a `single role`. + +```json +{ + "_id": "000000010000000000000000", + "name": "postAccount", + "routes": [{ + "uri": "/api/account/", + "requestType": "POST", + "_id": "000000010000000000000000", + }] +} +``` + +`user roles` are syntactically the same as custom roles that give permissions for a collection of URIs and request types. These are essentially collections of routes that a given user needs access to in order to properly function with the API. + +```json +{ + "_id": "000000020000000000000000", + "name": "Account", + "routes": [{ + "uri": "/api/account/", + "requestType": "POST", + "_id": "000000010000000000000000", + }, + { + "uri": "/api/account/:SELF", + "requestType": "GET", + "_id": "000000030000000000000000", + }, + // etc. + ] +} +``` + +Note that for each route in the `user role`, you have access to the `single role` document's `_id`! + #### `RoleBinding` A `RoleBinding` is a mapping between an `account` and a `Role`. In this way, we can say that an account has a certain set of allowed actions, defined by the `Role`. An `account` can have a `RoleBinding` to multiple `Roles`. @@ -174,15 +214,18 @@ The http request that this would translate to is: ``` ### Error Codes and Messages + Error messages are in the error.constant.js file. The error constants are of the for TYPE_HTTPCODE_MESSAGE. For example, HACKER_404_MESSAGE. When creating a response, use an existing error message, or create a new one. An example: -``` + +```js next({ status: 422, message: Constants.Error.ACCOUNT_DUPLICATE_422_MESSAGE, error: {...} }); ``` -Note that the error status and the HTTPCODE in the error constant name are the same. + +Note that the error status and the HTTPCODE in the error constant name are the same. Error codes currently in use are: 401 - Invalid authentication