add saving files documentModel #4
This commit is contained in:
parent
f22925dc03
commit
9adb323862
33 changed files with 1183 additions and 9385 deletions
44
app/Enums/Documents/LangEnum.php
Normal file
44
app/Enums/Documents/LangEnum.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Documents;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @method static self fr()
|
||||
* @method static self en()
|
||||
* @method static self de()
|
||||
* @method static self nl()
|
||||
*/
|
||||
final class LangEnum extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'fr' => 1,
|
||||
'en' => 2,
|
||||
'de' => 3,
|
||||
'nl' => 4,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* enum labels
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'fr' => 'Français (FR)',
|
||||
'en' => 'Anglais (EN)',
|
||||
'de' => 'Allemand (DE)',
|
||||
'nl' => 'Néerlandais (NL)',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ class DirectoriesController extends Controller
|
|||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Directory\StoreDirectoryRequest $request
|
||||
* @param \App\Http\Requests\Bo\Directory\StoreDirectoryRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreDirectoryRequest $request)
|
||||
|
|
@ -104,7 +104,7 @@ class DirectoriesController extends Controller
|
|||
{
|
||||
return DB::transaction(function () use ($directory) {
|
||||
foreach ($directory->children as $directoryChild) {
|
||||
$directoryChild->parent_id = null;
|
||||
$directoryChild->directory_id = null;
|
||||
$directoryChild->saveOrFail();
|
||||
}
|
||||
if ($directory->deleteOrFail()) {
|
||||
|
|
@ -136,18 +136,18 @@ class DirectoriesController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* Assign the new order and parent id to each directory.
|
||||
* Assign the new order and directory id to each directory.
|
||||
*
|
||||
* @param array $directories
|
||||
* @param mixed $parentId
|
||||
* @param mixed $directoryId
|
||||
* @return void
|
||||
*/
|
||||
public function assignOrder(array $directories, mixed $parentId = null)
|
||||
public function assignOrder(array $directories, mixed $directoryId = null)
|
||||
{
|
||||
foreach ($directories as $newDirectory) {
|
||||
$directory = Directory::where('id', $newDirectory['id'])->first();
|
||||
$directory['order'] = $newDirectory['order'];
|
||||
$directory['parent_id'] = $parentId;
|
||||
$directory = Directory::where('id', $newDirectory['id'])->first();
|
||||
$directory['order'] = $newDirectory['order'];
|
||||
$directory['directory_id'] = $directoryId;
|
||||
$directory->saveOrFail();
|
||||
if (isset($newDirectory['children']) && count($newDirectory['children']) > 0) {
|
||||
$this->assignOrder($newDirectory['children'], $newDirectory['id']);
|
||||
|
|
|
|||
|
|
@ -3,20 +3,22 @@
|
|||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Document\StoreDocumentRequest;
|
||||
use App\Http\Requests\Bo\Document\UpdateDocumentRequest;
|
||||
use App\Http\Requests\Bo\Documents\StoreDocumentRequest;
|
||||
use App\Http\Requests\Bo\Documents\UpdateDocumentRequest;
|
||||
use App\Models\Directory;
|
||||
use App\Models\Document;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Controllers\UpdateModelStatus;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException;
|
||||
use Pion\Laravel\ChunkUpload\Handler\HandlerFactory;
|
||||
use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;
|
||||
|
||||
class DocumentController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use UpdateModelStatus;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
|
|
@ -53,9 +55,8 @@ class DocumentController extends Controller
|
|||
*/
|
||||
public function create()
|
||||
{
|
||||
$documents = Document::where('status', true)->get();
|
||||
$directories = Directory::renderDirectories(Directory::where('needAuthorization', 1)
|
||||
->orderBy('name', 'ASC')->get());
|
||||
$documents = Document::get();
|
||||
$directories = Directory::getChildrenDirectories();
|
||||
|
||||
return view('bo.pages.documents.create', compact('documents', 'directories'));
|
||||
}
|
||||
|
|
@ -63,7 +64,7 @@ class DocumentController extends Controller
|
|||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Document\StoreDocumentRequest $request
|
||||
* @param \App\Http\Requests\Bo\Documents\StoreDocumentRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(StoreDocumentRequest $request)
|
||||
|
|
@ -98,9 +99,8 @@ class DocumentController extends Controller
|
|||
*/
|
||||
public function edit(Document $document)
|
||||
{
|
||||
$documents = Document::where('status', true)->get();
|
||||
$directories = Directory::renderDirectories(Directory::where('needAuthorization', 1)
|
||||
->orderBy('name', 'ASC')->get());
|
||||
$documents = Document::get();
|
||||
$directories = Directory::getChildrenDirectories();
|
||||
|
||||
return view('bo.pages.documents.edit', [
|
||||
'documents' => $documents,
|
||||
|
|
@ -118,13 +118,8 @@ class DocumentController extends Controller
|
|||
*/
|
||||
public function update(UpdateDocumentRequest $request, Document $document)
|
||||
{
|
||||
$params = $request->validated();
|
||||
if (\is_null($params['password'])) {
|
||||
unset($params['password']);
|
||||
}
|
||||
return DB::transaction(function () use ($params, $document) {
|
||||
$document->fill($params);
|
||||
|
||||
return DB::transaction(function () use ($request, $document) {
|
||||
$document->fill($request->validated());
|
||||
if ($document->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.documents.edit', $document)
|
||||
|
|
@ -166,4 +161,68 @@ class DocumentController extends Controller
|
|||
['model' => Str::singular(trans('models.classes.documents'))]
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws \Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException Bla.
|
||||
*/
|
||||
public function upload(Request $request)
|
||||
{
|
||||
if (isset($request->uuid)) {
|
||||
$uuid = $request->uuid;
|
||||
} else {
|
||||
$uuid = false;
|
||||
}
|
||||
// Create the file receiver.
|
||||
$receiver = new FileReceiver("file", $request, HandlerFactory::classFromRequest($request));
|
||||
// Check if the upload is success, throw exception or return response you need.
|
||||
if ($receiver->isUploaded() === false) {
|
||||
throw new UploadMissingFileException();
|
||||
}
|
||||
// Receive the file.
|
||||
$save = $receiver->receive();
|
||||
// Check if the upload has finished (in chunk mode it will send smaller files).
|
||||
if ($save->isFinished()) {
|
||||
// Save the file and return any response you need, current example uses `move` function.
|
||||
// If you are not using move, you need to manually delete the file: unlink($save->getFile()->getPathname()).
|
||||
return $this->saveFile($save->getFile(), $uuid);
|
||||
}
|
||||
// We are in chunk mode, lets send the current progress.
|
||||
/** @var AbstractHandler $handler */
|
||||
$handler = $save->handler();
|
||||
return response()->json([
|
||||
"done" => $handler->getPercentageDone(),
|
||||
'status' => true
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\UploadedFile $file
|
||||
* @param mixed $uuid
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException Bla.
|
||||
*/
|
||||
protected function saveFile(UploadedFile $file, mixed $uuid)
|
||||
{
|
||||
if ($uuid === false) {
|
||||
$uuid = sprintf(
|
||||
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff)
|
||||
);
|
||||
}
|
||||
$finalPath = storage_path('app/public/docs/');
|
||||
// Move the file name.
|
||||
$file->move($finalPath, $uuid . '.' . $file->getClientOriginalExtension());
|
||||
return response()->json([
|
||||
'uid' => $uuid,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Document;
|
||||
namespace App\Http\Requests\Bo\Documents;
|
||||
|
||||
use App\Enums\Documents\LangEnum;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
|
||||
class StoreDocumentRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -16,18 +18,6 @@ class StoreDocumentRequest extends FormRequest
|
|||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'status' => $this->status ? true : false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
|
|
@ -36,8 +26,16 @@ class StoreDocumentRequest extends FormRequest
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
'uuid' => 'required|min:3|max:255',
|
||||
'title' => 'required|min:3|max:255',
|
||||
'status' => 'required|boolean'
|
||||
'type' => 'required|min:3|max:255',
|
||||
'directory_id' => 'sometimes|nullable|integer',
|
||||
'document_id' => 'sometimes|nullable|integer',
|
||||
'path' => 'required|min:3|max:255',
|
||||
'lang' => [
|
||||
'required',
|
||||
new EnumIsValidRule(LangEnum::class)
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -50,7 +48,6 @@ class StoreDocumentRequest extends FormRequest
|
|||
{
|
||||
return [
|
||||
'title' => \trans('titre'),
|
||||
'status' => \trans('statut')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Document;
|
||||
namespace App\Http\Requests\Bo\Documents;
|
||||
|
||||
class UpdateDocumentRequest extends StoreDocumentRequest
|
||||
{
|
||||
|
|
@ -2,14 +2,13 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property integer $id
|
||||
* @property string $name
|
||||
* @property integer $parent_id
|
||||
* @property integer $directory_id
|
||||
* @property integer $order
|
||||
* @property boolean $needAuthorization
|
||||
*/
|
||||
|
|
@ -31,7 +30,7 @@ class Directory extends Model
|
|||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'parent_id',
|
||||
'directory_id',
|
||||
'order',
|
||||
'needAuthorization'
|
||||
];
|
||||
|
|
@ -55,27 +54,16 @@ class Directory extends Model
|
|||
static::creating(function (self $model) {
|
||||
self::setOrder($model);
|
||||
});
|
||||
static::deleting(function (self $tag) {
|
||||
$tag->appusers()->detach();
|
||||
static::deleting(function (self $model) {
|
||||
$model->appusers()->detach();
|
||||
foreach ($model->documents as $key => $document) {
|
||||
$document->delete();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Asserts using validation that the field is unique.
|
||||
*
|
||||
* @param string $nameField
|
||||
* @param string $valueField
|
||||
* @param integer|null $id
|
||||
* @return void
|
||||
*/
|
||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
||||
{
|
||||
$table = (new self())->getTable();
|
||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
|
|
@ -132,6 +120,22 @@ class Directory extends Model
|
|||
return $nameDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename directory.
|
||||
*
|
||||
* @return LaravelModelList
|
||||
*/
|
||||
public static function getChildrenDirectories()
|
||||
{
|
||||
$directories = [];
|
||||
foreach (Directory::orderBy('order', 'ASC')->get()->toArray() as $key => $value) {
|
||||
if (count(Directory::get()[$key]->children) === 0) {
|
||||
array_push($directories, Directory::get()[$key]);
|
||||
}
|
||||
}
|
||||
return Directory::renderDirectories($directories);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -141,7 +145,7 @@ class Directory extends Model
|
|||
*/
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Directory', 'parent_id');
|
||||
return $this->belongsTo('App\Models\Directory', 'directory_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -151,7 +155,7 @@ class Directory extends Model
|
|||
*/
|
||||
public function children()
|
||||
{
|
||||
return $this->hasMany('App\Models\Directory', 'parent_id');
|
||||
return $this->hasMany('App\Models\Directory', 'directory_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Enums\TypeEnum;
|
|||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* @property integer $id
|
||||
|
|
@ -13,7 +14,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||
* @property string $title
|
||||
* @property string $type
|
||||
* @property integer $directory_id
|
||||
* @property integer $parent_id
|
||||
* @property integer $document_id
|
||||
* @property string $path
|
||||
* @property string $lang
|
||||
* @property boolean $status
|
||||
|
|
@ -33,7 +34,7 @@ class Document extends Model
|
|||
'title',
|
||||
'type',
|
||||
'directory_id',
|
||||
'parent_id',
|
||||
'document_id',
|
||||
'path',
|
||||
'lang',
|
||||
'status',
|
||||
|
|
@ -46,6 +47,7 @@ class Document extends Model
|
|||
* @var array
|
||||
*/
|
||||
protected $enumCasts = [
|
||||
'lang' => LangEnum::class,
|
||||
'type' => TypeEnum::class,
|
||||
];
|
||||
|
||||
|
|
@ -60,6 +62,9 @@ class Document extends Model
|
|||
self::assertFieldIsUnique('title', $model->title);
|
||||
self::setOrder($model);
|
||||
});
|
||||
static::deleting(function (self $model) {
|
||||
self::removeDocument($model);
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
|
@ -100,6 +105,24 @@ class Document extends Model
|
|||
return $this->id === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return void
|
||||
*/
|
||||
private static function removeDocument(Model $model): void
|
||||
{
|
||||
$path = \ltrim(\urldecode("storage/docs/" . $model->uuid . $model->type), '/');
|
||||
if (\strpos($path, 'storage') !== 0) {
|
||||
return;
|
||||
}
|
||||
$path = ToolboxHelper::mbReplace('storage/', '', $path);
|
||||
if (Storage::disk('public')->exists($path)) {
|
||||
Storage::disk('public')->delete($path);
|
||||
}
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -119,7 +142,7 @@ class Document extends Model
|
|||
*/
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Documents', 'parent_id');
|
||||
return $this->belongsTo('App\Models\Documents', 'document_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -129,7 +152,7 @@ class Document extends Model
|
|||
*/
|
||||
public function children()
|
||||
{
|
||||
return $this->hasMany('App\Models\Documents', 'parent_id');
|
||||
return $this->hasMany('App\Models\Documents', 'document_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
"ldc/web-status-checker-laravel": "^1.0",
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"mews/purifier": "^3.3",
|
||||
"pion/laravel-chunk-upload": "^1.3",
|
||||
"sentry/sentry-laravel": "^3.2",
|
||||
"spatie/laravel-mix-preload": "^1.3"
|
||||
},
|
||||
|
|
|
|||
68
composer.lock
generated
68
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c367b4aa61b358b61bfe2b48a3a4e6ef",
|
||||
"content-hash": "e4d55d87b73a5b31ed2ede4aae62895a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
|
|
@ -3777,6 +3777,72 @@
|
|||
],
|
||||
"time": "2023-02-25T19:38:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pion/laravel-chunk-upload",
|
||||
"version": "v1.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pionl/laravel-chunk-upload.git",
|
||||
"reference": "dcf5cf42059910242c31fc34d0ea147d07478473"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pionl/laravel-chunk-upload/zipball/dcf5cf42059910242c31fc34d0ea147d07478473",
|
||||
"reference": "dcf5cf42059910242c31fc34d0ea147d07478473",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/console": "5.2 - 5.8 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0",
|
||||
"illuminate/filesystem": "5.2 - 5.8 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0",
|
||||
"illuminate/http": "5.2 - 5.8 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0",
|
||||
"illuminate/support": "5.2 - 5.8 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.16.0",
|
||||
"mockery/mockery": "^1.1.0 | ^1.3.0",
|
||||
"overtrue/phplint": "^1.1 | ^2.0",
|
||||
"phpunit/phpunit": "5.7 | 6.0 | 7.0 | 7.5 | 8.4 | ^8.5 | ^9.3 | ^10.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Pion\\Laravel\\ChunkUpload\\Providers\\ChunkUploadServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Pion\\Laravel\\ChunkUpload\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Martin Kluska",
|
||||
"email": "martin@kluska.cz"
|
||||
}
|
||||
],
|
||||
"description": "Service for chunked upload with several js providers",
|
||||
"support": {
|
||||
"issues": "https://github.com/pionl/laravel-chunk-upload/issues",
|
||||
"source": "https://github.com/pionl/laravel-chunk-upload/tree/v1.5.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://revolut.me/martinpv7n",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/pionl",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-15T21:02:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "1.1.1",
|
||||
|
|
|
|||
52
config/chunk-upload.php
Normal file
52
config/chunk-upload.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @see https://github.com/pionl/laravel-chunk-upload
|
||||
*/
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
* The storage config
|
||||
*/
|
||||
|
||||
'storage' => [
|
||||
|
||||
/*
|
||||
* Returns the folder name of the chunks. The location is in storage/app/{folder_name}
|
||||
*/
|
||||
|
||||
'chunks' => 'chunks',
|
||||
'disk' => 'local',
|
||||
],
|
||||
'clear' => [
|
||||
|
||||
/*
|
||||
* How old chunks we should delete
|
||||
*/
|
||||
|
||||
'timestamp' => '-3 HOURS',
|
||||
'schedule' => [
|
||||
'enabled' => true,
|
||||
// Run every hour on the 25th minute.
|
||||
'cron' => '25 * * * *',
|
||||
],
|
||||
],
|
||||
'chunk' => [
|
||||
// Setup for the chunk naming setup to ensure same name upload at same time.
|
||||
'name' => [
|
||||
'use' => [
|
||||
// Should the chunk name use the session id? The uploader must send cookie!
|
||||
'session' => true,
|
||||
// Instead of session we can use the ip and browser?
|
||||
'browser' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
'handlers' => [
|
||||
// A list of handlers/providers that will be appended to existing list of handlers.
|
||||
'custom' => [],
|
||||
// Overrides the list of handlers - use only what you really want.
|
||||
'override' => [],
|
||||
],
|
||||
];
|
||||
|
|
@ -31,7 +31,7 @@ class DirectoryFactory extends Factory
|
|||
"de" => $this->faker->unique()->word,
|
||||
"nl" => $this->faker->unique()->word,
|
||||
],
|
||||
'parent_id' => null,
|
||||
'directory_id' => null,
|
||||
'needAuthorization' => $this->faker->boolean(50),
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class DocumentFactory extends Factory
|
|||
{
|
||||
return [
|
||||
'title' => $this->faker->unique()->word,
|
||||
'parent_id' => null,
|
||||
'document_id' => null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ class UpdateDirectoryTable extends Migration
|
|||
{
|
||||
Schema::table('directories', function (Blueprint $table) {
|
||||
$table->dropForeign('directories_parent_foreign');
|
||||
$table->renameColumn('parent', 'parent_id');
|
||||
$table->foreign(['parent_id'])->references(['id'])->on('directories');
|
||||
$table->dropColumn('parent');
|
||||
$table->unsignedBigInteger('directory_id')->index()->nullable()->after('id');
|
||||
$table->foreign(['directory_id'])->references(['id'])->on('directories');
|
||||
$table->json('name')->change();
|
||||
});
|
||||
}
|
||||
|
|
@ -29,8 +30,9 @@ class UpdateDirectoryTable extends Migration
|
|||
public function down()
|
||||
{
|
||||
Schema::table('directories', function (Blueprint $table) {
|
||||
$table->dropForeign('directories_parent_id_foreign');
|
||||
$table->renameColumn('parent_id', 'parent');
|
||||
$table->dropForeign('directories_directory_id_foreign');
|
||||
$table->dropColumn('directory_id');
|
||||
$table->unsignedBigInteger('parent')->nullable()->index();
|
||||
$table->foreign(['parent'])->references('id')->on('directories');
|
||||
$table->string('name')->change();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,11 +15,15 @@ class UpdateDocumentTable extends Migration
|
|||
{
|
||||
Schema::table('documents', function (Blueprint $table) {
|
||||
$table->dropForeign('documents_directory_foreign');
|
||||
$table->renameColumn('directory', 'directory_id');
|
||||
$table->dropColumn('directory');
|
||||
$table->unsignedBigInteger('directory_id')->index()->nullable()->after('id');
|
||||
$table->foreign(['directory_id'])->references(['id'])->on('directories');
|
||||
$table->renameColumn('parent', 'parent_id');
|
||||
$table->renameColumn('published', 'status');
|
||||
$table->dropColumn('parent');
|
||||
$table->unsignedBigInteger('document_id')->index()->nullable()->after('directory_id');
|
||||
$table->foreign(['document_id'])->references(['id'])->on('documents')->constrained();
|
||||
$table->integer('order')->after('published')->comment('Ordonnance des documents.');
|
||||
$table->string('type', 255)->change();
|
||||
$table->dropColumn('published');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -32,11 +36,16 @@ class UpdateDocumentTable extends Migration
|
|||
{
|
||||
Schema::table('documents', function (Blueprint $table) {
|
||||
$table->dropForeign('documents_directory_id_foreign');
|
||||
$table->renameColumn('parent_id', 'parent');
|
||||
$table->foreign(['parent'])->references('id')->on('directories');
|
||||
$table->renameColumn('parent_id', 'parent');
|
||||
$table->renameColumn('status', 'published');
|
||||
$table->dropColumn('directory_id');
|
||||
$table->unsignedBigInteger('directory')->index();
|
||||
$table->foreign(['directory'])->references(['id'])->on('directories');
|
||||
$table->dropForeign('documents_document_id_foreign');
|
||||
$table->dropColumn('document_id');
|
||||
$table->unsignedBigInteger('parent')->index();
|
||||
$table->foreign(['parent'])->references(['id'])->on('documents');
|
||||
$table->dropColumn('order');
|
||||
$table->string('type', 3)->change();
|
||||
$table->boolean('published');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
9411
package-lock.json
generated
9411
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -43,6 +43,7 @@
|
|||
"postcss": "^8.1.14",
|
||||
"prettier": "^2.7.1",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"resumablejs": "^1.1.0",
|
||||
"sass": "^1.54.8",
|
||||
"sass-loader": "^12.6.0",
|
||||
"slugify": "^1.6.5",
|
||||
|
|
|
|||
1
resources/sass/bo/vendor/_bootstrap.scss
vendored
1
resources/sass/bo/vendor/_bootstrap.scss
vendored
|
|
@ -37,6 +37,7 @@
|
|||
@import "~bootstrap/scss/close";
|
||||
@import "~bootstrap/scss/card";
|
||||
@import "~bootstrap/scss/breadcrumb";
|
||||
@import "~bootstrap/scss/progress";
|
||||
|
||||
// 6. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
|
||||
@import "~bootstrap/scss/utilities/api";
|
||||
|
|
|
|||
|
|
@ -1,182 +0,0 @@
|
|||
<template>
|
||||
<div class="row">
|
||||
<!-- FILE LANGUAGE -->
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label
|
||||
for="selectLanguageDocument"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Langue du document") }} *</b>
|
||||
</label>
|
||||
<select
|
||||
id="selectLanguageDocument"
|
||||
class="form-select"
|
||||
aria-label="Default select example"
|
||||
@click="languageDocument($event)"
|
||||
role="button"
|
||||
>
|
||||
<option
|
||||
v-for="(language, languageIndex) in intLanguages"
|
||||
:key="languageIndex"
|
||||
:value="languageIndex"
|
||||
>
|
||||
{{ language }}
|
||||
</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Choisissez une langue parmis la liste.") }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- INPUT NAME -->
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label
|
||||
:for="intId"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Titre du document") }} *</b>
|
||||
</label>
|
||||
<WordCounter
|
||||
:id="intId"
|
||||
class="ck-word-count"
|
||||
/>
|
||||
<input
|
||||
:id="intId"
|
||||
type="text"
|
||||
:name="intName"
|
||||
class="form-control need-word-counter"
|
||||
:placeholder="intPlaceholder"
|
||||
:value="intModel?.title"
|
||||
>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Doit posséder 3 caractères minimum, 255 maximum.") }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- SELECT DIRECTORY -->
|
||||
<div
|
||||
v-if="intIsDocFR"
|
||||
class="col-12 col-md-6 mb-3"
|
||||
>
|
||||
<label
|
||||
:for="intId"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Dossier à associer") }} *</b>
|
||||
</label>
|
||||
<select
|
||||
id="directoryDirectoryId"
|
||||
class="form-select"
|
||||
name="directory_id"
|
||||
aria-describedby="directoryDirectoryIdHelp"
|
||||
role="button"
|
||||
>
|
||||
<option
|
||||
v-for="(directory, directoryIndex) in intDirectories"
|
||||
:key="directoryIndex"
|
||||
:value="directoryIndex"
|
||||
:selected="intModel?.directory_id === directory.id ? true : false"
|
||||
>
|
||||
{{ directory.name }}
|
||||
</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Choisissez un dossier à associer parmis la liste.") }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- SELECT FRENCH DOCUMENT -->
|
||||
<div
|
||||
v-else
|
||||
class="col-12 col-md-6 mb-3"
|
||||
>
|
||||
<label
|
||||
:for="intId"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Document français à associer") }} *</b>
|
||||
</label>
|
||||
<select
|
||||
id="documentParentId"
|
||||
class="form-select"
|
||||
name="parent_id"
|
||||
aria-describedby="documentParentIdHelp"
|
||||
role="button"
|
||||
>
|
||||
<option
|
||||
v-for="(document, documentIndex) in intDocuments"
|
||||
:key="documentIndex"
|
||||
:value="documentIndex"
|
||||
>
|
||||
{{ document.title }}
|
||||
</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Choisissez un document français à associer parmis la liste.") }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- CHOOSE FILE -->
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label
|
||||
:for="intId"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Document à ajouter") }} *</b>
|
||||
</label>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Doit être au format .pdf ou .mp4.") }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import WordCounter from "./WordCounterComponent.vue";
|
||||
import trans from "./../../modules/trans";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AddDocumentComponent",
|
||||
mixins: [trans],
|
||||
components: {
|
||||
WordCounter,
|
||||
},
|
||||
data(): {
|
||||
intId: string;
|
||||
intName: string;
|
||||
intPlaceholder: string;
|
||||
intLanguages: string[];
|
||||
intDocuments: { title: string }[];
|
||||
intDirectories: LaravelModel[];
|
||||
intIsDocFR: boolean;
|
||||
intModel: LaravelModel | null;
|
||||
} {
|
||||
return {
|
||||
intId: "",
|
||||
intName: "",
|
||||
intPlaceholder: "",
|
||||
intDocuments: [],
|
||||
intDirectories: [],
|
||||
intLanguages: [],
|
||||
intIsDocFR: true,
|
||||
intModel: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
this.intId = data.id;
|
||||
this.intName = data.name;
|
||||
this.intPlaceholder = data.placeholder;
|
||||
this.intLanguages = data.languages;
|
||||
this.intDocuments = data.documents;
|
||||
this.intDirectories = data.directories;
|
||||
this.intModel = data.model;
|
||||
},
|
||||
methods: {
|
||||
languageDocument(e: Event) {
|
||||
const target = e.target as HTMLSelectElement;
|
||||
this.intIsDocFR = target.value === "0" ? true : false;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
403
resources/ts/bo/components/CrudDocumentInputComponent.vue
Normal file
403
resources/ts/bo/components/CrudDocumentInputComponent.vue
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
<template>
|
||||
<div :class="`crud-document-input-${intId} row`">
|
||||
<!-- FILE LANGUAGE -->
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label
|
||||
for="selectLanguageDocument"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Langue du document") }} *</b>
|
||||
</label>
|
||||
<select
|
||||
id="selectLanguageDocument"
|
||||
name="lang"
|
||||
class="form-select"
|
||||
aria-label="Select language for the document"
|
||||
@click="languageDocument($event)"
|
||||
role="button"
|
||||
>
|
||||
<option
|
||||
v-for="(language, languageIndex) in intLanguages"
|
||||
:key="languageIndex"
|
||||
:value="language.value"
|
||||
>
|
||||
{{ language.label }}
|
||||
</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Choisissez une langue parmis la liste.") }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- INPUT NAME -->
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label
|
||||
for="documentTitle"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Titre du document") }} *</b>
|
||||
</label>
|
||||
<WordCounter
|
||||
id="documentTitle"
|
||||
class="ck-word-count"
|
||||
/>
|
||||
<input
|
||||
id="documentTitle"
|
||||
type="text"
|
||||
name="title"
|
||||
class="form-control need-word-counter"
|
||||
:placeholder="__('Un beau titre de document')"
|
||||
:value="intModel?.title"
|
||||
>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Doit posséder 3 caractères minimum, 255 maximum.") }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- SELECT DIRECTORY -->
|
||||
<div
|
||||
v-if="intIsDocFR"
|
||||
class="col-12 col-md-6 mb-3"
|
||||
>
|
||||
<label
|
||||
for="directoryDirectoryId"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Dossier à associer") }} *</b>
|
||||
</label>
|
||||
<select
|
||||
id="directoryDirectoryId"
|
||||
class="form-select"
|
||||
name="directory_id"
|
||||
aria-describedby="directoryDirectoryIdHelp"
|
||||
role="button"
|
||||
>
|
||||
<option
|
||||
v-for="(directory, directoryIndex) in intDirectories"
|
||||
:key="directoryIndex"
|
||||
:value="directory.id"
|
||||
:selected="intModel?.directory_id === directory.id ? true : false"
|
||||
>
|
||||
{{ directory.name }}
|
||||
</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Choisissez un dossier à associer parmis la liste.") }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- SELECT FRENCH DOCUMENT -->
|
||||
<div
|
||||
v-else
|
||||
class="col-12 col-md-6 mb-3"
|
||||
>
|
||||
<label
|
||||
for="documentParentId"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Document français à associer") }} *</b>
|
||||
</label>
|
||||
<select
|
||||
v-if="intDocuments.length > 0"
|
||||
id="documentParentId"
|
||||
class="form-select"
|
||||
name="document_id"
|
||||
aria-describedby="documentParentIdHelp"
|
||||
role="button"
|
||||
>
|
||||
<option
|
||||
v-for="(document, documentIndex) in intDocuments"
|
||||
:key="documentIndex"
|
||||
:value="documentIndex"
|
||||
>
|
||||
{{ document.title }}
|
||||
</option>
|
||||
</select>
|
||||
<p class="text-muted">
|
||||
{{ __("Aucun documents français n'est disponible") }}
|
||||
</p>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Choisissez un document français à associer parmis la liste.") }}
|
||||
</small>
|
||||
</div>
|
||||
<!-- CHOOSE FILE -->
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label
|
||||
for="documentInputFile"
|
||||
class="col-form-label"
|
||||
>
|
||||
<b>{{ __("Document à ajouter") }} *</b>
|
||||
</label>
|
||||
<div v-if="!intIsUploading">
|
||||
<div class="input-group">
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
type="button"
|
||||
data-bs="tooltip"
|
||||
:title="__('Modifier le document source')"
|
||||
>
|
||||
<FontAwesomeIcon icon="fa-solid fa-folder-open" />
|
||||
</button>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
role="button"
|
||||
ref="inputFile"
|
||||
:value="
|
||||
intDocumentDatas.path
|
||||
? intDocumentDatas.path
|
||||
: 'Sélectionnez un fichier'
|
||||
"
|
||||
data-bs="tooltip"
|
||||
:title="__('Modifier le document source')"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
<div v-if="intMessage">
|
||||
<p
|
||||
class="m-0"
|
||||
:class="intSuccess ? 'text-success' : 'text-danger'"
|
||||
>
|
||||
{{ intMessage }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="progress"
|
||||
>
|
||||
<div
|
||||
class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
ref="progressBar"
|
||||
role="progressbar"
|
||||
aria-label="Progress bar"
|
||||
aria-valuenow="0"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
>
|
||||
{{ intFilePercent }}%
|
||||
</div>
|
||||
</div>
|
||||
<small class="form-text text-muted">
|
||||
{{ __("Doit être au format .pdf ou .mp4.") }}
|
||||
</small>
|
||||
</div>
|
||||
<input
|
||||
class="d-none"
|
||||
name="path"
|
||||
:value="intDocumentDatas.path"
|
||||
>
|
||||
<input
|
||||
class="d-none"
|
||||
name="uuid"
|
||||
:value="intDocumentDatas.uuid"
|
||||
>
|
||||
<input
|
||||
class="d-none"
|
||||
name="type"
|
||||
:value="intDocumentDatas.type"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import { Tooltip } from "bootstrap";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import WordCounter from "./WordCounterComponent.vue";
|
||||
import route from "./../../modules/route";
|
||||
import trans from "./../../modules/trans";
|
||||
import Resumable from "resumablejs";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AddDocumentComponent",
|
||||
mixins: [route, trans],
|
||||
components: {
|
||||
WordCounter,
|
||||
FontAwesomeIcon,
|
||||
},
|
||||
data(): {
|
||||
intId: string;
|
||||
intMessage: string;
|
||||
intSuccess: boolean;
|
||||
intIsUploading: boolean;
|
||||
intFilePercent: number | null;
|
||||
intProgressbar: HTMLDivElement | null;
|
||||
intLanguages: {
|
||||
value: number;
|
||||
label: string;
|
||||
}[];
|
||||
intDocuments: { title: string }[];
|
||||
intDirectories: LaravelModel[];
|
||||
intIsDocFR: boolean;
|
||||
intModel: LaravelModel | null;
|
||||
intR: Resumable | null;
|
||||
intDocumentDatas: {
|
||||
directory_id: number;
|
||||
document_id: number | null;
|
||||
uuid: string;
|
||||
title: string;
|
||||
type: string;
|
||||
path: string;
|
||||
lang: string;
|
||||
published: boolean;
|
||||
};
|
||||
intCsrf: string;
|
||||
intTooltipList: HTMLButtonElement[];
|
||||
} {
|
||||
return {
|
||||
intId: "",
|
||||
intR: null,
|
||||
intMessage: "",
|
||||
intSuccess: false,
|
||||
intIsUploading: false,
|
||||
intFilePercent: 0,
|
||||
intProgressbar: null,
|
||||
intDocuments: [],
|
||||
intDirectories: [],
|
||||
intLanguages: [],
|
||||
intIsDocFR: true,
|
||||
intModel: null,
|
||||
intDocumentDatas: {
|
||||
directory_id: 0,
|
||||
document_id: null,
|
||||
uuid: "",
|
||||
title: "",
|
||||
type: "",
|
||||
path: "",
|
||||
lang: "",
|
||||
published: false,
|
||||
},
|
||||
intCsrf: "",
|
||||
intTooltipList: [],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
this.intId = data.id;
|
||||
this.intLanguages = data.languages;
|
||||
this.intDocuments = data.documents;
|
||||
this.intDirectories = data.directories;
|
||||
this.intModel = data.model;
|
||||
if (this.intModel != null) {
|
||||
this.intDocumentDatas.path = String(this.intModel.path);
|
||||
this.intDocumentDatas.uuid = String(this.intModel.uuid);
|
||||
this.intDocumentDatas.type = String(this.intModel.type);
|
||||
}
|
||||
this.intCsrf = data.csrf;
|
||||
this.$nextTick(() => {
|
||||
this.initResumable();
|
||||
this.updateBootstrapTooltip();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
languageDocument(e: Event) {
|
||||
const target = e.target as HTMLSelectElement;
|
||||
this.intIsDocFR =
|
||||
Number(target.value) === this.intLanguages[0].value ? true : false;
|
||||
},
|
||||
initResumable() {
|
||||
// Route.
|
||||
const uploadFileRoute = route.methods.route("bo.documents.upload");
|
||||
if (!uploadFileRoute) {
|
||||
throw new Error("Undefined route bo.documents.upload");
|
||||
}
|
||||
this.intR = new Resumable({
|
||||
chunkSize: 1024 * 1024, // 1MB
|
||||
simultaneousUploads: 1,
|
||||
maxFiles: 1,
|
||||
testChunks: false,
|
||||
target: uploadFileRoute,
|
||||
query: {
|
||||
_token: this.intCsrf,
|
||||
},
|
||||
});
|
||||
this.intR.on("fileAdded", this.fileAdded);
|
||||
this.intR.on("fileSuccess", this.fileSuccess);
|
||||
this.intR.on("fileError", this.fileError);
|
||||
this.intR.on("fileProgress", () => {
|
||||
if (this.intR !== null) {
|
||||
this.intFilePercent = Math.floor(this.intR.progress() * 100);
|
||||
if (this.intProgressbar !== null)
|
||||
this.intProgressbar.style.width = this.intFilePercent + "%";
|
||||
}
|
||||
});
|
||||
this.intR.assignBrowse(this.$refs.inputFile as Element, false);
|
||||
},
|
||||
/**
|
||||
*
|
||||
* @param file The file would like to store.
|
||||
*/
|
||||
fileAdded(file: any) {
|
||||
if (
|
||||
file.file.type !== "application/pdf" &&
|
||||
file.file.type !== "video/mp4"
|
||||
) {
|
||||
return !(this.intMessage = "Extension du fichier invalide.");
|
||||
}
|
||||
this.intIsUploading = true;
|
||||
setTimeout(() => {
|
||||
this.intProgressbar = this.$refs.progressBar as HTMLDivElement;
|
||||
this.intProgressbar.style.width = this.intFilePercent + "%";
|
||||
}, 10);
|
||||
this.closeBootstrapTooltip();
|
||||
if (this.intR !== null) this.intR.upload();
|
||||
},
|
||||
/**
|
||||
* Run method if the file is stored.
|
||||
* @param file The file stored.
|
||||
* @param message Set a new successful message.
|
||||
*/
|
||||
fileSuccess(file: any, message: string) {
|
||||
let result = JSON.parse(message);
|
||||
this.intDocumentDatas.path = file.fileName;
|
||||
this.intDocumentDatas.uuid = result.uid;
|
||||
if (file.file.type === "application/pdf") {
|
||||
this.intDocumentDatas.type = ".pdf";
|
||||
} else {
|
||||
this.intDocumentDatas.type = ".mp4";
|
||||
}
|
||||
this.intSuccess = true;
|
||||
this.intMessage = "Fichier chargé.";
|
||||
const intInputFileResult = this.$refs.progressBar as HTMLInputElement;
|
||||
intInputFileResult.value =
|
||||
this.intDocumentDatas.uuid + this.intDocumentDatas.type;
|
||||
setTimeout(() => {
|
||||
this.intIsUploading = false;
|
||||
this.$nextTick(() => {
|
||||
this.updateBootstrapTooltip();
|
||||
});
|
||||
}, 800);
|
||||
},
|
||||
/**
|
||||
* Set a new error message.
|
||||
*/
|
||||
fileError() {
|
||||
this.intMessage = "Une erreur est survenue, veuillez recharger la page.";
|
||||
},
|
||||
/**
|
||||
* Update Bootstrap tooltips.
|
||||
*/
|
||||
updateBootstrapTooltip() {
|
||||
let newTooltipList = [].slice.call(
|
||||
document.querySelectorAll(
|
||||
".crud-document-input-" + this.intId + " [data-bs=\"tooltip\"]"
|
||||
)
|
||||
) as HTMLButtonElement[];
|
||||
let tmp = newTooltipList.filter((x) => !this.intTooltipList.includes(x));
|
||||
tmp.map((tooltip) => {
|
||||
return new Tooltip(tooltip);
|
||||
});
|
||||
this.intTooltipList = newTooltipList;
|
||||
this.closeBootstrapTooltip();
|
||||
},
|
||||
/**
|
||||
* Close all Bootstrap tooltips.
|
||||
*/
|
||||
closeBootstrapTooltip() {
|
||||
this.intTooltipList.forEach((tooltip) => {
|
||||
tooltip.blur();
|
||||
Tooltip.getInstance(tooltip)?.hide();
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
@ -137,7 +137,7 @@ import trans from "../../modules/trans";
|
|||
type DirectoryObject = {
|
||||
id: number;
|
||||
name: string;
|
||||
parent_id: number | null;
|
||||
directory_id: number | null;
|
||||
text: string | null;
|
||||
order: number;
|
||||
needAuthorization: number;
|
||||
|
|
@ -189,7 +189,7 @@ export default defineComponent({
|
|||
* @param parent
|
||||
*/
|
||||
recursiveDir(list: DirectoryObject[], parent: number | null = null) {
|
||||
let root = list.filter((e: DirectoryObject) => e.parent_id == parent);
|
||||
let root = list.filter((e: DirectoryObject) => e.directory_id == parent);
|
||||
for (let i = 0; i < root.length; i++) {
|
||||
let childs = this.recursiveDir(list, root[i].id);
|
||||
root[i].children = [];
|
||||
|
|
@ -253,7 +253,7 @@ export default defineComponent({
|
|||
assignOrder(children: DirectoryObject[], parentId: number | null) {
|
||||
children.forEach((element, index) => {
|
||||
element.order = index;
|
||||
element.parent_id = parentId;
|
||||
element.directory_id = parentId;
|
||||
if (element.children && element.children.length) {
|
||||
element.children = this.assignOrder(element.children, element.id);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import {
|
|||
faLockOpen,
|
||||
faCircleCheck,
|
||||
faCircleXmark,
|
||||
faFloppyDisk,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
config.autoReplaceSvg = false;
|
||||
|
|
@ -77,6 +78,7 @@ library.add(faLock);
|
|||
library.add(faLockOpen);
|
||||
library.add(faCircleCheck);
|
||||
library.add(faCircleXmark);
|
||||
library.add(faFloppyDisk);
|
||||
|
||||
// Front
|
||||
library.add(faChevronLeft);
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ $ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
|
|||
</th>
|
||||
@endforeach
|
||||
{{-- Buttons Col --}}
|
||||
<th scope="col">
|
||||
<th class="text-end" scope="col">
|
||||
@if($noOrder and !$rst)
|
||||
<a class="btn btn-small btn-danger"
|
||||
<a class="btn btn-sm btn-danger"
|
||||
href="{{ request()->fullUrlWithQuery(['sort_col' => null, 'sort_way' => null, 'rst' => true, 'search' => null]) }}"
|
||||
data-bs-toggle="tooltip"
|
||||
title="{{ __('Supprimer le tri') }}">
|
||||
|
|
|
|||
|
|
@ -23,7 +23,12 @@
|
|||
</h1>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 d-flex justify-content-center justify-content-md-end align-items-center">
|
||||
<button id="formSubmitClone" class="btn btn-primary pull-end">{{ __('Save') }}</button>
|
||||
<button id="formSubmitClone"
|
||||
class="btn btn-primary pull-end"
|
||||
title="{{ __('Sauvegarder l\':model', ['model' => Str::singular(__('models.classes.app_users'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -37,9 +42,9 @@
|
|||
<button id="formSubmit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.app_users'))]) }}"
|
||||
title="{{ __('Sauvegarder l\':model', ['model' => Str::singular(__('models.classes.app_users'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
{{ __('Save') }}
|
||||
{{ __('Sauvegarder') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,12 +27,17 @@
|
|||
@method('DELETE')
|
||||
@csrf
|
||||
<div class="btn-group" role="group">
|
||||
<button id="formSubmitClone"
|
||||
class="btn btn-primary pull-end"
|
||||
title="{{ __('Sauvegarder l\':model', ['model' => Str::singular(__('models.classes.app_users'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
</button>
|
||||
<button class="btn btn-danger"
|
||||
title="{{ __('Supprimer :model', ['model' => Str::singular(__('models.classes.app_users'))]) }}"
|
||||
title="{{ __('Supprimer l\':model', ['model' => Str::singular(__('models.classes.app_users'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
<button id="formSubmitClone" class="btn btn-primary pull-end">{{ __('Save') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -48,9 +53,9 @@
|
|||
<button id="formSubmit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.app_users'))]) }}"
|
||||
title="{{ __('Sauvegarder l\':model', ['model' => Str::singular(__('models.classes.app_users'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
{{ __('Save') }}
|
||||
{{ __('Sauvegarder') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,16 +27,16 @@
|
|||
@method('POST')
|
||||
@csrf
|
||||
<div class="btn-group" role="group">
|
||||
<button class="btn btn-danger"
|
||||
title="{{ __('Supprimer le :model', ['model' => Str::singular(__('models.classes.directories'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
<button id="formSubmitClone"
|
||||
class="btn btn-primary pull-end"
|
||||
title="{{ __('Sauvegarder le :model', ['model' => Str::singular(__('models.classes.directories'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
{{ __('Sauvegarder') }}
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
</button>
|
||||
<button class="btn btn-danger"
|
||||
title="{{ __('Supprimer le :model', ['model' => Str::singular(__('models.classes.directories'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@
|
|||
<div class="col-12 input-group">
|
||||
<input
|
||||
id="directoryName"
|
||||
class="form-control @error('name') is-invalid @enderror"
|
||||
name="name"
|
||||
class="form-control @error('name[fr]') is-invalid @enderror"
|
||||
name="name[fr]"
|
||||
placeholder="{{ __('Ajouter un dossier (nom en français)') }}">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
class="btn btn-primary text-decoration-none m-0"
|
||||
data-bs="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ __('Return to the :model list', ['model' => __('models.classes.documents')]) }}"
|
||||
title="{{ __('Retourner sur la liste des :model', ['model' => __('models.classes.documents')]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
</a>
|
||||
|
|
@ -23,7 +23,12 @@
|
|||
</h1>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 d-flex justify-content-center justify-content-md-end align-items-center">
|
||||
<button id="formSubmitClone" class="btn btn-primary pull-end">{{ __('Save') }}</button>
|
||||
<button id="formSubmitClone"
|
||||
class="btn btn-primary pull-end"
|
||||
title="{{ __('Sauvegarder le :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -37,9 +42,9 @@
|
|||
<button id="formSubmit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
title="{{ __('Sauvegarder le :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
{{ __('Save') }}
|
||||
{{ __('Sauvegarder') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -27,12 +27,25 @@
|
|||
@method('DELETE')
|
||||
@csrf
|
||||
<div class="btn-group" role="group">
|
||||
<a href="{{ asset("storage/docs/" . $documentModel->uuid . $documentModel->type) }}"
|
||||
target="blank"
|
||||
class="btn btn-warning"
|
||||
role="button"
|
||||
title="{{ __('Visualiser le :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
</a>
|
||||
<button id="formSubmitClone"
|
||||
class="btn btn-primary pull-end"
|
||||
title="{{ __('Sauvegarder le :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
</button>
|
||||
<button class="btn btn-danger"
|
||||
title="{{ __('Supprimer :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
title="{{ __('Supprimer le :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
<button id="formSubmitClone" class="btn btn-primary pull-end">{{ __('Save') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -48,9 +61,9 @@
|
|||
<button id="formSubmit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Save :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
title="{{ __('Sauvegarder :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
{{ __('Save') }}
|
||||
{{ __('Sauvegarder') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,37 +6,14 @@
|
|||
@php
|
||||
$data = [
|
||||
'id' => 'document',
|
||||
'name' => 'title',
|
||||
'placeholder' => 'Un beau titre de document',
|
||||
'documents' => $documents,
|
||||
'directories' => $directories,
|
||||
'model' => $documentModel ?? null,
|
||||
'languages' => [
|
||||
"Français (FR)",
|
||||
"Anglais (EN)",
|
||||
"Allemand (DE)",
|
||||
"Néerlandais (NL)",
|
||||
]
|
||||
'languages' => \App\Enums\Documents\LangEnum::toArray(),
|
||||
'csrf' => csrf_token(),
|
||||
];
|
||||
@endphp
|
||||
<div class="add-document" data-json='@json($data)'></div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- STATUS --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Visibilité') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
@include('bo.partials.inputs.boolean-switch', [
|
||||
'id' => 'documentStatus',
|
||||
'name' => 'status',
|
||||
'label' => __('Le document est-il publié ?'),
|
||||
'model' => $documentModel ?? null,
|
||||
'helper' => __('Publication du document de l\'application.')
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
<div class="crud-document-input" data-json='@json($data)'></div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
$routeName = request()->route()->getName();
|
||||
$noOrder = Session::get("$routeName.sort_col") !== 'order' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
||||
$noOrder = Session::get("$routeName.sort_col") !== '' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
|
||||
$cols = ['title' => __('Title'), 'directory_id' => __('Dossier'), 'status' => __('Status'), 'order' => __('Order')];
|
||||
$cols = ['title' => __('Title'), 'directory_id' => __('Dossier'), 'order' => __('Order')];
|
||||
@endphp
|
||||
@include('bo.modules.table-col-sorter', [
|
||||
'cols' => $cols,
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
<span>{{ $documentModel->title }}</span>
|
||||
</td>
|
||||
<td>
|
||||
@if(!$documentModel->directory->is_system)
|
||||
<a href="{{ route('bo.directories.edit', ['directory' => $documentModel->directory_id]) }}">
|
||||
<button class="btn btn-sm btn-outline-dark"
|
||||
title="{{ __('Accéder au dossier') }}"
|
||||
|
|
@ -28,21 +29,7 @@
|
|||
{{ \App\Models\Directory::renderDirectories([$documentModel->directory])[0]->name }}
|
||||
</button>
|
||||
</a>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<form action="{{ route('bo.documents.change-published', $documentModel->id) }}" method="POST">
|
||||
@csrf
|
||||
<button type="submit"
|
||||
class="btn btn-sm @if($documentModel->status) btn-outline-success @else btn-outline-danger @endif"
|
||||
title="{{ __($documentModel->status ? __('Dépublier') : __('Publier')) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
@if($documentModel->status)
|
||||
<i class="fa-solid fa-circle-check"></i>
|
||||
@else
|
||||
<i class="fa-solid fa-circle-xmark"></i>
|
||||
@endif
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</td>
|
||||
@if(!$noOrder or $rst)
|
||||
<td class="align-middle">
|
||||
|
|
@ -78,16 +65,24 @@
|
|||
@method('DELETE')
|
||||
@csrf
|
||||
<div class="btn-group" role="group">
|
||||
<a href="{{ asset("storage/docs/" . $documentModel->uuid . $documentModel->type) }}"
|
||||
target="blank"
|
||||
class="btn btn-sm btn-warning"
|
||||
role="button"
|
||||
title="{{ __('Visualiser le :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
</a>
|
||||
<a id="formSubmitClone"
|
||||
href="{{ route('bo.documents.edit', $documentModel) }}"
|
||||
class="btn btn-sm btn-primary"
|
||||
role="button"
|
||||
title="{{ __('Modifier l\':model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
title="{{ __('Modifier le :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</a>
|
||||
<button class="btn btn-sm btn-danger"
|
||||
title="{{ __('Supprimer l\':model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
title="{{ __('Supprimer le :model', ['model' => Str::singular(__('models.classes.documents'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -12,4 +12,5 @@
|
|||
window.__SYSTEM._routes['bo.directories.edit'] = '{{ route('bo.directories.edit', 'ID') }}';
|
||||
window.__SYSTEM._routes['bo.directories.destroy'] = '{{ route('bo.directories.destroy', 'ID') }}';
|
||||
window.__SYSTEM._routes['bo.directories.need-authorization'] = '{{ route('bo.directories.need-authorization', 'ID') }}';
|
||||
window.__SYSTEM._routes['bo.documents.upload'] = '{{ route('bo.documents.upload') }}';
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -46,5 +46,6 @@ Route::prefix('bo')->name('bo.')->middleware(['admin-secure', 'throttle:credenti
|
|||
->name('documents.change-order');
|
||||
Route::post('/documents/{document}/change-published', [DocumentController::class, 'changePublished'])
|
||||
->name('documents.change-published');
|
||||
Route::post('/documents/upload', [DocumentController::class, 'upload'])->name('documents.upload');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"moduleResolution": "node",
|
||||
"typeRoots": ["resources/ts/@types", "node_modules/@types"]
|
||||
"typeRoots": ["resources/ts/@types", "node_modules/@types"],
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["resources/**/*.js", "resources/**/*.ts", "resources/**/*.vue"],
|
||||
"exclude": ["node_modules"],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue