Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/unlayer #72

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .php_cs.cache

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;

class AddJsonFieldToTemplatesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('templates', function ($table) {
$table->json('json')->nullable()->after('content');
});
}
}
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="FILESYSTEM_DRIVER" value="public"/>

<env name="DB_CONNECTION" value="testing" />
<env name="DB_DATABASE" value="sendportal_dev"/>
Expand Down
1 change: 1 addition & 0 deletions resources/views/layouts/app.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="csrf-token" content="{{ csrf_token() }}">

@include('sendportal::layouts.partials.favicons')

Expand Down
42 changes: 39 additions & 3 deletions resources/views/templates/create.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,46 @@
{{ __('Create Template') }}
</div>
<div class="card-body">
{!! Form::open(['route' => ['sendportal.templates.store'], 'class' => 'form-horizontal']) !!}

@include('sendportal::templates.partials.form')
{!! Form::open(['route' => ['sendportal.templates.store'], 'class' => 'form-horizontal', 'id' => 'template-form']) !!}

<div class="form-group row form-group-name">
<label for="id-field-name" class="control-label col-sm-2">{{ __('Template Name') }}</label>
<div class="col-sm-6">
<input id="id-field-name" class="form-control" name="name" type="text" value="{{ old('name') }}" required>
</div>
</div>

<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<a class="nav-link active" id="builder-tab" data-toggle="tab" href="#builder" role="tab">{{ __('Builder') }}</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="raw-tab" data-toggle="tab" href="#raw" role="tab">{{ __('Raw HTML') }}</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="builder" role="tabpanel">
@include('sendportal::templates.partials.unlayer')

<div class="form-group row">
<input type="submit" name="builder" value="{{ __('Save Template') }}" class="btn btn-primary btn-md">
</div>
</div>
<div class="tab-pane fade" id="raw" role="tabpanel">
@include('sendportal::templates.partials.editor')

<div class="form-group row">
<div class="col-12">
<a href="#" class="btn btn-md btn-secondary btn-preview">{{ __('Show Preview') }}</a>
<input type="submit" name="raw" value="{{ __('Save Template') }}" class="btn btn-primary btn-md">
</div>
</div>
</div>
</div>

{!! Form::close() !!}
</div>
</div>

@stop
@stop
30 changes: 27 additions & 3 deletions resources/views/templates/edit.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,33 @@
{{ __('Edit Template') }}
</div>
<div class="card-body">
{!! Form::model($template, ['method' => 'put', 'route' => ['sendportal.templates.update', $template->id], 'class' => 'form-horizontal']) !!}

@include('sendportal::templates.partials.form')
{!! Form::model($template, ['method' => 'put', 'route' => ['sendportal.templates.update', $template->id], 'id' => 'template-form', 'class' => 'form-horizontal']) !!}

<div class="form-group row form-group-name">
<label for="id-field-name" class="control-label col-sm-2">{{ __('Template Name') }}</label>
<div class="col-sm-6">
<input id="id-field-name" class="form-control" name="name" type="text" value="{{ $template->name }}" required>
</div>
</div>

@if ($template->json)
@include('sendportal::templates.partials.unlayer')

<div class="form-group row">
<input class="btn btn-primary btn-md" type="submit" name="builder" value="{{ __('Save Template') }}" />
</div>
@else
@include('sendportal::templates.partials.editor')

<div class="form-group row">
<div class="col-12">
<a href="#" class="btn btn-md btn-secondary btn-preview">{{ __('Show Preview') }}</a>
<input class="btn btn-primary btn-md" type="submit" name="raw" value="{{ __('Save Template') }}" />
</div>
</div>
@endif

{!! Form::close() !!}
</div>
</div>

Expand Down
5 changes: 2 additions & 3 deletions resources/views/templates/partials/editor.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
@endpush

<div class="form-group row form-group-content template-content">
<label for="id-field-content" class="control-label col-sm-2">{{ __('Content') }}</label>
<div class="col-sm-10">
<div class="col-12">
<textarea id="id-field-content" class="form-control" name="content" cols="50"
rows="20">{{ $template->content ?? null }}</textarea>
</div>
</div>

<div class="form-group row template-preview d-none">
<div class="offset-sm-2 col-sm-10">
<div class="col-12">
<div class="border border-light h-100">
<iframe width="100%" height="100%" scrolling="yes" frameborder="0"
srcdoc="{!! $template->content ?? null !!} "></iframe>
Expand Down
60 changes: 60 additions & 0 deletions resources/views/templates/partials/unlayer.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<div id="editor-container" style="height: 100vh"></div>

@push('js')

<script src="//editor.unlayer.com/embed.js"></script>
<script>
unlayer.init({
id: 'editor-container'
});

@if (isset($template) and $template->json)
unlayer.loadDesign({!! $template->json !!});
@endif

unlayer.registerCallback('image', function(file, done) {
var formData = new FormData();

formData.append('file', file.attachments[0]);

$.ajax({
type:'POST',
url: "{{ route('sendportal.ajax.file.store') }}",
data: formData,
cache: false,
contentType: false,
processData: false,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: (data) => {
done({ progress: 100, url: data.file });
},
error: function(res) {
alert('Upload failed!');
}
});
});

$(document).ready(function () {
$('#template-form').on('submit', function(e) {
if ($(document.activeElement).attr('name') === 'builder') {
e.preventDefault();

var $this = $(this);

unlayer.exportHtml(function(data) {
var json = data.design;
var html = data.html;

$this.append($("<input type='hidden'>").attr({ name: 'html', value: html }));
$this.append($("<input type='hidden'>").attr({ name: 'json', value: JSON.stringify(json) }));

$this.off('submit').submit();
});
}
});
});
</script>

@endpush
2 changes: 2 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@
// Ajax.
$appRouter->name('ajax.')->prefix('ajax')->namespace('Ajax')->group(static function (Router $ajaxRouter) {
$ajaxRouter->post('segments/store', 'SegmentsController@store')->name('segments.store');

$ajaxRouter->post('templates/file', 'FileController@store')->name('file.store');
});

// Workspace Management.
Expand Down
23 changes: 23 additions & 0 deletions src/Http/Controllers/Ajax/FileController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Sendportal\Base\Http\Controllers\Ajax;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Sendportal\Base\Http\Controllers\Controller;

class FileController extends Controller
{
public function store(Request $request)
{
request()->validate([
'file' => 'required|mimes:jpg,jpeg,png|max:2048',
]);

$file = $request->file->storePublicly('images');

return response()->json([
"file" => Storage::url($file)
]);
}
}
16 changes: 13 additions & 3 deletions src/Http/Controllers/TemplatesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@

use Exception;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Arr;
use Illuminate\View\View;
use Sendportal\Base\Http\Requests\TemplateStoreRequest;
use Sendportal\Base\Http\Requests\TemplateUpdateRequest;
use Sendportal\Base\Repositories\TemplateTenantRepository;
use Sendportal\Base\Services\Templates\TemplateService;
use Sendportal\Base\Traits\NormalizeTags;
use Throwable;

class TemplatesController extends Controller
{
use NormalizeTags;

/** @var TemplateTenantRepository */
private $templates;

Expand Down Expand Up @@ -52,6 +50,12 @@ public function store(TemplateStoreRequest $request): RedirectResponse
{
$data = $request->validated();

if (Arr::has($data, 'json')) {
$data['content'] = $data['html'];

unset($data['html']);
}

$this->service->store(auth()->user()->currentWorkspace()->id, $data);

return redirect()
Expand All @@ -75,6 +79,12 @@ public function update(TemplateUpdateRequest $request, int $id): RedirectRespons
{
$data = $request->validated();

if (Arr::has($data, 'json')) {
$data['content'] = $data['html'];

unset($data['html']);
}

$this->service->update(auth()->user()->currentWorkspace()->id, $id, $data);

return redirect()
Expand Down
4 changes: 3 additions & 1 deletion src/Http/Requests/TemplateStoreRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ public function rules(): array
{
return [
'name' => ['required', 'max:255'],
'content' => 'required',
'content' => 'required_without:html,json',
'html' => 'required_without:content',
'json' => 'required_without:content',
];
}
}
4 changes: 3 additions & 1 deletion src/Http/Requests/TemplateUpdateRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ public function rules(): array
{
return [
'name' => ['required', 'max:255'],
'content' => 'required',
'content' => 'required_without:html,json',
'html' => 'required_without:content',
'json' => 'required_without:content',
];
}
}
82 changes: 82 additions & 0 deletions tests/Feature/Ajax/FileControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace Tests\Feature\Ajax;

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;

class FileControllerTest extends TestCase
{
/** @test */
public function the_image_upload_endpoint_is_not_accessible_to_guest_users()
{
Storage::fake('public');

$file = UploadedFile::fake()->image('image.jpg');

$this
->json('POST', route('sendportal.ajax.file.store'), [
'image' => $file,
])
->assertUnauthorized();

$this->assertEmpty(Storage::disk('public')->allFiles());
}

/** @test */
public function images_bigger_than_2048_kb_are_not_allowed_for_upload()
{
Storage::fake('public');

$file = UploadedFile::fake()->image('image.jpg')->size(2048 + 1);

$user = $this->createUserWithWorkspace();

$this
->actingAs($user)
->json('POST', route('sendportal.ajax.file.store'), [
'file' => $file,
])
->assertJsonValidationErrors(['file']);
}

/** @test */
public function documents_are_not_allowed_for_upload()
{
Storage::fake('public');

$file = UploadedFile::fake()->create('document.pdf', 1024, 'application/pdf');

$user = $this->createUserWithWorkspace();

$this
->actingAs($user)
->json('POST', route('sendportal.ajax.file.store'), [
'file' => $file,
])
->assertJsonValidationErrors(['file']);
}

/** @test */
public function it_should_allow_image_uploads_to_authenticated_users()
{
Storage::fake('public');

$file = UploadedFile::fake()->image('image.jpg');

$user = $this->createUserWithWorkspace();

$this
->actingAs($user)
->json('POST', route('sendportal.ajax.file.store'), [
'file' => $file,
])
->assertOk()
->assertJsonStructure([
'file'
]);

Storage::disk('public')->assertExists('images/' . $file->hashName());
}
}
Loading