2022-09-20 19:59:52 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
namespace App\Service\Forms;
|
|
|
|
|
|
|
|
use App\Http\Requests\UserFormRequest;
|
|
|
|
use App\Http\Resources\FormResource;
|
|
|
|
use App\Models\Forms\Form;
|
|
|
|
use App\Models\Workspace;
|
|
|
|
use App\Models\User;
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
use Illuminate\Support\Arr;
|
|
|
|
use Stevebauman\Purify\Facades\Purify;
|
|
|
|
use function collect;
|
|
|
|
|
|
|
|
class FormCleaner
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* All the performed cleanings
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
private array $cleanings = [];
|
|
|
|
|
|
|
|
private array $data;
|
|
|
|
|
2023-08-30 09:43:11 +00:00
|
|
|
// For remove keys those have empty value
|
|
|
|
private array $customKeys = ['seo_meta'];
|
|
|
|
|
2022-09-20 19:59:52 +00:00
|
|
|
private array $formDefaults = [
|
|
|
|
'notifies' => false,
|
|
|
|
'no_branding' => false,
|
|
|
|
'webhook_url' => null,
|
|
|
|
'database_fields_update' => null,
|
2022-09-21 15:23:37 +00:00
|
|
|
'slack_webhook_url' => null,
|
2023-02-19 12:19:16 +00:00
|
|
|
'discord_webhook_url' => null,
|
2023-08-30 07:58:29 +00:00
|
|
|
'editable_submissions' => false,
|
|
|
|
'custom_code' => null,
|
2023-08-30 09:43:11 +00:00
|
|
|
'seo_meta' => []
|
2022-09-20 19:59:52 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
private array $fieldDefaults = [
|
|
|
|
// 'name' => '' TODO: prevent name changing, use alias for column and keep original name as it is
|
|
|
|
'file_upload' => false,
|
|
|
|
];
|
|
|
|
|
|
|
|
private array $cleaningMessages = [
|
|
|
|
// For form
|
|
|
|
'notifies' => "Email notification were disabled.",
|
|
|
|
'no_branding' => "OpenForm branding is not hidden.",
|
|
|
|
'webhook_url' => "Webhook disabled.",
|
|
|
|
'database_fields_update' => 'Form submission will only create new records (no updates).',
|
2022-09-21 15:23:37 +00:00
|
|
|
'slack_webhook_url' => "Slack webhook disabled.",
|
2023-02-19 12:19:16 +00:00
|
|
|
'discord_webhook_url' => "Discord webhook disabled.",
|
2023-08-30 07:58:29 +00:00
|
|
|
'editable_submissions' => 'Users will not be able to edit their submissions.',
|
|
|
|
'custom_code' => 'Custom code was disabled',
|
2023-08-30 09:43:11 +00:00
|
|
|
'seo_meta' => 'Custom code was disabled',
|
2022-09-20 19:59:52 +00:00
|
|
|
|
|
|
|
// For fields
|
|
|
|
'file_upload' => "Link field is not a file upload.",
|
|
|
|
'custom_block' => 'The custom block was removed.',
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns form data after request ingestion
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getData(): array
|
|
|
|
{
|
|
|
|
return $this->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if at least one cleaning was done
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function hasCleaned(): bool
|
|
|
|
{
|
|
|
|
return count($this->cleanings) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the messages for each cleaning step performed
|
|
|
|
*/
|
|
|
|
public function getPerformedCleanings(): array
|
|
|
|
{
|
|
|
|
$cleaningMsgs = [];
|
|
|
|
foreach ($this->cleanings as $key => $val) {
|
|
|
|
$cleaningMsgs[$key] = collect($val)->map(function ($cleaning) {
|
|
|
|
return $this->cleaningMessages[$cleaning];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return $cleaningMsgs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes form pro features from data if user isn't pro
|
|
|
|
*/
|
|
|
|
public function processRequest(UserFormRequest $request): FormCleaner
|
|
|
|
{
|
|
|
|
$data = $request->validated();
|
|
|
|
$this->data = $this->commonCleaning($data);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create form cleaner instance from existing form
|
|
|
|
*/
|
2023-08-30 07:58:29 +00:00
|
|
|
public function processForm(Request $request, Form $form) : FormCleaner
|
|
|
|
{
|
2022-09-20 19:59:52 +00:00
|
|
|
$data = (new FormResource($form))->toArray($request);
|
|
|
|
$this->data = $this->commonCleaning($data);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function isPro(Workspace $workspace) {
|
|
|
|
return $workspace->is_pro;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dry run celanings
|
|
|
|
* @param User|null $user
|
|
|
|
*/
|
2023-08-30 07:58:29 +00:00
|
|
|
public function simulateCleaning(Workspace $workspace): FormCleaner
|
|
|
|
{
|
|
|
|
if (!$this->isPro($workspace)) {
|
|
|
|
$this->data = $this->removeProFeatures($this->data, true);
|
|
|
|
}
|
2022-09-20 19:59:52 +00:00
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Perform Cleanigns
|
|
|
|
* @param User|null $user
|
|
|
|
* @return $this|array
|
|
|
|
*/
|
|
|
|
public function performCleaning(Workspace $workspace): FormCleaner
|
|
|
|
{
|
2023-08-30 07:58:29 +00:00
|
|
|
if (!$this->isPro($workspace)) {
|
|
|
|
$this->data = $this->removeProFeatures($this->data);
|
|
|
|
}
|
2022-09-20 19:59:52 +00:00
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clean all forms:
|
|
|
|
* - Escape html of custom text block
|
|
|
|
*/
|
|
|
|
private function commonCleaning(array $data)
|
|
|
|
{
|
|
|
|
foreach ($data['properties'] as &$property) {
|
|
|
|
if ($property['type'] == 'nf-text' && isset($property['content'])) {
|
|
|
|
$property['content'] = Purify::clean($property['content']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function removeProFeatures(array $data, $simulation = false)
|
|
|
|
{
|
|
|
|
$this->cleanForm($data, $simulation);
|
|
|
|
$this->cleanProperties($data, $simulation);
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function cleanForm(array &$data, $simulation = false): void
|
|
|
|
{
|
|
|
|
$this->clean($data, $this->formDefaults, $simulation);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function cleanProperties(array &$data, $simulation = false): void
|
|
|
|
{
|
|
|
|
foreach ($data['properties'] as $key => &$property) {
|
2023-08-30 07:58:29 +00:00
|
|
|
/*
|
2022-09-20 19:59:52 +00:00
|
|
|
// Remove pro custom blocks
|
|
|
|
if (\Str::of($property['type'])->startsWith('nf-')) {
|
|
|
|
$this->cleanings[$property['name']][] = 'custom_block';
|
|
|
|
if (!$simulation) {
|
|
|
|
unset($data['properties'][$key]);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-08-30 07:58:29 +00:00
|
|
|
// Remove logic
|
|
|
|
if (($property['logic']['conditions'] ?? null) != null || ($property['logic']['actions'] ?? []) != []) {
|
|
|
|
$this->cleanings[$property['name']][] = 'logic';
|
|
|
|
if (!$simulation) {
|
|
|
|
unset($data['properties'][$key]['logic']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2022-09-20 19:59:52 +00:00
|
|
|
// Clean pro field options
|
|
|
|
$this->cleanField($property, $this->fieldDefaults, $simulation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private function clean(array &$data, array $defaults, $simulation = false): void
|
|
|
|
{
|
|
|
|
foreach ($defaults as $key => $value) {
|
2023-08-30 07:58:29 +00:00
|
|
|
|
|
|
|
// Get value from form
|
|
|
|
$formVal = Arr::get($data, $key);
|
|
|
|
|
2023-08-30 09:43:11 +00:00
|
|
|
// Transform customkeys values
|
|
|
|
$formVal = $this->cleanCustomKeys($key, $formVal);
|
|
|
|
|
2023-08-30 07:58:29 +00:00
|
|
|
// Transform boolean values
|
|
|
|
$formVal = (($formVal === 0 || $formVal === "0") ? false : $formVal);
|
|
|
|
$formVal = (($formVal === 1 || $formVal === "1") ? true : $formVal);
|
|
|
|
|
|
|
|
if (!is_null($formVal) && $formVal !== $value) {
|
|
|
|
if (!isset($this->cleanings['form'])) {
|
|
|
|
$this->cleanings['form'] = [];
|
|
|
|
}
|
2022-09-20 19:59:52 +00:00
|
|
|
$this->cleanings['form'][] = $key;
|
|
|
|
|
|
|
|
// If not a simulation, do the cleaning
|
|
|
|
if (!$simulation) {
|
|
|
|
Arr::set($data, $key, $value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private function cleanField(array &$data, array $defaults, $simulation = false): void
|
|
|
|
{
|
|
|
|
foreach ($defaults as $key => $value) {
|
|
|
|
if (isset($data[$key]) && Arr::get($data, $key) !== $value) {
|
|
|
|
$this->cleanings[$data['name']][] = $key;
|
|
|
|
if (!$simulation) {
|
|
|
|
Arr::set($data, $key, $value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove pro types columns
|
2023-08-30 07:58:29 +00:00
|
|
|
/*foreach (['files'] as $proType) {
|
2022-09-20 19:59:52 +00:00
|
|
|
if ($data['type'] == $proType && (!isset($data['hidden']) || !$data['hidden'])) {
|
|
|
|
$this->cleanings[$data['name']][] = $proType;
|
|
|
|
if (!$simulation) {
|
|
|
|
$data['hidden'] = true;
|
|
|
|
}
|
|
|
|
}
|
2023-08-30 07:58:29 +00:00
|
|
|
}*/
|
2022-09-20 19:59:52 +00:00
|
|
|
}
|
|
|
|
|
2023-08-30 09:43:11 +00:00
|
|
|
// Remove keys those have empty value
|
|
|
|
private function cleanCustomKeys($key, $formVal)
|
|
|
|
{
|
|
|
|
if (in_array($key, $this->customKeys) && $formVal !== null) {
|
|
|
|
$newVal = [];
|
|
|
|
foreach ($formVal as $k => $val) {
|
|
|
|
if ($val) {
|
|
|
|
$newVal[$k] = $val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $newVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $formVal;
|
|
|
|
}
|
|
|
|
|
2022-09-20 19:59:52 +00:00
|
|
|
}
|