Initial commit

This commit is contained in:
Julien Nahum
2022-09-20 21:59:52 +02:00
commit f8e6cd4dd6
479 changed files with 77078 additions and 0 deletions

View File

@@ -0,0 +1,189 @@
<?php
namespace App\Http\Controllers\Forms;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreFormRequest;
use App\Http\Requests\UpdateFormRequest;
use App\Http\Requests\UploadAssetRequest;
use App\Http\Resources\FormResource;
use App\Models\Forms\Form;
use App\Models\Workspace;
use App\Service\Forms\FormCleaner;
use App\Service\Storage\StorageFileNameParser;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class FormController extends Controller
{
const ASSETS_UPLOAD_PATH = 'assets/forms';
private FormCleaner $formCleaner;
public function __construct()
{
$this->middleware('auth');
$this->formCleaner = new FormCleaner();
}
public function index($workspaceId)
{
$workspace = Workspace::findOrFail($workspaceId);
$this->authorize('view', $workspace);
$this->authorize('viewAny', Form::class);
return FormResource::collection($workspace->forms);
}
/**
* Return all user forms, used for zapier
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function indexAll()
{
$forms = collect();
foreach (Auth::user()->workspaces as $workspace) {
$this->authorize('view', $workspace);
$this->authorize('viewAny', Form::class);
$forms = $forms->merge($workspace->forms);
}
return FormResource::collection($forms);
}
public function store(StoreFormRequest $request)
{
$this->authorize('create', Form::class);
$workspace = Workspace::findOrFail($request->get('workspace_id'));
$this->authorize('view', $workspace);
$formData = $this->formCleaner
->processRequest($request)
->simulateCleaning($workspace)
->getData();
$form = Form::create(array_merge($formData, [
'creator_id' => $request->user()->id
]));
return $this->success([
'message' => $this->formCleaner->hasCleaned() ? 'Form successfully created, but the Pro features you used will be disabled when sharing your form:' : 'Form created.',
'form_cleaning' => $this->formCleaner->getPerformedCleanings(),
'form' => new FormResource($form),
'users_first_form' => $request->user()->forms()->count() == 1
]);
}
public function update(UpdateFormRequest $request, string $id)
{
$form = Form::findOrFail($id);
$this->authorize('update', $form);
$formData = $this->formCleaner
->processRequest($request)
->simulateCleaning($form->workspace)
->getData();
// Set Removed Properties
$formData['removed_properties'] = array_merge($form->removed_properties, collect($form->properties)->filter(function ($field) use ($formData) {
return (!Str::of($field['type'])->startsWith('nf-') && !in_array($field['id'], collect($formData['properties'])->pluck("id")->toArray()));
})->toArray());
$form->update($formData);
return $this->success([
'message' => $this->formCleaner->hasCleaned() ? 'Form successfully updated, but the Pro features you used will be disabled when sharing your form:' : 'Form updated.',
'form_cleaning' => $this->formCleaner->getPerformedCleanings(),
'form' => new FormResource($form)
]);
}
public function destroy($id)
{
$form = Form::findOrFail($id);
$this->authorize('delete', $form);
$form->delete();
return $this->success([
'message' => 'Form was deleted.'
]);
}
public function duplicate($id)
{
$form = Form::findOrFail($id);
$this->authorize('update', $form);
// Create copy
$formCopy = $form->replicate();
$formCopy->title = 'Copy of '.$formCopy->title;
$formCopy->save();
return $this->success([
'message' => 'Form successfully duplicated.',
'new_form' => new FormResource($formCopy)
]);
}
public function regenerateLink($id, $option)
{
$form = Form::findOrFail($id);
$this->authorize('update', $form);
if ( $option == 'slug') {
$form->generateSlug();
} elseif ($option == 'uuid') {
$form->slug = Str::uuid();
}
$form->save();
return $this->success([
'message' => 'Form url successfully updated. Your new form url now is: '.$form->share_url.'.',
'form' => new FormResource($form)
]);
}
/**
* Upload a form asset
*/
public function uploadAsset(UploadAssetRequest $request)
{
$this->authorize('viewAny', Form::class);
$fileNameParser = StorageFileNameParser::parse($request->url);
// Make sure we retrieve the file in tmp storage, move it to persistent
$fileName = PublicFormController::TMP_FILE_UPLOAD_PATH.'/'.$fileNameParser->uuid;;
if (!Storage::disk('s3')->exists($fileName)) {
// File not found, we skip
return null;
}
$newPath = self::ASSETS_UPLOAD_PATH.'/'.$fileNameParser->getMovedFileName();
Storage::disk('s3')->move($fileName, $newPath);
return $this->success([
'message' => 'File uploaded.',
'url' => route("forms.assets.show", [$fileNameParser->getMovedFileName()])
]);
}
/**
* File uploads retrieval
*/
public function viewFile($id, $fileName)
{
$form = Form::findOrFail($id);
$this->authorize('view', $form);
$path = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $form->id).'/'.$fileName;
if (!Storage::disk('s3')->exists($path)) {
return $this->error([
'message' => 'File not found.'
]);
}
return redirect()->to(Storage::disk('s3')->temporaryUrl($path, now()->addMinutes(5)));
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers\Forms;
use App\Http\Controllers\Controller;
use App\Models\Forms\Form;
use Carbon\CarbonPeriod;
use App\Models\Forms\FormStatistic;
use Illuminate\Http\Request;
class FormStatsController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function getFormStats(Request $request)
{
$form = $request->form; // Added by ProForm middleware
$this->authorize('view', $form);
$formStats = $form->statistics()->where('date','>',now()->subDays(29)->startOfDay())->get();
$periodStats = ["views" => [], "submissions" => []];
foreach (CarbonPeriod::create(now()->subDays(29), now()) as $dateObj) {
$date = $dateObj->format('d-m-Y');
$statisticData = $formStats->where('date', $dateObj->format('Y-m-d'))->first();
$periodStats["views"][$date] = $statisticData->data["views"] ?? 0;
$periodStats["submissions"][$date] = $statisticData->data["submissions"] ?? 0;
if($dateObj->toDateString() === now()->toDateString()){
$periodStats["views"][$date] += $form->views()->count();
$periodStats["submissions"][$date] += $form->submissions()->whereDate('created_at', '>=', now()->startOfDay())->count();
}
}
return $periodStats;
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers\Forms;
use App\Http\Controllers\Controller;
use App\Http\Resources\FormSubmissionResource;
use App\Models\Forms\Form;
use App\Exports\FormSubmissionExport;
use App\Service\Forms\FormSubmissionFormatter;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Maatwebsite\Excel\Facades\Excel;
class FormSubmissionController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function submissions(string $id)
{
$form = Form::findOrFail((int) $id);
$this->authorize('view', $form);
return FormSubmissionResource::collection($form->submissions()->paginate(100));
}
public function export(string $id)
{
$form = Form::findOrFail((int) $id);
$this->authorize('view', $form);
$allRows = [];
foreach ($form->submissions->toArray() as $row) {
$formatter = (new FormSubmissionFormatter($form, $row['data']))
->outputStringsOnly()
->setEmptyForNoValue();
$tmp = $formatter->getCleanKeyValue();
$tmp['Create Date'] = date("Y-m-d H:i", strtotime($row['created_at']));
$allRows[] = $tmp;
}
$csvExport = (new FormSubmissionExport($allRows));
return Excel::download(
$csvExport,
$form->slug.'-submission-data.csv',
\Maatwebsite\Excel\Excel::CSV
);
}
public function submissionFile($id, $fileName)
{
$form = Form::findOrFail((int) $id);
$this->authorize('view', $form);
$fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id).'/'
.urldecode($fileName);
if (!Storage::disk('s3')->exists($fileName)) {
return $this->error([
'message' => 'File not found.',
], 404);
}
return redirect(
Storage::disk('s3')->temporaryUrl($fileName, now()->addMinute())
);
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers\Forms\Integration;
use App\Http\Controllers\Controller;
use App\Http\Requests\Integration\StoreFormZapierWebhookRequest;
use App\Models\Integration\FormZapierWebhook;
use Illuminate\Http\Request;
use Spatie\WebhookServer\WebhookCall;
class FormZapierWebhookController extends Controller
{
/**
* Controller for Zappier webhook subscriptions.
*/
public function __construct() {
// $this->middleware('subscribed');
$this->middleware('auth');
}
public function store(StoreFormZapierWebhookRequest $request) {
$hook = $request->instanciateHook();
$this->authorize('store', $hook);
$hook->save();
return $this->success([
'message' => 'Webhook created.',
'hook' => $hook
]);
}
public function delete($id) {
$hook = FormZapierWebhook::findOrFail($id);
$this->authorize('store', $hook);
$hook->delete();
return $this->success([
'message' => 'Webhook deleted.',
]);
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace App\Http\Controllers\Forms;
use App\Http\Controllers\Controller;
use App\Http\Requests\AnswerFormRequest;
use App\Http\Resources\FormResource;
use App\Jobs\Form\StoreFormSubmissionJob;
use App\Models\Forms\Form;
use App\Service\Forms\FormCleaner;
use App\Service\WorkspaceHelper;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Auth;
class PublicFormController extends Controller
{
const FILE_UPLOAD_PATH = 'forms/?/submissions';
const TMP_FILE_UPLOAD_PATH = 'tmp/';
public function show(Request $request, string $slug)
{
$form = Form::whereSlug($slug)->firstOrFail();
if ($form->workspace == null) {
// Workspace deleted
return $this->error([
'message' => 'Form not found.'
], 404);
}
$formCleaner = new FormCleaner();
// Disable pro features if needed
$form->fill($formCleaner
->processForm($request, $form)
->performCleaning($form->workspace)
->getData()
);
// Increase form view counter if not login
if(!Auth::check()){
$form->views()->create();
}
$formResource = new FormResource($form);
$formResource->setCleanings($formCleaner->getPerformedCleanings());
return $formResource;
}
public function listUsers(Request $request)
{
// Check that form has user field
$form = $request->form;
if (!$form->has_user_field) {
return [];
}
// Use serializer
$workspace = $form->workspace;
return (new WorkspaceHelper($workspace))->getAllUsers();
}
public function showAsset($assetFileName)
{
$path = FormController::ASSETS_UPLOAD_PATH.'/'.$assetFileName;
if (!Storage::disk('s3')->exists($path)) {
return $this->error([
'message' => 'File not found.',
'file_name' => $assetFileName
]);
}
return redirect()->to(Storage::disk('s3')->temporaryUrl($path, now()->addMinutes(5)));
}
public function answer(AnswerFormRequest $request)
{
$form = $request->form;
StoreFormSubmissionJob::dispatch($form, $request->validated());
return $this->success(array_merge([
'message' => 'Form submission saved.',
], $request->form->is_pro && $request->form->redirect_url ? [
'redirect' => true,
'redirect_url' => $request->form->redirect_url
] : [
'redirect' => false
]));
}
}