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

wip - updated docs for uploads and easy mde #550

Open
wants to merge 3 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
48 changes: 24 additions & 24 deletions 6.x/crud-fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -1362,24 +1362,24 @@ Show a [Dropzone JS Input](https://docs.dropzone.dev/).

**Step 0.** Make sure the model attribute can hold all the information needed. Ideally, your model should cast this attribute as `array` and your migration should make the db column either `TEXT` or `JSON`. Other db column types such as `VARCHAR(255)` might not be enough all the time (for 3+ files).

**Step 1:** Add the `DropzoneOperation` to your `CrudController`
**Step 1:** Add the `AjaxUploadOperation` to your `EntityCrudController` [read more about the ajax upload operation](https://backpackforlaravel.com/docs/crud-operation-ajax-upload).

```php
class UserCrudController extends CrudController
class EntityCrudController extends CrudController
{
// ... other operations
use \Backpack\Pro\Http\Controllers\Operations\DropzoneOperation;
use \Backpack\Pro\Http\Controllers\Operations\AjaxUploadOperation;
}
```

**Step 2:** Add the field in CrudController
**Step 2:** Add the field in EntityCrudController

```php
CRUD::field([
'name' => 'photos',
'label' => 'Photos',
'type' => 'dropzone',

'withFiles' => true,
// optional configuration.
// check available options in https://docs.dropzone.dev/configuration/basics/configuration-options
// 'configuration' => [
Expand All @@ -1388,23 +1388,10 @@ CRUD::field([
]);
```

**Step 3:** Configure the file upload process.

At this point you have the dropzone field showing up, and the ajax routes setup to upload/delete files, but the process is not complete. Your files are now only uploaded to the temporary folder, they need to be moved to the permanent location and their paths stored in the database. The easiest way to do that is to add `withFiles => true` to your field definition, this will use the standard `AjaxUploader` that Backpack provides:

```php
CRUD::field([
'name' => 'photos',
'label' => 'Photos',
'type' => 'dropzone',
'withFiles' => true,
]);
```

Alternatively, you can manually implement the saving process yourself using model events, mutators or any other solution that suits you. To know more about the `withFiles`, how it works and how to configure it, [read its documentation](https://backpackforlaravel.com/docs/6.x/crud-uploaders).
Alternatively, you can manually implement the saving process yourself using model events, mutators or any other solution that suits you. To know more about the `withFiles`, how it works and how to configure it, [read its documentation](https://backpackforlaravel.com/docs/crud-uploaders).


**Step 4:** Configure validation. Yes you can do some basic validation in Javascript, but we highly advise you prioritize server-side validation. To make validation easy we created `ValidDropzone` validation rule. It allows you to define two set of rules:
**Step 4:** **VALIDATE YOUR INPUT**. Yes you can do some basic validation in Javascript, but we highly advise you to prioritize server-side validation. To make validation easy we created `ValidDropzone` validation rule. It allows you to define two set of rules:
- `::field()` - the field rules (independent of the file content);
- `->file()` - rules that apply to the sent files;

Expand All @@ -1415,10 +1402,6 @@ use Backpack\Pro\Uploads\Validation\ValidDropzone;
->file('file|mimes:jpeg,png,jpg,gif,svg|max:2048'),
```


**Step 5:** (optional) Configure the temp directory. Whenever new files are uploaded using the Dropzone operation, old files are automatically deleted from the temp directory. But you can also manually clean the temp directory. For more info and temp directory configuration options, see [this link](/docs/{{version}}/crud-how-to#configuring-the-temporary-directory).


Input preview:

![CRUD Field - dropzone](https://user-images.githubusercontent.com/7188159/236273902-ca7fb5a5-e7ce-4a03-91a7-2af81598331c.png)
Expand Down Expand Up @@ -1448,6 +1431,23 @@ CRUD::field([ // easymde

> NOTE: The contents displayed in this editor are NOT stripped, sanitized or escaped by default. Whenever you store Markdown or HTML inside your database, it's HIGHLY recommended that you sanitize the input or output. Laravel makes it super-easy to do that on the model using [accessors](https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators). If you do NOT trust the admins who have access to this field (or end-users can also store information to this db column), please make sure this attribute is always escaped, before it's shown. You can do that by running the value through `strip_tags()` in an accessor on the model (here's [an example](https://github.com/Laravel-Backpack/demo/commit/509c0bf0d8b9ee6a52c50f0d2caed65f1f986385)) or better yet, using an [HTML Purifier package](https://github.com/mewebstudio/Purifier) (here's [an example](https://github.com/Laravel-Backpack/demo/commit/7342cffb418bb568b9e4ee279859685ddc0456c1)).

#### Uploading images using EasyMDE drag & drop

Starting Backpack 6.7 you can now upload images using drag & drop directly into the EasyMDE editor. To enable this feature you need to follow these steps:

**Step 1:** Add the `AjaxUploadOperation` to your `EntityCrudController` where you defined your easyMDE field.
**Step 2:** Add the `withFiles => true` attribute to your field definition. You can check other available options in the [uploaders documentation](https://backpackforlaravel.com/docs/crud-uploaders).

**Note:** EasyMDE provides some basic javascript file validation. By default only `jpg, jpeg, png, gif, svg, webp` are allowed and files up to 2MB. You can change this by setting the `imageMaxSize` and `imageAccept` options in the `easymdeAttributes` attribute. Eg:

```php
'easymdeAttributes' => [
'imageMaxSize' => 1024 * 5, // up to 5MB
'imageAccept' => ['image/gif'], // to only accept gifs
]
```

```php
Input preview:

![CRUD Field - easymde](https://backpackforlaravel.com/uploads/docs-4-2/fields/easymde.png)
Expand Down
50 changes: 0 additions & 50 deletions 6.x/crud-how-to.md
Original file line number Diff line number Diff line change
Expand Up @@ -944,56 +944,6 @@ How do you find out what's the last version you have access to?

Why the ugly, general error? Because Composer doesn't allow vendors to customize the error, unfortunately. Backpack's server returns a better error message, but Composer doesn't show it.


<a name="configuring-the-temporary-directory"></a>
### Configuring the Temporary Directory

The [dropzone field](/docs/{{version}}/crud-fields#dropzone-pro) and DropzoneOperation will upload the files to a temporary directory using AJAX. When an entry is saved, they move that file to the final directory. But if the user doesn't finish the saving process, the temp directory can still hold files that are not used anywhere.

**Configure Temp Directory**

To configure that temporary directory for ALL dropzone operations, call `php artisan vendor:publish --provider="Backpack\Pro\AddonServiceProvider" --tag="dropzone-config"` and then edit your `config/backpack/operations/dropzone.php` to fit your needs. Here are the most important values you'll find there:

```php
'temporary_disk' => 'local', // disk in config/filesystems.php that will be used
'temporary_folder' => 'backpack/temp', // the directory inside the disk above
'purge_temporary_files_older_than' => 72 // automatically delete files older than 72 hours
```

Alternatively, you can also configure the temp directory for the current CRUD only using:

```php
public function setupDropzoneOperation()
{
CRUD::setOperationSetting('temporary_disk', 'public');
CRUD::setOperationSetting('temporary_folder', 'backpack/temp');
CRUD::setOperationSetting('purge_temporary_files_older_than', 72);
}
```

**Delete Old Temp Files**

Whenever new files are uploaded using the Dropzone operation, the operation deletes old files from the temp directory. But you can also run the `backpack:purge-temporary-files` command, to clean the temp directory.


```bash
php artisan backpack:purge-temporary-files --older-than=24 --disk=public --path="backpack/temp"
```

It accepts the following optional parameters:
- `--older-than=24`: the number of hours after which temporary files are deleted.
- `--disk=public`: the disk used by the temporary files.
- `--path="backpack/temp"`: the folder inside the disk where files will be stored.


You can use any strategy to run this command periodically - a cron job, a scheduled task or hooking into application termination hooks. Laravel provides a very easy way to setup your scheduled tasks. You can read more about it [here](https://laravel.com/docs/10.x/scheduling). For example, you can run the command every hour by adding the following line to your `app/Console/Kernel.php` in the `schedule()` method:
```php
// app/Console/Kernel.php
$schedule->command('backpack:purge-temporary-files')->hourly();
```

After adding this, you need to setup a cron job that will process the Laravel scheduler. You can manually run it in development with `php artisan schedule:run`. For production, you can setup a cron job take care of it for you. You can read more about it [here](https://laravel.com/docs/10.x/scheduling#running-the-scheduler).

<a name="enable-database-transactions-for-create-and-update"></a>
### Enable database transactions for create and update

Expand Down
85 changes: 85 additions & 0 deletions 6.x/crud-operation-ajax-upload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# AjaxUpload Operation

---

<a name="about"></a>
## About

This operation setup an endpoint to handle file uploads via AJAX in your CrudController. It's used by fields like [dropzone](https://backpackforlaravel.com/docs/crud-fields#dropzone) and [easymde](https://backpackforlaravel.com/docs/crud-fields#easymde).

<a name="security"></a>
## Security

There is a reason why the security is the first item in this list. It's important to understand that this operation creates an endpoint where authorized users can upload files to your server. Everytime uploads are allowed, you should be aware of the security implications and take the necessary steps to prevent unauthorized uploads to your server.

All Backpack fields that allow the user to upload files have their correspondent [validation rules](https://backpackforlaravel.com/docs/custom-validation-rules) to ensure that only allowed files are uploaded.

This enpoint comes with a default security configuration, only allow the upload of `jpg/jpeg/png/gif` images with a maximum size of 1MB. To overwrite this configuration, you need to validate your field using the previously mentioned rules that apply for your field, for example `ValidDropzone` or `ValidEasyMDE`.


<a name="how-to-use"></a>
## How to Use

In order to enable this operation, in your CrudController you need to **use the `AjaxUploadOperation` trait**. For example:

```php
use \Backpack\Pro\Http\Controllers\Operations\AjaxUploadOperation;

protected function setupAjaxUploadOperation()
{
if(! backpack_user()->hasRole('admin')) {
$this->crud->denyAccess('ajax-upload');
}
}
```

This operation will create an endpoint at `/crud/{EntityName}/ajax-upload`. This endpoint is used by the fields to upload files via AJAX. How those fields are stored is the responsability of each of the [field uploaders](https://backpackforlaravel.com/docs/crud-uploaders).

<a name="configuration"></a>
## Configuration

The operation accept has the following options:
| Option | Description | Default |
| --- | --- | --- |
| `temporary_disk` | The disk where the files will be stored temporarly. | `public` |
| `temporary_folder` | The folder inside the temporary disk where the files will be stored. | `backpack/temp` |
| `purge_temporary_files_older_than` | The number of hours after which temporary files are deleted. | `72` |
| `purge_after_request_dispatch` | If the temporary files should be deleted after the request has been served. | `true` |


To configure the temporary directory for ALL ajax upload operations, call `php artisan vendor:publish --provider="Backpack\Pro\AddonServiceProvider" --tag="ajax-upload-config"` and then edit the `config/backpack/operations/ajax-upload.php` file to fit your needs.

Alternatively, you can also configure the temporary directory only for the specific CRUDs by using:

```php
public function setupAjaxUploadOperation()
{
CRUD::setOperationSetting('temporary_disk', 'public');
CRUD::setOperationSetting('temporary_folder', 'backpack/temp');
CRUD::setOperationSetting('purge_temporary_files_older_than', 72);
CRUD::setOperationSetting('purge_after_request_dispatch', true);
}
```

**Delete Old Temp Files**

This enpoint automatically trigger the cleaning of the temporary directory files after the request has been served. Check `puge_after_request_dispatch` option to disable this behavior.
You can also run the `backpack:purge-temporary-files` command, to clean the temporary directory.

```bash
php artisan backpack:purge-temporary-files --older-than=24 --disk=public --path="backpack/temp"
```

It accepts the following optional parameters:
- `--older-than=24`: the number of hours after which temporary files are deleted.
- `--disk=public`: the disk used by the temporary files.
- `--path="backpack/temp"`: the folder inside the disk where files will be stored.


You can use any strategy to run this command periodically - a cron job, a scheduled task or hooking into application termination hooks. Laravel provides a very easy way to setup your scheduled tasks. You can read more about it [here](https://laravel.com/docs/scheduling). For example, you can run the command every hour by adding the following line to your `app/Console/Kernel.php` in the `schedule()` method:
```php
// app/Console/Kernel.php
$schedule->command('backpack:purge-temporary-files')->hourly();
```

After adding this, you need to setup a cron job that will process the Laravel scheduler. You can manually run it in development with `php artisan schedule:run`. For production, you can setup a cron job take care of it for you. You can read more about it [here](https://laravel.com/docs/scheduling#running-the-scheduler).
5 changes: 5 additions & 0 deletions 6.x/crud-uploaders.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ This allows you to overwrite or set the uploader class for this field. You can u
- **`fileNamer`** - default: **null**
It accepts a `FileNameGeneratorInterface` instance or a closure. As the name implies, this will be used to generate the file name. Read more about in the [Naming uploaded files](#upload-name-files) section.

<a name="upload-validation"></a>
### Upload Validation

We can't stress enough how **IMPORTANT** is to properly validate and autenticate the file uploads and the upload endpoints. We have created a set of custom validation rules that will make validation of upload fields dead-simple. Please see the [Custom Validation Rules](https://backpackforlaravel/docs/custom-validation-rules) section for more information.

<a name="handling-uploaders-in-relationship-fields"></a>
### Handling uploads in relationship fields

Expand Down
19 changes: 19 additions & 0 deletions 6.x/custom-validation-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,23 @@ use Backpack\Pro\Uploads\Validation\ValidDropzone;

'attachments' => ValidDropzone::field('min:2|max:5')->file('file|mimes:jpg,png,gif|max:10000'),

```

<a name="valid-easymde-validation-rule"></a>
## `ValidEasyMDE` for `easymde` field type

You can use this validation rule to handle validation for your `easymde` field - both for the Create and the Update operation in one go:
- use the `::field()` constructor to define the rules for the field;
- use the `->file()` method for rules specific to the files sent in field;

```php
// for the field
CRUD::field('photos')->type('dropzone');

// you can write the validation rule as

use Backpack\Pro\Uploads\Validation\ValidEasyMDE;

'easymde' => ValidEasyMDE::field('min:50|max:3000')->file('file|mimes:jpg,png,gif|max:2048'),

```