Skip to content

Commit

Permalink
Dev to main sync (#2349)
Browse files Browse the repository at this point in the history
Dev to Main Sync
  • Loading branch information
yesyash authored Jan 18, 2025
2 parents 4bf146e + 2aaed8f commit ba7a9e9
Show file tree
Hide file tree
Showing 17 changed files with 736 additions and 117 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:

strategy:
matrix:
node-version: [20.11.x]
node-version: [22.10.0]

steps:
- uses: actions/checkout@v3
Expand Down
86 changes: 82 additions & 4 deletions controllers/onboardingExtension.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import {
ERROR_WHILE_CREATING_REQUEST,
ERROR_WHILE_UPDATING_REQUEST,
LOG_ACTION,
ONBOARDING_REQUEST_CREATED_SUCCESSFULLY,
REQUEST_ALREADY_PENDING,
REQUEST_APPROVED_SUCCESSFULLY,
REQUEST_DOES_NOT_EXIST,
REQUEST_LOG_TYPE,
REQUEST_REJECTED_SUCCESSFULLY,
REQUEST_STATE,
REQUEST_TYPE,
UNAUTHORIZED_TO_CREATE_ONBOARDING_EXTENSION_REQUEST,
} from "../constants/requests";
import { userState } from "../constants/userStatus";
import { addLog } from "../services/logService";
import { createRequest, getRequestByKeyValues } from "../models/requests";
import { createRequest, getRequestByKeyValues, updateRequest } from "../models/requests";
import { fetchUser } from "../models/users";
import { getUserStatus } from "../models/userStatus";
import { User } from "../typeDefinitions/users";
import {
CreateOnboardingExtensionBody,
OnboardingExtension,
OnboardingExtensionCreateRequest,
OnboardingExtensionResponse
OnboardingExtensionResponse,
UpdateOnboardingExtensionStateRequest,
UpdateOnboardingExtensionStateRequestBody
} from "../types/onboardingExtension";
import { convertDateStringToMilliseconds, getNewDeadline } from "../utils/requests";
import { convertDaysToMilliseconds } from "../utils/time";
Expand All @@ -34,7 +40,11 @@ import { convertDaysToMilliseconds } from "../utils/time";
* @param {OnboardingExtensionResponse} res - The Express response object used to send back the response.
* @returns {Promise<OnboardingExtensionResponse>} Resolves to a response with the status and data or an error message.
*/
export const createOnboardingExtensionRequestController = async (req: OnboardingExtensionCreateRequest, res: OnboardingExtensionResponse): Promise<OnboardingExtensionResponse> => {
export const createOnboardingExtensionRequestController = async (
req: OnboardingExtensionCreateRequest,
res: OnboardingExtensionResponse )
: Promise<OnboardingExtensionResponse> => {

try {

const data = req.body as CreateOnboardingExtensionBody;
Expand Down Expand Up @@ -121,4 +131,72 @@ export const createOnboardingExtensionRequestController = async (req: Onboarding
logger.error(ERROR_WHILE_CREATING_REQUEST, err);
return res.boom.badImplementation(ERROR_WHILE_CREATING_REQUEST);
}
};
};

/**
* Updates the state of an onboarding extension request.
*
* @param {UpdateOnboardingExtensionStateRequest} req - The request object containing the update details.
* @param {OnboardingExtensionResponse} res - The response object to send the result of the update.
* @returns {Promise<OnboardingExtensionResponse>} Sends the response with the result of the update operation.
*/
export const updateOnboardingExtensionRequestState = async (
req: UpdateOnboardingExtensionStateRequest,
res: OnboardingExtensionResponse )
: Promise<OnboardingExtensionResponse> => {

const dev = req.query.dev === "true";

if(!dev) return res.boom.notImplemented("Feature not implemented");

const body = req.body as UpdateOnboardingExtensionStateRequestBody;
const lastModifiedBy = req?.userData?.id;
const extensionId = req.params.id;

let requestBody: UpdateOnboardingExtensionStateRequestBody = {
state: body.state,
type: body.type,
}

if(body.message){
requestBody = { ...requestBody, message: body.message };
}

try {
const response = await updateRequest(extensionId, requestBody, lastModifiedBy, REQUEST_TYPE.ONBOARDING);

if ("error" in response) {
if (response.error === REQUEST_DOES_NOT_EXIST) {
return res.boom.notFound(response.error);
}
return res.boom.badRequest(response.error);
}

const [logType, returnMessage] = response.state === REQUEST_STATE.APPROVED
? [REQUEST_LOG_TYPE.REQUEST_APPROVED, REQUEST_APPROVED_SUCCESSFULLY]
: [REQUEST_LOG_TYPE.REQUEST_REJECTED, REQUEST_REJECTED_SUCCESSFULLY];

const requestLog = {
type: logType,
meta: {
requestId: extensionId,
action: LOG_ACTION.UPDATE,
createdBy: lastModifiedBy,
},
body: response,
};

await addLog(requestLog.type, requestLog.meta, requestLog.body);

return res.status(200).json({
message: returnMessage,
data: {
id: response.id,
...response,
},
});
}catch(error){
logger.error(ERROR_WHILE_UPDATING_REQUEST, error);
return res.boom.badImplementation(ERROR_WHILE_UPDATING_REQUEST);
}
}
8 changes: 6 additions & 2 deletions controllers/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { createTaskExtensionRequest, updateTaskExtensionRequest } from "./extens
import { UpdateRequest } from "../types/requests";
import { TaskRequestRequest } from "../types/taskRequests";
import { createTaskRequestController } from "./taskRequestsv2";
import { OnboardingExtensionCreateRequest, OnboardingExtensionResponse } from "../types/onboardingExtension";
import { createOnboardingExtensionRequestController } from "./onboardingExtension";
import { OnboardingExtensionCreateRequest, OnboardingExtensionResponse, UpdateOnboardingExtensionStateRequest } from "../types/onboardingExtension";
import { createOnboardingExtensionRequestController, updateOnboardingExtensionRequestState } from "./onboardingExtension";

export const createRequestController = async (
req: OooRequestCreateRequest | ExtensionRequestRequest | TaskRequestRequest | OnboardingExtensionCreateRequest,
Expand All @@ -30,6 +30,8 @@ export const createRequestController = async (
return await createTaskRequestController(req as TaskRequestRequest, res as CustomResponse);
case REQUEST_TYPE.ONBOARDING:
return await createOnboardingExtensionRequestController(req as OnboardingExtensionCreateRequest, res as OnboardingExtensionResponse);
case REQUEST_TYPE.ONBOARDING:
return await createOnboardingExtensionRequestController(req as OnboardingExtensionCreateRequest, res as OnboardingExtensionResponse);
default:
return res.boom.badRequest("Invalid request type");
}
Expand All @@ -42,6 +44,8 @@ export const updateRequestController = async (req: UpdateRequest, res: CustomRes
return await updateOooRequestController(req as UpdateRequest, res as ExtensionRequestResponse);
case REQUEST_TYPE.EXTENSION:
return await updateTaskExtensionRequest(req as UpdateRequest, res as ExtensionRequestResponse);
case REQUEST_TYPE.ONBOARDING:
return await updateOnboardingExtensionRequestState(req as unknown as UpdateOnboardingExtensionStateRequest, res as OnboardingExtensionResponse);
default:
return res.boom.badRequest("Invalid request type");
}
Expand Down
5 changes: 3 additions & 2 deletions middlewares/validators/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ export const updateRequestsMiddleware = async (
.messages({
"any.only": "state must be APPROVED or REJECTED",
}),
type: joi.string().valid(REQUEST_TYPE.OOO, REQUEST_TYPE.EXTENSION).required(),
type: joi.string().valid(REQUEST_TYPE.OOO, REQUEST_TYPE.EXTENSION, REQUEST_TYPE.ONBOARDING).required(),
message: joi.string().optional()
});

try {
Expand All @@ -84,7 +85,7 @@ export const getRequestsMiddleware = async (req: OooRequestCreateRequest, res: O
id: joi.string().optional(),
type: joi
.string()
.valid(REQUEST_TYPE.OOO, REQUEST_TYPE.EXTENSION, REQUEST_TYPE.TASK, REQUEST_TYPE.ALL)
.valid(REQUEST_TYPE.OOO, REQUEST_TYPE.EXTENSION, REQUEST_TYPE.TASK, REQUEST_TYPE.ALL, REQUEST_TYPE.ONBOARDING)
.optional(),
requestedBy: joi.string().insensitive().optional(),
state: joi
Expand Down
52 changes: 51 additions & 1 deletion models/discordactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const { FIRESTORE_IN_CLAUSE_SIZE } = require("../constants/users");
const discordService = require("../services/discordService");
const { buildTasksQueryForMissedUpdates } = require("../utils/tasks");
const { buildProgressQueryForMissedUpdates } = require("../utils/progresses");
const { getRequestByKeyValues } = require("./requests");
const { REQUEST_TYPE, REQUEST_STATE } = require("../constants/requests");
const allMavens = [];

/**
Expand Down Expand Up @@ -753,12 +755,59 @@ const updateIdle7dUsersOnDiscord = async (dev) => {
};
};

/**
* Filters out onboarding users who have an approved onboarding extension request that is still valid.
*
* This function iterates through the given list of onboarding users and checks if each user has a valid
* approved onboarding extension request. If a valid extension request exists with a `newEndsOn`
* date greater than the current date, the user is skipped. Otherwise, the user is added to the
* returned list.
*
* @async
* @function skipOnboardingUsersHavingApprovedExtensionRequest
* @param {Array<Object>} [users=[]] - An array of user objects to be filtered. Each user object
* must have an `id` property.
* @returns {Promise<Array<Object>>} A promise that resolves to an array of users who do not have
* a valid approved onboarding extension request.
*/
const skipOnboardingUsersHavingApprovedExtensionRequest = async (users = []) => {
const currentTime = Date.now();

const results = await Promise.all(
users.map(async (user) => {
try {
const latestApprovedExtension = await getRequestByKeyValues({
type: REQUEST_TYPE.ONBOARDING,
state: REQUEST_STATE.APPROVED,
userId: user.id,
});

if (latestApprovedExtension && latestApprovedExtension.newEndsOn > currentTime) {
return null;
}

return user;
} catch (error) {
logger.error(`Error while fetching latest approved extension for user ${user.id}:`, error);
return null;
}
})
);

return results.filter(Boolean);
};

const updateUsersWith31DaysPlusOnboarding = async () => {
try {
const allOnboardingUsers31DaysCompleted = await getUsersBasedOnFilter({
let allOnboardingUsers31DaysCompleted = await getUsersBasedOnFilter({
state: userState.ONBOARDING,
time: "31d",
});

allOnboardingUsers31DaysCompleted = await skipOnboardingUsersHavingApprovedExtensionRequest(
allOnboardingUsers31DaysCompleted
);

const discordMembers = await getDiscordMembers();
const groupOnboardingRole = await getGroupRole("group-onboarding-31d+");
const groupOnboardingRoleId = groupOnboardingRole.role.roleid;
Expand Down Expand Up @@ -1131,4 +1180,5 @@ module.exports = {
addInviteToInviteModel,
groupUpdateLastJoinDate,
deleteGroupRole,
skipOnboardingUsersHavingApprovedExtensionRequest,
};
14 changes: 9 additions & 5 deletions models/logs.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,24 @@ const fetchAllLogs = async (query) => {
throw error;
}

const buildTimestamp = (date) => ({
_seconds: Math.floor(date / 1000),
_nanoseconds: 0,
const buildTimestamp = (milliseconds) => ({
_seconds: Math.floor(milliseconds / 1000),
_nanoseconds: (milliseconds % 1000) * 1000000,
});

if (startDate) {
requestQuery = requestQuery.where("timestamp", ">=", buildTimestamp(startDate));
const startTimestamp = buildTimestamp(startDate);
requestQuery = requestQuery.where("timestamp._seconds", ">=", startTimestamp._seconds);
}

if (endDate) {
requestQuery = requestQuery.where("timestamp", "<=", buildTimestamp(endDate));
const endTimestamp = buildTimestamp(endDate);
requestQuery = requestQuery.where("timestamp._seconds", "<=", endTimestamp._seconds);
}
}

requestQuery = requestQuery.orderBy("timestamp", "desc");

let requestQueryDoc = requestQuery;

if (prev) {
Expand Down
10 changes: 8 additions & 2 deletions models/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export const updateRequest = async (id: string, body: any, lastModifiedBy: strin

export const getRequests = async (query: any) => {
let { id, type, requestedBy, state, prev, next, page, size = SIZE } = query;
const dev = query.dev === "true";

size = parseInt(size);
page = parseInt(page);
try {
Expand All @@ -86,11 +88,15 @@ export const getRequests = async (query: any) => {
...requestDoc.data(),
};
}

if (requestedBy) {

if(requestedBy && dev){
requestQuery = requestQuery.where("requestedBy", "==", requestedBy);
}
else if (requestedBy) {
const requestedByUserId = await getUserId(requestedBy);
requestQuery = requestQuery.where("requestedBy", "==", requestedByUserId);
}

if (type) {
requestQuery = requestQuery.where("type", "==", type);
}
Expand Down
Loading

0 comments on commit ba7a9e9

Please sign in to comment.