From bca6020ab0424e1eb5be26a42ab4024e7e06b288 Mon Sep 17 00:00:00 2001 From: Miguel Nogueira Date: Wed, 15 Jul 2020 06:48:49 +0100 Subject: [PATCH] Add ability to edit forms and add new fields This commit adds the ability to edit and modify existing forms. On the technical side, it also adds a new reusable validation Facade which helps reduce duplicated code. --- .gitignore | 1 + .phive/phars.xml | 5 + app/Facades/ContextAwareValidation.php | 14 +++ app/Helpers/ContextAwareValidator.php | 72 ++++++++++++ app/Http/Controllers/FormController.php | 72 +++++++----- app/Policies/FormPolicy.php | 2 +- .../ContextAwareValidatorProvider.php | 34 ++++++ config/app.php | 2 + public/img/editor.svg | 1 + public/js/formbuilder.js | 1 + public/js/formeditor.js | 19 ++++ .../administration/editform.blade.php | 103 ++++++++++++++++++ .../administration/formpreview.blade.php | 4 +- .../dashboard/administration/forms.blade.php | 2 + .../views/dashboard/user/viewapp.blade.php | 48 +++++--- routes/web.php | 8 +- 16 files changed, 337 insertions(+), 51 deletions(-) create mode 100644 .phive/phars.xml create mode 100644 app/Facades/ContextAwareValidation.php create mode 100644 app/Helpers/ContextAwareValidator.php create mode 100644 app/Providers/ContextAwareValidatorProvider.php create mode 100644 public/img/editor.svg create mode 100644 public/js/formeditor.js create mode 100644 resources/views/dashboard/administration/editform.blade.php diff --git a/.gitignore b/.gitignore index cbc1634..e37360f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /public/storage /storage/*.key /vendor +/tools .env .env.backup .phpunit.result.cache diff --git a/.phive/phars.xml b/.phive/phars.xml new file mode 100644 index 0000000..c7b7b0f --- /dev/null +++ b/.phive/phars.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/Facades/ContextAwareValidation.php b/app/Facades/ContextAwareValidation.php new file mode 100644 index 0000000..2771c77 --- /dev/null +++ b/app/Facades/ContextAwareValidation.php @@ -0,0 +1,14 @@ + $field) + { + if(!in_array($fieldName, $excludedNames)) + { + $validator[$fieldName . ".0"] = 'required|string'; + $validator[$fieldName . ".1"] = 'required|string'; + + if ($generateStructure) + { + $formStructure['fields'][$fieldName]['title'] = $field[0]; + $formStructure['fields'][$fieldName]['type'] = $field[1]; + } + + } + } + + $validatorInstance = Validator::make($fields, $validator); + + return ($generateStructure) ? + collect([ + 'validator' => $validatorInstance, + 'structure' => json_encode($formStructure) + ]) + : $validatorInstance; + + + } + +} diff --git a/app/Http/Controllers/FormController.php b/app/Http/Controllers/FormController.php index deeeee0..3b1a7f4 100644 --- a/app/Http/Controllers/FormController.php +++ b/app/Http/Controllers/FormController.php @@ -7,6 +7,8 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Auth; +use ContextAwareValidator; + class FormController extends Controller { @@ -29,39 +31,17 @@ class FormController extends Controller { $this->authorize('create', Form::class); + $fields = $request->all(); - $formFields = $request->all(); + $contextValidation = ContextAwareValidator::getValidator($fields, true, true); - $formStructure = []; - $excludedNames = [ - '_token', - 'formName' // It's added outside the loop. Not excluding causes unwanted duplication. - ]; - $validator = [ - 'formName' => 'required|string|max:100' - ]; - - foreach ($formFields as $fieldName => $field) + if (!$contextValidation->get('validator')->fails()) { - if(!in_array($fieldName, $excludedNames)) - { - $validator[$fieldName . ".0"] = 'required|string'; - $validator[$fieldName . ".1"] = 'required|string'; - - $formStructure['fields'][$fieldName]['title'] = $field[0]; - $formStructure['fields'][$fieldName]['type'] = $field[1]; - } - } - - $validation = Validator::make($formFields, $validator); - - if (!$validation->fails()) - { - $storableFormStructure = json_encode($formStructure); + $storableFormStructure = $contextValidation->get('structure'); Form::create( [ - 'formName' => $formFields['formName'], + 'formName' => $fields['formName'], 'formStructure' => $storableFormStructure, 'formStatus' => 'ACTIVE' ] @@ -71,7 +51,7 @@ class FormController extends Controller return redirect()->to(route('showForms')); } - $request->session()->flash('errors', $validation->errors()->getMessages()); + $request->session()->flash('errors', $contextValidation->get('validator')->errors()->getMessages()); return redirect()->back(); } @@ -107,7 +87,41 @@ class FormController extends Controller { return view('dashboard.administration.formpreview') ->with('form', json_decode($form->formStructure, true)) - ->with('title', $form->formName); + ->with('title', $form->formName) + ->with('formID', $form->id); + } + + public function edit(Request $request, Form $form) + { + return view('dashboard.administration.editform') + ->with('formStructure', json_decode($form->formStructure, true)) + ->with('title', $form->formName) + ->with('formID', $form->id); + } + + public function update(Request $request, Form $form) + { + $contextValidation = ContextAwareValidator::getValidator($request->all(), true); + $this->authorize('update', $form); + + + if (!$contextValidation->get('validator')->fails()) + { + // Add the new structure into the form. New, subsquent fields will be identified by the "new" prefix + // This prefix doesn't actually change the app's behavior when it receives applications. + // Additionally, old applications won't of course display new and updated fields, because we can't travel into the past and get data for them + $form->formStructure = $contextValidation->get('structure'); + $form->save(); + + $request->session()->flash('success', 'Hooray! Your form was updated. New applications for it\'s vacancy will use it.'); + } + else + { + $request->session()->flash('errors', $contextValidation->get('validator')->errors()->getMessages()); + } + + return redirect()->to(route('previewForm', ['form' => $form->id])); + } } diff --git a/app/Policies/FormPolicy.php b/app/Policies/FormPolicy.php index 720b743..c382190 100644 --- a/app/Policies/FormPolicy.php +++ b/app/Policies/FormPolicy.php @@ -57,7 +57,7 @@ class FormPolicy */ public function update(User $user, Form $form) { - // unused + return $user->can('admin.hiring.forms'); } /** diff --git a/app/Providers/ContextAwareValidatorProvider.php b/app/Providers/ContextAwareValidatorProvider.php new file mode 100644 index 0000000..749de88 --- /dev/null +++ b/app/Providers/ContextAwareValidatorProvider.php @@ -0,0 +1,34 @@ + App\Facades\UUID::class, 'IP' => App\Facades\IP::class, 'Markdown' => GrahamCampbell\Markdown\Facades\Markdown::class, + 'ContextAwareValidator' => App\Facades\ContextAwareValidation::class ], diff --git a/public/img/editor.svg b/public/img/editor.svg new file mode 100644 index 0000000..3a6bd3e --- /dev/null +++ b/public/img/editor.svg @@ -0,0 +1 @@ +abstract \ No newline at end of file diff --git a/public/js/formbuilder.js b/public/js/formbuilder.js index bde6b88..43eeab6 100644 --- a/public/js/formbuilder.js +++ b/public/js/formbuilder.js @@ -1,3 +1,4 @@ +// TODO: Add cleaner and less verbose solution found in formeditor.js $(document).ready(function() { $("#add").click(function() { var lastField = $("#buildyourform div:last"); diff --git a/public/js/formeditor.js b/public/js/formeditor.js new file mode 100644 index 0000000..5b1c9a8 --- /dev/null +++ b/public/js/formeditor.js @@ -0,0 +1,19 @@ +// reminder: use vuejs instead, this is still an ugly and cheap solution +$(document).ready(function(){ + + var fieldID = 0; + var wrapper = $('.field-container'); + var newBtn = $('#add'); + + $(newBtn).click(function(e){ + e.preventDefault() + fieldID++; + + $(wrapper).append('
'); + $(wrapper).append(''); + //$(wrapper).append('
'); + + + }); + +}); diff --git a/resources/views/dashboard/administration/editform.blade.php b/resources/views/dashboard/administration/editform.blade.php new file mode 100644 index 0000000..81d8108 --- /dev/null +++ b/resources/views/dashboard/administration/editform.blade.php @@ -0,0 +1,103 @@ +@extends('adminlte::page') + +@section('title', 'Raspberry Network | Edit From') + +@section('content_header') + +

Administration / Forms / Editor

+ +@stop + +@section('js') + + + + +@stop + +@section('content') + +
+
+ +
+
+ + Editor illustration + +
+
+ +
+
+ + +
+ +
+ + +
+
+ +
+ @csrf + @method('PATCH') +
+ +
+ +

Editing {{ $title }}...

+ +
+ +
+ + @foreach($formStructure['fields'] as $fieldName => $field) + +
+ + + + + +
+ + @endforeach + +
+ + + +
+ +
+ + + + +
+ +
+ +
+ +
+ +
+ +
+ +@stop diff --git a/resources/views/dashboard/administration/formpreview.blade.php b/resources/views/dashboard/administration/formpreview.blade.php index 3c00ddd..57ace50 100644 --- a/resources/views/dashboard/administration/formpreview.blade.php +++ b/resources/views/dashboard/administration/formpreview.blade.php @@ -66,8 +66,8 @@ diff --git a/resources/views/dashboard/administration/forms.blade.php b/resources/views/dashboard/administration/forms.blade.php index 2ddf00b..75d500a 100644 --- a/resources/views/dashboard/administration/forms.blade.php +++ b/resources/views/dashboard/administration/forms.blade.php @@ -38,6 +38,7 @@ # Form Title Created On + Updated On Actions @@ -51,6 +52,7 @@ {{$form->id}} {{$form->formName}} {{$form->created_at}} + {{ $form->updated_at }}
diff --git a/resources/views/dashboard/user/viewapp.blade.php b/resources/views/dashboard/user/viewapp.blade.php index db9c073..7bb2490 100644 --- a/resources/views/dashboard/user/viewapp.blade.php +++ b/resources/views/dashboard/user/viewapp.blade.php @@ -75,6 +75,18 @@ @endhasrole +
+ +
+ +
+ × + Reminder: If this form has been updated, new fields and updated questions will not show up here! +
+ +
+ +
@@ -357,9 +369,9 @@
- +
- + @if ($comments->isEmpty())
@@ -378,11 +390,11 @@ @if (!$comments->isEmpty()) - + @foreach($comments as $comment) -
+
- +
@if($application->user->avatarPreference == 'gravatar') User profile picture @@ -394,24 +406,24 @@
- +

{{$comment->user->name}} ● {{Carbon\Carbon::parse($comment->created_at)->diffForHumans()}}

- +
- + {{$comment->text}}
@if(Auth::user()->is($comment->user) || Auth::user()->hasRole('admin')) - +