Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/fluentform/app/Api/Form.php
+++ b/fluentform/app/Api/Form.php
@@ -42,8 +42,8 @@
$query->where('status', $status);
}
- if ($allowIds = FormManagerService::getUserAllowedForms()) {
- $query->whereIn('id', $allowIds);
+ if (false !== ($allowIds = FormManagerService::getUserAllowedFormsScope())) {
+ $query->whereIn('id', $allowIds ?: [0]);
}
if ($filter_by && !$is_filter_by_conv_or_step_form) {
--- a/fluentform/app/Helpers/Protector.php
+++ b/fluentform/app/Helpers/Protector.php
@@ -73,10 +73,20 @@
$ciphertext_raw = substr($c, $ivlen + $sha2len);
+ // Verify with current HMAC (IV + ciphertext)
$calcmac = hash_hmac('sha256', $iv . $ciphertext_raw, $key, $as_binary = true);
if (!hash_equals($hmac, $calcmac)) {
- return null;
+ // Fallback: verify with legacy HMAC (ciphertext only) for tokens generated before v6.2.0 IV authentication fix.
+ if (!apply_filters('fluentform/allow_legacy_token_decrypt', false)) {
+ return null;
+ }
+
+ $legacymac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary = true);
+
+ if (!hash_equals($hmac, $legacymac)) {
+ return null;
+ }
}
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv);
--- a/fluentform/app/Helpers/Traits/GlobalDefaultMessages.php
+++ b/fluentform/app/Helpers/Traits/GlobalDefaultMessages.php
@@ -17,6 +17,8 @@
static::setGlobalDefaultMessages();
} else if ($message = Arr::get($globalSettings, 'default_messages.' . $key, '')) {
static::$globalDefaultMessages[$key] = $message;
+ } else {
+ static::setGlobalDefaultMessages();
}
return apply_filters('fluentform/global_default_message', Arr::get(static::$globalDefaultMessages, $key , ''), $key);
}
--- a/fluentform/app/Hooks/Ajax.php
+++ b/fluentform/app/Hooks/Ajax.php
@@ -28,9 +28,11 @@
* REST API seems not working for some servers with Mod Security Enabled
*/
$app->addAction('wp_ajax_fluentform-form-update', function () use ($app) {
- Acl::verify('fluentform_forms_manager', $app->request->get('form_id'));
+ $formId = Acl::verifyFormId($app->request->get('form_id'));
+ Acl::verify('fluentform_forms_manager', $formId);
try {
$data = $app->request->all();
+ $data['form_id'] = $formId;
$isValidJson = (!empty($data['formFields'])) && json_decode($data['formFields'], true);
if(!$isValidJson) {
@@ -57,10 +59,14 @@
* Mod-Security also block this request
*/
$app->addAction('wp_ajax_fluentform-save-settings-general-formSettings', function () use ($app) {
- Acl::verify('fluentform_forms_manager');
+ $formId = Acl::verifyFormId($app->request->get('form_id'));
+ Acl::verify('fluentform_forms_manager', $formId);
try {
$settingsService = new FluentFormAppServicesSettingsSettingsService();
- $settingsService->saveGeneral($app->request->all());
+ $attributes = $app->request->all();
+ $attributes['form_id'] = $formId;
+
+ $settingsService->saveGeneral($attributes);
wp_send_json([
'message' => __('Settings has been saved.', 'fluentform'),
]);
@@ -74,10 +80,14 @@
* Mod-Security also block this request
*/
$app->addAction('wp_ajax_fluentform-save-form-email-notification', function () use ($app) {
- Acl::verify('fluentform_forms_manager');
+ $formId = Acl::verifyFormId($app->request->get('form_id'));
+ Acl::verify('fluentform_forms_manager', $formId);
try {
$settingsService = new FluentFormAppServicesSettingsSettingsService();
- [$settingsId, $settings] = $settingsService->store($app->request->all());
+ $attributes = $app->request->all();
+ $attributes['form_id'] = $formId;
+
+ [$settingsId, $settings] = $settingsService->store($attributes);
wp_send_json([
'message' => __('Settings has been saved.', 'fluentform'),
@@ -93,7 +103,9 @@
// Legacy AJAX handlers removed — these routes are handled by the REST API.
// Kept: fluentform-form-find-shortcode-locations (still in active use)
$app->addAdminAjaxAction('fluentform-form-find-shortcode-locations', function () use ($app) {
- Acl::verify('fluentform_forms_manager');
+ $formId = Acl::verifyFormId($app->request->get('form_id'));
+ Acl::verify('fluentform_forms_manager', $formId);
+
(new FluentFormAppModulesFormForm($app))->findFormLocations();
});
@@ -101,20 +113,29 @@
+$resolveSubmissionFormId = function ($submissionId) {
+ if (!$submissionId) {
+ return null;
+ }
+
+ $submission = FluentFormAppModelsSubmission::select('form_id')->find($submissionId);
+
+ return $submission ? $submission->form_id : null;
+};
+
$app->addAction('wp_ajax_fluentform-form-entries-export', function () use ($app) {
- Acl::verify('fluentform_entries_viewer');
+ $formId = Acl::verifyFormId($app->request->get('form_id'));
+
+ Acl::verify('fluentform_entries_viewer', $formId);
(new FluentFormAppModulesTransferTransfer())->exportEntries();
});
-$app->addAction('wp_ajax_fluentform-update-entry-user', function () use ($app) {
- $submissionId = intval($app->request->get('submission_id'));
- $formId = null;
- if ($submissionId) {
- $submission = FluentFormAppModelsSubmission::select('form_id')->find($submissionId);
- $formId = $submission ? $submission->form_id : null;
- }
+$app->addAction('wp_ajax_fluentform-update-entry-user', function () use ($app, $resolveSubmissionFormId) {
+ $submissionId = absint($app->request->get('submission_id'));
+ $formId = $resolveSubmissionFormId($submissionId);
+
Acl::verify('fluentform_manage_entries', $formId);
- $userId = intval($app->request->get('user_id'));
+ $userId = absint($app->request->get('user_id'));
try {
$result = (new FluentFormAppServicesSubmissionSubmissionService())->updateSubmissionUser($userId, $submissionId);
wp_send_json_success($result);
@@ -143,10 +164,14 @@
// Legacy log AJAX handlers removed — these routes are now handled by the REST API.
-$app->addAction('wp_ajax_fluentform-change-entry-status', function () use ($app) {
- Acl::verify('fluentform_manage_entries');
+$app->addAction('wp_ajax_fluentform-change-entry-status', function () use ($app, $resolveSubmissionFormId) {
+ $entryId = absint($app->request->get('entry_id'));
+ $formId = $resolveSubmissionFormId($entryId);
+
+ Acl::verify('fluentform_manage_entries', $formId);
+
$attributes = [
- 'entry_id' => intval($app->request->get('entry_id')),
+ 'entry_id' => $entryId,
'status' => sanitize_text_field($app->request->get('status')),
];
$newStatus = (new FluentFormAppServicesSubmissionSubmissionService())->updateStatus($attributes);
@@ -200,7 +225,7 @@
if (!wp_verify_nonce(sanitize_text_field(wpFluentForm('request')->get('nonce')), 'fluentform_report_data_migrate')) {
die('invalid');
}
- $formId = intval(wpFluentForm('request')->get('form_id'));
+ $formId = Acl::normalizeFormId(wpFluentForm('request')->get('form_id'));
if ($formId && Acl::hasPermission('fluentform_entries_viewer', $formId)) {
FluentFormAppServicesReportReportHelper::runMigrationBatch($formId);
}
--- a/fluentform/app/Hooks/filters.php
+++ b/fluentform/app/Hooks/filters.php
@@ -323,7 +323,7 @@
// Get current user allowed form ids, if current user has specific form permission
$app->addFilter('fluentform/current_user_allowed_forms', function ($form){
- return FluentFormAppServicesManagerFormManagerService::getUserAllowedForms();
+ return FluentFormAppServicesManagerFormManagerService::getUserAllowedFormsScope();
});
$app->addFilter('fluentform/validate_input_item_input_email', ['FluentFormAppHelpersHelper', 'isUniqueValidation'], 10, 5);
--- a/fluentform/app/Http/Controllers/FormController.php
+++ b/fluentform/app/Http/Controllers/FormController.php
@@ -59,15 +59,11 @@
}
}
- public function duplicate(FormService $formService)
+ public function duplicate(FormService $formService, $formId)
{
try {
$attributes = $this->request->all();
-
- $sanitizeMap = [
- 'form_id' => 'intval',
- ];
- $attributes = fluentform_backend_sanitizer($attributes, $sanitizeMap);
+ $attributes['form_id'] = (int) $formId;
$form = $formService->duplicate($attributes);
@@ -83,10 +79,10 @@
}
}
- public function find(FormService $formService)
+ public function find(FormService $formService, $formId)
{
try {
- $id = (int)$this->request->get('form_id');
+ $id = (int) $formId;
$form = $formService->find($id);
@@ -98,10 +94,10 @@
}
}
- public function delete(FormService $formService)
+ public function delete(FormService $formService, $formId)
{
try {
- $id = (int)$this->request->get('form_id');
+ $id = (int) $formId;
$formService->delete($id);
@@ -115,11 +111,12 @@
}
}
- public function update(FormService $formService)
+ public function update(FormService $formService, $formId)
{
try {
// Sanitization handled in Updater::update() — only title, status, form_id, formFields are extracted
$attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
$formService->update($attributes);
@@ -133,10 +130,10 @@
}
}
- public function convert(FormService $formService)
+ public function convert(FormService $formService, $formId)
{
try {
- $formId = (int)$this->request->get('form_id');
+ $formId = (int) $formId;
$formService->convert($formId);
return $this->sendSuccess([
@@ -199,10 +196,10 @@
return $this->sendSuccess($historyService::get($formId));
}
- public function clearEditHistory(HistoryService $historyService)
+ public function clearEditHistory(HistoryService $historyService, $formId)
{
try {
- $id = (int)$this->request->get('form_id');
+ $id = (int) $formId;
$historyService->delete($id);
return $this->sendSuccess([
--- a/fluentform/app/Http/Controllers/FormIntegrationController.php
+++ b/fluentform/app/Http/Controllers/FormIntegrationController.php
@@ -6,10 +6,10 @@
class FormIntegrationController extends Controller
{
- public function index(FormIntegrationService $integrationService)
+ public function index(FormIntegrationService $integrationService, $formId)
{
try {
- $formId = (int) $this->request->get('form_id');
+ $formId = (int) $formId;
return $this->sendSuccess(
$integrationService->get($formId)
);
@@ -20,10 +20,13 @@
}
}
- public function find(FormIntegrationService $integrationService)
+ public function find(FormIntegrationService $integrationService, $formId)
{
try {
- $integration = $integrationService->find($this->request->all());
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
+
+ $integration = $integrationService->find($attributes);
return $this->sendSuccess($integration);
} catch (Exception $e) {
return $this->sendError([
@@ -32,10 +35,13 @@
}
}
- public function update(FormIntegrationService $integrationService)
+ public function update(FormIntegrationService $integrationService, $formId)
{
try {
- $integration = $integrationService->update($this->request->all());
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
+
+ $integration = $integrationService->update($attributes);
return $this->sendSuccess($integration);
} catch (Exception $e) {
return $this->sendError([
@@ -44,10 +50,10 @@
}
}
- public function delete(FormIntegrationService $integrationService)
+ public function delete(FormIntegrationService $integrationService, $formId)
{
try {
- $formId = intval($this->request->get('form_id'));
+ $formId = (int) $formId;
$id = intval($this->request->get('integration_id'));
$integrationService->delete($id, $formId);
return $this->sendSuccess([
@@ -60,10 +66,11 @@
}
}
- public function integrationListComponent()
+ public function integrationListComponent($formId)
{
try {
$attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
$sanitizeMap = [
'integration_name' => 'sanitize_text_field',
--- a/fluentform/app/Http/Controllers/FormSettingsController.php
+++ b/fluentform/app/Http/Controllers/FormSettingsController.php
@@ -10,9 +10,12 @@
class FormSettingsController extends Controller
{
- public function index(SettingsService $settingsService)
+ public function index(SettingsService $settingsService, $formId)
{
- $result = $settingsService->get($this->request->all());
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
+
+ $result = $settingsService->get($attributes);
return $this->sendSuccess($result);
}
@@ -24,10 +27,13 @@
return $this->sendSuccess($result);
}
- public function saveGeneral(SettingsService $settingsService)
+ public function saveGeneral(SettingsService $settingsService, $formId)
{
try {
- $settingsService->saveGeneral($this->request->all());
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
+
+ $settingsService->saveGeneral($attributes);
return $this->sendSuccess([
'message' => __('Settings has been saved.', 'fluentform'),
@@ -37,10 +43,13 @@
}
}
- public function store(SettingsService $settingsService)
+ public function store(SettingsService $settingsService, $formId)
{
try {
- [$settingsId, $settings] = $settingsService->store($this->request->all());
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
+
+ [$settingsId, $settings] = $settingsService->store($attributes);
return $this->sendSuccess([
'message' => __('Settings has been saved.', 'fluentform'),
@@ -52,9 +61,12 @@
}
}
- public function remove(SettingsService $settingsService)
+ public function remove(SettingsService $settingsService, $formId)
{
- $settingsService->remove($this->request->all());
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
+
+ $settingsService->remove($attributes);
return $this->sendSuccess([]);
}
@@ -74,7 +86,10 @@
public function storeCustomizer(Customizer $customizer, $id)
{
try {
- $customizer->store($this->request->all());
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $id;
+
+ $customizer->store($attributes);
return $this->sendSuccess([
'message' => __('Custom CSS & JS successfully saved.', 'fluentform'),
@@ -89,7 +104,10 @@
public function storeEntryColumns(SubmissionService $submissionService, $id)
{
try {
- $submissionService->storeColumnSettings($this->request->all());
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $id;
+
+ $submissionService->storeColumnSettings($attributes);
return $this->sendSuccess([
'message' => __('The column display order has been saved.', 'fluentform'),
@@ -134,10 +152,13 @@
}
}
- public function savePreset(SettingsService $settingsService)
+ public function savePreset(SettingsService $settingsService, $formId)
{
try {
- return $this->sendSuccess($settingsService->savePreset($this->request->all()));
+ $attributes = $this->request->all();
+ $attributes['form_id'] = (int) $formId;
+
+ return $this->sendSuccess($settingsService->savePreset($attributes));
} catch (Exception $e) {
return $this->sendError([
'message' => $e->getMessage(),
--- a/fluentform/app/Http/Controllers/LogController.php
+++ b/fluentform/app/Http/Controllers/LogController.php
@@ -62,6 +62,14 @@
$sanitizeMap = [
'log_id' => 'intval',
+ 'log_ids' => function ($value) {
+ if (is_array($value)) {
+ return array_map('intval', $value);
+ }
+
+ return [];
+ },
+ 'type' => 'sanitize_text_field',
];
$attributes = fluentform_backend_sanitizer($attributes, $sanitizeMap);
--- a/fluentform/app/Http/Controllers/ReportController.php
+++ b/fluentform/app/Http/Controllers/ReportController.php
@@ -3,33 +3,46 @@
namespace FluentFormAppHttpControllers;
use Exception;
+use FluentFormAppModulesAclAcl;
use FluentFormAppServicesReportReportService;
class ReportController extends Controller
{
- private function sanitizeReportAttributes()
+ private function sanitizeReportAttributes($formId = null)
{
$sanitizeMap = [
- 'form_id' => 'intval',
'period' => 'sanitize_text_field',
'group_by' => 'sanitize_text_field',
'status' => 'sanitize_text_field',
];
$attributes = fluentform_backend_sanitizer($this->request->all(), $sanitizeMap);
+ $requestFormId = $this->request->get('form_id');
if (isset($attributes['date_range']) && is_array($attributes['date_range'])) {
$attributes['date_range'] = array_map('sanitize_text_field', $attributes['date_range']);
}
+ $resolvedFormId = Acl::normalizeFormId($formId);
+
+ if (!$resolvedFormId) {
+ $resolvedFormId = Acl::normalizeFormId($requestFormId);
+ }
+
+ if ($resolvedFormId) {
+ $attributes['form_id'] = $resolvedFormId;
+ } else {
+ unset($attributes['form_id']);
+ }
+
return $attributes;
}
- public function form(ReportService $reportService)
+ public function form(ReportService $reportService, $formId)
{
try {
return $this->sendSuccess(
- $reportService->form($this->sanitizeReportAttributes())
+ $reportService->form($this->sanitizeReportAttributes($formId))
);
} catch (Exception $e) {
return $this->sendError([
@@ -80,7 +93,7 @@
public function netRevenue(ReportService $reportService)
{
try {
- $data = apply_filters('fluentform/reports/revenue_analysis', [], $this->request->all());
+ $data = apply_filters('fluentform/reports/revenue_analysis', [], $this->sanitizeReportAttributes());
return $this->sendSuccess($data);
} catch (Exception $e) {
@@ -97,7 +110,7 @@
public function submissionsAnalysis()
{
try {
- $data = apply_filters('fluentform/reports/submissions_analysis', [], $this->request->all());
+ $data = apply_filters('fluentform/reports/submissions_analysis', [], $this->sanitizeReportAttributes());
return $this->sendSuccess($data);
} catch (Exception $e) {
return $this->sendError([
@@ -147,7 +160,7 @@
public function getCompletionRate()
{
try {
- $data = apply_filters('fluentform/reports/completion_rate', [], $this->request->all());
+ $data = apply_filters('fluentform/reports/completion_rate', [], $this->sanitizeReportAttributes());
return $this->sendSuccess($data);
} catch (Exception $e) {
return $this->sendError([
@@ -180,7 +193,7 @@
public function getHeatmapData()
{
try {
- $data = apply_filters('fluentform/reports/heatmap_data', [], $this->request->all());
+ $data = apply_filters('fluentform/reports/heatmap_data', [], $this->sanitizeReportAttributes());
return $this->sendSuccess($data);
} catch (Exception $e) {
return $this->sendError([
@@ -196,7 +209,7 @@
public function getCountryHeatmap(ReportService $reportService)
{
try {
- $data = apply_filters('fluentform/reports/country_heatmap', [], $this->request->all());
+ $data = apply_filters('fluentform/reports/country_heatmap', [], $this->sanitizeReportAttributes());
return $this->sendSuccess($data);
} catch (Exception $e) {
return $this->sendError([
@@ -246,7 +259,7 @@
public function getSubscriptions()
{
try {
- $data = apply_filters('fluentform/reports/subscriptions', [], $this->request->all());
+ $data = apply_filters('fluentform/reports/subscriptions', [], $this->sanitizeReportAttributes());
return $this->sendSuccess($data);
} catch (Exception $e) {
return $this->sendError([
--- a/fluentform/app/Http/Controllers/SubmissionController.php
+++ b/fluentform/app/Http/Controllers/SubmissionController.php
@@ -201,7 +201,7 @@
$attributes = $this->request->all();
$sanitizeMap = [
- 'entry_ids' => function($value) {
+ 'submission_ids' => function($value) {
if (is_array($value)) {
return array_map('intval', $value);
}
@@ -210,6 +210,15 @@
'form_id' => 'intval',
];
$attributes = fluentform_backend_sanitizer($attributes, $sanitizeMap);
+
+ // Preserve backward compatibility with any legacy callers that still
+ // send entry_ids, while normalizing to the current submission_ids key.
+ if (empty($attributes['submission_ids']) && isset($attributes['entry_ids'])) {
+ $entryIds = $attributes['entry_ids'];
+ $attributes['submission_ids'] = is_array($entryIds)
+ ? array_map('intval', $entryIds)
+ : [];
+ }
return $this->sendSuccess(
$submissionService->getPrintContent($attributes)
--- a/fluentform/app/Http/Controllers/SubmissionLogController.php
+++ b/fluentform/app/Http/Controllers/SubmissionLogController.php
@@ -28,16 +28,23 @@
}
}
- public function remove(Logger $logger)
+ public function remove(Logger $logger, $submissionId)
{
try {
$attributes = $this->request->all();
$sanitizeMap = [
- 'log_id' => 'intval',
- 'submission_id' => 'intval',
+ 'log_ids' => function ($value) {
+ if (is_array($value)) {
+ return array_map('intval', $value);
+ }
+
+ return [];
+ },
+ 'type' => 'sanitize_text_field',
];
$attributes = fluentform_backend_sanitizer($attributes, $sanitizeMap);
+ $attributes['entry_id'] = intval($submissionId);
return $this->sendSuccess(
$logger->remove($attributes)
--- a/fluentform/app/Http/Policies/FormPolicy.php
+++ b/fluentform/app/Http/Policies/FormPolicy.php
@@ -5,6 +5,7 @@
use FluentFormAppModulesAclAcl;
use FluentFormFrameworkHttpRequestRequest;
use FluentFormFrameworkFoundationPolicy;
+use FluentFormFrameworkSupportArr;
class FormPolicy extends Policy
{
@@ -16,46 +17,59 @@
*/
public function verifyRequest(Request $request)
{
- return Acl::hasPermission('fluentform_forms_manager', $request->get('form_id'));
+ return Acl::hasPermission('fluentform_forms_manager', $this->resolveFormId($request));
}
public function index(Request $request)
{
- return Acl::hasPermission('fluentform_dashboard_access', $request->get('form_id'));
+ return Acl::hasPermission('fluentform_dashboard_access', $this->resolveFormId($request));
}
public function templates(Request $request)
{
- return Acl::hasAnyFormPermission($request->get('form_id'));
+ return Acl::hasAnyFormPermission($this->resolveFormId($request));
}
public function find(Request $request)
{
- return Acl::hasPermission('fluentform_forms_manager', $request->get('form_id'));
+ return Acl::hasPermission('fluentform_forms_manager', $this->resolveFormId($request));
}
public function delete(Request $request)
{
- return Acl::hasPermission('fluentform_forms_manager', $request->get('form_id'));
+ return Acl::hasPermission('fluentform_forms_manager', $this->resolveFormId($request));
}
public function integrationListComponent(Request $request)
{
- return Acl::hasPermission('fluentform_forms_manager', $request->get('form_id'));
+ return Acl::hasPermission('fluentform_forms_manager', $this->resolveFormId($request));
}
public function updateModuleStatus(Request $request)
{
- return Acl::hasPermission('fluentform_settings_manager', $request->get('form_id'));
+ return Acl::hasPermission('fluentform_settings_manager', $this->resolveFormId($request));
}
public function updateIntegration(Request $request)
{
- return Acl::hasPermission('fluentform_settings_manager', $request->get('form_id'));
+ return Acl::hasPermission('fluentform_settings_manager', $this->resolveFormId($request));
}
public function ping()
{
return Acl::hasAnyFormPermission();
}
+
+ private function resolveFormId(Request $request)
+ {
+ $route = $request->route();
+ $routeFormId = $route ? Arr::get($route->getParameter(), 'form_id') : null;
+ $routeFormId = Acl::normalizeFormId($routeFormId);
+
+ if ($routeFormId) {
+ return $routeFormId;
+ }
+
+ return Acl::normalizeFormId($request->get('form_id'));
+ }
}
--- a/fluentform/app/Http/Policies/ReportPolicy.php
+++ b/fluentform/app/Http/Policies/ReportPolicy.php
@@ -3,12 +3,59 @@
namespace FluentFormAppHttpPolicies;
use FluentFormAppModulesAclAcl;
+use FluentFormAppServicesManagerFormManagerService;
use FluentFormFrameworkHttpRequestRequest;
use FluentFormFrameworkFoundationPolicy;
use FluentFormFrameworkSupportArr;
class ReportPolicy extends Policy
{
+ private function canAccessReportData(Request $request)
+ {
+ $formId = $this->resolveFormId($request);
+
+ if ($formId) {
+ return Acl::hasPermission('fluentform_entries_viewer', $formId);
+ }
+
+ return Acl::hasPermission('fluentform_entries_viewer');
+ }
+
+ private function canAccessDashboardReport(Request $request)
+ {
+ if (!Acl::hasPermission('fluentform_dashboard_access')) {
+ return false;
+ }
+
+ return $this->canAccessReportData($request);
+ }
+
+ private function canAccessRequestedForm(Request $request)
+ {
+ return $this->canAccessReportData($request);
+ }
+
+ private function canAccessOptionalFormScopedReport(Request $request)
+ {
+ if (!Acl::hasPermission('fluentform_dashboard_access')) {
+ return false;
+ }
+
+ $formId = $this->resolveFormId($request);
+
+ if ($formId) {
+ return Acl::hasPermission('fluentform_entries_viewer', $formId);
+ }
+
+ if (!Acl::hasPermission('fluentform_entries_viewer')) {
+ return false;
+ }
+
+ $userId = get_current_user_id();
+
+ return !$userId || !FormManagerService::hasSpecificFormsPermission($userId);
+ }
+
/**
* Check permission for any method
*
@@ -22,11 +69,89 @@
public function form(Request $request)
{
- return Acl::hasPermission('fluentform_entries_viewer', intval($request->get('form_id')));
+ return $this->canAccessRequestedForm($request);
}
- public function submissions()
+ public function submissions(Request $request)
{
- return Acl::hasPermission('fluentform_entries_viewer');
+ return $this->canAccessRequestedForm($request);
+ }
+
+ public function getOverviewChart(Request $request)
+ {
+ return $this->canAccessRequestedForm($request);
+ }
+
+ public function getRevenueChart(Request $request)
+ {
+ return $this->canAccessRequestedForm($request);
+ }
+
+ public function getFormStats(Request $request)
+ {
+ return $this->canAccessRequestedForm($request);
+ }
+
+ public function getApiLogs(Request $request)
+ {
+ return $this->canAccessRequestedForm($request);
+ }
+
+ public function getPaymentTypes(Request $request)
+ {
+ return $this->canAccessRequestedForm($request);
+ }
+
+ public function getCompletionRate(Request $request)
+ {
+ return $this->canAccessOptionalFormScopedReport($request);
+ }
+
+ public function getHeatmapData(Request $request)
+ {
+ return $this->canAccessOptionalFormScopedReport($request);
+ }
+
+ public function getCountryHeatmap(Request $request)
+ {
+ return $this->canAccessOptionalFormScopedReport($request);
+ }
+
+ public function getTopPerformingForms(Request $request)
+ {
+ return $this->canAccessDashboardReport($request);
+ }
+
+ public function getSubscriptions(Request $request)
+ {
+ return $this->canAccessOptionalFormScopedReport($request);
+ }
+
+ public function getFormsDropdown(Request $request)
+ {
+ return $this->canAccessDashboardReport($request);
+ }
+
+ public function netRevenue(Request $request)
+ {
+ return $this->canAccessOptionalFormScopedReport($request);
+ }
+
+ public function submissionsAnalysis(Request $request)
+ {
+ return $this->canAccessOptionalFormScopedReport($request);
+ }
+
+ private function resolveFormId(Request $request)
+ {
+ $route = $request->route();
+ $routeFormId = $route ? Arr::get($route->getParameter(), 'form_id') : null;
+ $routeFormId = Acl::normalizeFormId($routeFormId);
+
+ if ($routeFormId) {
+ return $routeFormId;
+ }
+
+ return Acl::normalizeFormId($request->get('form_id'));
}
}
--- a/fluentform/app/Models/Submission.php
+++ b/fluentform/app/Models/Submission.php
@@ -96,7 +96,7 @@
return $this->hasMany(OrderItem::class, 'submission_id', 'id');
}
- public function customQuery($attributes = [])
+ public function customQuery($attributes = [], $searchExtender = null)
{
$entryType = Arr::get($attributes, 'entry_type');
$dateRange = Arr::get($attributes, 'date_range');
@@ -145,14 +145,17 @@
return $q->where('fluentform_submissions.created_at', '>=', $startDate)
->where('fluentform_submissions.created_at', '<=', $endDate);
})
- ->when($search, function ($q) use ($search) {
+ ->when($search, function ($q) use ($search, $searchExtender) {
global $wpdb;
$escaped = $wpdb->esc_like($search);
- return $q->where(function ($q) use ($escaped) {
- return $q->where('fluentform_submissions.id', 'LIKE', "%{$escaped}%")
+ return $q->where(function ($q) use ($escaped, $searchExtender) {
+ $q->where('fluentform_submissions.id', 'LIKE', "%{$escaped}%")
->orWhere('response', 'LIKE', "%{$escaped}%")
->orWhere('fluentform_submissions.status', 'LIKE', "%{$escaped}%")
->orWhere('fluentform_submissions.created_at', 'LIKE', "%{$escaped}%");
+ if ($searchExtender) {
+ $searchExtender($q, $escaped);
+ }
});
})
->when($wheres, function ($q) use ($wheres) {
@@ -183,7 +186,11 @@
public function paginateEntries($attributes = [])
{
$formId = Arr::get($attributes, 'form_id');
+ $allowFormIds = FormManagerService::getUserAllowedFormsScope();
$query = $this->customQuery($attributes);
+ $query = $query->when(false !== $allowFormIds, function ($q) use ($allowFormIds) {
+ return $q->whereIn('fluentform_submissions.form_id', $allowFormIds ?: [0]);
+ });
if (Arr::get($attributes, 'advanced_filter')) {
$query = apply_filters('fluentform/apply_entries_advance_filter', $query, $attributes);
}
@@ -297,9 +304,13 @@
}
public function allSubmissions($attributes = []) {
- $customQuery = $this->customQuery($attributes);
- $search = Arr::get($attributes, 'search');
- $allowFormIds = FormManagerService::getUserAllowedForms();
+ $searchExtender = function ($q, $escaped) {
+ $q->orWhereHas('form', function ($q) use ($escaped) {
+ $q->where('title', 'LIKE', "%{$escaped}%");
+ });
+ };
+ $customQuery = $this->customQuery($attributes, $searchExtender);
+ $allowFormIds = FormManagerService::getUserAllowedFormsScope();
$result = $customQuery
->with([
@@ -308,15 +319,8 @@
}
])
->select(['id', 'form_id', 'status', 'created_at', 'browser', 'currency', 'total_paid'])
- ->when($allowFormIds, function ($q) use ($allowFormIds){
- return $q->whereIn('form_id', $allowFormIds);
- })
- ->when($search, function ($q) use ($search){
- global $wpdb;
- $escaped = $wpdb->esc_like($search);
- return $q->orWhereHas('form', function ($q) use ($escaped) {
- return $q->orWhere('title', 'LIKE', "%{$escaped}%");
- });
+ ->when(false !== $allowFormIds, function ($q) use ($allowFormIds){
+ return $q->whereIn('form_id', $allowFormIds ?: [0]);
})
->paginate()
->toArray();
@@ -339,8 +343,8 @@
public function availableForms()
{
$form = new Form();
- if ($allowForms = FormManagerService::getUserAllowedForms()) {
- return $form->select('id', 'title')->whereIn('id', $allowForms)->get();
+ if (false !== ($allowForms = FormManagerService::getUserAllowedFormsScope())) {
+ return $form->select('id', 'title')->whereIn('id', $allowForms ?: [0])->get();
}
return $form->select('id', 'title')->get();
}
@@ -350,6 +354,7 @@
$from = date('Y-m-d H:i:s', strtotime('-30 days'));
$to = date('Y-m-d H:i:s', strtotime('+1 days'));
$formId = Arr::get($attributes, 'form_id');
+ $allowFormIds = FormManagerService::getUserAllowedFormsScope();
$status = Arr::get($attributes, 'entry_status');
$start = Arr::get($attributes, 'date_range.0', '');
$end = Arr::get($attributes, 'date_range.1', '');
@@ -357,6 +362,9 @@
if ('all' === $dateRange) {
$firstItem = self::orderBy('created_at', 'ASC')
+ ->when(false !== $allowFormIds, function ($q) use ($allowFormIds) {
+ return $q->whereIn('form_id', $allowFormIds ?: [0]);
+ })
->when($formId, function ($q) use ($formId) {
return $q->where('form_id', $formId);
})
@@ -393,6 +401,9 @@
->whereBetween('created_at', [$from, $to])
->groupBy('date')
->orderBy('date', 'ASC')
+ ->when(false !== $allowFormIds, function ($q) use ($allowFormIds) {
+ return $q->whereIn('form_id', $allowFormIds ?: [0]);
+ })
->when($formId, function ($q) use ($formId) {
return $q->where('form_id', $formId);
})
--- a/fluentform/app/Modules/Acl/Acl.php
+++ b/fluentform/app/Modules/Acl/Acl.php
@@ -11,6 +11,45 @@
public static $role = '';
+ public static function normalizeFormId($formId)
+ {
+ if ($formId === null || $formId === false || $formId === '') {
+ return null;
+ }
+
+ if (is_string($formId)) {
+ $formId = trim($formId);
+ }
+
+ if (!is_int($formId) && (!is_string($formId) || !ctype_digit($formId))) {
+ return null;
+ }
+
+ $formId = (int) $formId;
+
+ return $formId > 0 ? $formId : null;
+ }
+
+ public static function verifyFormId(
+ $formId,
+ $message = 'Invalid form id.',
+ $json = true
+ ) {
+ $formId = static::normalizeFormId($formId);
+
+ if ($formId) {
+ return $formId;
+ }
+
+ if ($json) {
+ wp_send_json_error([
+ 'message' => $message,
+ ], 422);
+ }
+
+ throw new InvalidArgumentException(esc_html($message));
+ }
+
public static function getPermissionSet()
{
$data = [
--- a/fluentform/app/Modules/AddOnModule.php
+++ b/fluentform/app/Modules/AddOnModule.php
@@ -441,7 +441,7 @@
'title' => __('Multilingual Forms for Fluent Forms (WPML)', 'fluentform'),
'description' => __('Make Fluent Forms multilingual with WPML integration', 'fluentform'),
'logo' => 'wpml-ff.png',
- 'slug' => 'multilingual-forms-fluent-forms-wpml/multilingual-forms-fluent-forms-wpml.php',
+ 'slug' => 'multilingual-forms-fluent-forms-wpml/multilingual-forms-for-fluent-forms-with-wpml.php',
'basename' => 'multilingual-forms-fluent-forms-wpml',
'badge_type' => 'official',
'wporg_url' => 'https://wordpress.org/plugins/multilingual-forms-fluent-forms-wpml/',
--- a/fluentform/app/Modules/Component/Component.php
+++ b/fluentform/app/Modules/Component/Component.php
@@ -724,6 +724,7 @@
$form_vars = [
'id' => $form->id,
+ 'ajaxUrl' => admin_url('admin-ajax.php'),
'settings' => $formSettings,
'form_instance' => $instanceCssClass,
'form_id_selector' => 'fluentform_' . $form->id,
@@ -949,7 +950,7 @@
$checkables = ['limitNumberOfEntries', 'scheduleForm', 'requireLogin'];
// Ensure settings is an array
- if (!is_array($form->settings)) {
+ if (!isset($form->settings) || !is_array($form->settings)) {
$form->settings = [];
}
--- a/fluentform/app/Modules/Form/FormHandler.php
+++ b/fluentform/app/Modules/Form/FormHandler.php
@@ -627,7 +627,11 @@
}
$errors = [
- '_fluentformakismet' => __('Submission marked as spammed. Please try again', 'fluentform'),
+ '_fluentformakismet' => apply_filters(
+ 'fluentform/akismet_spam_message',
+ __('Submission marked as spammed. Please try again', 'fluentform'),
+ $this->form->id
+ ),
];
wp_send_json(['errors' => $errors], 422);
@@ -699,13 +703,12 @@
$isValid = ReCaptcha::validate($token, $keys['secretKey'], $version);
if (!$isValid) {
- wp_send_json([
- 'errors' => [
- 'g-recaptcha-response' => [
- __('reCaptcha verification failed, please try again.', 'fluentform'),
- ],
- ],
- ], 422);
+ $message = apply_filters(
+ 'fluentform/recaptcha_failed_message',
+ __('reCaptcha verification failed, please try again.', 'fluentform'),
+ $this->form
+ );
+ wp_send_json(['errors' => ['g-recaptcha-response' => [$message]]], 422);
}
}
}
@@ -734,13 +737,12 @@
$isValid = HCaptcha::validate($token, $keys['secretKey']);
if (!$isValid) {
- wp_send_json([
- 'errors' => [
- 'h-captcha-response' => [
- __('hCaptcha verification failed, please try again.', 'fluentform'),
- ],
- ],
- ], 422);
+ $message = apply_filters(
+ 'fluentform/hcaptcha_failed_message',
+ __('hCaptcha verification failed, please try again.', 'fluentform'),
+ $this->form
+ );
+ wp_send_json(['errors' => ['h-captcha-response' => [$message]]], 422);
}
}
}
@@ -768,13 +770,12 @@
$isValid = Turnstile::validate($token, $keys['secretKey']);
if (!$isValid) {
- wp_send_json([
- 'errors' => [
- 'cf-turnstile-response' => [
- __('Turnstile verification failed, please try again.', 'fluentform'),
- ],
- ],
- ], 422);
+ $message = apply_filters(
+ 'fluentform/turnstile_failed_message',
+ __('Turnstile verification failed, please try again.', 'fluentform'),
+ $this->form
+ );
+ wp_send_json(['errors' => ['cf-turnstile-response' => [$message]]], 422);
}
}
}
--- a/fluentform/app/Modules/Form/HoneyPot.php
+++ b/fluentform/app/Modules/Form/HoneyPot.php
@@ -61,12 +61,12 @@
!ArrayHelper::exists($requestData, $honeyPotName) ||
!empty(ArrayHelper::get($requestData, $honeyPotName))
) {
- wp_send_json(
- [
- 'errors' => __('Sorry! You can not submit this form at this moment!', 'fluentform'),
- ],
- 422
+ $message = apply_filters(
+ 'fluentform/honeypot_spam_message',
+ __('Sorry! You can not submit this form at this moment!', 'fluentform'),
+ $formId
);
+ wp_send_json(['errors' => $message], 422);
}
return;
}
--- a/fluentform/app/Modules/Payments/Classes/PaymentEntries.php
+++ b/fluentform/app/Modules/Payments/Classes/PaymentEntries.php
@@ -50,7 +50,9 @@
// Sanitize request data
$sanitizeMap = [
- 'form_id' => 'intval',
+ 'form_id' => function ($value) {
+ return Acl::normalizeFormId($value);
+ },
'per_page' => 'intval',
'payment_statuses' => 'sanitize_text_field',
'payment_types' => 'sanitize_text_field',
@@ -89,8 +91,8 @@
}
$allowFormIds = apply_filters('fluentform/current_user_allowed_forms', false);
- if ($allowFormIds && is_array($allowFormIds)) {
- $paymentsQuery = $paymentsQuery->whereIn('fluentform_transactions.form_id', $allowFormIds);
+ if (false !== $allowFormIds && is_array($allowFormIds)) {
+ $paymentsQuery = $paymentsQuery->whereIn('fluentform_transactions.form_id', $allowFormIds ?: [0]);
}
if ($paymentStatus = ArrayHelper::get($attributes, 'payment_statuses')) {
$paymentsQuery = $paymentsQuery->where('fluentform_transactions.status', $paymentStatus);
@@ -123,8 +125,6 @@
public function handleBulkAction()
{
- Acl::verify('fluentform_forms_manager');
-
$request = wpFluentForm()->request;
$attributes = $request->all();
@@ -151,13 +151,13 @@
$statusCode = 400;
// permanently delete payment entries from transactions
if ($actionType == 'delete_items') {
-
-
// get submission ids to delete order items
- $transactionData = Transaction::select(['form_id', 'submission_id'])
+ $transactionData = Transaction::select(['id', 'form_id', 'submission_id'])
->whereIn('id', $entries)
->get();
+ $this->authorizeTransactionForms($transactionData);
+
$submission_ids = [];
foreach ($transactionData as $transactionDatum) {
@@ -227,6 +227,25 @@
], $statusCode);
}
+ private function authorizeTransactionForms($transactionData)
+ {
+ Acl::verify('fluentform_forms_manager');
+
+ $formIds = [];
+
+ foreach ($transactionData as $transaction) {
+ $formIds[(int) $transaction->form_id] = true;
+ }
+
+ foreach (array_keys($formIds) as $formId) {
+ if (!Acl::hasPermission('fluentform_forms_manager', $formId)) {
+ wp_send_json_error([
+ 'message' => __('You do not have permission to perform this action.', 'fluentform')
+ ], 422);
+ }
+ }
+ }
+
public function getFilters()
{
$transactionTypes = Transaction::select('transaction_type')
@@ -259,8 +278,8 @@
}
$allowFormIds = apply_filters('fluentform/current_user_allowed_forms', false);
$forms = Transaction::select('fluentform_transactions.form_id', 'fluentform_forms.title')
- ->when($allowFormIds && is_array($allowFormIds), function ($q) use ($allowFormIds){
- return $q->whereIn('fluentform_transactions.form_id', $allowFormIds);
+ ->when(false !== $allowFormIds && is_array($allowFormIds), function ($q) use ($allowFormIds){
+ return $q->whereIn('fluentform_transactions.form_id', $allowFormIds ?: [0]);
})
->groupBy('fluentform_transactions.form_id')
->orderBy('fluentform_transactions.form_id', 'DESC')
--- a/fluentform/app/Modules/Payments/PaymentHandler.php
+++ b/fluentform/app/Modules/Payments/PaymentHandler.php
@@ -395,17 +395,65 @@
public function handleAjaxEndpoints()
{
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Nonce verified by Acl::verify()
- if (isset($_REQUEST['form_id'])) {
- Acl::verify('fluentform_forms_manager');
+ $route = isset($_REQUEST['route']) ? sanitize_text_field(wp_unslash($_REQUEST['route'])) : '';
+ $formScopedRoutes = [
+ 'get_form_settings',
+ 'save_form_settings',
+ 'update_transaction',
+ 'cancel_subscription'
+ ];
+
+ if (in_array($route, $formScopedRoutes, true)) {
+ Acl::verify('fluentform_forms_manager', $this->resolveRouteFormId($route));
} else {
Acl::verify('fluentform_settings_manager');
}
-
- $route = isset($_REQUEST['route']) ? sanitize_text_field(wp_unslash($_REQUEST['route'])) : '';
// phpcs:enable WordPress.Security.NonceVerification.Recommended -- End of AJAX endpoint nonce verification by Acl::verify()
(new AjaxEndpoints())->handleEndpoint($route);
}
+
+ private function resolveRouteFormId($route)
+ {
+ switch ($route) {
+ case 'get_form_settings':
+ case 'save_form_settings':
+ return Acl::verifyFormId(wpFluentForm()->request->get('form_id'));
+ case 'update_transaction':
+ return $this->resolveTransactionFormId();
+ case 'cancel_subscription':
+ return $this->resolveSubscriptionFormId();
+ default:
+ return null;
+ }
+ }
+
+ private function resolveTransactionFormId()
+ {
+ $transactionData = wpFluentForm()->request->get('transaction', []);
+ $transactionId = absint(ArrayHelper::get($transactionData, 'id'));
+
+ if (!$transactionId) {
+ return -1;
+ }
+
+ $transaction = FluentFormAppModelsTransaction::select('form_id')->find($transactionId);
+
+ return $transaction ? (int) $transaction->form_id : -1;
+ }
+
+ private function resolveSubscriptionFormId()
+ {
+ $subscriptionId = absint(wpFluentForm()->request->get('subscription_id'));
+
+ if (!$subscriptionId) {
+ return -1;
+ }
+
+ $subscription = FluentFormAppModelsSubscription::select('form_id')->find($subscriptionId);
+
+ return $subscription ? (int) $subscription->form_id : -1;
+ }
public function maybeHandlePayment($insertData, $data, $form)
{
--- a/fluentform/app/Modules/Payments/TransactionShortcodes.php
+++ b/fluentform/app/Modules/Payments/TransactionShortcodes.php
@@ -5,6 +5,7 @@
use FluentFormAppHelpersHelper;
use FluentFormAppModelsSubscription;
use FluentFormAppModelsTransaction;
+use FluentFormAppModulesAclAcl;
use FluentFormFrameworkHelpersArrayHelper;
use FluentFormAppModulesPaymentsClassesPaymentReceipt;
use FluentFormAppModulesPaymentsOrdersOrderData;
@@ -452,10 +453,16 @@
$userid = get_current_user_id();
$submission = fluentFormApi('submissions')->find($subscription->submission_id);
- if (!$submission || ($submission->user_id != $userid && !$this->canCancelSubscription($subscription))) {
+ if (!$submission || !$this->canCancelSubscription($subscription)) {
$this->sendError(__('Sorry, you can not cancel this subscription at this moment', 'fluentform'));
}
-
+
+ $canManagePayments = Acl::hasPermission('fluentform_manage_payments', $submission->form_id);
+
+ if (!$canManagePayments && (int) $submission->user_id !== (int) $userid) {
+ $this->sendError(__('Sorry, you can not cancel this subscription at this moment', 'fluentform'));
+ }
+
$handler = apply_filters_deprecated(
'fluentform_payment_manager_class_' . $submission->payment_method,
[
--- a/fluentform/app/Modules/Registerer/AdminBar.php
+++ b/fluentform/app/Modules/Registerer/AdminBar.php
@@ -112,11 +112,11 @@
$title = __('Fluent Forms', 'fluentform');
}
- $allowForms = FormManagerService::getUserAllowedForms();
+ $allowForms = FormManagerService::getUserAllowedFormsScope();
$hasUnreadSubmissions = wpFluent()->table('fluentform_submissions')
->where('status', 'unread')
- ->when($allowForms, function ($q) use ($allowForms){
- return $q->whereIn('form_id', $allowForms);
+ ->when(false !== $allowForms, function ($q) use ($allowForms){
+ return $q->whereIn('form_id', $allowForms ?: [0]);
})
->count();
--- a/fluentform/app/Modules/Registerer/Menu.php
+++ b/fluentform/app/Modules/Registerer/Menu.php
@@ -465,11 +465,11 @@
$entriesTitle = __('Entries', 'fluentform');
if (Helper::isFluentAdminPage()) {
- $allowForms = FormManagerService::getUserAllowedForms();
+ $allowForms = FormManagerService::getUserAllowedFormsScope();
$entriesCount = wpFluent()->table('fluentform_submissions')
->where('status', 'unread')
- ->when($allowForms, function ($q) use ($allowForms){
- return $q->whereIn('form_id', $allowForms);
+ ->when(false !== $allowForms, function ($q) use ($allowForms){
+ return $q->whereIn('form_id', $allowForms ?: [0]);
})
->count();
@@ -814,8 +814,8 @@
(new ActivationHandler())->migrate();
}
- if ($allowForms = FormManagerService::getUserAllowedForms()) {
- $formsCount = wpFluent()->table('fluentform_forms')->whereIn('id', $allowForms)->count();
+ if (false !== ($allowForms = FormManagerService::getUserAllowedFormsScope())) {
+ $formsCount = wpFluent()->table('fluentform_forms')->whereIn('id', $allowForms ?: [0])->count();
} else {
$formsCount = wpFluent()->table('fluentform_forms')->count();
}
@@ -1140,12 +1140,12 @@
public function renderTransfer()
{
- $allowForms = FormManagerService::getUserAllowedForms();
+ $allowForms = FormManagerService::getUserAllowedFormsScope();
$forms = wpFluent()->table('fluentform_forms')
->orderBy('id', 'desc')
->select(['id', 'title'])
- ->when($allowForms, function ($q) use ($allowForms){
- return $q->whereIn('id', $allowForms);
+ ->when(false !== $allowForms, function ($q) use ($allowForms){
+ return $q->whereIn('id', $allowForms ?: [0]);
})
->get();
--- a/fluentform/app/Modules/Registerer/TranslationString.php
+++ b/fluentform/app/Modules/Registerer/TranslationString.php
@@ -997,8 +997,8 @@
'Managers' => __('Managers', 'fluentform'),
'Enable Specific Forms Permission' => __('Enable Specific Forms Permission', 'fluentform'),
'Access to Forms' => __('Access to Forms', 'fluentform'),
- 'Select specific forms to grant permission. Leave blank to give the manager access to all forms.' => __('Select specific forms to grant permission. Leave blank to give the manager access to all forms.', 'fluentform'),
- 'Select forms (leave blank for all)' => __('Select forms (leave blank for all)', 'fluentform'),
+ 'Select forms to limit this manager's access. Leave blank to keep access to all forms.' => __('Select forms to limit this manager's access. Leave blank to keep access to all forms.', 'fluentform'),
+ 'Select forms to limit access' => __('Select forms to limit access', 'fluentform'),
'Add Manager' => __('Add Manager', 'fluentform'),
'Global Layout Settings' => __('Global Layout Settings', 'fluentform'),
'Administrators have full access to Fluent Forms. Add other managers giving specific permissions.' => __('Administrators have full access to Fluent Forms. Add other managers giving specific permissions.', 'fluentform'),
@@ -2289,4 +2289,3 @@
}
}
-
--- a/fluentform/app/Services/Logger/Logger.php
+++ b/fluentform/app/Services/Logger/Logger.php
@@ -16,7 +16,8 @@
public function get($attributes = [])
{
$statuses = Arr::get($attributes, 'status');
- $formIds = Arr::get($attributes, 'form_id');
+ $formIds = $this->normalizeFormScope(Arr::get($attributes, 'form_id'));
+ $formIds = $this->resolveVisibleFormScope($formIds);
$components = Arr::get($attributes, 'component');
$sortBy = FluentFormAppHelpersHelper::sanitizeOrderValue(Arr::get($attributes, 'sort_by', 'DESC'));
$type = Arr::get($attributes, 'type', 'log');
@@ -25,15 +26,15 @@
$endDate = Arr::get($dateRange, 1);
[$table, $model, $columns, $join, $componentColumn, $dateColumn] = $this->getBases($type);
- if (!$formIds && $allowForms = FormManagerService::getUserAllowedForms()) {
- $formIds = $allowForms;
- }
$logsQuery = $model->select($columns)
->leftJoin('fluentform_forms', 'fluentform_forms.id', '=', $join)
->orderBy($table . '.id', $sortBy)
- ->when($formIds, function ($q) use ($formIds) {
+ ->when(false !== $formIds && [] !== $formIds, function ($q) use ($formIds) {
return $q->whereIn('fluentform_forms.id', array_map('intval', $formIds));
})
+ ->when([] === $formIds, function ($q) {
+ return $q->whereIn('fluentform_forms.id', [0]);
+ })
->when($statuses, function ($q) use ($statuses, $table) {
return $q->whereIn($table . '.status', array_map('sanitize_text_field', $statuses));
})
@@ -102,6 +103,32 @@
return apply_filters('fluentform/get_logs', $logs);
}
+ protected function normalizeFormScope($formIds)
+ {
+ if (null === $formIds || false === $formIds || '' === $formIds || [] === $formIds) {
+ return false;
+ }
+
+ $normalized = array_values(array_filter(array_map('intval', (array) $formIds)));
+
+ return $normalized ?: [];
+ }
+
+ protected function resolveVisibleFormScope($requestedFormIds)
+ {
+ $allowedForms = FormManagerService::getUserAllowedFormsScope();
+
+ if (false === $allowedForms) {
+ return $requestedFormIds;
+ }
+
+ if (false === $requestedFormIds) {
+ return $allowedForms;
+ }
+
+ return array_values(array_intersect($requestedFormIds, $allowedForms));
+ }
+
protected function getBases($type)
{
if ('log' === $type) {
@@ -167,13 +194,13 @@
})->values();
$formIds = $formIdRows->pluck('form_id')->filter()->toArray();
- if ($allowForms = FormManagerService::getUserAllowedForms()) {
+ if (false !== ($allowForms = FormManagerService::getUserAllowedFormsScope())) {
$formIds = array_filter($formIds, function($value) use ($allowForms) {
return in_array($value, $allowForms);
});
}
- $forms = Form::select('id', 'title')->whereIn('id', $formIds)->get();
+ $forms = Form::select('id', 'title')->whereIn('id', $formIds ?: [0])->get();
return apply_filters('fluentform/get_log_filters', [
'statuses' => $statuses,
@@ -294,7 +321,7 @@
public function remove($attributes = [])
{
- $ids = Arr::get($attributes, 'log_ids');
+ $ids = $this->normalizeLogIds($attributes);
if (!$ids) {
throw new ValidationException(
@@ -303,14 +330,97 @@
);
}
- $logType = Arr::get($attributes, 'type', 'logs');
+ $logType = Arr::get($attributes, 'type', Arr::get($attributes, 'log_type', 'logs'));
+ $entryId = intval(Arr::get($attributes, 'entry_id'));
+ $targetLogs = $this->getLogsForDeletion($ids, $logType);
- $model = 'logs' === $logType ? Log::query() : Scheduler::query();
+ if (!$targetLogs->count()) {
+ throw new ValidationException(
+ // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
+ __('No selections found', 'fluentform')
+ );
+ }
- $model->whereIn('id', $ids)->delete();
+ $this->assertDeletePermission($targetLogs, $entryId);
+ $this->getDeleteQuery($logType)
+ ->whereIn('id', $targetLogs->pluck('id')->all())
+ ->delete();
return [
'message' => __('Selected log(s) successfully deleted', 'fluentform'),
];
}
+
+ protected function normalizeLogIds($attributes)
+ {
+ $ids = Arr::get($attributes, 'log_ids',