From 56acb26137e7337fcaea1aaaa42e0345d8acafb0 Mon Sep 17 00:00:00 2001 From: A1Gard Date: Mon, 24 Jun 2024 21:08:48 +0330 Subject: [PATCH] added attachment controller --- app/Helpers/Helper.php | 51 ++++++ .../Admin/AttachmentController.php | 126 ++++++++++++++ app/Http/Requests/AttachmentSaveRequest.php | 32 ++++ app/Http/Requests/ClipSaveRequest.php | 2 +- app/Models/Attachment.php | 31 +++- app/Models/Prop.php | 14 +- ..._05_07_133653_create_attachments_table.php | 12 +- resources/js/app.js | 3 + .../attachments/attachment-form.blade.php | 163 ++++++++++++++++++ .../attachments/attachment-list.blade.php | 15 ++ .../components/panel-side-navbar.blade.php | 2 +- routes/web.php | 11 ++ 12 files changed, 449 insertions(+), 13 deletions(-) create mode 100644 app/Http/Controllers/Admin/AttachmentController.php create mode 100644 app/Http/Requests/AttachmentSaveRequest.php create mode 100644 resources/views/admin/attachments/attachment-form.blade.php create mode 100644 resources/views/admin/attachments/attachment-list.blade.php diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 762f17c..dad5e72 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -440,3 +440,54 @@ function modelWithCustomAttrs($model){ return $data; } + +/** + * get max size for upload + * @return int + */ +function getMaxUploadSize() { + $uploadMaxSize = returnBytes(ini_get('upload_max_filesize')); + $postMaxSize = returnBytes(ini_get('post_max_size')); + + return min($uploadMaxSize, $postMaxSize); +} + + +/** + * convert text to byte + * @param $val + * @return float|int|string + */ +function returnBytes($val) { + $last = strtolower($val[strlen($val)-1]); + $val = trim(strtolower($val),'kgm'); + switch($last) { + // The 'G' modifier is available since PHP 5.1.0 + case 'g': + $val *= 1024 * 1024 * 1024; + case 'm': + $val *= 1024 * 1024; + case 'k': + $val *= 1024; + } + + return $val; +} + + +/** + * convert byte to human readable + * @param $size + * @return string + */ +function formatFileSize($size) { + if ($size < 1024) { + return $size . ' bytes'; + } elseif ($size < 1048576) { + return number_format($size / 1024, 1) . ' KB'; + } elseif ($size < 1073741824) { + return number_format($size / 1048576, 1) . ' MB'; + } else { + return number_format($size / 1073741824, 1) . ' GB'; + } +} diff --git a/app/Http/Controllers/Admin/AttachmentController.php b/app/Http/Controllers/Admin/AttachmentController.php new file mode 100644 index 0000000..0630ddd --- /dev/null +++ b/app/Http/Controllers/Admin/AttachmentController.php @@ -0,0 +1,126 @@ + + ['title' => "Edit", 'class' => 'btn-outline-primary', 'icon' => 'ri-edit-2-line'], + 'show' => + ['title' => "Detail", 'class' => 'btn-outline-light', 'icon' => 'ri-eye-line'], + 'destroy' => + ['title' => "Remove", 'class' => 'btn-outline-danger delete-confirm', 'icon' => 'ri-close-line'], + ]; + + + public function __construct() + { + parent::__construct(Attachment::class, AttachmentSaveRequest::class); + } + + /** + * @param $attachment Attachment + * @param $request AttachmentSaveRequest + * @return Attachment + */ + public function save($attachment, $request) + { + + $attachment->title = $request->input('title'); + $attachment->slug = $this->getSlug($attachment,'slug','title'); + $attachment->body = $request->input('body'); + $attachment->subtitle = $request->input('subtitle'); + $attachment->is_fillable = $request->has('is_fillable'); + if ($request->has('file')){ + $attachment->file = $this->storeFile('file',$attachment, 'attachments'); + $attachment->size = $request->file('file')->getSize(); + $attachment->ext = $request->file('file')->getClientOriginalExtension(); + } + if ($request->has('attachable_id') && $request->has('attachable_id')){ + $attachment->attachable_type = $request->input('attachable_type'); + $attachment->attachable_id = $request->input('attachable_id'); + }else{ + $attachment->attachable_type = null; + $attachment->attachable_id = null; + } + $attachment->save(); + return $attachment; + + } + + + /** + * Show the form for creating a new resource. + */ + public function create() + { + // + + return view($this->formView); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Attachment $item) + { + // + return view($this->formView, compact('item')); + } + + public function bulk(Request $request) + { + +// dd($request->all()); + $data = explode('.', $request->input('action')); + $action = $data[0]; + $ids = $request->input('id'); + switch ($action) { + case 'delete': + $msg = __(':COUNT items deleted successfully', ['COUNT' => count($ids)]); + $this->_MODEL_::destroy($ids); + break; + + default: + $msg = __('Unknown bulk action : :ACTION', ["ACTION" => $action]); + } + + return $this->do_bulk($msg, $action, $ids); + } + + public function destroy(Attachment $item) + { + return parent::delete($item); + } + + + public function update(Request $request, Attachment $item) + { + return $this->bringUp($request, $item); + } + + +} diff --git a/app/Http/Requests/AttachmentSaveRequest.php b/app/Http/Requests/AttachmentSaveRequest.php new file mode 100644 index 0000000..987f38b --- /dev/null +++ b/app/Http/Requests/AttachmentSaveRequest.php @@ -0,0 +1,32 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + + return [ + 'title' => ['required','string','min:2'], + 'body' => ['nullable','string'], + 'subtitle' => ['nullable','string'], + 'file' => ['nullable','mimes:png,jpg,svg,mp4,pdf,docx,zip,rar','max:'.getMaxUploadSize()] + ]; + } +} diff --git a/app/Http/Requests/ClipSaveRequest.php b/app/Http/Requests/ClipSaveRequest.php index ecf50b4..0a8f5b9 100644 --- a/app/Http/Requests/ClipSaveRequest.php +++ b/app/Http/Requests/ClipSaveRequest.php @@ -25,7 +25,7 @@ class ClipSaveRequest extends FormRequest 'title' => ['required', 'string', 'max:255','min:5'], 'body' => ['nullable', 'string',], 'active' => ['nullable', 'boolean'], - 'clip' => ['nullable', 'mimes:mp4', 'max:15728640'], + 'clip' => ['nullable', 'mimes:mp4', 'max:'.'max:'.getMaxUploadSize()], 'cover' => ['nullable', 'image', 'mimes:jpeg,png,jpg,gif,svg', 'max:2048'], ]; } diff --git a/app/Models/Attachment.php b/app/Models/Attachment.php index dc04c23..f746e47 100644 --- a/app/Models/Attachment.php +++ b/app/Models/Attachment.php @@ -4,8 +4,37 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Spatie\Translatable\HasTranslations; class Attachment extends Model { - use HasFactory; + use HasFactory,HasTranslations; + + public static $mrohps = [Product::class,Post::class,Group::class, + Category::class,Clip::class,Gallery::class]; + + public $translatable = ['title','subtitle','body']; + + public function getRouteKeyName() + { + return 'slug'; + } + + public function url() + { + if ($this->file == null) { + return asset('/assets/upload/logo.svg'); + } + + return \Storage::url('attachments/' . $this->file); + } + + public function tempUrl() // WIP + { + if ($this->file == null) { + return asset('/assets/upload/logo.svg'); + } + + return \Storage::url('attachments/' . $this->file); + } } diff --git a/app/Models/Prop.php b/app/Models/Prop.php index 644b9d6..781071f 100644 --- a/app/Models/Prop.php +++ b/app/Models/Prop.php @@ -10,22 +10,24 @@ use Spatie\Translatable\HasTranslations; class Prop extends Model { - use HasFactory,HasTranslations,SoftDeletes; - public $translatable = ['label','unit']; + use HasFactory, HasTranslations, SoftDeletes; + + public $translatable = ['label', 'unit']; protected $casts = [ 'dataz', 'optionz' ]; - public static $prop_types = ['text','number','checkbox','color','select','multi','singlemulti']; + public static $prop_types = ['text', 'number', 'checkbox', 'color', 'select', 'multi', 'singlemulti']; public function categories() { return $this->belongsToMany(Category::class); } - public function getDatazAttribute(){ + public function getDatazAttribute() + { $result = []; foreach (json_decode($this->options) as $item) { $result[$item->title] = $item->value; @@ -33,7 +35,9 @@ class Prop extends Model return $result; } - public function getOptionzAttribute(){ + + public function getOptionzAttribute() + { return json_decode($this->options); } } diff --git a/database/migrations/2024_05_07_133653_create_attachments_table.php b/database/migrations/2024_05_07_133653_create_attachments_table.php index a4ec04e..5d70563 100644 --- a/database/migrations/2024_05_07_133653_create_attachments_table.php +++ b/database/migrations/2024_05_07_133653_create_attachments_table.php @@ -13,14 +13,16 @@ return new class extends Migration { Schema::create('attachments', function (Blueprint $table) { $table->id(); - $table->string('title'); - $table->string('subtitle'); + $table->text('title'); + $table->string('slug')->unique(); + $table->text('subtitle'); $table->text('body'); - $table->string('file',2048); - $table->string('type'); + $table->string('file',2048)->nullable(); + $table->string('ext')->nullable(); + $table->unsignedBigInteger('downloads')->default(0)->comment('downloads count'); $table->boolean('is_fillable')->default(true); $table->unsignedBigInteger('size')->default(0); - $table->morphs('attachable'); + $table->nullableMorphs('attachable'); $table->timestamps(); }); } diff --git a/resources/js/app.js b/resources/js/app.js index 5517341..9ce72cd 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -81,6 +81,9 @@ app.component('props-type-input', PropTypeInput); import MetaInput from "./components/MetaInput.vue"; app.component('meta-input', MetaInput); +import MorphSelector from "./components/MorphSelector.vue"; +app.component('morph-selector', MorphSelector); + /** * The following block of code may be used to automatically register your * Vue components. It will recursively scan this directory for the Vue diff --git a/resources/views/admin/attachments/attachment-form.blade.php b/resources/views/admin/attachments/attachment-form.blade.php new file mode 100644 index 0000000..e8df046 --- /dev/null +++ b/resources/views/admin/attachments/attachment-form.blade.php @@ -0,0 +1,163 @@ +@extends('admin.templates.panel-form-template') +@section('title') + @if(isset($item)) + {{__("Edit attachment")}} [{{$item->title}}] + @else + {{__("Add new attachment")}} + @endif - +@endsection +@section('form') + +
+
+ + @include('components.err') +
+

+ + {{__("Tips")}} +

+
    +
  • + {{__("If you want to only attach to other staff members and do not want to appear in the website attachment list, uncheck `fillable`")}} +
  • + @if($item->file == null) +
  • + {{__("There is noting file to show!")}} +
  • +
  • + {{__("Please upload file")}} +
  • + @endif + +
+
+ @if($item) +
+

+ + {{__("File")}} +

+ @if($item->file != null) +
+
    +
  • + {{__("File name")}}: {{$item->file}} +
  • +
  • + {{__("File ext")}}: {{$item->ext}} +
  • + {{__("File size")}}: {{formatFileSize($item->size)}} +
  • +
+ + + + + {{__("Download")}} + +
+ @endif +
+
+

+ + {{__("Attaching")}} +

+
+ +
+
+ @endif + +
+
+
+ +

+ @if(isset($item)) + {{__("Edit attachment")}} [{{$item->title}}] + @else + {{__("Add new attachment")}} + @endif +

+ +
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
 
+
+ is_fillable??null) == 1) checked="" @endif + value="1"> + +
+
+
+ + +
+
+
+
+
+@endsection diff --git a/resources/views/admin/attachments/attachment-list.blade.php b/resources/views/admin/attachments/attachment-list.blade.php new file mode 100644 index 0000000..277f77a --- /dev/null +++ b/resources/views/admin/attachments/attachment-list.blade.php @@ -0,0 +1,15 @@ +@extends('admin.templates.panel-list-template') + +@section('list-title') + + {{__("Attachments list")}} +@endsection +@section('title') + {{__("Attachments list")}} - +@endsection +@section('filter') + {{-- Other filters --}} +@endsection +@section('bulk') + {{-- --}} +@endsection diff --git a/resources/views/components/panel-side-navbar.blade.php b/resources/views/components/panel-side-navbar.blade.php index 43fde57..a1d5d3f 100644 --- a/resources/views/components/panel-side-navbar.blade.php +++ b/resources/views/components/panel-side-navbar.blade.php @@ -103,7 +103,7 @@
  • - + {{__("Attachments")}} diff --git a/routes/web.php b/routes/web.php index 3b8f0d7..77f42a2 100644 --- a/routes/web.php +++ b/routes/web.php @@ -104,6 +104,17 @@ Route::prefix(config('app.panel.prefix'))->name('admin.')->group( Route::post('bulk', [\App\Http\Controllers\Admin\PostController::class, "bulk"])->name('bulk'); Route::get('trashed', [\App\Http\Controllers\Admin\PostController::class, "trashed"])->name('trashed'); }); + Route::prefix('attachments')->name('attachment.')->group( + function () { + Route::get('', [\App\Http\Controllers\Admin\AttachmentController::class, 'index'])->name('index'); + Route::get('create', [\App\Http\Controllers\Admin\AttachmentController::class, 'create'])->name('create'); + Route::post('store', [\App\Http\Controllers\Admin\AttachmentController::class, 'store'])->name('store'); + Route::get('show/{item}', [\App\Http\Controllers\Admin\AttachmentController::class, 'show'])->name('show'); + Route::get('edit/{item}', [\App\Http\Controllers\Admin\AttachmentController::class, 'edit'])->name('edit'); + Route::post('update/{item}', [\App\Http\Controllers\Admin\AttachmentController::class, 'update'])->name('update'); + Route::get('delete/{item}', [\App\Http\Controllers\Admin\AttachmentController::class, 'destroy'])->name('destroy'); + Route::post('bulk', [\App\Http\Controllers\Admin\AttachmentController::class, "bulk"])->name('bulk'); + }); Route::prefix('clips')->name('clip.')->group( function () { Route::get('', [\App\Http\Controllers\Admin\ClipController::class, 'index'])->name('index');