Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions constants/error.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const SPONSOR_ID_409_MESSAGE = "Conflict with sponsor accountId link";
const VOLUNTEER_ID_409_MESSAGE = "Conflict with volunteer accountId link";
const HACKER_ID_409_MESSAGE = "Conflict with hacker accountId link";
const TEAM_MEMBER_409_MESSAGE = "Conflict with team member being in another team";
const TEAM_NAME_409_MESSAGE = "Conflict with team name already in use";
const HACKER_STATUS_409_MESSAGE = "Conflict with hacker status";
const TEAM_SIZE_409_MESSAGE = "Team full";
const TEAM_JOIN_SAME_409_MESSAGE = "Hacker is already on receiving team";
Expand Down Expand Up @@ -70,5 +71,6 @@ module.exports = {
TEAM_SIZE_409_MESSAGE: TEAM_SIZE_409_MESSAGE,
ROLE_DUPLICATE_422_MESSAGE: ROLE_DUPLICATE_422_MESSAGE,
ROLE_CREATE_500_MESSAGE: ROLE_CREATE_500_MESSAGE,
TEAM_NAME_409_MESSAGE: TEAM_NAME_409_MESSAGE,
TEAM_JOIN_SAME_409_MESSAGE: TEAM_JOIN_SAME_409_MESSAGE,
};
1 change: 1 addition & 0 deletions constants/role.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const hackerRole = {
Constants.Routes.hackerRoutes.getSelf,

Constants.Routes.teamRoutes.join,
Constants.Routes.teamRoutes.post,
Constants.Routes.teamRoutes.get
]
};
Expand Down
9 changes: 1 addition & 8 deletions docs/api/api_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -2158,7 +2158,7 @@ define({
{
"type": "post",
"url": "/team/",
"title": "create a new team",
"title": "create a new team consisting of only the logged in user",
"name": "createTeam",
"group": "Team",
"version": "0.0.8",
Expand All @@ -2171,13 +2171,6 @@ define({
"field": "name",
"description": "<p>Name of the team.</p>"
},
{
"group": "body",
"type": "MongoID[]",
"optional": true,
"field": "members",
"description": "<p>Array of members in team.</p>"
},
{
"group": "body",
"type": "String",
Expand Down
9 changes: 1 addition & 8 deletions docs/api/api_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -2157,7 +2157,7 @@
{
"type": "post",
"url": "/team/",
"title": "create a new team",
"title": "create a new team consisting of only the logged in user",
"name": "createTeam",
"group": "Team",
"version": "0.0.8",
Expand All @@ -2170,13 +2170,6 @@
"field": "name",
"description": "<p>Name of the team.</p>"
},
{
"group": "body",
"type": "MongoID[]",
"optional": true,
"field": "members",
"description": "<p>Array of members in team.</p>"
},
{
"group": "body",
"type": "String",
Expand Down
2 changes: 1 addition & 1 deletion docs/api/api_project.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ define({
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2019-01-07T19:14:21.760Z",
"time": "2019-01-05T01:35:07.317Z",
"url": "http://apidocjs.com",
"version": "0.17.7"
}
Expand Down
2 changes: 1 addition & 1 deletion docs/api/api_project.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2019-01-07T19:14:21.760Z",
"time": "2019-01-05T01:35:07.317Z",
"url": "http://apidocjs.com",
"version": "0.17.7"
}
Expand Down
130 changes: 115 additions & 15 deletions middlewares/team.middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,42 @@ async function ensureUniqueHackerId(req, res, next) {

/**
* @async
* @function ensureSpance
* @function createTeam
* @param {{body: {teamDetails: {_id: ObjectId, name: string, members: ObjectId[], devpostURL?: string, projectName: string}}}} req
* @param {*} res
* @description create a team from information in req.body.teamDetails.
*/
async function createTeam(req, res, next) {
const teamDetails = req.body.teamDetails;

const team = await Services.Team.createTeam(teamDetails);

if (!team) {
return res.status(500).json({
message: Constants.Error.TEAM_CREATE_500_MESSAGE,
data: {}
});
}

for (const hackerId of teamDetails.members) {
const hacker = await Services.Hacker.updateOne(hackerId, {
teamId: team._id
});

if (!hacker) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to perform this check?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good check in case some error happens with db, or something to cause the update to fail.

return res.status(500).json({
message: Constants.Error.HACKER_UPDATE_500_MESSAGE,
data: {}
});
}
}

req.body.team = team;
return next();
}

/**
* @function ensureSpace
* @param {{body: {name: string}}} req
* @param {JSON} res
* @param {(err?)=>void} next
Expand Down Expand Up @@ -85,26 +120,49 @@ async function ensureSpace(req, res, next) {
}

/**
* @async
* @function createTeam
* @param {{body: {teamDetails: {_id: ObjectId, name: string, members: ObjectId[], devpostURL?: string, projectName: string}}}} req
* @param {*} res
* @description create a team from information in req.body.teamDetails.
* @function ensureFreeTeamName
* @param {{body: {teamDetails: {name: String}}}} req
* @param {JSON} res
* @param {(err?)=>void} next
* @return {void}
* @description Checks to see that the team name is not in use.
*/
async function createTeam(req, res, next) {
async function ensureFreeTeamName(req, res, next) {
const teamDetails = req.body.teamDetails;

const team = await Services.Team.createTeam(teamDetails);
const team = await Services.Team.findByName(teamDetails.name);

if (team) {
return next({
status: 409,
message: Constants.Error.TEAM_NAME_409_MESSAGE,
data: teamDetails.name
});
}

return next();
}

/**
* @async
* @function findById
* @param {{body: {id: ObjectId}}} req
* @param {*} res
* @return {JSON} Success or error status
* @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.
*/
async function findById(req, res, next) {
const team = await Services.Team.findById(req.body.id);

if (!team) {
return res.status(500).json({
message: Constants.Error.TEAM_CREATE_500_MESSAGE,
return res.status(404).json({
message: Constants.Error.TEAM_404_MESSAGE,
data: {}
});
} else {
req.body.team = team;
return next();
}

req.body.team = team;
return next();
}

/**
Expand Down Expand Up @@ -145,7 +203,7 @@ async function updateHackerTeam(req, res, next) {
return next({
status: 409,
message: Constants.Error.TEAM_JOIN_SAME_409_MESSAGE,
data: req.body.teamName
data: req.body.name
});
}

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


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

Expand Down Expand Up @@ -258,12 +315,55 @@ function parseTeam(req, res, next) {
return next();
}

async function parseNewTeam(req, res, next) {
const teamDetails = {
_id: mongoose.Types.ObjectId(),
name: req.body.name,
members: [],
devpostURL: req.body.devpostURL,
projectName: req.body.projectName
};

delete req.body.name;
delete req.body.members;
delete req.body.devpostURL;
delete req.body.projectName;

// hacker should exist because of authorization
const hacker = await Services.Hacker.findByAccountId(req.user.id);

if (!hacker) {
return next({
status: 404,
message: Constants.Error.HACKER_404_MESSAGE,
data: {
id: req.user.id
}
});
}

// hacker should not be in another team
if (hacker.teamId !== undefined) {
return next({
status: 409,
message: Constants.Error.TEAM_MEMBER_409_MESSAGE,
});
}

teamDetails.members.push(hacker._id);

req.body.teamDetails = teamDetails;
return next();
}

module.exports = {
parseTeam: parseTeam,
findById: Util.asyncMiddleware(findById),
createTeam: Util.asyncMiddleware(createTeam),
ensureUniqueHackerId: Util.asyncMiddleware(ensureUniqueHackerId),
ensureSpace: Util.asyncMiddleware(ensureSpace),
updateHackerTeam: Util.asyncMiddleware(updateHackerTeam),
parseNewTeam: Util.asyncMiddleware(parseNewTeam),
ensureFreeTeamName: Util.asyncMiddleware(ensureFreeTeamName),
populateMemberAccountsById: Util.asyncMiddleware(populateMemberAccountsById),
};
2 changes: 0 additions & 2 deletions middlewares/validators/team.validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ const Constants = require("../../constants/general.constant");
module.exports = {
newTeamValidator: [
VALIDATOR.asciiValidator("body", "name", false),
// members by mongoID if the team creator is able to provide
VALIDATOR.mongoIdArrayValidator("body", "members", true),
VALIDATOR.regexValidator("body", "devpostURL", true, Constants.DEVPOST_REGEX),
VALIDATOR.asciiValidator("body", "projectName", true)
],
Expand Down
2 changes: 1 addition & 1 deletion models/team.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const Constants = require("../constants/general.constant");
const TeamSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true,
required: true
},
members: {
type: [{
Expand Down
15 changes: 5 additions & 10 deletions routes/api/team.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,18 @@ const Middleware = {
Team: require("../../middlewares/team.middleware"),
Auth: require("../../middlewares/auth.middleware"),
};
const Services = {
Hacker: require("../../services/hacker.service"),
};

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

/**
* @api {post} /team/ create a new team
* @api {post} /team/ create a new team consisting of only the logged in user
* @apiName createTeam
* @apiGroup Team
* @apiVersion 0.0.8
*
* @apiParam (body) {String} name Name of the team.
* @apiParam (body) {MongoID[]} [members] Array of members in team.
* @apiParam (body) {String} [devpostURL] Devpost link to hack. Once the link is sent, the hack will be considered to be submitted.
* @apiParam (body) {String} [projectName] Name of the team.
*
Expand All @@ -49,15 +45,14 @@ module.exports = {
* {"message": "Error while creating team", "data": {}}
*/
teamRouter.route("/").post(
Middleware.Auth.ensureAuthenticated(),
Middleware.Auth.ensureAuthorized(),
// Validators
Middleware.Validator.Team.newTeamValidator,

Middleware.parseBody.middleware,
Middleware.Team.parseNewTeam,

Middleware.Team.parseTeam,

// check that member is not already in a team
Middleware.Team.ensureUniqueHackerId,
Middleware.Team.ensureFreeTeamName,

Middleware.Team.createTeam,
Controllers.Team.createdTeam
Expand Down
2 changes: 1 addition & 1 deletion services/team.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function findTeamByHackerId(hackerId) {
* @return {Promise<Team>} The promise will resolve to a team object if save was successful.
* @description Adds a new team to database.
*/
function createTeam(teamDetails) {
async function createTeam(teamDetails) {
const TAG = `[Team Service # createTeam]:`;

const team = new Team(teamDetails);
Expand Down
Loading