Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unverified role to db and remove on /verify #2257

2 changes: 2 additions & 0 deletions constants/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const logType = {
TASKS_MISSED_UPDATES_ERRORS: "TASKS_MISSED_UPDATES_ERRORS",
DISCORD_INVITES: "DISCORD_INVITES",
EXTERNAL_SERVICE: "EXTERNAL_SERVICE",
ADD_UNVERIFIED_ROLE: "ADD_UNVERIFIED_ROLE",
REMOVE_UNVERIFIED_ROLE: "REMOVE_UNVERIFIED_ROLE",
EXTENSION_REQUESTS: "extensionRequests",
TASK: "task",
TASK_REQUESTS: "taskRequests",
Expand Down
24 changes: 15 additions & 9 deletions controllers/external-accounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { getDiscordMembers } = require("../services/discordService");
const { addOrUpdate, getUsersByRole, updateUsersInBatch } = require("../models/users");
const { retrieveDiscordUsers, fetchUsersForKeyValues } = require("../services/dataAccessLayer");
const { EXTERNAL_ACCOUNTS_POST_ACTIONS } = require("../constants/external-accounts");
const discordServices = require("../services/discordService");
const removeDiscordRoleUtils = require("../utils/removeDiscordRoleFromUser");
const config = require("config");
const logger = require("../utils/logger");
const { markUnDoneTasksOfArchivedUsersBacklog } = require("../models/tasks");
Expand Down Expand Up @@ -71,14 +71,20 @@ const linkExternalAccount = async (req, res) => {
userId
);

try {
const unverifiedRoleId = config.get("discordUnverifiedRoleId");
await discordServices.removeRoleFromUser(unverifiedRoleId, attributes.discordId, req.userData);
} catch (error) {
logger.error(`Error getting external account data: ${error}`);
return res.boom.internal("Role Deletion failed. Please contact admin.", {
message: "Role Deletion failed. Please contact admin.",
});
const unverifiedRoleId = config.get("discordUnverifiedRoleId");
const unverifiedRoleRemovalResponse = await removeDiscordRoleUtils.removeDiscordRoleFromUser(
req.userData,
attributes.discordId,
unverifiedRoleId
);

if (!unverifiedRoleRemovalResponse.success) {
return res.boom.internal(
`User details updated but ${unverifiedRoleRemovalResponse.message}. Please contact admin`,
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved
{
message: `User details updated but ${unverifiedRoleRemovalResponse.message}. Please contact admin`,
}
);
}

return res.status(204).json({ message: "Your discord profile has been linked successfully" });
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
18 changes: 16 additions & 2 deletions controllers/users.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const chaincodeQuery = require("../models/chaincodes");
const userQuery = require("../models/users");
const profileDiffsQuery = require("../models/profileDiffs");
const admin = require("firebase-admin");
const logsQuery = require("../models/logs");
const imageService = require("../services/imageService");
const { profileDiffStatus } = require("../constants/profileDiff");
Expand Down Expand Up @@ -30,6 +31,8 @@ const { addLog } = require("../models/logs");
const { getUserStatus } = require("../models/userStatus");
const config = require("config");
const { generateUniqueUsername } = require("../services/users");
const { addGroupRoleToMember } = require("../models/discordactions");

const discordDeveloperRoleId = config.get("discordDeveloperRoleId");

const verifyUser = async (req, res) => {
Expand Down Expand Up @@ -595,7 +598,6 @@ const markUnverified = async (req, res) => {
const unverifiedRoleId = config.get("discordUnverifiedRoleId");
const usersToApplyUnverifiedRole = [];
const addRolePromises = [];
const discordDeveloperRoleId = config.get("discordDeveloperRoleId");

allRdsLoggedInUsers.forEach((user) => {
rdsUserMap[user.discordId] = true;
Expand All @@ -612,7 +614,19 @@ const markUnverified = async (req, res) => {
});

usersToApplyUnverifiedRole.forEach((id) => {
addRolePromises.push(addRoleToUser(id, unverifiedRoleId));
addRolePromises.push(
addRoleToUser(id, unverifiedRoleId),
addGroupRoleToMember({
roleid: unverifiedRoleId,
userid: id,
date: admin.firestore.Timestamp.fromDate(new Date()),
}),
addLog(
Achintya-Chatterjee marked this conversation as resolved.
Show resolved Hide resolved
logType.ADD_UNVERIFIED_ROLE,
{ roleid: unverifiedRoleId, userid: id },
{ message: "Unverified role added successfully" }
)
);
});

await Promise.all(addRolePromises);
Expand Down
50 changes: 43 additions & 7 deletions test/integration/external-accounts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ const externalAccountsModel = require("../../models/external-accounts");
const { usersFromRds, getDiscordMembers } = require("../fixtures/discordResponse/discord-response");
const Sinon = require("sinon");
const { INTERNAL_SERVER_ERROR } = require("../../constants/errorMessages");
const removeDiscordRoleUtils = require("../../utils/removeDiscordRoleFromUser");
const firestore = require("../../utils/firestore");
const userData = require("../fixtures/user/user")();
const userModel = firestore.collection("users");
const tasksModel = firestore.collection("tasks");
const discordServices = require("../../services/discordService");
const { EXTERNAL_ACCOUNTS_POST_ACTIONS } = require("../../constants/external-accounts");
chai.use(chaiHttp);
const cookieName = config.get("userToken.cookieName");
Expand Down Expand Up @@ -538,7 +538,10 @@ describe("External Accounts", function () {
expect(getUserResponseBeforeUpdate.body).to.not.have.property("discordId");
expect(getUserResponseBeforeUpdate.body).to.not.have.property("discordJoinedAt");

const removeRoleFromUserStub = Sinon.stub(discordServices, "removeRoleFromUser").resolves();
const removeDiscordRoleStub = Sinon.stub(removeDiscordRoleUtils, "removeDiscordRoleFromUser").resolves({
success: true,
message: "Role deleted successfully",
});

const response = await chai
.request(app)
Expand All @@ -557,26 +560,59 @@ describe("External Accounts", function () {
expect(updatedUserDetails.body).to.have.property("discordId");
expect(updatedUserDetails.body).to.have.property("discordJoinedAt");

removeRoleFromUserStub.restore();
removeDiscordRoleStub.restore();
});

it("Should return 500 when removeDiscordRole fails because role doesn't exist", async function () {
await externalAccountsModel.addExternalAccountData(externalAccountData[2]);

const removeDiscordRoleStub = Sinon.stub(removeDiscordRoleUtils, "removeDiscordRoleFromUser").resolves({
success: false,
message: "Role doesn't exist",
});

const response = await chai
.request(app)
.patch(`/external-accounts/link/${externalAccountData[2].token}`)
.query({ action: EXTERNAL_ACCOUNTS_POST_ACTIONS.DISCORD_USERS_SYNC })
.set("Cookie", `${cookieName}=${newUserJWT}`);

const unverifiedRoleRemovalResponse = await removeDiscordRoleStub();

expect(response).to.have.status(500);
expect(response.body).to.be.an("object");
expect(response.body).to.have.property("message");
expect(response.body.message).to.equal(
`User details updated but ${unverifiedRoleRemovalResponse.message}. Please contact admin`
);

removeDiscordRoleStub.restore();
});

it("Should return 500 when unverified role deletion failed", async function () {
it("Should return 500 when removeDiscordRole fails because role deletion failed", async function () {
await externalAccountsModel.addExternalAccountData(externalAccountData[2]);

const removeRoleFromUserStub = Sinon.stub(discordServices, "removeRoleFromUser").rejects();
const removeDiscordRoleStub = Sinon.stub(removeDiscordRoleUtils, "removeDiscordRoleFromUser").resolves({
success: false,
message: "Role deletion failed",
});

const response = await chai
.request(app)
.patch(`/external-accounts/link/${externalAccountData[2].token}`)
.query({ action: EXTERNAL_ACCOUNTS_POST_ACTIONS.DISCORD_USERS_SYNC })
.set("Cookie", `${cookieName}=${newUserJWT}`);

const unverifiedRoleRemovalResponse = await removeDiscordRoleStub();

expect(response).to.have.status(500);
expect(response.body).to.be.an("object");
expect(response.body).to.have.property("message");
expect(response.body.message).to.equal(`Role Deletion failed. Please contact admin.`);
expect(response.body.message).to.equal(
`User details updated but ${unverifiedRoleRemovalResponse.message}. Please contact admin`
);

removeRoleFromUserStub.restore();
removeDiscordRoleStub.restore();
});
});
});
72 changes: 72 additions & 0 deletions test/unit/utils/remvoeDiscordRoleFromUser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const chai = require("chai");
const Sinon = require("sinon");
const { expect } = chai;
const { removeDiscordRoleFromUser } = require("../../../utils/removeDiscordRoleFromUser");
const addUser = require("../../utils/addUser");
const cleanDb = require("../../utils/cleanDb");
const firestore = require("../../../utils/firestore");
const discordRolesModel = firestore.collection("discord-roles");
const memberRoleModel = firestore.collection("member-group-roles");
const userData = require("../../fixtures/user/user")();
const { groupData, memberGroupData } = require("../../fixtures/discordactions/discordactions");

describe("removeDiscordRoleFromUser", function () {
let userId;
let discordId;
let roleid;
let fetchStub;

beforeEach(async function () {
userData[0].roles = { archived: false, in_discord: true };
userId = await addUser(userData[0]);
discordId = userData[0].discordId;
userData[0] = { ...userData[0], id: userId };

const addRolePromises = memberGroupData.map(async (data) => {
await memberRoleModel.add(data);
});
const discordRolesModelPromise = [discordRolesModel.add(groupData[0]), discordRolesModel.add(groupData[1])];
await Promise.all(discordRolesModelPromise);
roleid = groupData[0].roleid;
await memberRoleModel.add({ roleid, userid: discordId });
await Promise.all(addRolePromises);

fetchStub = Sinon.stub(global, "fetch");
});

afterEach(async function () {
await cleanDb();
fetchStub.restore();
});

it("should remove discord role successfully", async function () {
fetchStub.returns(
Promise.resolve({ json: () => Promise.resolve({ success: true, message: "Role deleted successfully" }) })
);

const isDiscordRoleRemoved = await removeDiscordRoleFromUser(userData[0], discordId, roleid);

expect(isDiscordRoleRemoved.success).to.be.equal(true);
expect(isDiscordRoleRemoved.message).to.be.equal("Role deleted successfully");
});

it("should throw an error if role doesn't exist in database when attempting to remove", async function () {
roleid = "randomRoleId";

try {
await removeDiscordRoleFromUser(userData[0], discordId, roleid);
} catch (error) {
expect(error.message).to.equal("Role doesn't exist");
}
});

it("should throw an error if role deletion failed", async function () {
fetchStub.rejects(new Error("Role deletion failed"));

try {
await removeDiscordRoleFromUser(userData[0], discordId, roleid);
} catch (error) {
expect(error.message).to.equal("Role deletion failed");
}
});
});
Achintya-Chatterjee marked this conversation as resolved.
Show resolved Hide resolved
44 changes: 44 additions & 0 deletions utils/removeDiscordRoleFromUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const discordRolesModel = require("../models/discordactions");
const discordServices = require("../services/discordService");
const { logType } = require("../constants/logs");
const { addLog } = require("../models/logs");

/**
* Removes a Discord role from a user using Discord Id.
*
* @param {Object} userData - User data.
* @param {string} discordId - User's Discord ID.
* @param {string} roleid - Discord Role ID.
*
* @returns {Promise<Object>} - Result with success status and message.
*/
export const removeDiscordRoleFromUser = async (userData, discordId, roleid) => {
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved
try {
const role = await discordRolesModel.isGroupRoleExists({ roleid });
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved

if (!role.roleExists) {
throw new Error("Role doesn't exist");
}

const roleData = role.existingRoles.docs[0].data();
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved

await discordServices.removeRoleFromUser(roleData.roleid, discordId, userData);

const { wasSuccess } = await discordRolesModel.removeMemberGroup(roleData.roleid, discordId);
if (!wasSuccess) {
throw new Error("Role deletion failed");
}

await addLog(
logType.REMOVE_UNVERIFIED_ROLE,
{ roleid, userid: discordId },
{ message: "Unverified role removed successfully" }
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved
);

return { success: true, message: "Role deleted successfully" };
} catch (error) {
logger.error(`Error removing role ${roleid} for user ${discordId}: ${error.message}`);

return { success: false, message: error.message };
shobhan-sundar-goutam marked this conversation as resolved.
Show resolved Hide resolved
}
};
Loading