diff --git a/controllers/discordactions.js b/controllers/discordactions.js index 7c71c885e..7b4e4fb6e 100644 --- a/controllers/discordactions.js +++ b/controllers/discordactions.js @@ -464,15 +464,18 @@ const setRoleToUsersWith31DaysPlusOnboarding = async (req, res) => { const generateInviteForUser = async (req, res) => { try { - const { userId } = req.query; + const { userId, dev } = req.query; const userIdForInvite = userId || req.userData.id; - - const modelResponse = await discordRolesModel.getUserDiscordInvite(userIdForInvite); - - if (!modelResponse.notFound) { - return res.status(409).json({ - message: "User invite is already present!", - }); + let inviteLink = ""; + const isDev = dev === "true"; + + if (!isDev) { + const modelResponse = await discordRolesModel.getUserDiscordInvite(userIdForInvite); + if (!modelResponse.notFound) { + return res.status(409).json({ + message: "User invite is already present!", + }); + } } const channelId = config.get("discordNewComersChannelId"); @@ -492,7 +495,18 @@ const generateInviteForUser = async (req, res) => { const discordInviteResponse = await response.json(); const inviteCode = discordInviteResponse.data.code; - const inviteLink = `discord.gg/${inviteCode}`; + inviteLink = `discord.gg/${inviteCode}`; + + if (isDev) { + const purpose = req.body.purpose; + await discordRolesModel.addInviteToInviteModel({ userId: userIdForInvite, inviteLink, purpose }); + + return res.status(201).json({ + message: "invite generated successfully", + inviteLink, + purpose, + }); + } await discordRolesModel.addInviteToInviteModel({ userId: userIdForInvite, inviteLink }); @@ -508,8 +522,9 @@ const generateInviteForUser = async (req, res) => { const getUserDiscordInvite = async (req, res) => { try { - const { userId } = req.query; + const { userId, dev } = req.query; const isSuperUser = req.userData.roles.super_user; + const isDev = dev === "true"; if (userId && !isSuperUser) return res.boom.forbidden("User should be super user to get link for other users"); @@ -521,7 +536,14 @@ const getUserDiscordInvite = async (req, res) => { return res.boom.notFound("User invite doesn't exist"); } - return res.json({ + if (isDev) { + return res.status(200).json({ + message: "Invite returned successfully", + inviteLink: invite?.inviteLink, + purpose: invite?.purpose, + }); + } + return res.status(200).json({ message: "Invite returned successfully", inviteLink: invite?.inviteLink, }); diff --git a/middlewares/validators/discordactions.js b/middlewares/validators/discordactions.js index 96db3b09b..88cf25695 100644 --- a/middlewares/validators/discordactions.js +++ b/middlewares/validators/discordactions.js @@ -40,8 +40,24 @@ const validateUpdateUsersNicknameStatusBody = async (req, res, next) => { } }; +export const validateGenerateInviteForUserBody = async (req, res, next) => { + const schema = Joi.object().strict().keys({ + purpose: Joi.string().trim(), + }); + + try { + await schema.validateAsync(req.body); + next(); + } catch (error) { + const errorMessages = error.details.map((detail) => detail.message); + logger.error(`Error while validating invite creation payload: ${errorMessages}`); + res.boom.badRequest(errorMessages); + } +}; + module.exports = { validateGroupRoleBody, validateMemberRoleBody, validateUpdateUsersNicknameStatusBody, + validateGenerateInviteForUserBody, }; diff --git a/routes/discordactions.js b/routes/discordactions.js index 1d7621787..efbc80609 100644 --- a/routes/discordactions.js +++ b/routes/discordactions.js @@ -21,6 +21,7 @@ const { validateGroupRoleBody, validateMemberRoleBody, validateUpdateUsersNicknameStatusBody, + validateGenerateInviteForUserBody, } = require("../middlewares/validators/discordactions"); const checkIsVerifiedDiscord = require("../middlewares/verifydiscord"); const checkCanGenerateDiscordLink = require("../middlewares/checkCanGenerateDiscordLink"); @@ -45,7 +46,13 @@ router.delete( ); router.post("/roles", authenticate, checkIsVerifiedDiscord, validateMemberRoleBody, addGroupRoleToMember); router.get("/invite", authenticate, getUserDiscordInvite); -router.post("/invite", authenticate, checkCanGenerateDiscordLink, generateInviteForUser); +router.post( + "/invite", + authenticate, + checkCanGenerateDiscordLink, + validateGenerateInviteForUserBody, + generateInviteForUser +); router.delete("/roles", authenticate, checkIsVerifiedDiscord, deleteRole); router.get("/roles", authenticate, checkIsVerifiedDiscord, getGroupsRoleId); router.patch( diff --git a/test/integration/discordactions.test.js b/test/integration/discordactions.test.js index d943f85e6..298912a11 100644 --- a/test/integration/discordactions.test.js +++ b/test/integration/discordactions.test.js @@ -993,6 +993,27 @@ describe("Discord actions", function () { expect(res.body.message).to.be.equal("User should be super user to generate link for other users"); }); + it("Should return the invite and the purpose for other user if the dev=true is provided in the query and the user is super user", async function () { + fetchStub.returns( + Promise.resolve({ + status: 201, + json: () => Promise.resolve({ data: { code: "xyz" } }), + }) + ); + + const res = await chai + .request(app) + .post(`/discord-actions/invite?dev=true`) + .set("cookie", `${cookieName}=${superUserAuthToken}`) + .send({ + purpose: "testing", + }); + expect(res).to.have.status(201); + expect(res.body.message).to.be.equal("invite generated successfully"); + expect(res.body.inviteLink).to.be.equal("discord.gg/xyz"); + expect(res.body.purpose).to.be.equal("testing"); + }); + // eslint-disable-next-line mocha/no-skipped-tests it.skip("should return 403 if the user has discord id in their user object, which means user is already in discord", async function () { const res = await chai diff --git a/test/unit/middlewares/discordactions-validators.test.js b/test/unit/middlewares/discordactions-validators.test.js index b96804bc5..212030117 100644 --- a/test/unit/middlewares/discordactions-validators.test.js +++ b/test/unit/middlewares/discordactions-validators.test.js @@ -3,6 +3,7 @@ const { validateGroupRoleBody, validateMemberRoleBody, validateUpdateUsersNicknameStatusBody, + validateGenerateInviteForUserBody, } = require("../../../middlewares/validators/discordactions"); const { expect } = require("chai"); @@ -127,4 +128,34 @@ describe("Middleware | Validators | discord actions", function () { expect(nextSpy.callCount).to.be.equal(0); }); }); + + describe("validateGenerateInviteForUserBody", function () { + it("lets the request pass to the next function", async function () { + const res = {}; + const req = { + body: { + purpose: "testing", + }, + }; + const nextSpy = Sinon.spy(); + await validateGenerateInviteForUserBody(req, res, nextSpy); + expect(nextSpy.calledOnce).to.be.equal(true); + }); + + it("stops the propogation to the next function", async function () { + const res = { + boom: { + badRequest: () => {}, + }, + }; + const nextSpy = Sinon.spy(); + const req = { + body: {}, + }; + await validateMemberRoleBody(req, res, nextSpy).catch((err) => { + expect(err).to.be.an.instanceOf(Error); + }); + expect(nextSpy.callCount).to.be.equal(0); + }); + }); }); diff --git a/test/unit/models/discordactions.test.js b/test/unit/models/discordactions.test.js index 249e70601..03233eca9 100644 --- a/test/unit/models/discordactions.test.js +++ b/test/unit/models/discordactions.test.js @@ -1,3 +1,4 @@ +import { generateDiscordInviteLink } from "../../../utils/discord-actions"; const chai = require("chai"); const expect = chai.expect; const sinon = require("sinon"); @@ -862,6 +863,54 @@ describe("discordactions", function () { }); }); + describe("generateInviteForUser", function () { + let fetchStub; + + beforeEach(async function () { + fetchStub = sinon.stub(global, "fetch"); + }); + + afterEach(function () { + fetchStub.restore(); + }); + + it("should return the invite link and purpose", async function () { + const inviteLink = "discord.gg/xyz"; + const discordInviteLink = { + data: { + code: "xyz", + }, + }; + fetchStub.resolves({ + ok: true, + json: () => discordInviteLink, + }); + + const result = await generateDiscordInviteLink(); + expect(result).to.be.equal(inviteLink); + + const inviteObject = { userId: "123456", inviteLink: "discord.gg/xyz", purpose: "testing" }; + await addInviteToInviteModel(inviteObject); + + const invite = await getUserDiscordInvite("123456"); + expect(invite).to.have.property("id"); + expect(invite.notFound).to.be.equal(false); + expect(invite.userId).to.be.equal("123456"); + expect(invite.inviteLink).to.be.equal("discord.gg/xyz"); + expect(invite.purpose).to.be.equal("testing"); + }); + + it("should resolve with an error", async function () { + const error = new Error("Error"); + fetchStub.rejects(error); + try { + await generateDiscordInviteLink(); + } catch (err) { + expect(err).to.be.equal(error); + } + }); + }); + describe("groupUpdateLastJoinDate", function () { beforeEach(function () { sinon.stub(discordRoleModel, "doc").returns({