diff --git a/.env.example b/.env.example
index 2a4a8b7..b4360df 100644
--- a/.env.example
+++ b/.env.example
@@ -4,48 +4,37 @@ APP_KEY=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=http://localhost
-
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
-
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
-
BCRYPT_ROUNDS=12
-
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
-
-DB_CONNECTION=sqlite
-# DB_HOST=127.0.0.1
-# DB_PORT=3306
-# DB_DATABASE=laravel
-# DB_USERNAME=root
-# DB_PASSWORD=
-
+DB_CONNECTION=mysql
+DB_HOST=127.0.0.1
+DB_PORT=3306
+DB_DATABASE=raffles
+DB_USERNAME=root
+DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
-
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
-
CACHE_STORE=database
CACHE_PREFIX=
-
MEMCACHED_HOST=127.0.0.1
-
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
-
MAIL_MAILER=log
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
@@ -54,11 +43,9 @@ MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
-
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
-
-VITE_APP_NAME="${APP_NAME}"
+VITE_APP_NAME="${APP_NAME}"
\ No newline at end of file
diff --git a/Modules/CCMS/app/Models/Country.php b/Modules/CCMS/app/Models/Country.php
index 76ddb86..ac49801 100644
--- a/Modules/CCMS/app/Models/Country.php
+++ b/Modules/CCMS/app/Models/Country.php
@@ -8,10 +8,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Modules\CCMS\Traits\UpdateCustomFields;
use Modules\Document\Models\Document;
+use App\Traits\AddToDocumentCollection;
+
class Country extends Model
{
- use HasFactory, UpdateCustomFields, CreatedUpdatedBy;
+ use HasFactory, AddToDocumentCollection, UpdateCustomFields, CreatedUpdatedBy;
/**
* The attributes that are mass assignable.
@@ -102,4 +104,5 @@ class Country extends Model
{
return $this->morphMany(Document::class, 'documentable');
}
+
}
diff --git a/Modules/CCMS/app/Models/Service.php b/Modules/CCMS/app/Models/Service.php
index 786b884..ec31f6d 100644
--- a/Modules/CCMS/app/Models/Service.php
+++ b/Modules/CCMS/app/Models/Service.php
@@ -8,10 +8,12 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Modules\CCMS\Traits\UpdateCustomFields;
use Modules\Document\Models\Document;
+use App\Traits\AddToDocumentCollection;
+
class Service extends Model
{
- use HasFactory, UpdateCustomFields, CreatedUpdatedBy;
+ use HasFactory, UpdateCustomFields, AddToDocumentCollection, CreatedUpdatedBy;
/**
* The attributes that are mass assignable.
diff --git a/Modules/CCMS/app/Models/Test.php b/Modules/CCMS/app/Models/Test.php
index 3c0bda3..0b5d039 100644
--- a/Modules/CCMS/app/Models/Test.php
+++ b/Modules/CCMS/app/Models/Test.php
@@ -8,12 +8,13 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Modules\CCMS\Traits\UpdateCustomFields;
use Modules\Document\Models\Document;
+use App\Traits\AddToDocumentCollection;
// use Modules\CCMS\Database\Factories\TestFactory;
class Test extends Model
{
- use HasFactory, UpdateCustomFields, CreatedUpdatedBy;
+ use HasFactory, UpdateCustomFields, AddToDocumentCollection, CreatedUpdatedBy;
/**
* The attributes that are mass assignable.
diff --git a/Modules/Document/app/Http/Controllers/DocumentController.php b/Modules/Document/app/Http/Controllers/DocumentController.php
index eddc41b..67255d7 100644
--- a/Modules/Document/app/Http/Controllers/DocumentController.php
+++ b/Modules/Document/app/Http/Controllers/DocumentController.php
@@ -6,10 +6,13 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Modules\CCMS\Models\Country;
+use Modules\Document\Models\Document;
use Modules\CCMS\Models\Service;
use Modules\CCMS\Models\Test;
use Modules\Document\Services\DocumentService;
use Yajra\DataTables\Facades\DataTables;
+use Illuminate\Support\Facades\Validator;
+
class DocumentController extends Controller
{
@@ -33,39 +36,151 @@ class DocumentController extends Controller
}
- public function dropzoneUpload(Request $request)
+ public function destroy($id)
{
- $request->validate([
- 'model' => 'required|string',
- 'file' => 'required|array',
- 'file.*' => 'file|mimes:pdf,doc,docx,jpg,png|max:5120',
- 'title' => 'nullable|string',
+ try {
+ $document = Document::findOrFail($id);
+ if (File::exists('storage/' . $document->document_path)) {
+ File::delete('storage/' . $document->document_path);
+ }
+
+ $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 (count($parts) !== 2) {
- return response()->json(['error' => 'Invalid model format.'], 422);
+ if ($validator->fails()) {
+ return response()->json(['status' => 422, 'errors' => $validator->errors()], 422);
}
- [$modelType, $modelId] = $parts;
- $modelClass = "App\\Models\\$modelType";
+ try {
- if (!class_exists($modelClass)) {
- return response()->json(['error' => 'Invalid model selected.'], 422);
+ $modelValues = explode(':', $request->model);
+ $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) {
- $path = $uploadedFile->store('documents');
+ $name = uniqid() . '_' . trim($file->getClientOriginalName());
- $model->documents()->create([
- 'title' => $request->title ?? 'Untitled',
- 'file_path' => $path,
- ]);
- }
+ $file->move($path, $name);
- 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()
+ ? "
"
+ : "";
+
+ return "
+ {$html}
+
{$document->title}
+
+
";
+ })
+ ->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);
}
}
diff --git a/Modules/Document/app/Models/Document.php b/Modules/Document/app/Models/Document.php
index 4d121c4..6f2c728 100644
--- a/Modules/Document/app/Models/Document.php
+++ b/Modules/Document/app/Models/Document.php
@@ -13,9 +13,16 @@ class Document extends Model
{
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
{
return $this->morphTo();
@@ -23,13 +30,13 @@ class Document extends Model
public function getUrl()
{
- $path = $this->document_path;
+ $path = $this->collection_name . '/' . $this->file_path;
return Storage::disk('public')->url($path);
}
public function getSize()
{
- $path = $this->document_path;
+ $path = $this->collection_name . '/' . $this->file_path;
if (Storage::disk('public')->exists($path)) {
$sizeInBytes = Storage::disk('public')->size($path);
@@ -41,13 +48,13 @@ class Document extends Model
public function getExtension()
{
- return pathinfo($this->document_path, PATHINFO_EXTENSION);
+ return pathinfo($this->file_path, PATHINFO_EXTENSION);
}
public function isImageFile()
{
$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);
}
@@ -56,7 +63,7 @@ class Document extends Model
return Attribute::make(
get: function (mixed $value, array $attributes) {
$collectionName = $attributes['collection_name'];
- $path = $attributes['document_path'];
+ $path = $attributes['file_path'];
return "{$collectionName}/{$path}";
}
);
diff --git a/Modules/Document/database/migrations/2025_08_01_053627_create_documents_table.php b/Modules/Document/database/migrations/2025_08_01_053627_create_documents_table.php
index be9235c..d4e0a3f 100644
--- a/Modules/Document/database/migrations/2025_08_01_053627_create_documents_table.php
+++ b/Modules/Document/database/migrations/2025_08_01_053627_create_documents_table.php
@@ -13,13 +13,14 @@ return new class extends Migration
{
Schema::create('documents', function (Blueprint $table) {
$table->id();
- $table->string('title');
- $table->string('file_path');
+ $table->string('title')->nullable();
+ $table->string('file_path')->nullable();
+ $table->string('collection_name')->default('uploads');
$table->unsignedBigInteger('documentable_id');
$table->string('documentable_type');
- $table->index(['documentable_type', 'documentable_id']);
+ $table->unsignedBigInteger("order")->nullable();
$table->timestamps();
- });
+ });
}
/**
diff --git a/Modules/Document/resources/views/document/form.blade.php b/Modules/Document/resources/views/document/form.blade.php
index 6ee54d8..611d54a 100644
--- a/Modules/Document/resources/views/document/form.blade.php
+++ b/Modules/Document/resources/views/document/form.blade.php
@@ -2,87 +2,113 @@
- @push('js')
-
- document.getElementById("submitAll").addEventListener("click", function(e) {
- const title = document.getElementById('docTitle').value;
- const model = document.getElementById('modelSelect').value;
+
- @endpush
+ button.text('Upload').prop('disabled', false);
+ toastr.success(response.msg);
+
+ }
+ },
+ error: (xhr) => {
+ if (xhr.status === 422) {
+ const errors = xhr.responseJSON.errors;
+ $('.error-message').remove();
+
+ for (const [key, value] of Object.entries(errors)) {
+ const errorMessage = $(
+ '
').text(
+ value[0]);
+ $(`#${key}`).after(errorMessage);
+ }
+ } else {
+ console.error(xhr);
+ }
+ },
+ complete: () => {
+ button.text('Upload');
+ button.prop('disabled', true);
+ }
+ });
+ });
+
+@endPushOnce
diff --git a/Modules/Document/resources/views/document/index.blade.php b/Modules/Document/resources/views/document/index.blade.php
index 282c859..3a8efe7 100644
--- a/Modules/Document/resources/views/document/index.blade.php
+++ b/Modules/Document/resources/views/document/index.blade.php
@@ -8,26 +8,17 @@
@endif
-
+
@include('document::document.form')
- {{--
+
@php
$columns = [
- [
- 'title' => '',
- 'data' => 'checkbox',
- 'name' => 'checkbox',
- 'orderable' => false,
- 'searchable' => false,
- 'printable' => false,
- 'exportable' => false,
- ],
['title' => 'Document', 'data' => 'name', 'name' => 'name'],
['title' => 'Type', 'data' => 'type', 'name' => 'type'],
['title' => 'Size', 'data' => 'size', 'name' => 'size'],
@@ -41,10 +32,11 @@
];
@endphp
-
+
+
-
--}}
+
@endsection
diff --git a/Modules/Document/resources/views/document/partials/action.blade.php b/Modules/Document/resources/views/document/partials/action.blade.php
new file mode 100644
index 0000000..8b99faf
--- /dev/null
+++ b/Modules/Document/resources/views/document/partials/action.blade.php
@@ -0,0 +1,7 @@
+
+
+ @can('documents.destroy')
+
+ @endcan
+
diff --git a/Modules/Document/routes/web.php b/Modules/Document/routes/web.php
index a64f256..9dd9589 100644
--- a/Modules/Document/routes/web.php
+++ b/Modules/Document/routes/web.php
@@ -15,6 +15,9 @@ use Modules\Document\Http\Controllers\DocumentController;
*/
Route::group(['middleware' => ['web', 'auth', 'permission'], 'prefix' => 'admin/'], function () {
- Route::get('/documents', [DocumentController::class, 'index'])->name('documents.index');
- Route::post('/documents/dropzone-upload', [DocumentController::class, 'dropzoneUpload'])->name('documents.dropzone.upload');
+ // Route::get('/documents', [DocumentController::class, 'index'])->name('documents.index');
+ 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');
});
diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php
index dc2386a..e1fba1e 100644
--- a/app/Helpers/Helper.php
+++ b/app/Helpers/Helper.php
@@ -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')) {
function uploadImage($file, $path = 'uploads')
{
diff --git a/app/Traits/AddToDocumentCollection.php b/app/Traits/AddToDocumentCollection.php
new file mode 100644
index 0000000..bff2a4b
--- /dev/null
+++ b/app/Traits/AddToDocumentCollection.php
@@ -0,0 +1,33 @@
+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');
+ }
+}
diff --git a/config/sidebar.php b/config/sidebar.php
index 273a139..810aa27 100644
--- a/config/sidebar.php
+++ b/config/sidebar.php
@@ -228,10 +228,10 @@ return [
[
'text' => 'Documents',
- 'url' => 'admin/document',
+ 'url' => 'admin/documents',
'icon' => 'ri-file-text-line',
'module' => 'Document',
- 'can' => ['document.index'],
+ 'can' => ['documents.index'],
],
[
'text' => 'Resume Builder',
diff --git a/resources/views/client/raffles/pages/resources-template.blade.php b/resources/views/client/raffles/pages/resources-template.blade.php
index 6cd75df..16c3588 100644
--- a/resources/views/client/raffles/pages/resources-template.blade.php
+++ b/resources/views/client/raffles/pages/resources-template.blade.php
@@ -13,16 +13,20 @@