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

Individual validation #753

Merged
merged 2 commits into from
May 30, 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
73 changes: 51 additions & 22 deletions utilities/project-factory/src/server/api/campaignApis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ async function enrichCampaign(requestBody: any) {
}

async function getAllFacilitiesInLoop(searchedFacilities: any[], facilitySearchParams: any, facilitySearchBody: any) {
await new Promise(resolve => setTimeout(resolve, 3000)); // Wait for 3 seconds
const response = await httpRequest(config.host.facilityHost + config.paths.facilitySearch, facilitySearchBody, facilitySearchParams);

if (Array.isArray(response?.Facilities)) {
Expand Down Expand Up @@ -251,22 +250,57 @@ function matchCreatedAndSearchedData(createdData: any[], searchedData: any[], re
request.body.Activities = activities
}

function matchUserValidation(createdData: any[], searchedData: any[], request: any, createAndSearchConfig: any) {
var count = 0;
const errors = []
const codeSet = new Set(searchedData.map(item => item?.code));
const numberSet = new Set(searchedData.map(item => item?.user?.mobileNumber));
for (const data of createdData) {
if (codeSet.has(data.code) && numberSet.has(data?.user?.mobileNumber)) {
errors.push({ status: "INVALID", rowNumber: data["!row#number!"], errorDetails: `User with mobileNumber ${data?.user?.mobileNumber} and userName ${data.code} already exists` })
count++;
async function getUserWithMobileNumbers(request: any, mobileNumbers: any[]) {
logger.info("mobileNumbers to search: " + JSON.stringify(mobileNumbers));
const BATCH_SIZE = 50;
let allResults: any[] = [];

for (let i = 0; i < mobileNumbers.length; i += BATCH_SIZE) {
const batch = mobileNumbers.slice(i, i + BATCH_SIZE);
const searchBody = {
RequestInfo: request?.body?.RequestInfo,
Individual: {
mobileNumber: batch
}
};
const params = {
limit: 55,
offset: 0,
tenantId: request?.body?.ResourceDetails?.tenantId,
includeDeleted: true
};

const response = await httpRequest(config.host.healthIndividualHost + "health-individual/v1/_search", searchBody, params);

if (!response) {
throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Error occurred during user search while validating mobile number.");
}
else if (codeSet.has(data.code)) {
errors.push({ status: "INVALID", rowNumber: data["!row#number!"], errorDetails: `User with userName ${data.code} already exists` })
count++;

if (response?.Individual?.length > 0) {
const resultMobileNumbers = response.Individual.map((item: any) => item?.mobileNumber);
allResults = allResults.concat(resultMobileNumbers);
}
else if (numberSet.has(data?.user?.mobileNumber)) {
errors.push({ status: "INVALID", rowNumber: data["!row#number!"], errorDetails: `User with mobileNumber ${data?.user?.mobileNumber} already exists` })
}

// Convert the results array to a Set to eliminate duplicates
const resultSet = new Set(allResults);
logger.info("Already Exsisted mobile numbers : " + JSON.stringify(resultSet));
return resultSet;
}

async function matchUserValidation(createdData: any[], request: any) {
var count = 0;
const errors = []
const mobileNumbers = createdData.filter(item => item?.user?.mobileNumber).map(item => (item?.user?.mobileNumber));
const mobileNumberRowNumberMapping = createdData.reduce((acc, curr) => {
acc[curr.user.mobileNumber] = curr["!row#number!"];
return acc;
}, {});
logger.info("mobileNumberRowNumberMapping : " + JSON.stringify(mobileNumberRowNumberMapping));
const mobileNumberResponse = await getUserWithMobileNumbers(request, mobileNumbers);
for (const key in mobileNumberRowNumberMapping) {
if (mobileNumberResponse.has(key)) {
errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[key], errorDetails: `User with mobileNumber ${key} already exists` })
count++;
}
}
Expand Down Expand Up @@ -307,7 +341,6 @@ function matchViaUserIdAndCreationTime(createdData: any[], searchedData: any[],
async function processSearch(createAndSearchConfig: any, request: any, params: any) {
setSearchLimits(createAndSearchConfig, request, params);
const arraysToMatch = await performSearch(createAndSearchConfig, request, params);

return arraysToMatch;
}

Expand All @@ -330,7 +363,6 @@ function setLimitOrOffset(limitOrOffsetConfig: any, params: any, requestBody: an
async function performSearch(createAndSearchConfig: any, request: any, params: any) {
const arraysToMatch: any[] = [];
let searchAgain = true;

while (searchAgain) {
const searcRequestBody = {
RequestInfo: request?.body?.RequestInfo
Expand All @@ -347,7 +379,6 @@ async function performSearch(createAndSearchConfig: any, request: any, params: a
searchAgain = false;
}
updateOffset(createAndSearchConfig, params, request.body);
await new Promise(resolve => setTimeout(resolve, 5000));
}
return arraysToMatch;
}
Expand Down Expand Up @@ -376,9 +407,7 @@ async function processSearchAndValidation(request: any, createAndSearchConfig: a
}
if (request?.body?.ResourceDetails?.type == "user") {
await enrichEmployees(request?.body?.dataToCreate, request)
const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request);
const arraysToMatch = await processSearch(createAndSearchConfig, request, params)
matchUserValidation(request.body.dataToCreate, arraysToMatch, request, createAndSearchConfig)
await matchUserValidation(request.body.dataToCreate, request)
}
}

Expand Down Expand Up @@ -531,8 +560,8 @@ async function performAndSaveResourceActivity(request: any, createAndSearchConfi
var activity = await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, responsePayload, type, createAndSearchConfig?.createBulkDetails?.url, responsePayload?.statusCode)
logger.info("Activity : " + JSON.stringify(activity));
activities.push(activity);
await new Promise(resolve => setTimeout(resolve, 10000));
}
await new Promise(resolve => setTimeout(resolve, 5000));
await confirmCreation(createAndSearchConfig, request, dataToCreate, creationTime, activities);
}
await generateProcessedFileAndPersist(request, localizationMap);
Expand Down
2 changes: 0 additions & 2 deletions utilities/project-factory/src/server/api/genericApis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -984,8 +984,6 @@ async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key:

flag = 0;
requestBody.BoundaryRelationship = boundary;
// Introducing a delay of 1 second
// await new Promise(resolve => setTimeout(resolve, config.boundary.boundaryRelationShipDelay));
await confirmBoundaryParentCreation(request, modifiedChildParentMap.get(boundaryCode) || null);
try {
const response = await httpRequest(`${config.host.boundaryHost}${config.paths.boundaryRelationshipCreate}`, requestBody, {}, 'POST', undefined, undefined, true);
Expand Down
3 changes: 2 additions & 1 deletion utilities/project-factory/src/server/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ const config = {
userHost: process.env.EGOV_USER_HOST || "https://unified-dev.digit.org/",
productHost: process.env.EGOV_PRODUCT_HOST || "https://unified-dev.digit.org/",
hrmsHost: process.env.EGOV_HRMS_HOST || "https://unified-dev.digit.org/",
localizationHost: process.env.EGOV_LOCALIZATION_HOST || "https://unified-dev.digit.org/"
localizationHost: process.env.EGOV_LOCALIZATION_HOST || "https://unified-dev.digit.org/",
healthIndividualHost: process.env.EGOV_HEALTH_INDIVIDUAL_HOST || "https://unified-dev.digit.org/",
},
// Paths for different services
paths: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const campaignDetailsSchema = {
},
"action": {
"type": "string",
"enum": ["create", "draft"],
"enum": ["create", "draft", "changeDates"],
"maxLength": 64,
"minLength": 1
},
Expand Down
1 change: 1 addition & 0 deletions utilities/project-factory/src/server/kafka/Listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function listener() {
* @returns A promise that resolves when the messages are successfully produced.
*/
async function produceModifiedMessages(modifiedMessages: any[], topic: any) {

logger.info(`KAFKA :: PRODUCER :: a message sent to topic ${topic}`);
logger.debug(`KAFKA :: PRODUCER :: message ${getFormattedStringForDebug(modifiedMessages)}`);
return new Promise<void>((resolve, reject) => {
Expand Down
46 changes: 23 additions & 23 deletions utilities/project-factory/src/server/utils/campaignUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1099,25 +1099,27 @@ async function getRelatedProjects(request: any) {
}
}

async function updateProjectDates(request: any) {
const projects = await getRelatedProjects(request);
const { startDate, endDate } = request?.body?.CampaignDetails;
for (const project of projects) {
project.startDate = startDate || project.startDate;
project.endDate = endDate || project.endDate;
delete project?.address;
}
logger.info("Projects related to current Campaign : " + JSON.stringify(projects));
const projectUpdateBody = {
RequestInfo: request?.body?.RequestInfo,
Projects: projects
}
const projectUpdateResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectUpdate, projectUpdateBody);
if (projectUpdateResponse?.Project && Array.isArray(projectUpdateResponse?.Project) && projectUpdateResponse?.Project?.length == projects?.length) {
logger.info("Project dates updated successfully")
}
else {
throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR")
async function updateProjectDates(request: any, actionInUrl: any) {
const { startDate, endDate, projectId } = request?.body?.CampaignDetails
if ((startDate || endDate) && projectId && actionInUrl == "update") {
const projects = await getRelatedProjects(request);
for (const project of projects) {
project.startDate = startDate || project.startDate;
project.endDate = endDate || project.endDate;
delete project?.address;
}
logger.info("Projects related to current Campaign : " + JSON.stringify(projects));
const projectUpdateBody = {
RequestInfo: request?.body?.RequestInfo,
Projects: projects
}
const projectUpdateResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectUpdate, projectUpdateBody);
if (projectUpdateResponse?.Project && Array.isArray(projectUpdateResponse?.Project) && projectUpdateResponse?.Project?.length == projects?.length) {
logger.info("Project dates updated successfully")
}
else {
throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR")
}
Comment on lines +1102 to +1122
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor updateProjectDates to handle errors more gracefully.

- throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR")
+ if (!projectUpdateResponse?.Project || !Array.isArray(projectUpdateResponse?.Project) || projectUpdateResponse?.Project?.length !== projects?.length) {
+     logger.error("Failed to update project dates");
+     throw new Error("PROJECT_UPDATE_ERROR");
+ } else {
+     logger.info("Project dates updated successfully");
+ }

This change ensures that errors are logged before throwing, providing better traceability and error handling.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
async function updateProjectDates(request: any, actionInUrl: any) {
const { startDate, endDate, projectId } = request?.body?.CampaignDetails
if ((startDate || endDate) && projectId && actionInUrl == "update") {
const projects = await getRelatedProjects(request);
for (const project of projects) {
project.startDate = startDate || project.startDate;
project.endDate = endDate || project.endDate;
delete project?.address;
}
logger.info("Projects related to current Campaign : " + JSON.stringify(projects));
const projectUpdateBody = {
RequestInfo: request?.body?.RequestInfo,
Projects: projects
}
const projectUpdateResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectUpdate, projectUpdateBody);
if (projectUpdateResponse?.Project && Array.isArray(projectUpdateResponse?.Project) && projectUpdateResponse?.Project?.length == projects?.length) {
logger.info("Project dates updated successfully")
}
else {
throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR")
}
async function updateProjectDates(request: any, actionInUrl: any) {
const { startDate, endDate, projectId } = request?.body?.CampaignDetails
if ((startDate || endDate) && projectId && actionInUrl == "update") {
const projects = await getRelatedProjects(request);
for (const project of projects) {
project.startDate = startDate || project.startDate;
project.endDate = endDate || project.endDate;
delete project?.address;
}
logger.info("Projects related to current Campaign : " + JSON.stringify(projects));
const projectUpdateBody = {
RequestInfo: request?.body?.RequestInfo,
Projects: projects
}
const projectUpdateResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectUpdate, projectUpdateBody);
if (!projectUpdateResponse?.Project || !Array.isArray(projectUpdateResponse?.Project) || projectUpdateResponse?.Project?.length !== projects?.length) {
logger.error("Failed to update project dates");
throw new Error("PROJECT_UPDATE_ERROR");
} else {
logger.info("Project dates updated successfully");
}
}
}

}
}

Expand Down Expand Up @@ -1148,7 +1150,7 @@ async function getCodesTarget(request: any, localizationMap?: any) {

async function createProject(request: any, actionUrl: any, localizationMap?: any) {
logger.info("Create Projects started for the given Campaign")
var { tenantId, boundaries, projectType, projectId, startDate, endDate } = request?.body?.CampaignDetails;
var { tenantId, boundaries, projectType, projectId } = request?.body?.CampaignDetails;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper type definitions to avoid using any.

// Before
var { tenantId, boundaries, projectType, projectId } = request?.body?.CampaignDetails;

// After
interface CampaignDetails {
    tenantId: string;
    boundaries: Boundary[];
    projectType: string;
    projectId: string | null;
}

const { tenantId, boundaries, projectType, projectId }: CampaignDetails = request?.body?.CampaignDetails;

This change introduces a TypeScript interface to ensure type safety and avoid the use of any.

if (boundaries && projectType && !projectId) {
const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId);
var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse);
Expand Down Expand Up @@ -1179,9 +1181,6 @@ async function createProject(request: any, actionUrl: any, localizationMap?: any
await projectCreate(projectCreateBody, request)
}
}
else if ((startDate || endDate) && projectId && actionUrl == "update") {
await updateProjectDates(request);
}
}


Expand All @@ -1194,6 +1193,7 @@ async function processAfterPersist(request: any, actionInUrl: any) {
await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap)
}
else {
await updateProjectDates(request, actionInUrl);
await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap)
}
} catch (error: any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -763,13 +763,15 @@ function validateProjectCampaignMissingFields(CampaignDetails: any) {

function validateDraftProjectCampaignMissingFields(CampaignDetails: any) {
validateCampaignBodyViaSchema(campaignDetailsDraftSchema, CampaignDetails)
const { startDate, endDate } = CampaignDetails;
if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) {
throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate");
}
const today: any = Date.now();
if (startDate <= today) {
throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date");
const { startDate, endDate, action } = CampaignDetails;
if (action != "changeDates") {
if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) {
throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate");
}
const today: any = Date.now();
if (startDate <= today) {
throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date");
}
Comment on lines +766 to +774
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure consistent date validation logic across different actions.

The validation logic for startDate and endDate is duplicated in both validateDraftProjectCampaignMissingFields and validateProjectCampaignMissingFields. Consider refactoring this into a separate utility function to avoid code duplication and ensure consistency across different validation scenarios.

- if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) {
-     throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate");
- }
- const today: any = Date.now();
- if (startDate <= today) {
-     throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date");
- }
+ validateCampaignDates(startDate, endDate);

Committable suggestion was skipped due low confidence.

}
}

Expand Down Expand Up @@ -812,7 +814,7 @@ async function validateCampaignName(request: any, actionInUrl: any) {
}

async function validateById(request: any) {
const { id, tenantId } = request?.body?.CampaignDetails
const { id, tenantId, action } = request?.body?.CampaignDetails
if (!id) {
throwError("COMMON", 400, "VALIDATION_ERROR", "id is required");
}
Expand All @@ -829,8 +831,10 @@ async function validateById(request: any) {
if (searchResponse?.CampaignDetails?.length > 0) {
logger.info("CampaignDetails : " + JSON.stringify(searchResponse?.CampaignDetails));
request.body.ExistingCampaignDetails = searchResponse?.CampaignDetails[0];
if (request.body.ExistingCampaignDetails?.campaignName != request?.body?.CampaignDetails?.campaignName && request.body.ExistingCampaignDetails?.status != campaignStatuses?.drafted) {
throwError("CAMPAIGN", 400, "CAMPAIGNNAME_MISMATCH", `CampaignName can only be updated in ${campaignStatuses?.drafted} state. CampaignName mismatch, Provided CampaignName = ${request?.body?.CampaignDetails?.campaignName} but Existing CampaignName = ${request.body.ExistingCampaignDetails?.campaignName}`);
if (action != "changeDates") {
if (request.body.ExistingCampaignDetails?.status != campaignStatuses?.drafted) {
throwError("COMMON", 400, "VALIDATION_ERROR", `Campaign can only be updated in drafted state. Change action to changeDates if you want to just update date.`);
}
}
}
else {
Expand Down Expand Up @@ -878,27 +882,50 @@ async function validateProjectType(request: any, projectType: any, tenantId: any
}
}

function isObjectOrArray(value: any) {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}



async function validateProjectCampaignRequest(request: any, actionInUrl: any) {
const CampaignDetails = request.body.CampaignDetails;
const { id, hierarchyType, action, tenantId, boundaries, resources, projectType } = CampaignDetails;
if (actionInUrl == "update") {
if (!id) {
throwError("COMMON", 400, "VALIDATION_ERROR", "id is required for update");
async function validateChangeDatesRequest(request: any) {
var ExistingCampaignDetails = request?.body?.ExistingCampaignDetails;
const { startDate: exsistingStartDate, endDate: exsistingEndDate } = ExistingCampaignDetails;
var newCampaignDetails = request?.body?.CampaignDetails;
const { startDate: newStartDate, endDate: newEndDate } = newCampaignDetails;

for (const key in newCampaignDetails) {
if (!isObjectOrArray(newCampaignDetails[key])) {
// If the value is not an object or array, compare it with the corresponding value in ExistingCampaignDetails
if (!(key == "startDate" || key == "endDate") && newCampaignDetails[key] !== ExistingCampaignDetails[key]) {
// Handle the validation failure (for example, throw an error or log a message)
throwError("COMMON", 400, "VALIDATION_ERROR", `${key} value in request campaign is not matching with existing campaign`);
}
}
}
if (!CampaignDetails) {
throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is required");
const today: any = Date.now();
if (exsistingStartDate >= today) {
logger.info("Existing start date is greater than or equal to current date");
logger.info("Now only endDate can be updated")
if (exsistingStartDate != newStartDate) {
throwError("COMMON", 400, "VALIDATION_ERROR", "StartDate cannot be updated as campaign is started or completed.");
}
}
if (!action) {
throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails.action is required and must be either 'create' or 'draft'")
if (exsistingEndDate > today) {
logger.info("Existing end date is greater than or equal to current date");
if (exsistingEndDate != newEndDate) {
throwError("COMMON", 400, "VALIDATION_ERROR", "EndDate cannot be updated as campaign is completed.");
}
}
if (!(action == "create" || action == "draft")) {
throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create or draft");
request.body.CampaignDetails = ExistingCampaignDetails;
request.body.CampaignDetails.startDate = newStartDate;
request.body.CampaignDetails.endDate = newEndDate;
}
Comment on lines +885 to +921
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify logic and improve readability in validateChangeDatesRequest.

This function contains complex conditional logic that could be simplified. Consider breaking down the function into smaller, more focused functions and using early returns to reduce nesting and improve readability.

- for (const key in newCampaignDetails) {
-     if (!isObjectOrArray(newCampaignDetails[key])) {
-         if (!(key == "startDate" || key == "endDate") && newCampaignDetails[key] !== ExistingCampaignDetails[key]) {
-             throwError("COMMON", 400, "VALIDATION_ERROR", `${key} value in request campaign is not matching with existing campaign`);
-         }
-     }
- }
+ validateCampaignDetails(newCampaignDetails, ExistingCampaignDetails);

Committable suggestion was skipped due low confidence.


async function validateCampaignBody(request: any, CampaignDetails: any, actionInUrl: any) {
const { hierarchyType, action, tenantId, boundaries, resources, projectType } = CampaignDetails;
if (action == "changeDates") {
await validateChangeDatesRequest(request);
}
if (action == "create") {
else if (action == "create") {
validateProjectCampaignMissingFields(CampaignDetails);
await validateCampaignName(request, actionInUrl);
if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) {
Expand All @@ -915,9 +942,32 @@ async function validateProjectCampaignRequest(request: any, actionInUrl: any) {
await validateHierarchyType(request, hierarchyType, tenantId);
await validateProjectType(request, projectType, tenantId);
}
}

async function validateProjectCampaignRequest(request: any, actionInUrl: any) {
const CampaignDetails = request.body.CampaignDetails;
const { id, action } = CampaignDetails;
if (actionInUrl == "update") {
if (!id) {
throwError("COMMON", 400, "VALIDATION_ERROR", "id is required for update");
}
}
if (!CampaignDetails) {
throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is required");
}
if (!action) {
throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails.action is required and must be either 'create' or 'draft'")
}
if (!(action == "create" || action == "draft" || action == "changeDates")) {
throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create, draft or changeDates");
}
if (actionInUrl == "update") {
await validateById(request);
}
if (action == "changeDates" && actionInUrl == "create") {
throwError("COMMON", 400, "VALIDATION_ERROR", "changeDates is not allowed during create");
}
await validateCampaignBody(request, CampaignDetails, actionInUrl);
}

async function validateSearchProjectCampaignRequest(request: any) {
Expand Down
Loading