raffles document uploader added / Free Resource Completed
This commit is contained in:
27
.env.example
27
.env.example
@@ -4,48 +4,37 @@ APP_KEY=
|
|||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_TIMEZONE=UTC
|
APP_TIMEZONE=UTC
|
||||||
APP_URL=http://localhost
|
APP_URL=http://localhost
|
||||||
|
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en
|
||||||
APP_FALLBACK_LOCALE=en
|
APP_FALLBACK_LOCALE=en
|
||||||
APP_FAKER_LOCALE=en_US
|
APP_FAKER_LOCALE=en_US
|
||||||
|
|
||||||
APP_MAINTENANCE_DRIVER=file
|
APP_MAINTENANCE_DRIVER=file
|
||||||
# APP_MAINTENANCE_STORE=database
|
# APP_MAINTENANCE_STORE=database
|
||||||
|
|
||||||
BCRYPT_ROUNDS=12
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
LOG_CHANNEL=stack
|
LOG_CHANNEL=stack
|
||||||
LOG_STACK=single
|
LOG_STACK=single
|
||||||
LOG_DEPRECATIONS_CHANNEL=null
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
DB_CONNECTION=mysql
|
||||||
DB_CONNECTION=sqlite
|
DB_HOST=127.0.0.1
|
||||||
# DB_HOST=127.0.0.1
|
DB_PORT=3306
|
||||||
# DB_PORT=3306
|
DB_DATABASE=raffles
|
||||||
# DB_DATABASE=laravel
|
DB_USERNAME=root
|
||||||
# DB_USERNAME=root
|
DB_PASSWORD=
|
||||||
# DB_PASSWORD=
|
|
||||||
|
|
||||||
SESSION_DRIVER=database
|
SESSION_DRIVER=database
|
||||||
SESSION_LIFETIME=120
|
SESSION_LIFETIME=120
|
||||||
SESSION_ENCRYPT=false
|
SESSION_ENCRYPT=false
|
||||||
SESSION_PATH=/
|
SESSION_PATH=/
|
||||||
SESSION_DOMAIN=null
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
BROADCAST_CONNECTION=log
|
BROADCAST_CONNECTION=log
|
||||||
FILESYSTEM_DISK=local
|
FILESYSTEM_DISK=local
|
||||||
QUEUE_CONNECTION=database
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
CACHE_STORE=database
|
CACHE_STORE=database
|
||||||
CACHE_PREFIX=
|
CACHE_PREFIX=
|
||||||
|
|
||||||
MEMCACHED_HOST=127.0.0.1
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
REDIS_CLIENT=phpredis
|
REDIS_CLIENT=phpredis
|
||||||
REDIS_HOST=127.0.0.1
|
REDIS_HOST=127.0.0.1
|
||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=log
|
MAIL_MAILER=log
|
||||||
MAIL_HOST=127.0.0.1
|
MAIL_HOST=127.0.0.1
|
||||||
MAIL_PORT=2525
|
MAIL_PORT=2525
|
||||||
@@ -54,11 +43,9 @@ MAIL_PASSWORD=null
|
|||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
MAIL_FROM_ADDRESS="hello@example.com"
|
MAIL_FROM_ADDRESS="hello@example.com"
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
AWS_ACCESS_KEY_ID=
|
AWS_ACCESS_KEY_ID=
|
||||||
AWS_SECRET_ACCESS_KEY=
|
AWS_SECRET_ACCESS_KEY=
|
||||||
AWS_DEFAULT_REGION=us-east-1
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
AWS_BUCKET=
|
AWS_BUCKET=
|
||||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
VITE_APP_NAME="${APP_NAME}"
|
|
@@ -8,10 +8,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Modules\CCMS\Traits\UpdateCustomFields;
|
use Modules\CCMS\Traits\UpdateCustomFields;
|
||||||
use Modules\Document\Models\Document;
|
use Modules\Document\Models\Document;
|
||||||
|
use App\Traits\AddToDocumentCollection;
|
||||||
|
|
||||||
|
|
||||||
class Country extends Model
|
class Country extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, UpdateCustomFields, CreatedUpdatedBy;
|
use HasFactory, AddToDocumentCollection, UpdateCustomFields, CreatedUpdatedBy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
@@ -102,4 +104,5 @@ class Country extends Model
|
|||||||
{
|
{
|
||||||
return $this->morphMany(Document::class, 'documentable');
|
return $this->morphMany(Document::class, 'documentable');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -8,10 +8,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Modules\CCMS\Traits\UpdateCustomFields;
|
use Modules\CCMS\Traits\UpdateCustomFields;
|
||||||
use Modules\Document\Models\Document;
|
use Modules\Document\Models\Document;
|
||||||
|
use App\Traits\AddToDocumentCollection;
|
||||||
|
|
||||||
|
|
||||||
class Service extends Model
|
class Service extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, UpdateCustomFields, CreatedUpdatedBy;
|
use HasFactory, UpdateCustomFields, AddToDocumentCollection, CreatedUpdatedBy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
|
@@ -8,12 +8,13 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Modules\CCMS\Traits\UpdateCustomFields;
|
use Modules\CCMS\Traits\UpdateCustomFields;
|
||||||
use Modules\Document\Models\Document;
|
use Modules\Document\Models\Document;
|
||||||
|
use App\Traits\AddToDocumentCollection;
|
||||||
|
|
||||||
// use Modules\CCMS\Database\Factories\TestFactory;
|
// use Modules\CCMS\Database\Factories\TestFactory;
|
||||||
|
|
||||||
class Test extends Model
|
class Test extends Model
|
||||||
{
|
{
|
||||||
use HasFactory, UpdateCustomFields, CreatedUpdatedBy;
|
use HasFactory, UpdateCustomFields, AddToDocumentCollection, CreatedUpdatedBy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes that are mass assignable.
|
* The attributes that are mass assignable.
|
||||||
|
@@ -6,10 +6,13 @@ use App\Http\Controllers\Controller;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Modules\CCMS\Models\Country;
|
use Modules\CCMS\Models\Country;
|
||||||
|
use Modules\Document\Models\Document;
|
||||||
use Modules\CCMS\Models\Service;
|
use Modules\CCMS\Models\Service;
|
||||||
use Modules\CCMS\Models\Test;
|
use Modules\CCMS\Models\Test;
|
||||||
use Modules\Document\Services\DocumentService;
|
use Modules\Document\Services\DocumentService;
|
||||||
use Yajra\DataTables\Facades\DataTables;
|
use Yajra\DataTables\Facades\DataTables;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
|
||||||
class DocumentController extends Controller
|
class DocumentController extends Controller
|
||||||
{
|
{
|
||||||
@@ -33,39 +36,151 @@ class DocumentController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function dropzoneUpload(Request $request)
|
public function destroy($id)
|
||||||
{
|
{
|
||||||
$request->validate([
|
try {
|
||||||
'model' => 'required|string',
|
$document = Document::findOrFail($id);
|
||||||
'file' => 'required|array',
|
if (File::exists('storage/' . $document->document_path)) {
|
||||||
'file.*' => 'file|mimes:pdf,doc,docx,jpg,png|max:5120',
|
File::delete('storage/' . $document->document_path);
|
||||||
'title' => 'nullable|string',
|
}
|
||||||
|
|
||||||
|
$document->delete();
|
||||||
|
|
||||||
|
session()->flash('Document Deleted');
|
||||||
|
return response()->json(['status' => true, 'msg' => 'Document Deleted']);
|
||||||
|
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
session()->flash('error', $th->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uploadDocument(Request $request)
|
||||||
|
{
|
||||||
|
$isNumeric = is_numeric($request->title);
|
||||||
|
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'title' => $isNumeric ? 'required|exists:required_documents,id' : 'required|string',
|
||||||
|
'model' => 'required',
|
||||||
|
'document' => 'required|array',
|
||||||
|
], [
|
||||||
|
'title.required' => 'Document title is required!',
|
||||||
|
'title.exists' => 'Document does not exists in record!',
|
||||||
|
'document' => 'Please upload document first!',
|
||||||
|
'model' => 'Please Select Category'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$parts = explode(':', $request->model);
|
if ($validator->fails()) {
|
||||||
|
return response()->json(['status' => 422, 'errors' => $validator->errors()], 422);
|
||||||
if (count($parts) !== 2) {
|
|
||||||
return response()->json(['error' => 'Invalid model format.'], 422);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[$modelType, $modelId] = $parts;
|
try {
|
||||||
$modelClass = "App\\Models\\$modelType";
|
|
||||||
|
|
||||||
if (!class_exists($modelClass)) {
|
$modelValues = explode(':', $request->model);
|
||||||
return response()->json(['error' => 'Invalid model selected.'], 422);
|
$modelClass = "Modules\\CCMS\\Models\\{$modelValues[0]}";
|
||||||
|
|
||||||
|
$model = $modelClass::findOrFail($modelValues[1]);
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($request->input('document', []) as $file) {
|
||||||
|
$model->addToDocumentCollection(collectionName: 'uploads/document', file: $file, documentName: $request->title, referenceDocumentId: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'status' => true,
|
||||||
|
'msg' => 'Document has been uploaded!',
|
||||||
|
// 'view' => view('student::student.section.document.table', [
|
||||||
|
// 'student' => $student,
|
||||||
|
// ])->render(),
|
||||||
|
], 200);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => false,
|
||||||
|
'msg' => $th->getMessage(),
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$path = storage_path('tmp/uploads');
|
||||||
|
|
||||||
|
if (!file_exists($path)) {
|
||||||
|
mkdir($path, 0777, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$model = $modelClass::findOrFail($modelId);
|
$file = $request->file('file');
|
||||||
|
|
||||||
foreach ($request->file('file') as $uploadedFile) {
|
$name = uniqid() . '_' . trim($file->getClientOriginalName());
|
||||||
$path = $uploadedFile->store('documents');
|
|
||||||
|
|
||||||
$model->documents()->create([
|
$file->move($path, $name);
|
||||||
'title' => $request->title ?? 'Untitled',
|
|
||||||
'file_path' => $path,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json(['success' => 'Files uploaded successfully']);
|
return response()->json([
|
||||||
|
'name' => $name,
|
||||||
|
'original_name' => $file->getClientOriginalName(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllDocuments()
|
||||||
|
{
|
||||||
|
$model = Document::query()->latest();
|
||||||
|
return DataTables::eloquent($model)
|
||||||
|
->setRowClass('tableRow')
|
||||||
|
->addColumn('name', function (Document $document) {
|
||||||
|
$extension = $document->getExtension();
|
||||||
|
$assetUrl = $document->getUrl();
|
||||||
|
$html = $document->isImageFile()
|
||||||
|
? "<div class='flex-shrink-0'>
|
||||||
|
<div class='avatar-sm bg-light rounded p-1'>
|
||||||
|
<a href='{$assetUrl}' data-fancybox='gallery' data-caption='{$document->title}'>
|
||||||
|
<img src='{$assetUrl}' alt='' class='avatar-sm img-fluid d-block'>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>"
|
||||||
|
: "<div class='flex-shrink-0'>
|
||||||
|
<div class='avatar-sm'>
|
||||||
|
<a href='{$assetUrl}' data-fancybox='gallery' data-caption='{$document->title}'>
|
||||||
|
<div class='avatar-title bg-" . getFileIcon($extension)[1] . "-subtle text-" . getFileIcon($extension)[1] . " fs-20 material-shadow rounded'>
|
||||||
|
<i class='" . getFileIcon($extension)[0] . "'></i>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>";
|
||||||
|
|
||||||
|
return "<div class='d-flex align-items-center'>
|
||||||
|
{$html} <div class='flex-grow-1 ms-3'>
|
||||||
|
<h6 class='fs-12 mb-0'>{$document->title}</h6>
|
||||||
|
</div>
|
||||||
|
</div>";
|
||||||
|
})
|
||||||
|
->addColumn('type', function (Document $document) {
|
||||||
|
return $document->getExtension();
|
||||||
|
})
|
||||||
|
->addColumn('size', function (Document $document) {
|
||||||
|
return $document->getSize();
|
||||||
|
})
|
||||||
|
->editColumn('created_at', function (Document $document) {
|
||||||
|
return getFormatted($document->created_at);
|
||||||
|
})
|
||||||
|
->addColumn('action', function (Document $document) {
|
||||||
|
return view('document::document.partials.action', ['document' => $document]);
|
||||||
|
})
|
||||||
|
->rawColumns(['action', 'name', 'size'])
|
||||||
|
->toJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reorder(Request $request)
|
||||||
|
{
|
||||||
|
Document::chunkById(100, function (Collection $documents) use ($request) {
|
||||||
|
foreach ($documents as $document) {
|
||||||
|
foreach ($request->order as $order) {
|
||||||
|
if ($order['id'] == $document->id) {
|
||||||
|
$document->update(['order' => $order['position']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return response(['status' => true, 'message' => 'Reordered successfully'], 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,9 +13,16 @@ class Document extends Model
|
|||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $fillable = ['title', 'file_path'];
|
protected $fillable = ['title', 'file_path', 'collection_name', 'order'];
|
||||||
|
|
||||||
|
|
||||||
|
protected static function booted()
|
||||||
|
{
|
||||||
|
static::creating(function ($model) {
|
||||||
|
$model->order = ($model::max('order') ?? 0) + 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public function documentable(): MorphTo
|
public function documentable(): MorphTo
|
||||||
{
|
{
|
||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
@@ -23,13 +30,13 @@ class Document extends Model
|
|||||||
|
|
||||||
public function getUrl()
|
public function getUrl()
|
||||||
{
|
{
|
||||||
$path = $this->document_path;
|
$path = $this->collection_name . '/' . $this->file_path;
|
||||||
return Storage::disk('public')->url($path);
|
return Storage::disk('public')->url($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSize()
|
public function getSize()
|
||||||
{
|
{
|
||||||
$path = $this->document_path;
|
$path = $this->collection_name . '/' . $this->file_path;
|
||||||
|
|
||||||
if (Storage::disk('public')->exists($path)) {
|
if (Storage::disk('public')->exists($path)) {
|
||||||
$sizeInBytes = Storage::disk('public')->size($path);
|
$sizeInBytes = Storage::disk('public')->size($path);
|
||||||
@@ -41,13 +48,13 @@ class Document extends Model
|
|||||||
|
|
||||||
public function getExtension()
|
public function getExtension()
|
||||||
{
|
{
|
||||||
return pathinfo($this->document_path, PATHINFO_EXTENSION);
|
return pathinfo($this->file_path, PATHINFO_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isImageFile()
|
public function isImageFile()
|
||||||
{
|
{
|
||||||
$imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp', 'tiff', 'tif', 'ico'];
|
$imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp', 'tiff', 'tif', 'ico'];
|
||||||
$extension = pathinfo($this->document_path, PATHINFO_EXTENSION);
|
$extension = pathinfo($this->file_path, PATHINFO_EXTENSION);
|
||||||
return in_array(Str::lower($extension), $imageExtensions);
|
return in_array(Str::lower($extension), $imageExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +63,7 @@ class Document extends Model
|
|||||||
return Attribute::make(
|
return Attribute::make(
|
||||||
get: function (mixed $value, array $attributes) {
|
get: function (mixed $value, array $attributes) {
|
||||||
$collectionName = $attributes['collection_name'];
|
$collectionName = $attributes['collection_name'];
|
||||||
$path = $attributes['document_path'];
|
$path = $attributes['file_path'];
|
||||||
return "{$collectionName}/{$path}";
|
return "{$collectionName}/{$path}";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -13,13 +13,14 @@ return new class extends Migration
|
|||||||
{
|
{
|
||||||
Schema::create('documents', function (Blueprint $table) {
|
Schema::create('documents', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->string('title');
|
$table->string('title')->nullable();
|
||||||
$table->string('file_path');
|
$table->string('file_path')->nullable();
|
||||||
|
$table->string('collection_name')->default('uploads');
|
||||||
$table->unsignedBigInteger('documentable_id');
|
$table->unsignedBigInteger('documentable_id');
|
||||||
$table->string('documentable_type');
|
$table->string('documentable_type');
|
||||||
$table->index(['documentable_type', 'documentable_id']);
|
$table->unsignedBigInteger("order")->nullable();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -2,87 +2,113 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
|
|
||||||
<form method="POST" action="{{ route('documents.dropzone.upload') }}" class="dropzone" id="mainForm"
|
{{ html()->form('POST', route('documents.upload'))->class(['needs-validation'])->attributes(['novalidate', 'enctype' => 'multipart/form-data', 'id' => 'documentForm'])->open() }}
|
||||||
enctype="multipart/form-data">
|
|
||||||
@csrf
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
{{ html()->label('Title')->for('title') }}
|
{{ html()->label('Title')->for('title') }}
|
||||||
{{ html()->span('*')->class('text-danger') }}
|
{{ html()->span('*')->class('text-danger') }}
|
||||||
{{ html()->text('title')->id('docTitle')->class('form-control')->placeholder('Enter Title')->required() }}
|
{{ html()->text('title')->id('docTitle')->class('form-control')->placeholder('Enter Title')->required() }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
{{ html()->label('Select Model')->class('form-label')->for('model') }}
|
{{ html()->label('Select Model')->class('form-label')->for('model') }}
|
||||||
{{ html()->span('*')->class('text-danger') }}
|
{{ html()->span('*')->class('text-danger') }}
|
||||||
{{ html()->select('model')->id('modelSelect')->class('form-select')->required()->options(['' => '-- Select --'] + $modelOptions->toArray()) }}
|
{{ html()->select('model')->id('modelSelect')->class('form-select select2')->required()->options(['' => '-- Select --'] + $modelOptions->toArray()) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dropzone-previews mb-3"></div>
|
<div class="mb-3">
|
||||||
|
<x-document::file-upload :uploadUrl="route('documents.store')" dropzoneId="document-dropzone"
|
||||||
<div class="dz-message mb-3">
|
formId="documentForm" message="Upload Document (PDF or Images Only)"
|
||||||
<p class="fs-14">Drop files here or click to upload.</p>
|
inputName="document" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="btn btn-primary" id="submitAll">Submit</button>
|
<div class="col-sm-12">
|
||||||
</form>
|
<div class="hstack justify-content-end gap-2">
|
||||||
|
<button type="submit" class="btn btn-primary upload-btn">Upload</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ html()->form()->close() }}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@push('js')
|
|
||||||
<script>
|
@pushOnce('js')
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
<script>
|
||||||
Dropzone.autoDiscover = false;
|
function clearDropzone(dropzoneIds = [], formId = '', fileFieldNames = []) {
|
||||||
|
dropzoneIds.forEach(function(id) {
|
||||||
|
const dropzoneElement = Dropzone.forElement(`#${id}`);
|
||||||
|
if (dropzoneElement) {
|
||||||
|
dropzoneElement.removeAllFiles(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const myDropzone = new Dropzone("#mainForm", {
|
fileFieldNames.forEach(function(field) {
|
||||||
url: "{{ route('documents.dropzone.upload') }}",
|
$(`#${formId} input[name="${field}[]"]`).remove();
|
||||||
autoProcessQueue: false,
|
});
|
||||||
uploadMultiple: true,
|
}
|
||||||
parallelUploads: 5,
|
</script>
|
||||||
maxFilesize: 5,
|
|
||||||
addRemoveLinks: true,
|
|
||||||
acceptedFiles: ".pdf,.doc,.docx,.jpg,.png",
|
|
||||||
paramName: "file[]",
|
|
||||||
headers: {
|
|
||||||
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value
|
|
||||||
},
|
|
||||||
init: function() {
|
|
||||||
const dz = this;
|
|
||||||
|
|
||||||
document.getElementById("submitAll").addEventListener("click", function(e) {
|
<script>
|
||||||
const title = document.getElementById('docTitle').value;
|
$(document).on('submit', '#documentForm', function(event) {
|
||||||
const model = document.getElementById('modelSelect').value;
|
event.preventDefault();
|
||||||
|
|
||||||
if (!title || !model) {
|
const url = $(this).attr('action');
|
||||||
alert("Please fill in both Title and Model.");
|
const formData = new FormData(this);
|
||||||
return;
|
const button = $(this).find('button[type="submit"]');
|
||||||
}
|
|
||||||
|
|
||||||
if (dz.getQueuedFiles().length > 0) {
|
$.ajax({
|
||||||
dz.processQueue();
|
type: "POST",
|
||||||
} else {
|
url: url,
|
||||||
alert("Please select at least one file.");
|
data: formData,
|
||||||
}
|
processData: false,
|
||||||
});
|
contentType: false,
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
|
||||||
|
},
|
||||||
|
beforeSend: () => {
|
||||||
|
button.text('Uploading...').prop('disabled', true);
|
||||||
|
},
|
||||||
|
success: (response) => {
|
||||||
|
if (response.status == true) {
|
||||||
|
$('#documentForm')[0].reset();
|
||||||
|
|
||||||
dz.on("sending", function(file, xhr, formData) {
|
// if (DataTable.isDataTable("#documents-table")) {
|
||||||
formData.append("title", document.getElementById('docTitle').value);
|
// $("#documents-table").DataTable().ajax.reload();
|
||||||
formData.append("model", document.getElementById('modelSelect').value);
|
// } else {
|
||||||
});
|
// target.html(response.view);
|
||||||
|
// }
|
||||||
|
|
||||||
dz.on("successmultiple", function(files, response) {
|
clearDropzone(dropzoneIds = ["document-dropzone"],
|
||||||
alert("Files uploaded successfully.");
|
"documentForm", ["document"]);
|
||||||
dz.removeAllFiles();
|
|
||||||
document.getElementById('mainForm').reset();
|
|
||||||
});
|
|
||||||
|
|
||||||
dz.on("errormultiple", function(files, response) {
|
button.text('Upload').prop('disabled', false);
|
||||||
alert("An error occurred during upload.");
|
toastr.success(response.msg);
|
||||||
console.error(response);
|
|
||||||
});
|
}
|
||||||
}
|
},
|
||||||
});
|
error: (xhr) => {
|
||||||
});
|
if (xhr.status === 422) {
|
||||||
</script>
|
const errors = xhr.responseJSON.errors;
|
||||||
@endpush
|
$('.error-message').remove();
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(errors)) {
|
||||||
|
const errorMessage = $(
|
||||||
|
'<p class="error-message text-danger mt-2"></p>').text(
|
||||||
|
value[0]);
|
||||||
|
$(`#${key}`).after(errorMessage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
button.text('Upload');
|
||||||
|
button.prop('disabled', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endPushOnce
|
||||||
|
@@ -8,26 +8,17 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6 col-xl-6">
|
<div class="col-lg-4 col-xl-4">
|
||||||
<div class="card profile-card">
|
<div class="card profile-card">
|
||||||
@include('document::document.form')
|
@include('document::document.form')
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- <div class="col-lg-xl-8 col-lg-9">
|
<div class="col-lg-xl-8 col-lg-8">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@php
|
@php
|
||||||
$columns = [
|
$columns = [
|
||||||
[
|
|
||||||
'title' => '<input type="checkbox" id="select-all">',
|
|
||||||
'data' => 'checkbox',
|
|
||||||
'name' => 'checkbox',
|
|
||||||
'orderable' => false,
|
|
||||||
'searchable' => false,
|
|
||||||
'printable' => false,
|
|
||||||
'exportable' => false,
|
|
||||||
],
|
|
||||||
['title' => 'Document', 'data' => 'name', 'name' => 'name'],
|
['title' => 'Document', 'data' => 'name', 'name' => 'name'],
|
||||||
['title' => 'Type', 'data' => 'type', 'name' => 'type'],
|
['title' => 'Type', 'data' => 'type', 'name' => 'type'],
|
||||||
['title' => 'Size', 'data' => 'size', 'name' => 'size'],
|
['title' => 'Size', 'data' => 'size', 'name' => 'size'],
|
||||||
@@ -41,10 +32,11 @@
|
|||||||
];
|
];
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<x-data-table-script :route="route('gallery.index')" :reorder="route('gallery.reorder')" :columns="$columns" />
|
<x-data-table-script :route="route('documents.getAllDocuments')" :columns="$columns" id="documents-table" :reorder="route('documents.reorder')" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div> --}}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="hstack flex-wrap gap-3 align-items-center">
|
||||||
|
<a href="{{ $document->getUrl() }}" class="link-primary fs-15" download><i class="ri-download-2-line"></i></a>
|
||||||
|
@can('documents.destroy')
|
||||||
|
<a href="javascript:void(0);" data-link="{{ route('documents.destroy', $document->id) }}"
|
||||||
|
class="link-danger fs-15 remove-item"><i class="ri-delete-bin-line"></i></a>
|
||||||
|
@endcan
|
||||||
|
</div>
|
@@ -15,6 +15,9 @@ use Modules\Document\Http\Controllers\DocumentController;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Route::group(['middleware' => ['web', 'auth', 'permission'], 'prefix' => 'admin/'], function () {
|
Route::group(['middleware' => ['web', 'auth', 'permission'], 'prefix' => 'admin/'], function () {
|
||||||
Route::get('/documents', [DocumentController::class, 'index'])->name('documents.index');
|
// Route::get('/documents', [DocumentController::class, 'index'])->name('documents.index');
|
||||||
Route::post('/documents/dropzone-upload', [DocumentController::class, 'dropzoneUpload'])->name('documents.dropzone.upload');
|
Route::post('documents/reorder', [DocumentController::class, 'reorder'])->name('documents.reorder');
|
||||||
|
Route::resource('documents', DocumentController::class)->names('documents');
|
||||||
|
Route::post('/documents/upload', [DocumentController::class, 'uploadDocument'])->name('documents.upload');
|
||||||
|
Route::get('get-all-documents', [DocumentController::class, 'getAllDocuments'])->name('documents.getAllDocuments');
|
||||||
});
|
});
|
||||||
|
@@ -20,6 +20,49 @@ if (!function_exists('setting')) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!function_exists('getFileIcon')) {
|
||||||
|
|
||||||
|
function getFileIcon($extension)
|
||||||
|
{
|
||||||
|
switch ($extension) {
|
||||||
|
case 'pdf':
|
||||||
|
return ['ri-file-pdf-line', 'danger'];
|
||||||
|
case 'doc':
|
||||||
|
case 'docx':
|
||||||
|
return ['ri-file-word-line', 'primary'];
|
||||||
|
case 'xls':
|
||||||
|
case 'xlsx':
|
||||||
|
return ['ri-file-excel-line', 'success'];
|
||||||
|
case 'ppt':
|
||||||
|
case 'pptx':
|
||||||
|
return ['ri-file-powerpoint-line', 'danger'];
|
||||||
|
case 'txt':
|
||||||
|
return ['ri-file-alt-line', 'secondary'];
|
||||||
|
case 'jpg':
|
||||||
|
case 'jpeg':
|
||||||
|
case 'png':
|
||||||
|
case 'gif':
|
||||||
|
return ['ri-file-image-line', 'info'];
|
||||||
|
case 'zip':
|
||||||
|
case 'rar':
|
||||||
|
return ['ri-file-archive-line', 'warning'];
|
||||||
|
case 'mp3':
|
||||||
|
case 'wav':
|
||||||
|
return ['ri-file-audio-line', 'warning'];
|
||||||
|
case 'mp4':
|
||||||
|
case 'mov':
|
||||||
|
case 'avi':
|
||||||
|
return ['ri-file-video-line', 'warning'];
|
||||||
|
default:
|
||||||
|
return ['ri-file-line', 'warning'];
|
||||||
|
}
|
||||||
|
// return collect([
|
||||||
|
// 'icon' => $res[0],
|
||||||
|
// 'color' => $res[1],
|
||||||
|
// ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!function_exists('uploadImage')) {
|
if (!function_exists('uploadImage')) {
|
||||||
function uploadImage($file, $path = 'uploads')
|
function uploadImage($file, $path = 'uploads')
|
||||||
{
|
{
|
||||||
|
33
app/Traits/AddToDocumentCollection.php
Normal file
33
app/Traits/AddToDocumentCollection.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Modules\Document\Models\Document;
|
||||||
|
|
||||||
|
trait AddToDocumentCollection
|
||||||
|
{
|
||||||
|
public function addToDocumentCollection(string $collectionName = 'uploads', string $file, ?string $documentName = null, ?int $referenceDocumentId = null)
|
||||||
|
{
|
||||||
|
if (!Storage::disk('public')->exists($collectionName)) {
|
||||||
|
Storage::disk('public')->makeDirectory($collectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetFile = Storage::disk('public')->path("{$collectionName}/{$file}");
|
||||||
|
|
||||||
|
File::copy(storage_path("tmp/uploads/{$file}"), $targetFile);
|
||||||
|
|
||||||
|
$this->documents()->create([
|
||||||
|
'title' => $documentName,
|
||||||
|
'file_path' => $file,
|
||||||
|
'collection_name' => $collectionName,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function documents(): MorphMany
|
||||||
|
{
|
||||||
|
return $this->morphMany(Document::class, 'documentable')->orderBy('order');
|
||||||
|
}
|
||||||
|
}
|
@@ -228,10 +228,10 @@ return [
|
|||||||
|
|
||||||
[
|
[
|
||||||
'text' => 'Documents',
|
'text' => 'Documents',
|
||||||
'url' => 'admin/document',
|
'url' => 'admin/documents',
|
||||||
'icon' => 'ri-file-text-line',
|
'icon' => 'ri-file-text-line',
|
||||||
'module' => 'Document',
|
'module' => 'Document',
|
||||||
'can' => ['document.index'],
|
'can' => ['documents.index'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'text' => 'Resume Builder',
|
'text' => 'Resume Builder',
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@
|
|||||||
<link href="{{ asset('assets/css/custom.min.css') }}" rel="stylesheet" type="text/css" />
|
<link href="{{ asset('assets/css/custom.min.css') }}" rel="stylesheet" type="text/css" />
|
||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.css" rel="stylesheet">
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.css" />
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.css" />
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" rel="stylesheet" />
|
||||||
@livewireStyles
|
@livewireStyles
|
||||||
|
|
||||||
@stack('css')
|
@stack('css')
|
||||||
@@ -119,6 +119,7 @@
|
|||||||
<script>
|
<script>
|
||||||
const app_url = "{{ config('app.url') }}";
|
const app_url = "{{ config('app.url') }}";
|
||||||
</script>
|
</script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.9.3/min/dropzone.min.js"></script>
|
||||||
<script src="{{ asset('assets/libs/jquery/jquery-3.7.1.min.js') }}"></script>
|
<script src="{{ asset('assets/libs/jquery/jquery-3.7.1.min.js') }}"></script>
|
||||||
<script src="{{ asset('assets/libs/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
|
<script src="{{ asset('assets/libs/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
|
||||||
|
BIN
storage/tmp/uploads/688e37041003e_Resume_Subash_PHP_1Yrs (1).pdf
Normal file
BIN
storage/tmp/uploads/688e37041003e_Resume_Subash_PHP_1Yrs (1).pdf
Normal file
Binary file not shown.
BIN
storage/tmp/uploads/688e386660f13_index.png
Normal file
BIN
storage/tmp/uploads/688e386660f13_index.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
BIN
storage/tmp/uploads/688e38f9307e6_Resume_Subash_PHP_1Yrs (1).pdf
Normal file
BIN
storage/tmp/uploads/688e38f9307e6_Resume_Subash_PHP_1Yrs (1).pdf
Normal file
Binary file not shown.
BIN
storage/tmp/uploads/688e3b58d10f8_Resume_Subash_PHP_1Yrs (1).pdf
Normal file
BIN
storage/tmp/uploads/688e3b58d10f8_Resume_Subash_PHP_1Yrs (1).pdf
Normal file
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
BIN
storage/tmp/uploads/688e438468483_report (15).pdf
Normal file
BIN
storage/tmp/uploads/688e438468483_report (15).pdf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
storage/tmp/uploads/688e5589e5624_intern covers_removed.pdf
Normal file
BIN
storage/tmp/uploads/688e5589e5624_intern covers_removed.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user