-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from Xitija/main
PS-1371 and PS-1387
- Loading branch information
Showing
17 changed files
with
695 additions
and
661 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; | ||
import { Response, Request } from 'express'; | ||
import APIResponse from '../utils/response'; | ||
import { ERROR_MESSAGES } from '../utils/constants.util'; | ||
|
||
@Catch() | ||
export class AllExceptionsFilter implements ExceptionFilter { | ||
constructor(private readonly apiId?: string) { } | ||
|
||
catch(exception: unknown, host: ArgumentsHost) { | ||
const ctx = host.switchToHttp(); | ||
const response = ctx.getResponse<Response>(); | ||
const status = exception instanceof HttpException ? exception.getStatus() : 500; | ||
const exceptionResponse = exception instanceof HttpException ? exception.getResponse() : null; | ||
const errorMessage = | ||
exception instanceof HttpException | ||
? (exceptionResponse as any).message || exception.message | ||
: ERROR_MESSAGES.INTERNAL_SERVER_ERROR; | ||
const detailedErrorMessage = `${errorMessage}`; | ||
console.log('detailedErrorMessage', detailedErrorMessage); | ||
const errorResponse = APIResponse.error( | ||
this.apiId, | ||
detailedErrorMessage, | ||
exception instanceof HttpException ? exception.name : ERROR_MESSAGES.INTERNAL_SERVER_ERROR, // error | ||
status.toString(), | ||
); | ||
return response.status(status).json(errorResponse); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,208 @@ | ||
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common'; | ||
import { ConfigService } from '@nestjs/config'; | ||
import { | ||
PipeTransform, | ||
Injectable, | ||
BadRequestException, | ||
forwardRef, | ||
Inject, | ||
} from '@nestjs/common'; | ||
import { CreateEventDto } from 'src/modules/event/dto/create-event.dto'; | ||
|
||
import { getTimezoneDate } from '../utils/pipe.util'; | ||
import { get } from 'http'; | ||
import { ERROR_MESSAGES } from '../utils/constants.util'; | ||
import { | ||
ValidatorConstraint, | ||
ValidatorConstraintInterface, | ||
ValidationArguments, | ||
} from 'class-validator'; | ||
@Injectable() | ||
export class DateValidationPipe implements PipeTransform { | ||
transform(createEventDto: CreateEventDto) { | ||
const startDate = new Date(createEventDto.startDatetime); | ||
const endDate = new Date(createEventDto.endDatetime); | ||
const currentDate = new Date(); // Current date | ||
// Check if start date is today or in the future | ||
if (startDate < currentDate) { | ||
throw new BadRequestException('Start date must be today or a future date'); | ||
} | ||
if (endDate < startDate) { | ||
throw new BadRequestException('End date should be greater than or equal to start date'); | ||
} | ||
return createEventDto; | ||
// constructor(@Inject(forwardRef(() => ConfigService)) private configService: ConfigService) { | ||
|
||
// } | ||
|
||
transform(createEventDto: CreateEventDto) { | ||
const timeZone = 'Asia/Kolkata'; | ||
const startDate = getTimezoneDate( | ||
timeZone, | ||
new Date(createEventDto.startDatetime), | ||
); | ||
const endDate = getTimezoneDate( | ||
timeZone, | ||
new Date(createEventDto.endDatetime), | ||
); | ||
const currentDate = getTimezoneDate(timeZone); // Current date | ||
// this.configService.get<string>('TIMEZONE'); // Get the timezone from the config service | ||
|
||
console.log('currentDate', currentDate); | ||
console.log('startDate', startDate); | ||
console.log('endDate', endDate); | ||
|
||
console.log(startDate <= currentDate, 'startDate <= currentDate'); | ||
|
||
if (startDate <= currentDate) { | ||
throw new BadRequestException( | ||
'Start date must be today or a future date', | ||
); | ||
} | ||
if (endDate < startDate) { | ||
throw new BadRequestException( | ||
'End date should be greater than or equal to start date', | ||
); | ||
} | ||
return createEventDto; | ||
} | ||
} | ||
|
||
|
||
@Injectable() | ||
export class DeadlineValidationPipe implements PipeTransform { | ||
transform(createEventDto: CreateEventDto) { | ||
const startDate = new Date(createEventDto.startDatetime); | ||
const endDate = new Date(createEventDto.endDatetime); | ||
const registrationDeadline = new Date(createEventDto.registrationDeadline); | ||
|
||
if (registrationDeadline < startDate || registrationDeadline > endDate) { | ||
throw new BadRequestException('Registration deadline should be between start date and end date'); | ||
} | ||
return createEventDto; | ||
export class RegistrationDateValidationPipe implements PipeTransform { | ||
transform(createEventDto: CreateEventDto) { | ||
const timeZone = 'Asia/Kolkata'; | ||
const currentDate = getTimezoneDate(timeZone); | ||
const startDate = getTimezoneDate( | ||
timeZone, | ||
new Date(createEventDto.startDatetime), | ||
); | ||
const endDate = getTimezoneDate( | ||
timeZone, | ||
new Date(createEventDto.endDatetime), | ||
); | ||
const registrationStartDate = createEventDto.registrationEndDate | ||
? getTimezoneDate( | ||
timeZone, | ||
new Date(createEventDto.registrationStartDate), | ||
) | ||
: null; | ||
const isRestricted = createEventDto.isRestricted; | ||
const registrationEndDate = createEventDto.registrationEndDate | ||
? getTimezoneDate(timeZone, new Date(createEventDto.registrationEndDate)) | ||
: null; | ||
|
||
console.log( | ||
registrationStartDate, | ||
'rrrrr', | ||
startDate, | ||
registrationStartDate > startDate, | ||
registrationStartDate < startDate, | ||
); | ||
console.log( | ||
createEventDto.isRestricted && registrationStartDate, | ||
'createEventDto.isRestricted && registrationStartDate ', | ||
); | ||
console.log( | ||
createEventDto.isRestricted && registrationEndDate, | ||
'createEventDto.isRestricted && registrationEndDate', | ||
); | ||
if ( | ||
(createEventDto.isRestricted && registrationStartDate) || | ||
(createEventDto.isRestricted && registrationEndDate) | ||
) { | ||
console.log(''); | ||
throw new BadRequestException( | ||
ERROR_MESSAGES.RESTRICTED_EVENT_NO_REGISTRATION_DATE, | ||
); | ||
} | ||
|
||
// Ensure registration dates are not in the past | ||
if (registrationStartDate < currentDate && !isRestricted) { | ||
throw new BadRequestException( | ||
ERROR_MESSAGES.REGISTRATION_START_DATE_INVALID, | ||
); | ||
} | ||
|
||
if (registrationEndDate < currentDate && !isRestricted) { | ||
throw new BadRequestException( | ||
ERROR_MESSAGES.REGISTRATION_END_DATE_INVALID, | ||
); | ||
} | ||
|
||
// Validate registration dates | ||
if (registrationStartDate > registrationEndDate && !isRestricted) { | ||
throw new BadRequestException( | ||
ERROR_MESSAGES.REGISTRATION_START_DATE_BEFORE_END_DATE, | ||
); | ||
} | ||
|
||
// Registration period must fall between the event period | ||
if (registrationStartDate > startDate && !isRestricted) { | ||
throw new BadRequestException( | ||
ERROR_MESSAGES.REGISTRATION_START_DATE_BEFORE_EVENT_DATE, | ||
); | ||
} | ||
|
||
if (registrationEndDate > startDate && !isRestricted) { | ||
throw new BadRequestException( | ||
ERROR_MESSAGES.REGISTRATION_END_DATE_BEFORE_EVENT_DATE, | ||
); | ||
} | ||
|
||
return createEventDto; | ||
} | ||
} | ||
|
||
export class RecurringEndDateValidationPipe implements PipeTransform { | ||
transform(createEventDto: CreateEventDto) { | ||
const currentDate = getTimezoneDate('Asia/Kolkata'); | ||
if (createEventDto.isRecurring) { | ||
const recurrenceEndDate = new Date(createEventDto.recurrenceEndDate); | ||
const startDate = new Date(createEventDto.startDatetime); | ||
|
||
if (recurrenceEndDate < currentDate) { | ||
throw new BadRequestException( | ||
ERROR_MESSAGES.RECURRENCE_END_DATE_INVALID, | ||
); | ||
} | ||
|
||
if (recurrenceEndDate < startDate) { | ||
throw new BadRequestException( | ||
ERROR_MESSAGES.RECURRENCE_END_DATE_BEFORE_EVENT_DATE, | ||
); | ||
} | ||
} | ||
|
||
return createEventDto; | ||
} | ||
} | ||
|
||
@Injectable() | ||
export class ParamsValidationPipe implements PipeTransform { | ||
transform(createEventDto: CreateEventDto) { | ||
if (createEventDto.isRestricted) { | ||
const params = createEventDto.params; | ||
if (!params || typeof params !== 'object') { | ||
throw new BadRequestException('Invalid params object'); | ||
} | ||
|
||
if (!params.cohortIds && !params.userIds) { | ||
throw new BadRequestException('Either cohortIds or userIds must be provided in params'); | ||
} | ||
|
||
if (params.cohortIds && params.userIds) { | ||
throw new BadRequestException('Only one of cohortIds or userIds should be provided in params'); | ||
} | ||
|
||
if (params.cohortIds) { | ||
this.validateUUIDs(params.cohortIds); | ||
} else if (params.userIds) { | ||
this.validateUUIDs(params.userIds); | ||
} | ||
} else if (!createEventDto.isRestricted) { | ||
createEventDto.params = {}; | ||
} | ||
|
||
return createEventDto; | ||
transform(createEventDto: CreateEventDto) { | ||
if (createEventDto.isRestricted) { | ||
const params = createEventDto.params; | ||
if (!params || typeof params !== 'object') { | ||
throw new BadRequestException('Invalid params object'); | ||
} | ||
|
||
// if (!params.cohortIds && !params.userIds) { | ||
// throw new BadRequestException( | ||
// 'Either cohortIds or userIds must be provided in params', | ||
// ); | ||
// } | ||
|
||
// if (params.cohortIds && params.userIds) { | ||
// throw new BadRequestException( | ||
// 'Only one of cohortIds or userIds should be provided in params', | ||
// ); | ||
// } | ||
|
||
// if (params.cohortIds) { | ||
// this.validateUUIDs(params.cohortIds); | ||
// } else if (params.userIds) { | ||
// this.validateUUIDs(params.userIds); | ||
// } | ||
} else if (!createEventDto.isRestricted) { | ||
createEventDto.params = {}; | ||
} | ||
|
||
private validateUUIDs(ids: string[]) { | ||
const uuidRegex = /^[a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}$/i; // UUID regex pattern | ||
for (const id of ids) { | ||
if (!uuidRegex.test(id)) { | ||
throw new BadRequestException(`Invalid UUID format: ${id}`); | ||
} | ||
} | ||
return createEventDto; | ||
} | ||
|
||
private validateUUIDs(ids: string[]) { | ||
const uuidRegex = /^[a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}$/i; // UUID regex pattern | ||
for (const id of ids) { | ||
if (!uuidRegex.test(id)) { | ||
throw new BadRequestException(`Invalid UUID format: ${id}`); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
export const ERROR_MESSAGES = { | ||
INVALID_REQUEST: 'Invalid request', | ||
NOT_FOUND: 'Not found', | ||
UNAUTHORIZED: 'Unauthorized', | ||
FORBIDDEN: 'Forbidden', | ||
BAD_REQUEST: 'Bad request', | ||
INVALID_REQUEST_BODY: 'Invalid request body', | ||
INTERNAL_SERVER_ERROR: 'Internal Server Error', | ||
REGISTRATION_DATE_INVALID: 'Registration date must be in the future', | ||
REGISTRATION_START_DATE_BEFORE_EVENT_DATE: 'Registration start date must be before the event start date', | ||
REGISTRATION_END_DATE_BEFORE_EVENT_DATE: 'Registration end date must be on or before the event start date', | ||
REGISTRATION_START_DATE_INVALID: 'Registration start date must be in the future', | ||
REGISTRATION_END_DATE_INVALID: 'Registration end date must be in the future', | ||
REGISTRATION_START_DATE_BEFORE_END_DATE: 'Registration start date must be before registration end date', | ||
RECURRENCE_END_DATE_INVALID: 'Recurrence end date must be in the future', | ||
RECURRENCE_END_DATE_BEFORE_EVENT_DATE: 'Recurrence end date must be after the event start date', | ||
RECURRING_PATTERN_REQUIRED: 'Recurrence Pattern required for event', | ||
REGISTRATION_START_DATE_REQUIRED: 'Registration Start Date required for event', | ||
INVITEES_REQUIRED: 'Invitees required for private event', | ||
INVITEES_NOT_REQUIRED: 'Invitees not required for public event', | ||
EVENT_NOT_FOUND: 'Event not found', | ||
EVENT_ATTENDEE_NOT_FOUND: 'Event attendee not found', | ||
EVENT_ATTENDEE_HISTORY_NOT_FOUND: 'Event attendee history not found', | ||
EVENT_ATTENDEE_HISTORY_ITEM_NOT_FOUND: 'Event attendee history item not found', | ||
} | ||
|
||
export const SUCCESS_MESSAGES = { | ||
EVENT_CREATED: 'Event created successfully', | ||
EVENT_UPDATED: 'Event updated successfully', | ||
EVENT_DELETED: 'Event deleted successfully', | ||
EVENT_NOT_FOUND: 'Event not found', | ||
EVENT_ATTENDEE_CREATED: 'Event attendee created successfully', | ||
EVENT_ATTENDEE_UPDATED: 'Event attendee updated successfully', | ||
EVENT_ATTENDEE_DELETED: 'Event attendee deleted successfully', | ||
EVENT_ATTENDEE_HISTORY_ITEM_CREATED: 'Event attendee history item created successfully', | ||
EVENT_ATTENDEE_HISTORY_ITEM_UPDATED: 'Event attendee history item updated successfully', | ||
EVENT_ATTENDEE_HISTORY_ITEM_DELETED: 'Event attendee history item deleted successfully', | ||
} | ||
|
||
export const API_ID = { | ||
CREATE_EVENT: 'api.event.create', | ||
GET_EVENT_BY_ID: 'api.event.getbyid', | ||
GET_EVENTS: 'api.events.get', | ||
UPDATE_EVENT: 'api.event.update', | ||
DELETE_EVENT: 'api.event.delete', | ||
GET_EVENT_ATTENDEES: 'api.event.attendees.get', | ||
GET_EVENT_ATTENDEE: 'api.event.attendee.get', | ||
CREATE_EVENT_ATTENDEE: 'api.event.attendee.create', | ||
UPDATE_EVENT_ATTENDEE: 'api.event.attendee.update', | ||
DELETE_EVENT_ATTENDEE: 'api.event.attendee.delete', | ||
GET_EVENT_ATTENDEE_HISTORY: 'api.event.attendee.history.get', | ||
GET_EVENT_ATTENDEE_HISTORY_ITEM: 'api.event.attendee.history.item.get', | ||
CREATE_EVENT_ATTENDEE_HISTORY_ITEM: 'api.event.attendee.history.item.create', | ||
UPDATE_EVENT_ATTENDEE_HISTORY_ITEM: 'api.event.attendee.history.item.update', | ||
DELETE_EVENT_ATTENDEE_HISTORY_ITEM: 'api.event.attendee.history.item.delete', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export function getTimezoneDate(timeZone: string, nowUtc: Date = new Date()) { | ||
// converts the current date(UTC) to the timezone -> 2024-07-15T11:07:09.827Z => 2024-07-15T16:37:09.827Z | ||
const nowTimezone = new Date( | ||
nowUtc.toLocaleString('en-US', { timeZone: timeZone }), | ||
); | ||
|
||
const offset = nowTimezone.getTimezoneOffset() * 60000; | ||
|
||
return new Date(nowTimezone.getTime() - offset); //.toISOString() //.slice(0, -1); | ||
} |
Oops, something went wrong.