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
15 changes: 10 additions & 5 deletions constants/routes.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ const authRoutes = {
requestType: Constants.REQUEST_TYPES.POST,
uri: "/api/auth/logout"
},
"invite": {
requestType: Constants.REQUEST_TYPES.POST,
uri: "/api/auth/invite"
},
"getSelfRoleBindindings": {
requestType: Constants.REQUEST_TYPES.GET,
uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.SELF
Expand Down Expand Up @@ -181,7 +177,16 @@ const staffRoutes = {
"hackerStats": {
requestType: Constants.REQUEST_TYPES.GET,
uri: "/api/hacker/stats",
}
},
"postInvite": {
requestType: Constants.REQUEST_TYPES.POST,
uri: "/api/account/invite"
},
"getInvite": {
requestType: Constants.REQUEST_TYPES.GET,
uri: "/api/account/invite"
},

}

const allRoutes = {
Expand Down
3 changes: 2 additions & 1 deletion constants/success.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const ACCOUNT_READ = "Account retrieval successful.";
const ACCOUNT_CREATE = "Account creation successful.";
const ACCOUNT_UPDATE = "Account update successful.";
const ACCOUNT_INVITE = "Account invitation successful.";
const ACCOUNT_GET_INVITES = "Invite retrieval successful.";

const AUTH_LOGIN = "Login successful.";
const AUTH_LOGOUT = "Logout successful.";
Expand Down Expand Up @@ -46,8 +47,8 @@ module.exports = {
ACCOUNT_CREATE: ACCOUNT_CREATE,
ACCOUNT_UPDATE: ACCOUNT_UPDATE,
ACCOUNT_INVITE: ACCOUNT_INVITE,
ACCOUNT_GET_INVITES: ACCOUNT_GET_INVITES,
ACCOUNT_READ: ACCOUNT_READ,

AUTH_LOGIN: AUTH_LOGIN,
AUTH_LOGOUT: AUTH_LOGOUT,
AUTH_SEND_RESET_EMAIL: AUTH_SEND_RESET_EMAIL,
Expand Down
9 changes: 9 additions & 0 deletions controllers/account.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,18 @@ function invitedAccount(req, res) {
});
}

function gotInvites(req, res) {
return res.status(200).json({
message: Constants.Success.ACCOUNT_GET_INVITES,
data: {
invites: req.body.invites
}
});
}

module.exports = {
addUser: addUser,
gotInvites: gotInvites,
updatedAccount: updatedAccount,
invitedAccount: invitedAccount,
showAccount: showAccount,
Expand Down
21 changes: 21 additions & 0 deletions docs/api/api_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,27 @@ define({
"url": "https://api.mchacks.ca/api/account/:id"
}]
},
{
"type": "get",
"url": "/account/invite",
"title": "Get all of the invites.",
"name": "getAllInvites",
"group": "Account",
"version": "0.0.8",
"description": "<p>Get all of the invites that currently exist in the database.</p>",
"success": {
"examples": [{
"title": "Success-Response: ",
"content": "{\n \"message\": \"Invite retrieval successful.\", \n \"data\": [{\n \"email\":\"abc@def.com\",\n \"accountType\":\"Hacker\"\n }]\n }",
"type": "object"
}]
},
"filename": "routes/api/account.js",
"groupTitle": "Account",
"sampleRequest": [{
"url": "https://api.mchacks.ca/api/account/invite"
}]
},
{
"type": "post",
"url": "/account/invite",
Expand Down
21 changes: 21 additions & 0 deletions docs/api/api_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,27 @@
"url": "https://api.mchacks.ca/api/account/:id"
}]
},
{
"type": "get",
"url": "/account/invite",
"title": "Get all of the invites.",
"name": "getAllInvites",
"group": "Account",
"version": "0.0.8",
"description": "<p>Get all of the invites that currently exist in the database.</p>",
"success": {
"examples": [{
"title": "Success-Response: ",
"content": "{\n \"message\": \"Invite retrieval successful.\", \n \"data\": [{\n \"email\":\"abc@def.com\",\n \"accountType\":\"Hacker\"\n }]\n }",
"type": "object"
}]
},
"filename": "routes/api/account.js",
"groupTitle": "Account",
"sampleRequest": [{
"url": "https://api.mchacks.ca/api/account/invite"
}]
},
{
"type": "post",
"url": "/account/invite",
Expand Down
14 changes: 13 additions & 1 deletion middlewares/account.middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,24 @@ async function inviteAccount(req, res, next) {
message: Constants.Error.EMAIL_500_MESSAGE,
});
}

}
/**
* Gets all of the invites in the database and adds it to req.body.
* @param {{}} req
* @param {*} res
* @param {(err?)=>void} next
*/
async function getInvites(req, res, next) {
Copy link
Member

Choose a reason for hiding this comment

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

Function comments - also what does find do when the query is empty?

Copy link
Member Author

Choose a reason for hiding this comment

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

Query is not an input parameter, so it is always set to {}.

const invites = await Services.AccountConfirmation.find({});
req.body.invites = invites;
next();
}

module.exports = {
parsePatch: parsePatch,
parseAccount: parseAccount,
// untested
getInvites: Middleware.Util.asyncMiddleware(getInvites),
getByEmail: Middleware.Util.asyncMiddleware(getByEmail),
getById: Middleware.Util.asyncMiddleware(getById),
// untested
Expand Down
94 changes: 58 additions & 36 deletions routes/api/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,64 @@ module.exports = {
Controllers.Account.addUser
);

/**
* @api {post} /account/invite invites a user to create an account with the specified accountType
* @apiName inviteAccount
* @apiGroup Account
* @apiVersion 0.0.8
* @apiDescription sends link with token to be used with the account/create route
*
* @apiParam (body) {String} [email] email of the account to be created and where to send the link
* @apiParam (body) {String} [accountType] the type of the account which the user can create, for sponsor this should specify tier as well
*
* @apiSuccess {string} message Success message
* @apiSuccess {object} data Account object
* @apiSuccessExample {object} Success-Response:
* {
"message": "Successfully invited user",
"data": {}
}
* @apiError {string} message Error message
* @apiError {object} data Error object
* @apiErrorExample {object} Error-Response:
* {
"message": "Invalid Authentication",
"data": {
"route": "/invite"
}
}
*/
accountRouter.route("/invite").post(
Middleware.Auth.ensureAuthenticated(),
Middleware.Auth.ensureAuthorized(),
Middleware.Validator.Account.inviteAccountValidator,
Middleware.parseBody.middleware,
Middleware.Account.inviteAccount,
Controllers.Account.invitedAccount
);
/**
* @api {get} /account/invite Get all of the invites.
* @apiName getAllInvites
* @apiGroup Account
* @apiVersion 0.0.8
* @apiDescription Get all of the invites that currently exist in the database.
* @apiSuccessExample {object} Success-Response:
* {
"message": "Invite retrieval successful.",
"data": [{
"email":"abc@def.com",
"accountType":"Hacker"
}]
}
*/
accountRouter.route("/invite").get(
Middleware.Auth.ensureAuthenticated(),
Middleware.Auth.ensureAuthorized(),
Middleware.parseBody.middleware,
Middleware.Account.getInvites,
Controllers.Account.gotInvites
);

/**
* @api {patch} /account/:id update an account's information
* @apiName updateOneUser
Expand Down Expand Up @@ -241,42 +299,6 @@ module.exports = {
Controllers.Account.showAccount
);

/**
* @api {post} /account/invite invites a user to create an account with the specified accountType
* @apiName inviteAccount
* @apiGroup Account
* @apiVersion 0.0.8
* @apiDescription sends link with token to be used with the account/create route
*
* @apiParam (body) {String} [email] email of the account to be created and where to send the link
* @apiParam (body) {String} [accountType] the type of the account which the user can create, for sponsor this should specify tier as well
*
* @apiSuccess {string} message Success message
* @apiSuccess {object} data Account object
* @apiSuccessExample {object} Success-Response:
* {
"message": "Successfully invited user",
"data": {}
}
* @apiError {string} message Error message
* @apiError {object} data Error object
* @apiErrorExample {object} Error-Response:
* {
"message": "Invalid Authentication",
"data": {
"route": "/invite"
}
}
*/
accountRouter.route("/invite").post(
Middleware.Auth.ensureAuthenticated(),
Middleware.Auth.ensureAuthorized(),
Middleware.Validator.Account.inviteAccountValidator,
Middleware.parseBody.middleware,
Middleware.Account.inviteAccount,
Controllers.Account.invitedAccount
);

apiRouter.use("/account", accountRouter);
}
};
12 changes: 12 additions & 0 deletions services/accountConfirmation.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ function findById(id) {
return AccountConfirmation.findById(id, logger.queryCallbackFactory(TAG, "AccountConfirmation", "mongoId"));
}

/**
* @function find
* @param {*} query the query to search the database by.
* @return {DocumentQuery<any[]>} The document query will resolve to either account confirmations or null.
* @description Finds an account by query.
*/
function find(query) {
const TAG = `[ AccountConfirmation Service # find ]`;
return AccountConfirmation.find(query, logger.queryCallbackFactory(TAG, "AccountConfirmation", query));
}

/**
* Creates Account Confirmation document in the database
* @param {String} type the type of user which to create the token for
Expand Down Expand Up @@ -158,6 +169,7 @@ function generateAccountInvitationEmail(address, receiverEmail, type, token) {
return mailData;
}
module.exports = {
find: find,
findById: findById,
findByAccountId: findByAccountId,
create: create,
Expand Down
51 changes: 51 additions & 0 deletions tests/account.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -544,4 +544,55 @@ describe("POST invite account", function () {
});
});
});
});

describe("GET invites", function () {
it("Should FAIL to get all invites due to Authentication", function (done) {
chai.request(server.app)
.get("/api/account/invite")
.end(function (err, res) {
res.should.have.status(401);
res.body.should.have.property("message");
res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE);
done();
});
});
it("Should FAIL to get all invites due to Authorization", function (done) {
util.auth.login(agent, storedAccount1, (error) => {
if (error) {
agent.close();
return done(error);
}
return agent
.get("/api/account/invite")
.end(function (err, res) {
res.should.have.status(403);
res.body.should.have.property("message");
res.body.message.should.equal(Constants.Error.AUTH_403_MESSAGE);
done();
});
});
});
it("Should SUCCEED to get all invites", function (done) {
util.auth.login(agent, Admin1, (error) => {
if (error) {
agent.close();
return done(error);
}
return agent
.get("/api/account/invite")
.end(function (err, res) {
if (err) {
return done(err);
}
res.should.have.status(200);
res.body.should.have.property("message");
res.body.message.should.equal(Constants.Success.ACCOUNT_GET_INVITES);
res.body.should.have.property("data");
res.body.data.should.have.property("invites");
res.body.data.invites.length.should.equal(util.accountConfirmation.AccountConfirmationTokens.length);
done();
});
});
});
});
13 changes: 10 additions & 3 deletions tests/util/accountConfirmation.test.util.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@ const HackerConfirmation2 = {
"accountId": Util.Account.NonConfirmedAccount2._id,
"accountType": Constants.HACKER,
"email": Util.Account.NonConfirmedAccount2.email
}
};

const HackerConfirmation3 = {
"_id": mongoose.Types.ObjectId(),
"email": Util.Account.newAccount1
"email": Util.Account.newAccount1.email
};

const HackerConfirmation4 = {
"_id": mongoose.Types.ObjectId(),
"accountType": Constants.HACKER,
"email": "abcd@efgh.com"
};

// Using a real ID which is stored but corresponds to another account
Expand All @@ -46,7 +52,8 @@ const FakeToken = Services.AccountConfirmation.generateToken(FakeHackerToken._id
const AccountConfirmationTokens = [
HackerConfirmation,
HackerConfirmation2,
HackerConfirmation3
HackerConfirmation3,
HackerConfirmation4
];

function storeAll(attributes) {
Expand Down