Skip to content

Commit

Permalink
Documentation :TSDoc Comments in config, directives, helpers directory (
Browse files Browse the repository at this point in the history
PalisadoesFoundation#2380)

* config folder done

* directives done

* helpers done

* lint fixed
  • Loading branch information
gautam-divyanshu authored Jul 5, 2024
1 parent 71c17b9 commit dccb451
Show file tree
Hide file tree
Showing 20 changed files with 391 additions and 240 deletions.
13 changes: 13 additions & 0 deletions src/config/appConfig.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
/**
* Application configuration settings.
* This object contains various configuration options for the application.
*/
export const appConfig = {
/** The current environment of the application (e.g., 'development', 'production'). */
env: process.env.NODE_ENV,

/** Determines if logs should be colorized. */
colorize_logs: process.env.COLORIZE_LOGS,

/** The logging level for the application (e.g., 'info', 'error'). */
log_level: process.env.LOG_LEVEL,

/** The default language for the application. */
defaultLocale: "en",

/** An array of supported language for the application. */
supportedLocales: ["hi", "en", "zh", "fr", "sp"],
};
4 changes: 4 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
/**
* Exports all configurations from the appConfig module.
* This allows other modules to import configurations easily.
*/
export * from "./appConfig";
37 changes: 33 additions & 4 deletions src/config/plugins/loadPlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,60 @@ import _ from "lodash";
import pluginData from "./pluginData.json";
import { logger } from "../../libraries";
import mongoose from "mongoose";
// Only loads plugin data for the time if it's not currently present in the database

/**
* Loads plugin data into the MongoDB database if it is not already present.
*
* This function connects to the MongoDB database using the connection URL specified in the environment variables.
* It checks if the plugin data already exists in the database. If the data does not exist, it inserts the data from
* the provided JSON file (`pluginData.json`). If the data is already present, it logs a message indicating so.
*
* @example
* ```typescript
* import loadPlugins from './path/to/loadPlugins';
*
* loadPlugins().then(() => {
* console.log('Plugins loaded successfully.');
* }).catch(error => {
* console.error('Error loading plugins:', error);
* });
* ```
* @see Parent File:
* - `src/index.ts`
*
* @returns A promise that resolves when the plugins have been loaded or confirms that they are already present.
*
*/

const loadPlugins = async (): Promise<void> => {
try {
// Connect to the MongoDB database
await mongoose.connect(process.env.MONGO_DB_URL as string);
logger.info("\x1b[1m\x1b[32m%s\x1b[0m", `Connected to the database`);

// Fetch existing plugins from the database
const res = await Plugin.find();
const databaseTitle = mongoose.connection.db.databaseName;

if (_.isEmpty(res)) {
//no previous data then update with our new data. (Only happens once)
// No previous data, so insert new plugin data from JSON file
// eslint-disable-next-line @typescript-eslint/no-explicit-any
pluginData.forEach(async (plugin: any) => {
await Plugin.create(plugin);
});
logger.info(
"\x1b[1m\x1b[32m%s\x1b[0m",
`Uploaded Plugins in ${databaseTitle} `,
`Uploaded Plugins in ${databaseTitle}`,
);
} else {
//plugin data already present
// Plugin data is already present in the database
logger.info(
"\x1b[1m\x1b[32m%s\x1b[0m",
`Plugin data already present at ${databaseTitle}`,
);
}
} catch (error) {
// Log any errors that occur during the process
logger.error(error);
}
};
Expand Down
24 changes: 23 additions & 1 deletion src/directives/directiveTransformer/authDirectiveTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ import { defaultFieldResolver } from "graphql";
import type { GraphQLSchema } from "graphql/type/schema";
import { errors, requestContext } from "../../libraries";

/**
* A function to transform a GraphQL schema by adding authentication logic
* to the fields with the specified directive.
*
* @param schema - The original GraphQL schema to be transformed.
* @param directiveName - The name of the directive that will trigger the transformation.
*
* @see Parent File:
* - `src/index.ts`
*
* @returns A new GraphQL schema with the authentication logic applied.
*
* @example
* `const transformedSchema = authDirectiveTransformer(originalSchema, 'auth');`
*/

function authDirectiveTransformer(
schema: GraphQLSchema,
directiveName: string,
Expand All @@ -15,18 +31,24 @@ function authDirectiveTransformer(
fieldConfig,
directiveName,
)?.[0];

if (authDirective) {
const { resolve = defaultFieldResolver } = fieldConfig;

fieldConfig.resolve = (root, args, context, info): string => {
if (context.expired || !context.isAuth)
// Check if the user is authenticated and the session is not expired
if (context.expired || !context.isAuth) {
throw new errors.UnauthenticatedError(
requestContext.translate("user.notAuthenticated"),
"user.notAuthenticated --auth directive",
"userAuthentication",
);
}

// Call the original resolver with the context
return resolve(root, args, context, info) as string;
};

return fieldConfig;
}
},
Expand Down
20 changes: 20 additions & 0 deletions src/directives/directiveTransformer/roleDirectiveTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ import { USER_NOT_FOUND_ERROR } from "../../constants";
import { errors } from "../../libraries";
import { User } from "../../models";

/**
* A function to transform a GraphQL schema by adding role-based authorization
* logic to the fields with the specified directive.
*
* @param schema - The original GraphQL schema to be transformed.
* @param directiveName - The name of the directive that will trigger the transformation.
*
* @see Parent File:
* - `src/index.ts`
*
* @returns A new GraphQL schema with the role-based authorization logic applied.
*
* @example
* const transformedSchema = roleDirectiveTransformer(originalSchema, 'role');
*/

function roleDirectiveTransformer(
schema: GraphQLSchema,
directiveName: string,
Expand All @@ -29,10 +45,12 @@ function roleDirectiveTransformer(
context,
info,
): Promise<string> => {
// Fetch the current user from the database using the userId from the context
const currentUser = await User.findOne({
_id: context.userId,
}).lean();

// If no user is found, throw a "Not Found" error
if (!currentUser) {
throw new errors.NotFoundError(
USER_NOT_FOUND_ERROR.MESSAGE,
Expand All @@ -49,8 +67,10 @@ function roleDirectiveTransformer(
// );
// }

// Add the current user to the context for use in the resolver
context.user = currentUser;

// Call the original resolver with the updated context
return resolve(root, args, context, info) as string;
};

Expand Down
63 changes: 36 additions & 27 deletions src/helpers/event/createEventHelpers/createRecurringEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,26 @@ import {
} from "../recurringEventHelpers";

/**
* This function creates the instances of a recurring event upto a certain date.
* @param args - payload of the createEvent mutation
* @param creatorId - _id of the creator
* @param organizationId - _id of the organization the events belongs to
* @remarks The following steps are followed:
* 1. Create a default recurrenceRuleData.
* 2. Generate a recurrence rule string based on the recurrenceRuleData.
* 3. Create a baseRecurringEvent on which recurring instances would be based.
* 4. Get the dates for recurring instances.
* 5. Create a recurrenceRule document.
* 6. Generate recurring instances according to the recurrence rule.
* @returns Created recurring event instance
* Creates instances of a recurring event up to a specified end date.
*
* @param args - The payload of the createEvent mutation, including event data and recurrence rule.
* @param creatorId - The ID of the event creator.
* @param organizationId - The ID of the organization to which the event belongs.
* @param session - The MongoDB client session for transactional operations.
* @returns The created instance of the recurring event.
*
* @see Parent file:
* - `resolvers/Mutation/createEvent.ts`
* - `resolvers/Query/eventsByOrganizationConnection.ts`
*
* @remarks
* Steps performed by this function:
* 1. If no recurrence rule is provided, defaults to weekly recurrence starting from a given date.
* 2. Generates a recurrence rule string based on provided or default recurrence data.
* 3. Creates a base recurring event template in the database.
* 4. Retrieves dates for all recurring instances based on the recurrence rule.
* 5. Saves the recurrence rule in the database for future reference.
* 6. Generates and saves instances of recurring events based on the recurrence rule.
*/

export const createRecurringEvent = async (
Expand All @@ -30,11 +38,12 @@ export const createRecurringEvent = async (
organizationId: string,
session: mongoose.ClientSession,
): Promise<InterfaceEvent> => {
// Extract event data and recurrence rule information from arguments
const { data } = args;
let { recurrenceRuleData } = args;

// Set a default weekly recurrence rule if none is provided
if (!recurrenceRuleData) {
// create a default recurrence rule -> infinite weekly recurrence
recurrenceRuleData = {
frequency: "WEEKLY",
recurrenceStartDate: data.startDate,
Expand All @@ -44,16 +53,15 @@ export const createRecurringEvent = async (

const { recurrenceStartDate, recurrenceEndDate } = recurrenceRuleData;

// generate a recurrence rule string which would be used to generate rrule object
// and get recurrence dates
// 1. Generate a string representation of the recurrence rule
const recurrenceRuleString = generateRecurrenceRuleString(recurrenceRuleData);

// create a base recurring event first, based on which all the
// 2.create a base recurring event first, based on which all the
// recurring instances would be dynamically generated
const baseRecurringEvent = await Event.create(
[
{
...data,
...data, // Spread event data from original arguments
recurring: true,
startDate: recurrenceStartDate,
endDate: recurrenceEndDate,
Expand All @@ -63,37 +71,38 @@ export const createRecurringEvent = async (
organization: organizationId,
},
],
{ session },
{ session }, // Use the provided session if available
);

// get the dates for the recurringInstances, and the date of the last instance
// 3. get the dates for the recurringInstances, and the date of the last instance
// to be generated in this operation (rest would be generated dynamically during query)
const recurringInstanceDates = getRecurringInstanceDates(
recurrenceRuleString,
recurrenceStartDate,
recurrenceEndDate,
);

// get the date for the latest created instance
// 4. Extract the date of the last created instance
const latestInstanceDate =
recurringInstanceDates[recurringInstanceDates.length - 1];
// create a recurrenceRule document that would contain the recurrence pattern

// 5. Create a separate document to store the recurrence pattern details
const recurrenceRule = await createRecurrenceRule(
recurrenceRuleString,
recurrenceStartDate,
recurrenceEndDate,
organizationId,
baseRecurringEvent[0]?._id.toString(),
baseRecurringEvent[0]?._id.toString(), // Get ID of the base event
latestInstanceDate,
session,
);

// generate the recurring instances and get an instance back
// 6. Generate all the recurring event instances based on the rule and dates
const recurringEventInstance = await generateRecurringEventInstances({
data,
baseRecurringEventId: baseRecurringEvent[0]?._id.toString(),
recurrenceRuleId: recurrenceRule?._id.toString(),
recurringInstanceDates,
data, // Event data for all instances
baseRecurringEventId: baseRecurringEvent[0]?._id.toString(), // Base event ID
recurrenceRuleId: recurrenceRule?._id.toString(), // Recurrence rule ID
recurringInstanceDates, // Array of dates for each instance
creatorId,
organizationId,
session,
Expand Down
Loading

0 comments on commit dccb451

Please sign in to comment.