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

Dev To Main #2260

Merged
merged 6 commits into from
Nov 21, 2024
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
8 changes: 8 additions & 0 deletions config/custom-environment-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ module.exports = {
__name: "PORT",
__format: "number",
},

aws: {
region: "AWS_REGION",
access_key: "AWS_ACCESS_KEY",
secret_key: "AWS_SECRET_KEY",
identity_store_id: "IDENTITY_STORE_ID",
},

enableFileLogs: {
__name: "ENABLE_FILE_LOGS",
__format: "boolean",
Expand Down
7 changes: 7 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
org: "Real-Dev-Squad",
},

aws: {
region: "<aws-region>",
access_key: "<aws-access-key>",
secret_key: "<aws-secret-key>",
identity_store_id: "<identity-store-id>",
},

githubOauth: {
clientId: "<clientId>",
clientSecret: "<clientSecret>",
Expand Down Expand Up @@ -66,7 +73,7 @@
},

cors: {
allowedOrigins: /(https:\/\/([a-zA-Z0-9-_]+\.)?realdevsquad\.com$)/, // Allow realdevsquad.com, *.realdevsquad.com

Check warning on line 76 in config/default.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Unsafe Regular Expression
},

userToken: {
Expand Down
1 change: 1 addition & 0 deletions constants/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const logType = {
EXTENSION_REQUESTS: "extensionRequests",
TASK: "task",
TASK_REQUESTS: "taskRequests",
USER_DETAILS_UPDATED: "USER_DETAILS_UPDATED",
...REQUEST_LOG_TYPE,
};

Expand Down
2 changes: 2 additions & 0 deletions constants/urls.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export const GITHUB_URL = "https://github.com";
export const PROFILE_SVC_GITHUB_URL = "https://github.com/Real-Dev-Squad/sample-profile-service";

module.exports = {
GITHUB_URL,
PROFILE_SVC_GITHUB_URL,
};
2 changes: 1 addition & 1 deletion constants/userDataLevels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const ACCESS_LEVEL = {

const ROLE_LEVEL = {
private: ["super_user"],
internal: ["super_user"],
internal: ["super_user", "cloudfare_worker"],
confidential: ["super_user"],
};

Expand Down
9 changes: 9 additions & 0 deletions controllers/arts.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ const getSelfArts = async (req, res) => {
try {
const { id } = req.userData;
const arts = await artsQuery.fetchUserArts(id);
res.set(
"X-Deprecation-Warning",
"WARNING: This endpoint is deprecated and will be removed in the future. Please use /arts/:userId to get the art details."
);
return res.json({
message: "User arts returned successfully!",
arts,
Expand All @@ -64,6 +68,11 @@ const getUserArts = async (req, res) => {
try {
const userId = req.params.userId;
const arts = await artsQuery.fetchUserArts(userId);

if (!arts || arts.length === 0) {
return res.status(204).send();
}

return res.json({
message: `User Arts of userId ${userId} returned successfully`,
arts,
Expand Down
46 changes: 46 additions & 0 deletions controllers/awsAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { PROFILE_SVC_GITHUB_URL } from "../constants/urls";
import {addUserToGroup, createUser, fetchAwsUserIdByUsername} from "../utils/awsFunctions";
const dataAccess = require("../services/dataAccessLayer");
const userDataLevels = require('../constants/userDataLevels');

export const addUserToAWSGroup = async (req, res) => {
const { groupId, userId } = req.body;

try {
const userInfoData = await dataAccess.retrieveUsers({ discordId: userId, level: userDataLevels.ACCESS_LEVEL.INTERNAL, role: 'cloudfare_worker'});
if (!userInfoData.userExists) {
return res.status(400).json({ error: "User not found" });
} else if(!userInfoData.user.email) {
return res.status(400).json({ error: `User email is required to create an AWS user. Please update your email by setting up Profile service, url : ${PROFILE_SVC_GITHUB_URL}` });
}

let awsUserId = await fetchAwsUserIdByUsername(userInfoData.user.username);

let userCreationResponse = null;

if (awsUserId === null){
// We need to create the user in AWS before and then fetch its Id
userCreationResponse = await createUser(userInfoData.user.username, userInfoData.user.email);
awsUserId = userCreationResponse.UserId;
}

let userAdditionResponse = await addUserToGroup(groupId, awsUserId)

if (userAdditionResponse){
if (userAdditionResponse.conflict){
return res.status(200).json({
message: `User ${userId} is already part of the AWS group, please try signing in.`
})
} else {
return res.status(200).json({
message: `User ${userId} successfully added to group ${groupId}.`
});
}
}
} catch (error) {
logger.error(`Error in adding user - ${userId} to AWS group - ${groupId} error - ${error}`);
return res.status(500).json({
error: `Something went wrong, please try again`
});
}
};
56 changes: 56 additions & 0 deletions controllers/discordactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
const discordServices = require("../services/discordService");
const { fetchAllUsers, fetchUser } = require("../models/users");
const { generateCloudFlareHeaders } = require("../utils/discord-actions");
const { addLog } = require("../models/logs");
const discordDeveloperRoleId = config.get("discordDeveloperRoleId");
const discordMavenRoleId = config.get("discordMavenRoleId");

Expand Down Expand Up @@ -63,6 +64,60 @@
}
};

/**
* Controller function to handle the soft deletion of a group role.
*
* @param {Object} req - The request object
* @param {Object} res - The response object
* @returns {Promise<void>}
*/
const deleteGroupRole = async (req, res) => {
const { groupId } = req.params;

try {
const { roleExists, existingRoles } = await discordRolesModel.isGroupRoleExists({ groupId });

if (!roleExists) {
return res.boom.notFound("Group role not found");
}

const roleData = existingRoles.data();

const discordDeletion = await discordServices.deleteGroupRoleFromDiscord(roleData.roleid);

if (!discordDeletion.success) {
return res.boom.badImplementation(discordDeletion.message);
}

const { isSuccess } = await discordRolesModel.deleteGroupRole(groupId, req.userData.id);

if (!isSuccess) {
logger.error(`Role deleted from Discord but failed to delete from database for groupId: ${groupId}`);
return res.boom.badImplementation("Group role deletion failed");
}

const groupDeletionLog = {
type: "group-role-deletion",
meta: {
userId: req.userData.id,
},
body: {
groupId: groupId,
roleName: roleData.rolename,
discordRoleId: roleData.roleid,
action: "delete",
},
};
await addLog(groupDeletionLog.type, groupDeletionLog.meta, groupDeletionLog.body);
return res.status(200).json({
message: "Group role deleted successfully",
});
} catch (error) {
logger.error(`Error while deleting group role: ${error}`);
return res.boom.badImplementation("Internal server error");
}
};

/**
* Gets all group-roles
*
Expand Down Expand Up @@ -286,7 +341,7 @@
const nickNameUpdatedUsers = [];
let counter = 0;
for (let i = 0; i < usersToBeEffected.length; i++) {
const { discordId, username, first_name: firstName } = usersToBeEffected[i];

Check warning on line 344 in controllers/discordactions.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Variable Assigned to Object Injection Sink
try {
if (counter % 10 === 0 && counter !== 0) {
await new Promise((resolve) => setTimeout(resolve, 5500));
Expand All @@ -302,7 +357,7 @@
if (message) {
counter++;
totalNicknamesUpdated.count++;
nickNameUpdatedUsers.push(usersToBeEffected[i].id);

Check warning on line 360 in controllers/discordactions.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Generic Object Injection Sink
}
}
} catch (error) {
Expand Down Expand Up @@ -491,4 +546,5 @@
setRoleToUsersWith31DaysPlusOnboarding,
getUserDiscordInvite,
generateInviteForUser,
deleteGroupRole,
};
36 changes: 32 additions & 4 deletions models/discordactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,31 @@
}
};

/**
* Soft deletes a group role by marking it as deleted in the database.
* This function updates the role document in Firestore, setting isDeleted to true
* and recording who deleted it and when.
*
* @param {string} groupId - The ID of the group role to be deleted
* @param {string} deletedBy - The ID of the user performing the deletion for logging purpose
* @returns {Promise<Object>} An object indicating whether the operation was successful
*/
const deleteGroupRole = async (groupId, deletedBy) => {
try {
const roleRef = admin.firestore().collection("discord-roles").doc(groupId);
await roleRef.update({
isDeleted: true,
deletedAt: admin.firestore.Timestamp.fromDate(new Date()),
deletedBy: deletedBy,
});

return { isSuccess: true };
} catch (error) {
logger.error(`Error in deleteGroupRole: ${error}`);
return { isSuccess: false };
}
};

const removeMemberGroup = async (roleId, discordId) => {
try {
const backendResponse = await deleteRoleFromDatabase(roleId, discordId);
Expand Down Expand Up @@ -139,10 +164,13 @@

const isGroupRoleExists = async (options = {}) => {
try {
const { rolename = null, roleid = null } = options;
const { groupId = null, rolename = null, roleid = null } = options;

let existingRoles;
if (rolename && roleid) {
if (groupId) {
existingRoles = await discordRoleModel.doc(groupId).get();
return { roleExists: existingRoles.exists, existingRoles };
} else if (rolename && roleid) {
existingRoles = await discordRoleModel
.where("rolename", "==", rolename)
.where("roleid", "==", roleid)
Expand All @@ -153,9 +181,8 @@
} else if (roleid) {
existingRoles = await discordRoleModel.where("roleid", "==", roleid).limit(1).get();
} else {
throw Error("Either rolename or roleId is required");
throw Error("Either rolename, roleId, or groupId is required");
}

return { roleExists: !existingRoles.empty, existingRoles };
} catch (err) {
logger.error("Error in getting all group-roles", err);
Expand Down Expand Up @@ -496,7 +523,7 @@

for (let i = 0; i < nicknameUpdateBatches.length; i++) {
const promises = [];
const usersStatusDocsBatch = nicknameUpdateBatches[i];

Check warning on line 526 in models/discordactions.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Variable Assigned to Object Injection Sink
usersStatusDocsBatch.forEach((document) => {
const doc = document.data();
const userId = doc.userId;
Expand Down Expand Up @@ -1075,4 +1102,5 @@
getUserDiscordInvite,
addInviteToInviteModel,
groupUpdateLastJoinDate,
deleteGroupRole,
};
1 change: 1 addition & 0 deletions models/userStatus.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const { userState } = require("../constants/userStatus");
const discordRoleModel = firestore.collection("discord-roles");
const memberRoleModel = firestore.collection("member-group-roles");
const usersCollection = firestore.collection("users");
const config = require("config");
const DISCORD_BASE_URL = config.get("services.discordBot.baseUrl");
const { generateAuthTokenForCloudflare } = require("../utils/discord-actions");

Expand Down
17 changes: 17 additions & 0 deletions models/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const admin = require("firebase-admin");
const { INTERNAL_SERVER_ERROR } = require("../constants/errorMessages");
const { AUTHORITIES } = require("../constants/authorities");
const { formatUsername } = require("../utils/username");
const { logType } = require("../constants/logs");
const { addLog } = require("../services/logService");

/**
* Adds or updates the user data
Expand All @@ -48,6 +50,13 @@ const addOrUpdate = async (userData, userId = null) => {
},
{ merge: true }
);

const logData = {
type: logType.USER_DETAILS_UPDATED,
meta: { userId: userId },
body: userData,
};
await addLog(logData.type, logData.meta, logData.body);
}

return { isNewUser, userId };
Expand All @@ -63,6 +72,14 @@ const addOrUpdate = async (userData, userId = null) => {
}
if (user && !user.empty && user.docs !== null) {
await userModel.doc(user.docs[0].id).set({ ...userData, updated_at: Date.now() }, { merge: true });

const logData = {
type: logType.USER_DETAILS_UPDATED,
meta: { userId: user.docs[0].id },
body: userData,
};
await addLog(logData.type, logData.meta, logData.body);

const data = user.docs[0].data();
return {
isNewUser: false,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"tdd:watch": "sh scripts/tests/tdd.sh"
},
"dependencies": {
"@aws-sdk/client-identitystore": "^3.665.0",
"@types/nodemailer": "^6.4.15",
"axios": "1.7.2",
"cloudinary": "2.0.3",
Expand Down
6 changes: 4 additions & 2 deletions routes/arts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ const router = express.Router();
import authenticate from "../middlewares/authenticate";
import arts from "../controllers/arts";
import artValidator from "../middlewares/validators/arts";
import { devFlagMiddleware } from "../middlewares/devFlag";

router.get("/", arts.fetchArts);
router.get("/user/self", authenticate, arts.getSelfArts);
router.get("/user/:userId", authenticate, arts.getUserArts);
router.get("/user/self", authenticate, arts.getSelfArts); // this route is soon going to be deprecated soon, please use /arts/:userId endpoint.
router.get("/user/:userId", authenticate, arts.getUserArts); // this route is soon going to be deprecated soon, please use /arts/:userId endpoint.
router.get("/:userId", devFlagMiddleware, authenticate, arts.getUserArts);
router.post("/user/add", authenticate, artValidator.createArt, arts.addArt);

module.exports = router;
8 changes: 8 additions & 0 deletions routes/awsAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import express from "express"
import { addUserToAWSGroup } from "../controllers/awsAccess";
const router = express.Router();
const { verifyDiscordBot } = require("../middlewares/authorizeBot");

router.post("/access", verifyDiscordBot, addUserToAWSGroup);

module.exports = router;
11 changes: 10 additions & 1 deletion routes/discordactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const {
updateUsersNicknameStatus,
syncDiscordGroupRolesInFirestore,
setRoleToUsersWith31DaysPlusOnboarding,
deleteGroupRole,
} = require("../controllers/discordactions");
const {
validateGroupRoleBody,
Expand All @@ -29,11 +30,19 @@ const ROLES = require("../constants/roles");
const { Services } = require("../constants/bot");
const { verifyCronJob } = require("../middlewares/authorizeBot");
const { authorizeAndAuthenticate } = require("../middlewares/authorizeUsersAndService");

const { devFlagMiddleware } = require("../middlewares/devFlag");
const router = express.Router();

router.post("/groups", authenticate, checkIsVerifiedDiscord, validateGroupRoleBody, createGroupRole);
router.get("/groups", authenticate, checkIsVerifiedDiscord, getAllGroupRoles);
router.delete(
"/groups/:groupId",
authenticate,
checkIsVerifiedDiscord,
authorizeRoles([SUPERUSER]),
devFlagMiddleware,
deleteGroupRole
);
router.post("/roles", authenticate, checkIsVerifiedDiscord, validateMemberRoleBody, addGroupRoleToMember);
router.get("/invite", authenticate, getUserDiscordInvite);
router.post("/invite", authenticate, checkCanGenerateDiscordLink, generateInviteForUser);
Expand Down
1 change: 1 addition & 0 deletions routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import express from "express";
const app = express.Router();
import { devFlagMiddleware } from "../middlewares/devFlag";

app.use("/aws/groups", devFlagMiddleware, require("./awsAccess"))
app.use("/answers", require("./answers"));
app.use("/auctions", require("./auctions"));
app.use("/arts", require("./arts"));
Expand Down
2 changes: 1 addition & 1 deletion services/discordMembersService.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const jwt = require("jsonwebtoken");

const config = require("config");
const DISCORD_BASE_URL = config.get("services.discordBot.baseUrl");

/**
Expand Down
Loading
Loading