diff --git a/.env.sample b/.env.sample index bb73d1a9..cc9a927c 100755 --- a/.env.sample +++ b/.env.sample @@ -63,7 +63,8 @@ NHANCE_LOGO = helpdeskURL = TOKENTIMEOUT = POST_ENROLLMENT_APP_LINK = -GDRIVE_ROOT_FOLDER_ID = +GDRIVE_ROOT_FOLDER_ID = +RFQ_PARENT_FOLDER_ID = email.fromEmail = @@ -150,3 +151,11 @@ LEAD_CLIENT_FROM_MAIL_ID = # BDS Daily Report Emails Configuration bds.dailyReportEmails = + +#-------------------------------------------------------------------- +# MEDI ASSIST WELLNESS SSO Configuration +#-------------------------------------------------------------------- + +MEDIASSIST_WELLNESS_KEY = +MEDIASSIST_WELLNESS_IV = +MEDIASSIST_WELLNESS_LOGIN_URL = diff --git a/app/Config/Acl.php b/app/Config/Acl.php index b4d85eac..c1a1e56a 100644 --- a/app/Config/Acl.php +++ b/app/Config/Acl.php @@ -15,8 +15,16 @@ class Acl '#^/loginPos#' => ['public' => true], '#^/getVerifyPosMobileNo#' => ['public' => true], '#^/getVerifiedPosUserData#' => ['public' => true], + '#^/chat#' => ['public' => true], + '#^/widget#' => ['public' => true], + '#^/chatbottest#' => ['public' => true], + '#^/chatbot#' => ['public' => true], + '#^/getSSORedirectUrl#' => ['public' => true], + '#^/getEmployeePolicy#' => ['public' => true], + '#^/downloadFileTableFile#' => ['public' => true], '#^/swagger#' => ['roles' => [ADMIN_ROLE_ID]], '#^/getEmployeeActiveOrInactivePolicy#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], + '#^/test/chartbrewDashboardDemo#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/bulkEcardDownloadAsZip#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/sheet#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], '#^/sendextraparam#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID]], @@ -54,6 +62,34 @@ class Acl 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [] ], + '#^/hrFileDownload#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/sendPushNotification#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/sendEmail#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/getPolicyLevelEmployeeSummaryData#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/cdTransactionData#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/claimsSearch#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/getBackToEnrolledDetails#' => [ + 'roles' => [ ADMIN_ROLE_ID,HEAD_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], // ===================== USER MANAGEMENT ===================== '#^/user#' => [ @@ -88,6 +124,18 @@ class Acl 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] ], + '#^/dmsSearch#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] + ], + '#^/downloadGdriveFile#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] + ], + '#^/driveListFiles#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] + ], '#^/bds_upload#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] @@ -108,12 +156,60 @@ class Acl 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] ], + '#^/importRules#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [FINANCE_TEAM_ID,POS_TEAM_ID] + ], // ===================== CLAIMS / TICKETS ===================== '#^/ticket#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [CLAIMS_TEAM_ID] ], + '#^/ticketSave#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketList#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketConversationSave#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketConversationList#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketType#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketHistoryList#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/ticketAutoFetchDetails#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/initiateClaim#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/departments#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/get_ticket_data#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], + '#^/claimView#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [CLAIMS_TEAM_ID] + ], '#^/claim_mis#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], 'teams' => [CLAIMS_TEAM_ID] @@ -126,11 +222,11 @@ class Acl ], '#^/rfq#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], - 'teams' => [SALES_TEAM_ID] + 'teams' => [BUSINESS_SUPPORT_TEAM_ID, SALES_TEAM_ID] ], '#^/sales#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID], - 'teams' => [SALES_TEAM_ID] + 'teams' => [BUSINESS_SUPPORT_TEAM_ID, SALES_TEAM_ID] ], // ===================== CMS / CONTENT ===================== @@ -138,6 +234,22 @@ class Acl 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], 'teams' => [] ], + '#^/add_advertise_image#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], + '#^/remove_advertise_image#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], + '#^/getAdvertiseImage#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], + '#^/showAdvertiseImage#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], '#^/frontend_content#' => [ 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], 'teams' => [] @@ -146,6 +258,10 @@ class Acl 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], 'teams' => [] ], + '#^/getFEContent#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], // ===================== LOGS ===================== '#^/logs#' => [ @@ -167,9 +283,25 @@ class Acl // ===================== WEBHOOKS / 3RD PARTY ===================== '#^/dispatchWebhookData#' => ['public' => true], '#^/retrieveWebhookData#' => ['public' => true], - // '#^/ICICI#' => ['public' => true], - // '#^/Vidal#' => ['public' => true], - // '#^/MediAssist#' => ['public' => true], + '#^/ecardRequest#' => ['public' => true], + '#^/getTPAID#' => ['public' => true], + '#^/fileDownload#' => ['public' => true], + '#^/generateAuthToken#' => ['public' => true], + '#^/createEnrollmentBatch#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [ENROLLMENT_TEAM_ID]], + '#^/getEnrollmentBatchStatus#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [ENROLLMENT_TEAM_ID]], + '#^/fetchUHIDDetails#' => ['roles' => [ADMIN_ROLE_ID, HEAD_ROLE_ID], 'teams' => [ENROLLMENT_TEAM_ID]], + '#^/FhplGetBenefDetails#' => ['roles' => [ADMIN_ROLE_ID]], + '#^/EcardRequest#' => ['public' => true], + '#^/HospitalNetwork#' => ['public' => true], + '#^/VidalGetBenefDetails#' => ['public' => true], + '#^/ClaimDetail#' => ['public' => true], + '#^/SubmitClaim#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/IntimateClaim#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/IRSubmission#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/ClaimStatusUpdate#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/syncTpaClaimToNhance#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/HealthIndiaGetBenefDetails#' => ['roles' => [ADMIN_ROLE_ID,HEAD_ROLE_ID,ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID]], + '#^/testTracelog#' => ['roles' => [ADMIN_ROLE_ID]], // ===================== CLI ===================== '#^/cli/#' => ['public' => true], diff --git a/app/Config/Constants.php b/app/Config/Constants.php index d47699d8..9078b11c 100755 --- a/app/Config/Constants.php +++ b/app/Config/Constants.php @@ -131,3 +131,4 @@ define('UPLOAD_EXT_POLICY_DOCS', ['pdf', 'jpg', 'jpeg', 'png', 'xls', 'xlsx']); define('UPLOAD_EXT_LEAD_FILES', ['xls', 'xlsx', 'pdf', 'jpg', 'jpeg', 'png']); define('UPLOAD_EXT_EXCEL', ['xls', 'xlsx', 'ods', 'csv']); define('UPLOAD_EXT_MAIL_ATTACHMENTS', ['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx', 'xls', 'xlsx']); +define('UPLOAD_EXT_NON_EB_RACK_RATE', ['pdf', 'xls', 'xlsx']); diff --git a/app/Config/Filters.php b/app/Config/Filters.php index e70e75ef..609b6738 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -69,8 +69,8 @@ class Filters extends BaseConfig 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], 'Cors', - // 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','employeeRest/*','processjob','getCommission','downloadEmployeeEcardZip']], - 'SecurityInputFilter' => ['except' => ['/client/notification/create','/ticket/crud_mail_template/*','test_mail','leads/sendMail'] ], + 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','employeeRest/*','processjob','getCommission','downloadEmployeeEcardZip', 'downloadClaimFile/*']], + 'SecurityInputFilter' => ['except' => ['/client/notification/create','/ticket/crud_mail_template/*','test_mail','leads/sendMail', 'ticket/reply'] ], 'GlobalPostFileUploadGuard' // 'csrf', // 'invalidchars', diff --git a/app/Config/RfqConfig.php b/app/Config/RfqConfig.php index ca536901..0d0268cc 100644 --- a/app/Config/RfqConfig.php +++ b/app/Config/RfqConfig.php @@ -7,9 +7,17 @@ class RfqConfig extends BaseConfig { /** * Google Drive parent folder IDs for RFQ and QCR sheets. + * Values are loaded from .env (RFQ_PARENT_FOLDER_ID). */ - public string $rfqParentFolderId = '1MnYh5PTPDlc9mYMGsjmTv02y8EZ-BQf1'; - public string $qcrParentFolderId = '1MnYh5PTPDlc9mYMGsjmTv02y8EZ-BQf1'; + public string $rfqParentFolderId = ''; + public string $qcrParentFolderId = ''; + + public function __construct() + { + parent::__construct(); + $this->rfqParentFolderId = env('RFQ_PARENT_FOLDER_ID', '1MnYh5PTPDlc9mYMGsjmTv02y8EZ-BQf1'); + $this->qcrParentFolderId = env('RFQ_PARENT_FOLDER_ID', '1MnYh5PTPDlc9mYMGsjmTv02y8EZ-BQf1'); + } /** * Default permissions for created sheets. @@ -48,4 +56,27 @@ class RfqConfig extends BaseConfig 'groups' => [], ], ]; + + /** + * Placeholder token for past 3 years claims table (written as multi-row values at that cell). + */ + public string $rfqClaimsPlaceholder = '{{CLAIMS_DETAILS}}'; + + /** + * Maps Google Sheet placeholder => internal key from buildRfqPlaceholderData(). + * Add these exact strings in your RFQ templates (any sheet/tab). + * + * @var array + */ + public array $rfqPlaceholders = [ + '{{INSURED_NAME}}' => 'insured_name', + '{{COMMUNICATION_ADDRESS}}' => 'communication_address', + '{{GST}}' => 'gst', + '{{PAN}}' => 'pan', + '{{POLICY_PERIOD}}' => 'policy_period', + '{{OPPORTUNITY_TYPE}}' => 'opportunity_type', + '{{RISK_LOCATION}}' => 'risk_location', + '{{OCCUPANCY}}' => 'occupancy', + '{{CLAIMS_DETAILS}}' => 'claims_details', + ]; } diff --git a/app/Config/Routes.php b/app/Config/Routes.php index d4d68de3..9bad6caa 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -100,6 +100,7 @@ $routes->group("/user", ["filter" => "authMVC"], function ($routes) { $routes->get("list", "UserController::list"); $routes->get("getuser/(:hash)", "UserController::getuser/$1"); $routes->get("deactive/(:hash)", "UserController::deactive/$1"); + $routes->get("activateUser/(:any)", "UserController::activateUser/$1"); $routes->get("rolesandteams", "UserController::getRolesAndTeams"); $routes->get("getUserActivityHistory", "UserController::getUserActivityHistory"); $routes->match(['get','post','put'], 'partner', 'UserController::partner'); @@ -170,6 +171,9 @@ $routes->group("/client", ["filter" => "authMVC"], function ($routes) { $routes->post("policyGMCTerms", "ClientController::policyGMCTerms"); $routes->get("getterms", "ClientController::getterms"); $routes->get("remove/(:any)", "ClientController::removePolicy/$1"); + $routes->get("getNonEbRackRateFiles", "ClientController::getNonEbRackRateFiles"); + $routes->post("uploadNonEbRackRateFile", "ClientController::uploadNonEbRackRateFile"); + $routes->post("removeNonEbRackRateFile", "ClientController::removeNonEbRackRateFile"); }); $routes->group("kyc", ["filter" => "authMVC"], function ($routes) { @@ -227,6 +231,8 @@ $routes->group("/employee", ["filter" => "authMVC"], function ($routes) { $routes->get("retail-endorsement-list", "EmployeeController::retailendorsementlist"); $routes->post("retail-endorsement-save", "EmployeeController::retailendorsementsave"); $routes->get("getTPADataVariationReport/(:num)", "EmployeeController::getTPADataVariationReport/$1"); + $routes->get("getTPADataVariationReportView/(:num)", "EmployeeController::getTPADataVariationReport/$1/view"); + $routes->get("proceedTPADataVariationNextStep/(:num)", "EmployeeController::proceedTPADataVariationNextStep/$1"); $routes->get("bulkGenerateEcardAndStoreinS3", "EmployeeController::bulkGenerateEcardAndStoreinS3"); $routes->get('clearCdSession', 'EmployeeController::clearCdSession'); $routes->get('checkSessionStatus', 'EmployeeController::checkSessionStatus'); @@ -447,6 +453,9 @@ $routes->group("/util", ["filter" => "authMVC"], function ($routes) { $routes->post('insufficientCdBalanceHrMailSend', 'EmployeeController::insufficientCdBalanceHrMailSend'); $routes->get('getTpaClaimDumpErrorData/(:any)', 'TicketServiceController::getTpaClaimDumpErrorData/$1'); $routes->get('croneDailyActivityReport', 'DashboardController::croneDailyActivityReport'); + $routes->get('insertSampleTpaApiData/(:any)', 'TestingController::insertSampleTpaApiData/$1'); + $routes->get('listEmployeeCountByClientPolicy', 'TestingController::listEmployeeCountByClientPolicy'); + $routes->get('testMediAssistWellness','TestingController::testMediAssistWellness'); }); $routes->post("policy_tranction/sendInstallmentRemainderMail","PolicyTransactionController::sendInstallmentRemainderMail"); @@ -511,6 +520,8 @@ $routes->group("leads", ["filter" => "authMVC"], function ($routes) { $routes->post("create", "LeadsController::createLead"); $routes->get("list/(:any)", "LeadsController::getLeadDataForEdit/$1"); $routes->get("createRfqSheet", "LeadsController::createRfqSheet"); + $routes->get("createQcrSheet", "LeadsController::createQcrSheet"); + $routes->post("uploadLeadAttachment", "LeadsController::uploadLeadAttachment"); $routes->get("mailTemplate", "LeadsController::getLeadMailTemplate"); $routes->get("sendMail", "LeadsController::sendMailWithAttachement"); $routes->post("sendMail", "LeadsController::sendMailWithAttachement"); @@ -550,6 +561,8 @@ $routes->cli('cli/sendZeptoMail', 'MasterController::testZeptoSMTP'); $routes->cli('cli/check_bounce_mail_cli', 'MasterController::testCheckBounceMails'); $routes->cli('cli/app_check_list', 'MasterController::appCheckList'); $routes->cli('cli/new_gdrive_token', 'GoogleDriveController::generateNewGoogleDriveAccessToken'); +$routes->cli('cli/list-sheet-folder-files', 'GoogleSheetController::listFolderSheetFilesCli'); +$routes->cli('cli/list-sheet-folder-files/(:any)', 'GoogleSheetController::listFolderSheetFilesCli/$1'); $routes->cli('cli/check_env', 'MasterController::checkEnv'); //crone job @@ -877,6 +890,7 @@ $routes->group('test', function($routes) { $routes->get('logo_renaming','TestingController::logo_renaming'); $routes->get('testingquerys','TestingController::testingquerys'); $routes->get('thzReminderCrone','ThzController::getOpenTicketsOlderThan24HoursAndAssignNextLevel'); + $routes->get('chartbrewDashboardDemo','TestingController::chartbrewDashboardDemo'); // $routes->get('createDefaultMailTempalteInDB','TestingController::createDefaultMailTempalteInCrossDB'); // $routes->get('createDefaultMailTempalteInSameDB','TestingController::createDefaultMailTempalteInSameDB'); }); @@ -1033,6 +1047,10 @@ $routes->group('sales', function($routes) { $routes->get('dashboard', 'SalesController::dashboard'); $routes->get('branchLevelDashboard', 'SalesController::branchLevelDashboard'); $routes->get('salesManagerLevelDashboard', 'SalesController::salesManagerLevelDashboard'); + + //Validations + $routes->get('checkDuplicate', 'SalesController::checkDuplicate'); + $routes->get('searchClients', 'SalesController::searchClients'); }); // Expence Module Route Group diff --git a/app/Controllers/ApiServiceController.php b/app/Controllers/ApiServiceController.php index 31cb0a0c..013aea7a 100644 --- a/app/Controllers/ApiServiceController.php +++ b/app/Controllers/ApiServiceController.php @@ -245,7 +245,13 @@ class ApiServiceController extends BaseController $policy_id = $this->request->getPost('client_policy_id') ?? null; $fileModel = new BatchFileModel(); - $filesData = $fileModel->where('is_active', 1)->where('event_type', 'api')->where('status', 'inprogress')->countAllResults(); + $filesData = $fileModel + ->join('client_policy', 'client_policy.id = batch_files.client_policy_id') + ->where('client_policy.tpa_id', $tpa_id) + ->where('batch_files.is_active', 1) + ->where('batch_files.event_type', 'api') + ->where('batch_files.status', 'inprogress') + ->countAllResults(); if($filesData > 0){ log_message('error', "TPA GetBenefDetails job is already in process."); @@ -453,13 +459,17 @@ class ApiServiceController extends BaseController $userParams = []; foreach ($data as $row) { - if($row['wellness_vendor_id'] != null) + if($row['wellness_vendor_id'] == $this->vidal_primary_key) { $vidalApiController = new VidalApiController(); return $vidalApiController->getWellnessSSORedirectUrl($row['email']); + }else if ($row['wellness_vendor_id'] == $this->medi_assist_primary_key) + { + $mediAssistController = new MediAssistApiController(); + return $mediAssistController->getWellnessSSORedirectUrl($row['planId'], $row['memberId']); } - else if ($row['planId'] != null) // VISIT + else if ($row['planId'] != null && empty($row['wellness_vendor_id'])) // VISIT { $userParams['name'] = $row['name']; $userParams['email'] = $row['email']; diff --git a/app/Controllers/AppContentManagementController.php b/app/Controllers/AppContentManagementController.php index c3bcde67..a3db36ec 100755 --- a/app/Controllers/AppContentManagementController.php +++ b/app/Controllers/AppContentManagementController.php @@ -226,6 +226,14 @@ class AppContentManagementController extends AdminController if ($this->request->getMethod() === 'post') { + /** + * -------------------------------------------------------------------------- + * STEP 1: INITIAL VALIDATION + * -------------------------------------------------------------------------- + * These are the basic validation rules. For 'content' and 'notes', we only + * check if they are provided and within the allowed length. + * The more advanced security check for script tags happens next. + */ $rules = [ 'fe_id' => [ 'rules' => 'permit_empty|integer|is_natural', @@ -239,7 +247,7 @@ class AppContentManagementController extends AdminController 'errors' => [ 'required' => 'Type is required', 'max_length' => 'Type cannot exceed 255 characters', - 'regex_match' => 'Type contains invalid characters' + 'regex_match' => 'Type can contain only letters, numbers, spaces, _ and -' ] ], 'content_section' => [ @@ -247,7 +255,7 @@ class AppContentManagementController extends AdminController 'errors' => [ 'required' => 'Content Section is required', 'max_length' => 'Content Section cannot exceed 255 characters', - 'regex_match' => 'Content Section contains invalid characters' + 'regex_match' => 'Content Section can contain only letters, numbers, spaces, _ and -' ] ], 'heading' => [ @@ -255,25 +263,23 @@ class AppContentManagementController extends AdminController 'errors' => [ 'required' => 'Heading is required', 'max_length' => 'Heading cannot exceed 255 characters', - 'regex_match' => 'Heading contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' + 'regex_match' => 'Heading can contain only letters, numbers, spaces, and these characters: . , ; : ! ? ( ) & / -' ] ], - 'content' => [ - 'rules' => 'required|max_length[5000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'content' => [ + 'rules' => 'required|max_length[5000]', 'errors' => [ - 'required' => 'Content is required', - 'max_length' => 'Content cannot exceed 5000 characters', - 'regex_match' => 'Content contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' + 'required' => 'Content is required', + 'max_length' => 'Content cannot exceed 5000 characters', ] ], 'notes' => [ - 'rules' => 'required|max_length[1500]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'rules' => 'required|max_length[1500]', 'errors' => [ - 'required' => 'Notes are required', - 'max_length' => 'Notes cannot exceed 1500 characters', - 'regex_match' => 'Notes contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' + 'required' => 'Notes are required', + 'max_length' => 'Notes cannot exceed 1500 characters', ] - ] + ], ]; if (!$this->validate($rules)) { @@ -284,9 +290,60 @@ class AppContentManagementController extends AdminController 'errors' => $this->validator->getErrors() ]); } - $request_post_data = $this->request->getPost(); - $data = sanitizeInputArrayAdvanced($request_post_data); - $id = $data['fe_id'] ?? null; + + /************************************************************************** + * REFACTORED SANITIZATION LOGIC (XSS Protection) + ************************************************************************** + * + * Per the user's request, we are avoiding the generic `sanitizeInputArrayAdvanced` + * on the `content` and `notes` fields, as they require special HTML + * handling. + * + * The new process is: + * 1. Get the raw `content` and `notes` directly from the POST request. + * 2. Perform the critical XSS validation on this raw content using `hasXssTags()`. + * If it fails, the request is rejected immediately. This satisfies all + * the failure test cases (Tests 4-9). + * 3. Take all *other* POST data and sanitize it using the generic + * `sanitizeInputArrayAdvanced` function. + * 4. Sanitize the now-validated `content` and `notes` using our specific + * `sanitizeHtml()` function, which allows safe HTML. + * 5. Combine the sanitized data into a final array for database insertion. + * + *************************************************************************/ + + // Step 1: Get raw `content` and `notes`. + $rawContent = $this->request->getPost('content'); + $rawNotes = $this->request->getPost('notes'); + + // Step 2: Perform critical XSS validation on raw input. + $xssErrors = []; + if ($this->hasXssTags($rawContent)) { + $xssErrors['content'] = 'Content contains restricted tags. Script, iframe and event handlers are not allowed'; + } + if ($this->hasXssTags($rawNotes)) { + $xssErrors['notes'] = 'Notes contains restricted tags. Script, iframe and event handlers are not allowed'; + } + + if (!empty($xssErrors)) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => false, + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => $xssErrors + ]); + } + + // Step 3: Sanitize all *other* POST data. + $otherPostData = $this->request->getPost(); + unset($otherPostData['content'], $otherPostData['notes']); + $data = sanitizeInputArrayAdvanced($otherPostData); + + // Step 4 & 5: Sanitize and re-combine `content` and `notes`. + $data['content'] = $this->sanitizeHtml($rawContent); + $data['notes'] = $this->sanitizeHtml($rawNotes); + + $id = $data['fe_id'] ?? null; if (!empty($id) && (!ctype_digit((string)$id) || (int)$id <= 0)) { return $this->response->setStatusCode(400)->setJSON([ @@ -408,27 +465,29 @@ class AppContentManagementController extends AdminController if ($method === 'post') { $rules = [ 'category' => [ - 'rules' => 'required|max_length[100]|alpha_numeric_space', + // Allow letters, numbers, spaces and / - . , " ' + 'rules' => 'required|max_length[100]|regex_match[/^[a-zA-Z0-9 \\/\\-\\.\,\"\\\']+$/]', 'errors' => [ - 'required' => 'Category is required', - 'max_length' => 'Category cannot exceed 100 characters', - 'alpha_numeric_space' => 'Category contains invalid characters' + 'required' => 'Category is required', + 'max_length' => 'Category cannot exceed 100 characters', + 'regex_match' => 'Category can contain only letters, numbers, spaces, and these characters: / - . , " \'', + ] ], 'question' => [ - 'rules' => 'required|max_length[1000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + // Allow only letters, numbers, spaces and basic punctuation . , ; : ! ? ( ) & / - + 'rules' => 'required|max_length[1000]|regex_match[/^[a-zA-Z0-9 _\\-.,;:!?()&\\/]+$/]', 'errors' => [ 'required' => 'Question is required', 'max_length' => 'Question cannot exceed 1000 characters', - 'regex_match' => 'Question contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' + 'regex_match' => 'Question can contain only letters, numbers, spaces, and these characters: . , ; : ! ? ( ) & / -', ] ], 'answer' => [ - 'rules' => 'required|max_length[5000]|regex_match[/^[a-zA-Z0-9 _\-.,;:!?()&\/\r\n]+$/]', + 'rules' => 'required|max_length[5000]', 'errors' => [ 'required' => 'Answer is required', 'max_length' => 'Answer cannot exceed 5000 characters', - 'regex_match' => 'Answer contains invalid characters. Only letters, numbers, spaces and basic punctuation are allowed' ] ] ]; @@ -443,9 +502,50 @@ class AppContentManagementController extends AdminController ]); } - $request_post_data = $this->request->getPost(); - $sanitized_post_data = sanitizeInputArrayAdvanced($request_post_data); - $data = array_filter($sanitized_post_data, fn($v) => $v !== '' && $v !== null); + /************************************************************************** + * XSS PROTECTION FOR 'question' and 'answer' + ************************************************************************** + * + * Applying the same security model as `frontend_content`. + * + * 1. Validate raw `question` and `answer` for malicious tags using `hasXssTags()`. + * If found, reject the request immediately. + * 2. Sanitize all *other* fields using the generic `sanitizeInputArrayAdvanced`. + * 3. Sanitize the `question` and `answer` using the HTML-aware `sanitizeHtml()` + * function to allow safe tags before saving. + * + *************************************************************************/ + + // Step 1: Validate raw input for XSS threats. + $rawQuestion = $this->request->getPost('question'); + $rawAnswer = $this->request->getPost('answer'); + $xssErrors = []; + + if ($this->hasXssTags($rawQuestion)) { + $xssErrors['question'] = 'Question contains restricted tags. Script, iframe and event handlers are not allowed'; + } + if ($this->hasXssTags($rawAnswer)) { + $xssErrors['answer'] = 'Answer contains restricted tags. Script, iframe and event handlers are not allowed'; + } + + if (!empty($xssErrors)) { + return $this->response->setStatusCode(400)->setJSON([ + 'status' => 'error', + 'message' => 'Input validation failed', + 'code' => 400, + 'errors' => $xssErrors, + 'ref' => $ref + ]); + } + + // Step 2 & 3: Sanitize and combine data. + $otherPostData = $this->request->getPost(); + unset($otherPostData['question'], $otherPostData['answer']); + $data = sanitizeInputArrayAdvanced($otherPostData); + + $data['question'] = $this->sanitizeHtml($rawQuestion); + $data['answer'] = $this->sanitizeHtml($rawAnswer); + $id = $data['faq_id'] ?? null; if (!empty($id) && (!ctype_digit((string)$id) || (int)$id <= 0)) { @@ -470,12 +570,6 @@ class AppContentManagementController extends AdminController $msg = "Updated"; } - // if ($returnType === 'web') { - // return redirect()->back()->with($status ? 'success' : 'error', "FAQ $msg " . ($status ? 'successfully' : 'failed')); - // } - - // return $this->response->setJSON([ - // ])->setStatusCode($result ? 200 : 400); return $this->response->setJSON([ 'status' => $status ? 'success' : 'error', 'message' => "FAQ $msg " . ($status ? 'successfully' : 'failed'), @@ -611,4 +705,105 @@ class AppContentManagementController extends AdminController // } + + // Add these two private methods inside AppContentManagementController + + + /** + * ================================================================================= + * HTML SANITIZATION & VALIDATION HELPER METHODS + * ================================================================================= + * The following two methods are the core of the XSS protection logic. + */ + + + /** + * sanitizeHtml() + * + * This function cleans a string of HTML, ensuring it is safe to display in a browser. + * It allows a specific set of safe HTML tags and removes any dangerous attributes + * from those tags. + * + * @param string $input The raw HTML string from user input. + * @return string The cleaned, safe HTML string. + */ + private function sanitizeHtml(string $input): string + { + /** + * Define a whitelist of allowed HTML tags. Any tag not in this list will be + * completely removed. We are allowing basic formatting, lists, tables, etc. + */ + // ✅ Added , ,

-

,
,
, , 
for Jodit support + $allowed_tags = '