Skip to content

Commit dff8614

Browse files
YiFeiZhang2pierreTklein
authored andcommitted
Feature/team post (#273)
* change to enum validation * Add authentication to team create * Create team * Add tests for team * WIP team post duplication issue * Add check for duplicate team name, and test for hacker already being in a team * uncomment tests * fix git merge mistake * Remove testing code, make sure create also updates hacker * docs * Remove test index * re-add index on team name * fix merge issue
1 parent 433a103 commit dff8614

14 files changed

Lines changed: 262 additions & 57 deletions

File tree

constants/error.constant.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const SPONSOR_ID_409_MESSAGE = "Conflict with sponsor accountId link";
1111
const VOLUNTEER_ID_409_MESSAGE = "Conflict with volunteer accountId link";
1212
const HACKER_ID_409_MESSAGE = "Conflict with hacker accountId link";
1313
const TEAM_MEMBER_409_MESSAGE = "Conflict with team member being in another team";
14+
const TEAM_NAME_409_MESSAGE = "Conflict with team name already in use";
1415
const HACKER_STATUS_409_MESSAGE = "Conflict with hacker status";
1516
const TEAM_SIZE_409_MESSAGE = "Team full";
1617
const TEAM_JOIN_SAME_409_MESSAGE = "Hacker is already on receiving team";
@@ -70,5 +71,6 @@ module.exports = {
7071
TEAM_SIZE_409_MESSAGE: TEAM_SIZE_409_MESSAGE,
7172
ROLE_DUPLICATE_422_MESSAGE: ROLE_DUPLICATE_422_MESSAGE,
7273
ROLE_CREATE_500_MESSAGE: ROLE_CREATE_500_MESSAGE,
74+
TEAM_NAME_409_MESSAGE: TEAM_NAME_409_MESSAGE,
7375
TEAM_JOIN_SAME_409_MESSAGE: TEAM_JOIN_SAME_409_MESSAGE,
7476
};

constants/role.constant.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const hackerRole = {
4141
Constants.Routes.hackerRoutes.getSelf,
4242

4343
Constants.Routes.teamRoutes.join,
44+
Constants.Routes.teamRoutes.post,
4445
Constants.Routes.teamRoutes.get
4546
]
4647
};

docs/api/api_data.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,7 +2158,7 @@ define({
21582158
{
21592159
"type": "post",
21602160
"url": "/team/",
2161-
"title": "create a new team",
2161+
"title": "create a new team consisting of only the logged in user",
21622162
"name": "createTeam",
21632163
"group": "Team",
21642164
"version": "0.0.8",
@@ -2171,13 +2171,6 @@ define({
21712171
"field": "name",
21722172
"description": "<p>Name of the team.</p>"
21732173
},
2174-
{
2175-
"group": "body",
2176-
"type": "MongoID[]",
2177-
"optional": true,
2178-
"field": "members",
2179-
"description": "<p>Array of members in team.</p>"
2180-
},
21812174
{
21822175
"group": "body",
21832176
"type": "String",

docs/api/api_data.json

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,7 +2157,7 @@
21572157
{
21582158
"type": "post",
21592159
"url": "/team/",
2160-
"title": "create a new team",
2160+
"title": "create a new team consisting of only the logged in user",
21612161
"name": "createTeam",
21622162
"group": "Team",
21632163
"version": "0.0.8",
@@ -2170,13 +2170,6 @@
21702170
"field": "name",
21712171
"description": "<p>Name of the team.</p>"
21722172
},
2173-
{
2174-
"group": "body",
2175-
"type": "MongoID[]",
2176-
"optional": true,
2177-
"field": "members",
2178-
"description": "<p>Array of members in team.</p>"
2179-
},
21802173
{
21812174
"group": "body",
21822175
"type": "String",

docs/api/api_project.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ define({
99
"apidoc": "0.3.0",
1010
"generator": {
1111
"name": "apidoc",
12-
"time": "2019-01-07T19:14:21.760Z",
12+
"time": "2019-01-05T01:35:07.317Z",
1313
"url": "http://apidocjs.com",
1414
"version": "0.17.7"
1515
}

docs/api/api_project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"apidoc": "0.3.0",
1010
"generator": {
1111
"name": "apidoc",
12-
"time": "2019-01-07T19:14:21.760Z",
12+
"time": "2019-01-05T01:35:07.317Z",
1313
"url": "http://apidocjs.com",
1414
"version": "0.17.7"
1515
}

middlewares/team.middleware.js

Lines changed: 115 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,42 @@ async function ensureUniqueHackerId(req, res, next) {
5555

5656
/**
5757
* @async
58-
* @function ensureSpance
58+
* @function createTeam
59+
* @param {{body: {teamDetails: {_id: ObjectId, name: string, members: ObjectId[], devpostURL?: string, projectName: string}}}} req
60+
* @param {*} res
61+
* @description create a team from information in req.body.teamDetails.
62+
*/
63+
async function createTeam(req, res, next) {
64+
const teamDetails = req.body.teamDetails;
65+
66+
const team = await Services.Team.createTeam(teamDetails);
67+
68+
if (!team) {
69+
return res.status(500).json({
70+
message: Constants.Error.TEAM_CREATE_500_MESSAGE,
71+
data: {}
72+
});
73+
}
74+
75+
for (const hackerId of teamDetails.members) {
76+
const hacker = await Services.Hacker.updateOne(hackerId, {
77+
teamId: team._id
78+
});
79+
80+
if (!hacker) {
81+
return res.status(500).json({
82+
message: Constants.Error.HACKER_UPDATE_500_MESSAGE,
83+
data: {}
84+
});
85+
}
86+
}
87+
88+
req.body.team = team;
89+
return next();
90+
}
91+
92+
/**
93+
* @function ensureSpace
5994
* @param {{body: {name: string}}} req
6095
* @param {JSON} res
6196
* @param {(err?)=>void} next
@@ -85,26 +120,49 @@ async function ensureSpace(req, res, next) {
85120
}
86121

87122
/**
88-
* @async
89-
* @function createTeam
90-
* @param {{body: {teamDetails: {_id: ObjectId, name: string, members: ObjectId[], devpostURL?: string, projectName: string}}}} req
91-
* @param {*} res
92-
* @description create a team from information in req.body.teamDetails.
123+
* @function ensureFreeTeamName
124+
* @param {{body: {teamDetails: {name: String}}}} req
125+
* @param {JSON} res
126+
* @param {(err?)=>void} next
127+
* @return {void}
128+
* @description Checks to see that the team name is not in use.
93129
*/
94-
async function createTeam(req, res, next) {
130+
async function ensureFreeTeamName(req, res, next) {
95131
const teamDetails = req.body.teamDetails;
96132

97-
const team = await Services.Team.createTeam(teamDetails);
133+
const team = await Services.Team.findByName(teamDetails.name);
134+
135+
if (team) {
136+
return next({
137+
status: 409,
138+
message: Constants.Error.TEAM_NAME_409_MESSAGE,
139+
data: teamDetails.name
140+
});
141+
}
142+
143+
return next();
144+
}
145+
146+
/**
147+
* @async
148+
* @function findById
149+
* @param {{body: {id: ObjectId}}} req
150+
* @param {*} res
151+
* @return {JSON} Success or error status
152+
* @description Finds a team by it's mongoId that's specified in req.param.id in route parameters. The id is moved to req.body.id from req.params.id by validation.
153+
*/
154+
async function findById(req, res, next) {
155+
const team = await Services.Team.findById(req.body.id);
98156

99157
if (!team) {
100-
return res.status(500).json({
101-
message: Constants.Error.TEAM_CREATE_500_MESSAGE,
158+
return res.status(404).json({
159+
message: Constants.Error.TEAM_404_MESSAGE,
102160
data: {}
103161
});
104-
} else {
105-
req.body.team = team;
106-
return next();
107162
}
163+
164+
req.body.team = team;
165+
return next();
108166
}
109167

110168
/**
@@ -145,7 +203,7 @@ async function updateHackerTeam(req, res, next) {
145203
return next({
146204
status: 409,
147205
message: Constants.Error.TEAM_JOIN_SAME_409_MESSAGE,
148-
data: req.body.teamName
206+
data: req.body.name
149207
});
150208
}
151209

@@ -155,7 +213,6 @@ async function updateHackerTeam(req, res, next) {
155213
await Services.Team.removeTeamIfEmpty(previousTeamId);
156214
}
157215

158-
159216
// add hacker to the new team and change teamId of hacker
160217
const update = await Services.Team.addMember(receivingTeam._id, hacker._id);
161218

@@ -258,12 +315,55 @@ function parseTeam(req, res, next) {
258315
return next();
259316
}
260317

318+
async function parseNewTeam(req, res, next) {
319+
const teamDetails = {
320+
_id: mongoose.Types.ObjectId(),
321+
name: req.body.name,
322+
members: [],
323+
devpostURL: req.body.devpostURL,
324+
projectName: req.body.projectName
325+
};
326+
327+
delete req.body.name;
328+
delete req.body.members;
329+
delete req.body.devpostURL;
330+
delete req.body.projectName;
331+
332+
// hacker should exist because of authorization
333+
const hacker = await Services.Hacker.findByAccountId(req.user.id);
334+
335+
if (!hacker) {
336+
return next({
337+
status: 404,
338+
message: Constants.Error.HACKER_404_MESSAGE,
339+
data: {
340+
id: req.user.id
341+
}
342+
});
343+
}
344+
345+
// hacker should not be in another team
346+
if (hacker.teamId !== undefined) {
347+
return next({
348+
status: 409,
349+
message: Constants.Error.TEAM_MEMBER_409_MESSAGE,
350+
});
351+
}
352+
353+
teamDetails.members.push(hacker._id);
354+
355+
req.body.teamDetails = teamDetails;
356+
return next();
357+
}
358+
261359
module.exports = {
262360
parseTeam: parseTeam,
263361
findById: Util.asyncMiddleware(findById),
264362
createTeam: Util.asyncMiddleware(createTeam),
265363
ensureUniqueHackerId: Util.asyncMiddleware(ensureUniqueHackerId),
266364
ensureSpace: Util.asyncMiddleware(ensureSpace),
267365
updateHackerTeam: Util.asyncMiddleware(updateHackerTeam),
366+
parseNewTeam: Util.asyncMiddleware(parseNewTeam),
367+
ensureFreeTeamName: Util.asyncMiddleware(ensureFreeTeamName),
268368
populateMemberAccountsById: Util.asyncMiddleware(populateMemberAccountsById),
269369
};

middlewares/validators/team.validator.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ const Constants = require("../../constants/general.constant");
55
module.exports = {
66
newTeamValidator: [
77
VALIDATOR.asciiValidator("body", "name", false),
8-
// members by mongoID if the team creator is able to provide
9-
VALIDATOR.mongoIdArrayValidator("body", "members", true),
108
VALIDATOR.regexValidator("body", "devpostURL", true, Constants.DEVPOST_REGEX),
119
VALIDATOR.asciiValidator("body", "projectName", true)
1210
],

models/team.model.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ const Constants = require("../constants/general.constant");
66
const TeamSchema = new mongoose.Schema({
77
name: {
88
type: String,
9+
required: true,
910
unique: true,
10-
required: true
1111
},
1212
members: {
1313
type: [{

routes/api/team.js

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,18 @@ const Middleware = {
1616
Team: require("../../middlewares/team.middleware"),
1717
Auth: require("../../middlewares/auth.middleware"),
1818
};
19-
const Services = {
20-
Hacker: require("../../services/hacker.service"),
21-
};
2219

2320
module.exports = {
2421
activate: function (apiRouter) {
2522
const teamRouter = new express.Router();
2623

2724
/**
28-
* @api {post} /team/ create a new team
25+
* @api {post} /team/ create a new team consisting of only the logged in user
2926
* @apiName createTeam
3027
* @apiGroup Team
3128
* @apiVersion 0.0.8
3229
*
3330
* @apiParam (body) {String} name Name of the team.
34-
* @apiParam (body) {MongoID[]} [members] Array of members in team.
3531
* @apiParam (body) {String} [devpostURL] Devpost link to hack. Once the link is sent, the hack will be considered to be submitted.
3632
* @apiParam (body) {String} [projectName] Name of the team.
3733
*
@@ -49,15 +45,14 @@ module.exports = {
4945
* {"message": "Error while creating team", "data": {}}
5046
*/
5147
teamRouter.route("/").post(
48+
Middleware.Auth.ensureAuthenticated(),
49+
Middleware.Auth.ensureAuthorized(),
5250
// Validators
5351
Middleware.Validator.Team.newTeamValidator,
54-
5552
Middleware.parseBody.middleware,
53+
Middleware.Team.parseNewTeam,
5654

57-
Middleware.Team.parseTeam,
58-
59-
// check that member is not already in a team
60-
Middleware.Team.ensureUniqueHackerId,
55+
Middleware.Team.ensureFreeTeamName,
6156

6257
Middleware.Team.createTeam,
6358
Controllers.Team.createdTeam

0 commit comments

Comments
 (0)