427 lines
15 KiB
PHP
427 lines
15 KiB
PHP
<?php
|
|
|
|
namespace FluentForm\App\Services\Logger;
|
|
|
|
use FluentForm\App\Models\Log;
|
|
use FluentForm\App\Models\Form;
|
|
use FluentForm\App\Helpers\Helper;
|
|
use FluentForm\App\Models\Scheduler;
|
|
use FluentForm\App\Services\Manager\FormManagerService;
|
|
use FluentForm\Framework\Support\Arr;
|
|
use FluentForm\Framework\Support\Collection;
|
|
use FluentForm\Framework\Validator\ValidationException;
|
|
|
|
class Logger
|
|
{
|
|
public function get($attributes = [])
|
|
{
|
|
$statuses = Arr::get($attributes, 'status');
|
|
$formIds = $this->normalizeFormScope(Arr::get($attributes, 'form_id'));
|
|
$formIds = $this->resolveVisibleFormScope($formIds);
|
|
$components = Arr::get($attributes, 'component');
|
|
$sortBy = \FluentForm\App\Helpers\Helper::sanitizeOrderValue(Arr::get($attributes, 'sort_by', 'DESC'));
|
|
$type = Arr::get($attributes, 'type', 'log');
|
|
$dateRange = Arr::get($attributes, 'date_range', []);
|
|
$startDate = Arr::get($dateRange, 0);
|
|
$endDate = Arr::get($dateRange, 1);
|
|
[$table, $model, $columns, $join, $componentColumn, $dateColumn] = $this->getBases($type);
|
|
|
|
$logsQuery = $model->select($columns)
|
|
->leftJoin('fluentform_forms', 'fluentform_forms.id', '=', $join)
|
|
->orderBy($table . '.id', $sortBy)
|
|
->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));
|
|
})
|
|
->when($components, function ($q) use ($components, $componentColumn) {
|
|
return $q->whereIn($componentColumn, array_map('sanitize_text_field', $components));
|
|
})
|
|
->when($startDate && $endDate, function ($q) use ($startDate, $endDate, $dateColumn) {
|
|
// Concatenate time if not time included on start/end date string
|
|
if ($startDate != date("Y-m-d H:i:s", strtotime($startDate))) {
|
|
$startDate .= ' 00:00:01';
|
|
}
|
|
if ($endDate != date("Y-m-d H:i:s", strtotime($endDate))) {
|
|
$endDate .= ' 23:59:59';
|
|
}
|
|
return $q->where($dateColumn, '>=', $startDate)
|
|
->where($dateColumn, '<=', $endDate);
|
|
});
|
|
|
|
$logs = $logsQuery->paginate();
|
|
|
|
$logItems = $logs->items();
|
|
|
|
foreach ($logItems as $log) {
|
|
$hasUrl = ('api' === $type) || (
|
|
'submission_item' == $log->source_type && $log->submission_id
|
|
);
|
|
|
|
if ($hasUrl) {
|
|
$log->submission_url = admin_url(
|
|
'admin.php?page=fluent_forms&route=entries&form_id=' . $log->form_id . '#/entries/' . $log->submission_id
|
|
);
|
|
}
|
|
|
|
$log->component = Helper::getLogInitiator($log->component, $type);
|
|
$log->integration_enabled = false;
|
|
|
|
$notificationKeys = apply_filters('fluentform/global_notification_active_types', [], $log->form_id);
|
|
|
|
unset($notificationKeys['user_registration_feeds']);
|
|
unset($notificationKeys['notifications']);
|
|
|
|
$notificationKeys = array_flip($notificationKeys);
|
|
|
|
$actionName = $log->getOriginal('component');
|
|
if ($actionName) {
|
|
$actionName = str_replace(['fluentform_integration_notify_', 'fluentform/integration_notify_'], '', $actionName);
|
|
|
|
if (in_array($actionName, $notificationKeys)) {
|
|
$log->integration_enabled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
$logItems = apply_filters_deprecated(
|
|
'fluentform_all_logs',
|
|
[
|
|
$logItems
|
|
],
|
|
FLUENTFORM_FRAMEWORK_UPGRADE,
|
|
'fluentform/get_logs',
|
|
'Use fluentform/get_logs instead of fluentform_all_logs'
|
|
);
|
|
|
|
$logs->setCollection(Collection::make($logItems));
|
|
|
|
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) {
|
|
$table = 'fluentform_logs';
|
|
$model = Log::query();
|
|
$columns = [
|
|
'fluentform_logs.*',
|
|
'fluentform_forms.title as form_title',
|
|
'fluentform_logs.source_id as submission_id',
|
|
'fluentform_logs.parent_source_id as form_id',
|
|
];
|
|
$join = 'fluentform_logs.parent_source_id';
|
|
$componentColumn = 'fluentform_logs.component';
|
|
$dateColumn = 'fluentform_logs.created_at';
|
|
} else {
|
|
$table = 'ff_scheduled_actions';
|
|
$model = Scheduler::query();
|
|
$columns = [
|
|
'ff_scheduled_actions.id',
|
|
'ff_scheduled_actions.action as component',
|
|
'ff_scheduled_actions.form_id',
|
|
'ff_scheduled_actions.origin_id as submission_id',
|
|
'ff_scheduled_actions.status',
|
|
'ff_scheduled_actions.note',
|
|
'ff_scheduled_actions.updated_at',
|
|
'ff_scheduled_actions.feed_id',
|
|
'fluentform_forms.title as form_title',
|
|
];
|
|
$join = 'ff_scheduled_actions.form_id';
|
|
$componentColumn = 'ff_scheduled_actions.action';
|
|
$dateColumn = 'ff_scheduled_actions.updated_at';
|
|
}
|
|
|
|
return [$table, $model, $columns, $join, $componentColumn, $dateColumn];
|
|
}
|
|
|
|
public function getFilters($attributes = [])
|
|
{
|
|
$type = Arr::get($attributes, 'type', 'log');
|
|
|
|
if ('log' === $type) {
|
|
$statusRows = Log::select('status')->distinct()->get();
|
|
$componentRows = Log::select('component')->distinct()->get();
|
|
$formIdRows = Log::select('parent_source_id as form_id')->distinct()->get();
|
|
} else {
|
|
$statusRows = Scheduler::select('status')->distinct()->get();
|
|
$componentRows = Scheduler::select('action as component')->distinct()->get();
|
|
$formIdRows = Scheduler::select('form_id')->distinct()->get();
|
|
}
|
|
|
|
$statuses = $statusRows->pluck('status')->filter()->map(function ($item) {
|
|
return [
|
|
'label' => ucwords($item),
|
|
'value' => $item,
|
|
];
|
|
})->values();
|
|
|
|
$components = $componentRows->pluck('component')->filter()->map(function ($item) use ($type) {
|
|
return [
|
|
'label' => Helper::getLogInitiator($item, $type),
|
|
'value' => $item,
|
|
];
|
|
})->values();
|
|
|
|
$formIds = $formIdRows->pluck('form_id')->filter()->toArray();
|
|
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 ?: [0])->get();
|
|
|
|
return apply_filters('fluentform/get_log_filters', [
|
|
'statuses' => $statuses,
|
|
'components' => $components,
|
|
'forms' => $forms,
|
|
]);
|
|
}
|
|
|
|
public function getSubmissionLogs($submissionId, $attributes = [])
|
|
{
|
|
$logType = Arr::get($attributes, 'log_type', 'logs');
|
|
|
|
$sourceType = Arr::get($attributes, 'source_type', 'submission_item');
|
|
|
|
if ('logs' === $logType) {
|
|
$logs = Log::where('source_id', $submissionId)
|
|
->where('source_type', $sourceType)
|
|
->orderBy('id', 'DESC')
|
|
->get();
|
|
|
|
$logs = apply_filters_deprecated(
|
|
'fluentform_entry_logs',
|
|
[
|
|
$logs,
|
|
$submissionId
|
|
],
|
|
FLUENTFORM_FRAMEWORK_UPGRADE,
|
|
'fluentform/submission_logs',
|
|
'Use fluentform/submission_logs instead of fluentform_entry_logs.'
|
|
);
|
|
|
|
$logs = apply_filters('fluentform/submission_logs', $logs, $submissionId);
|
|
|
|
$entryLogs = [];
|
|
|
|
foreach ($logs as $log) {
|
|
if (isset($log->component) && $log->component === 'slack') {
|
|
continue;
|
|
}
|
|
$entryLogs[] = [
|
|
'id' => $log->id,
|
|
'status' => $log->status,
|
|
'title' => $log->component . ' (' . $log->title . ')',
|
|
'description' => $log->description,
|
|
'created_at' => (string)$log->created_at,
|
|
];
|
|
}
|
|
} else {
|
|
$columns = [
|
|
'id',
|
|
'action',
|
|
'status',
|
|
'note',
|
|
'created_at',
|
|
'form_id',
|
|
'feed_id',
|
|
'origin_id',
|
|
];
|
|
|
|
$logs = Scheduler::select($columns)
|
|
->where('origin_id', $submissionId)
|
|
->orderBy('id', 'DESC')
|
|
->get();
|
|
|
|
$logs = apply_filters_deprecated(
|
|
'fluentform_entry_api_logs',
|
|
[
|
|
$logs,
|
|
$submissionId
|
|
],
|
|
FLUENTFORM_FRAMEWORK_UPGRADE,
|
|
'fluentform/submission_api_logs',
|
|
'Use fluentform/submission_api_logs instead of fluentform_entry_api_logs.'
|
|
);
|
|
$logs = apply_filters('fluentform/submission_api_logs', $logs, $submissionId);
|
|
|
|
$entryLogs = [];
|
|
|
|
foreach ($logs as $log) {
|
|
$entryLog = [
|
|
'id' => $log->id,
|
|
'status' => $log->status,
|
|
'title' => 'n/a',
|
|
'description' => $log->note,
|
|
'created_at' => (string)$log->created_at,
|
|
'form_id' => $log->form_id,
|
|
'feed_id' => $log->feed_id,
|
|
'submission_id' => $log->origin_id,
|
|
'integration_enabled' => false
|
|
];
|
|
|
|
$notificationKeys = apply_filters('fluentform/global_notification_active_types', [], $log->form_id);
|
|
|
|
unset($notificationKeys['user_registration_feeds']);
|
|
unset($notificationKeys['notifications']);
|
|
|
|
$notificationKeys = array_flip($notificationKeys);
|
|
|
|
$actionName = Helper::getLogInitiator($log->action);
|
|
if ($actionName) {
|
|
$actionName = str_replace(['Fluentform_integration_notify_', 'Fluentform/integration_notify_'], '', $actionName);
|
|
|
|
if (in_array($actionName, $notificationKeys)) {
|
|
$entryLog['integration_enabled'] = true;
|
|
}
|
|
}
|
|
|
|
if ($log->action) {
|
|
$entryLog['title'] = Helper::getLogInitiator($log->action, $logType);
|
|
}
|
|
|
|
$entryLogs[] = $entryLog;
|
|
}
|
|
}
|
|
|
|
return apply_filters('fluentform/submission_logs', $entryLogs, $submissionId);
|
|
}
|
|
|
|
public function remove($attributes = [])
|
|
{
|
|
$ids = $this->normalizeLogIds($attributes);
|
|
|
|
if (!$ids) {
|
|
throw new ValidationException(
|
|
// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
|
|
__('No selections found', 'fluentform')
|
|
);
|
|
}
|
|
|
|
$logType = Arr::get($attributes, 'type', Arr::get($attributes, 'log_type', 'logs'));
|
|
$entryId = intval(Arr::get($attributes, 'entry_id'));
|
|
$targetLogs = $this->getLogsForDeletion($ids, $logType);
|
|
|
|
if (!$targetLogs->count()) {
|
|
throw new ValidationException(
|
|
// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
|
|
__('No selections found', 'fluentform')
|
|
);
|
|
}
|
|
|
|
$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', []);
|
|
|
|
if (!is_array($ids)) {
|
|
$ids = [];
|
|
}
|
|
|
|
$singleLogId = intval(Arr::get($attributes, 'log_id'));
|
|
if ($singleLogId) {
|
|
$ids[] = $singleLogId;
|
|
}
|
|
|
|
$ids = array_map('intval', $ids);
|
|
$ids = array_filter($ids);
|
|
|
|
return array_values(array_unique($ids));
|
|
}
|
|
|
|
protected function getLogsForDeletion($ids, $logType)
|
|
{
|
|
if ('logs' === $logType) {
|
|
return Log::select([
|
|
'id',
|
|
'parent_source_id as form_id',
|
|
'source_id as submission_id',
|
|
])->whereIn('id', $ids)->get();
|
|
}
|
|
|
|
return Scheduler::select([
|
|
'id',
|
|
'form_id',
|
|
'origin_id as submission_id',
|
|
])->whereIn('id', $ids)->get();
|
|
}
|
|
|
|
protected function getDeleteQuery($logType)
|
|
{
|
|
return 'logs' === $logType ? Log::query() : Scheduler::query();
|
|
}
|
|
|
|
protected function assertDeletePermission($targetLogs, $entryId = 0)
|
|
{
|
|
if ($entryId) {
|
|
foreach ($targetLogs as $targetLog) {
|
|
if (intval($targetLog->submission_id) !== $entryId) {
|
|
$this->throwDeletePermissionError();
|
|
}
|
|
}
|
|
}
|
|
|
|
$allowedForms = FormManagerService::getUserAllowedFormsScope();
|
|
if (false === $allowedForms) {
|
|
return;
|
|
}
|
|
|
|
foreach ($targetLogs as $targetLog) {
|
|
$formId = intval($targetLog->form_id);
|
|
|
|
if (!$formId || !in_array($formId, $allowedForms, true)) {
|
|
$this->throwDeletePermissionError();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected function throwDeletePermissionError()
|
|
{
|
|
throw new ValidationException(
|
|
// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message, not output
|
|
__('You do not have permission to delete the selected logs', 'fluentform')
|
|
);
|
|
}
|
|
}
|