Merge branch 'application' into 'settings'

restrict CRUD settings

See merge request ldc-web/projets/com-app-bo!5
This commit is contained in:
Vincent BRIDIER 2023-07-13 08:35:54 +00:00
commit dd59842842
104 changed files with 3765 additions and 919 deletions

View file

@ -3,6 +3,9 @@ APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
API_TOKEN=toto
BRAND=
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null

4
CHANGELOG.md Normal file
View file

@ -0,0 +1,4 @@
#### **21/04/23 ► v2.1**
- Refonte totale du back-office
- Ajout des étiquettes sur les documents
- Ajout d'une section administration des étiquettes

View file

@ -1,7 +1,10 @@
## reste à faire
## Migration v2.1
FO :
ts
view
route
les fichiers à la racine
- add default table of laravel named "Migrations" :
`php artisan migrate:install`
 
- seed migrations already passed :
`php artisan db:seed --class=MigrationSeeder --force`
 
- continue migrations :
`php artisan migrate`

View file

@ -3,7 +3,7 @@
namespace App\Console\Commands;
use App\Models\User;
use App\Enums\AppUserRolesEnum;
use App\Enums\UserRolesEnum;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
@ -201,16 +201,16 @@ class CreateAdmin extends Command
try {
$tmp = $this->choice(
'Select his role',
[AppUserRolesEnum::total()->label, AppUserRolesEnum::user()->label],
AppUserRolesEnum::user()->label,
[UserRolesEnum::admin()->label, UserRolesEnum::client()->label],
UserRolesEnum::client()->label,
$maxAttempts = null,
$allowMultipleSelections = false
);
if ($tmp === AppUserRolesEnum::total()->label) {
$tmp = AppUserRolesEnum::total();
if ($tmp === UserRolesEnum::admin()->label) {
$tmp = UserRolesEnum::admin();
}
if ($tmp === AppUserRolesEnum::user()->label) {
$tmp = AppUserRolesEnum::user();
if ($tmp === UserRolesEnum::client()->label) {
$tmp = UserRolesEnum::client();
}
$validator = Validator::make(['role' => $tmp], [
'role' => 'required'

View file

@ -8,10 +8,10 @@ use Kwaadpepper\Enum\BaseEnumRoutable;
* This defines a data type.
*
* @method static self string() string type
* @method static self json() string type
* @method static self numeric() numeric type
* @method static self boolean() boolean type
* @method static self picture() picture type
* @method static self json() string type
* @method static self boolean() boolean type
* @method static self color() color type
* @method static self directory() directory type
*/
@ -25,10 +25,10 @@ final class SettingTypesEnum extends BaseEnumRoutable
{
return [
'string' => 1,
'json' => 2,
'numeric' => 3,
'boolean' => 4,
'picture' => 5,
'numeric' => 2,
'picture' => 3,
'json' => 4,
'boolean' => 5,
'color' => 6,
'directory' => 7
];
@ -42,10 +42,10 @@ final class SettingTypesEnum extends BaseEnumRoutable
{
return [
'string' => 'String (Hexa)',
'json' => 'Json',
'numeric' => 'Numeric',
'boolean' => 'Boolean',
'picture' => 'Picture',
'json' => 'Json',
'boolean' => 'Boolean',
'color' => 'Color',
'directory' => 'Directory',
];

View file

@ -0,0 +1,38 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* This defines a data type.
*
* @method static self admin() admin role
* @method static self client() client role
*/
final class UserRolesEnum extends BaseEnumRoutable
{
/**
* enum values
* @return array
*/
protected static function values(): array
{
return [
'admin' => 1,
'client' => 2,
];
}
/**
* enum labels
* @return array
*/
protected static function labels(): array
{
return [
'admin' => 'Administrateur',
'client' => 'Client',
];
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Http\Resources\ApiResponseResource;
use App\Models\Directory;
use App\Models\Setting;
class AppController extends Controller
{
/**
* Get App Config.
* @return ApiResponseResource
*/
public function get()
{
$response = [];
$settings = Setting::where('key', 'Button1')->orWhere('key', 'Button2')->orWhere('key', 'Button3')->get();
foreach ($settings as $setting) {
$response['folders'][$setting->key] = Directory::find($setting->value)->only('id', 'name');
}
return new ApiResponseResource("OK", $response);
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Controllers\API;
use App\Enums\SettingTypesEnum;
use App\Http\Controllers\Controller;
use App\Models\Setting;
use App\Http\Resources\ApiResponseResource;
class SettingsController extends Controller
{
/**
* Get Settings.
*
* @return \Illuminate\Http\JsonResponse
*/
public function get()
{
$response = [];
$settings = Setting::all();
foreach ($settings as $setting) {
$response[$setting->key] =
SettingTypesEnum::numeric()->equals($setting->type) ||
SettingTypesEnum::boolean()->equals($setting->type) ||
SettingTypesEnum::directory()->equals($setting->type)
? \intval($setting->value)
: $setting->value;
}
return new ApiResponseResource("OK", $response);
}
}

View file

@ -0,0 +1,246 @@
<?php
namespace App\Http\Controllers\API;
use App\Http\Controllers\Controller;
use App\Mail\SendFlyer;
use App\Mail\SendFlyerFailed;
use App\Models\AppUser;
use App\Models\Contact;
use App\Models\Directory;
use App\Models\Document;
use App\Models\Setting;
use Google\Cloud\Vision\V1\ImageAnnotatorClient;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
class SyncController extends Controller
{
/**
* @param \Illuminate\Http\Request $request
* @return \App\Http\Resources\AppUserCollection
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function getUsers(Request $request)
{
return new \App\Http\Resources\AppUserCollection(AppUser::where('status', 1)->get());
}
/**
* @param \Illuminate\Http\Request $request
* @return \App\Http\Resources\ContactsCollection
*/
public function getContacts(Request $request)
{
$userId = $request->userId;
$this->syncContacts($request->contacts, $userId);
return new \App\Http\Resources\ContactsCollection(Contact::where('app_user_id', $userId)->get());
}
/**
* @param \Illuminate\Http\Request $request
* @return \App\Http\Resources\DirectoriesCollection
*/
public function getDirectories(Request $request)
{
return new \App\Http\Resources\DirectoriesCollection(Directory::all());
}
/**
* @param \Illuminate\Http\Request $request
* @return \App\Http\Resources\DocumentsCollection
*/
public function getDocuments(Request $request)
{
return new \App\Http\Resources\DocumentsCollection(Document::where('status', 1)->get());
}
/**
* @param \Illuminate\Http\Request $request
* @return array
*/
public function getVersion(Request $request)
{
$app_uuid = $request->app_uuid;
$app_version = $request->app_version;
$version = Setting::select('value AS version')->where('key', 'version')->first();
$ShowIsActive = Setting::select('value AS ShowIsActive')->where('key', 'ShowIsActive')->first();
try {
$client = new \GuzzleHttp\Client();
$response = $client->request(
'GET',
'https://store.ldc.fr/api/get-version?token=@P$oi6or!bL2-r%3C&app_uuid=' . $app_uuid
);
$body = $response->getBody();
$storeVersion = json_decode($body)->version;
} catch (ClientException $e) {
$storeVersion = $app_version;
}
if ($storeVersion > $app_version) {
$newApp = true;
} else {
$newApp = false;
}
return ['version' => $version->version, 'ShowIsActive' => $ShowIsActive->ShowIsActive, 'newApp' => $newApp];
}
/**
* @param \Illuminate\Http\Request $request
* @return string
*/
public function sendFlyer(Request $request)
{
$email = $request->emails['email'];
$subject = $request->emails['subject'];
$message = $request->emails['message'];
$app_user_id = $request->emails['app_user_id'];
$docs = $request->emails['documents'];
$user = AppUser::find($app_user_id);
$attach = [];
$filesName = [];
$noExists = [];
foreach ($docs as $doc) {
$exists = Storage::disk('public')->exists('docs/' . $doc['uuid'] . '.' . $doc['type']);
if ($exists) {
array_push($attach, URL::temporarySignedRoute(
'bo.docs.download',
now()->addDays(30),
['uuid' => $doc['uuid']]
));
array_push($filesName, $doc['title']);
} else {
array_push($noExists, $doc['title']);
}
}
if (count($noExists) === 0) {
$message = new SendFlyer([
'body' => $message,
'from' => $user->email,
'fromName' => $user->firstname . ' ' . $user->lastname,
'subject' => '[' . config('app.BRAND') . '] - ' . $subject,
'attach' => $attach,
'filesName' => $filesName,
]);
Mail::to($email)
->cc($user->email)
->queue($message);
} else {
$message = new SendFlyerFailed([
'email' => $email,
'message' => $message,
'subject' => $subject,
'filesName' => $filesName,
'noExists' => $noExists
]);
Mail::to($user->email)
->queue($message);
} //end if
return 'OK';
}
/**
* @param mixed $contacts
* @param mixed $userId
* @return void
*/
private function syncContacts(mixed $contacts, mixed $userId)
{
$contacts = json_decode(json_encode($contacts), false);
foreach ($contacts as $contact) {
if ($contact->to_delete === true) {
$tmp = Contact::where([
['id', '=', $contact->uniq_id],
['app_user_id', '=', $contact->app_user_id]
])->first();
if ($tmp) {
$tmp->delete();
}
} else {
if ($contact->app_user_id != $userId) {
$tmp = Contact::where([
['id', '=', $contact->uniq_id],
['app_user_id', '=', $userId]
])->first();
if ($tmp) {
$tmp->delete();
}
}
$tmp = Contact::where([
['id', '=', $contact->uniq_id],
['app_user_id', '=', $contact->app_user_id]
])->first();
if ($tmp) {
$tmp->email = $contact->email;
$tmp->type = $contact->type;
$tmp->other = $contact->other;
$tmp->select1 = $contact->select1;
$tmp->select2 = $contact->select2;
$tmp->lastname = $contact->lastname;
$tmp->firstname = $contact->firstname;
$tmp->company = $contact->company;
$tmp->address = $contact->address;
$tmp->phone = empty($contact->phone) ? "" : $contact->phone;
$tmp->products = $contact->products;
$tmp->notes = $contact->notes;
$tmp->visits = $contact->visits;
$tmp->app_user_id = $contact->app_user_id;
$tmp->save();
} else {
$tmp = new Contact();
$tmp->id = $contact->uniq_id;
$tmp->email = $contact->email;
$tmp->type = $contact->type;
$tmp->other = $contact->other;
$tmp->select1 = $contact->select1;
$tmp->select2 = $contact->select2;
$tmp->lastname = $contact->lastname;
$tmp->firstname = $contact->firstname;
$tmp->company = $contact->company;
$tmp->address = $contact->address;
$tmp->phone = empty($contact->phone) ? "" : $contact->phone;
$tmp->products = json_encode($contact->products);
$tmp->notes = $contact->notes;
$tmp->visits = $contact->visits;
$tmp->app_user_id = $contact->app_user_id;
$tmp->save();
} //end if
} //end if
} //end foreach
}
/**
* @param \Illuminate\Http\Request $request
* @return void
*/
public function processOcr(Request $request)
{
// Instantiates a client.
$imageAnnotator = new ImageAnnotatorClient([
'credentials' => public_path() . '/credentials.json'
]);
// The name of the image file to annotate.
$fileName = 'test.jpg';
// Prepare the image to be annotated.
$image = file_get_contents(public_path() . "/" . $fileName);
// Performs label detection on the image file.
$response = $imageAnnotator->textDetection($image);
$labels = $response->getTextAnnotations();
foreach ($labels as $label) {
echo $label->getDescription() . "<br>";
}
}
}

View file

@ -3,11 +3,15 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\Contact;
use Illuminate\Support\Facades\Storage;
use Parsedown;
use Illuminate\Support\Facades\File;
class DashboardController extends Controller
{
/**
* Dashboard Page
* Show the application dashboard.
*
* @return \Illuminate\Contracts\View\View
*/
@ -15,4 +19,48 @@ class DashboardController extends Controller
{
return view('bo.pages.dashboard');
}
/**
* Récupérer les contacts (fichier .csv) et les fichiers.
*
* @return \Illuminate\Http\Response|\Illuminate\Contracts\Routing\ResponseFactory
*/
public function exportContact()
{
$csv_file = 'export-contacts.csv';
$csvExporter = new \Laracsv\Export();
$contacts = Contact::all();
$csvExporter->beforeEach(function ($contact) {
$contact->app_user_id = $contact->firstname . " " . $contact->lastname;
$contact->phone = "$contact->phone";
});
$csvExporter->getWriter()->setDelimiter(';');
$csvExporter->getWriter()->setEnclosure('"');
$csvExporter->getWriter()->setOutputBOM(\League\Csv\Reader::BOM_UTF8);
$csvExporter->build($contacts, [
'app_user_id' => 'Propriétaire',
'email' => 'Email',
'type' => 'Type du contact',
'other' => 'Type autre',
'select1' => 'Select n°1',
'select2' => 'Select n°2',
'name' => 'Nom',
'firstname' => 'Prénom',
'company' => 'Entreprise',
'address' => 'Adresse',
'phone' => 'Téléphone',
'notes' => 'Notes',
'visits' => 'Visites',
]);
Storage::disk('public')->put($csv_file, $csvExporter->getWriter()->getContent());
return response()->download(
storage_path('app/public/') . "$csv_file",
'contacts.csv',
['Content-Type' => 'text/csv; charset=utf-8']
)->deleteFileAfterSend();
}
}

View file

@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Directories\StoreDirectoryRequest;
use App\Http\Requests\Bo\Directories\UpdateDirectoryRequest;
use App\Models\Directory;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
@ -35,7 +36,6 @@ class DirectoriesController extends Controller
return DB::transaction(function () use ($request) {
$directory = new Directory();
$directory->fill($request->validated());
if ($directory->saveOrFail()) {
return redirect()
->route('bo.directories.index')
@ -44,7 +44,6 @@ class DirectoriesController extends Controller
['model' => Str::singular(trans('models.classes.directories'))]
));
}
return redirect()
->back()
->with('error', trans(
@ -102,26 +101,28 @@ class DirectoriesController extends Controller
*/
public function destroy(Directory $directory)
{
return DB::transaction(function () use ($directory) {
foreach ($directory->children as $directoryChild) {
$directoryChild->directory_id = null;
$directoryChild->saveOrFail();
foreach ($directory->children as $directoryChild) {
$directoryChild->directory_id = null;
$directoryChild->saveOrFail();
}
$buttons = Setting::where('key', 'Button1')->orWhere('key', 'Button2')->orWhere('key', 'Button3')->get();
foreach ($buttons as $button) {
if (isset($button->value) && intval($button->value) === $directory->id) {
return [
$button->id => trans(
':model :name n\'a pas été supprimé,
un bouton est encore associé à ce dernier dans les paramètres :',
[
'model' => Str::singular(trans('models.classes.directories')),
'name' => $directory->name['fr']
]
)
];
}
if ($directory->deleteOrFail()) {
return redirect()
->route('bo.directories.index')
->with('warning', trans(
':model a bien été supprimé',
['model' => Str::singular(trans('models.classes.directories'))]
));
}
return redirect()
->back()
->with('error', trans(
':model n\'a pas été supprimé',
['model' => Str::singular(trans('models.classes.directories'))]
));
});
}
if ($directory->deleteOrFail()) {
return Directory::orderBy('order', 'ASC')->get();
}
}
/**
@ -138,11 +139,11 @@ class DirectoriesController extends Controller
/**
* Assign the new order and directory id to each directory.
*
* @param array $directories
* @param mixed $directoryId
* @param array $directories
* @param integer $directoryId
* @return void
*/
public function assignOrder(array $directories, mixed $directoryId = null)
public function assignOrder(array $directories, int $directoryId = null)
{
foreach ($directories as $newDirectory) {
$directory = Directory::where('id', $newDirectory['id'])->first();
@ -167,18 +168,7 @@ class DirectoriesController extends Controller
$directory->needAuthorization = $directory->needAuthorization ? false : true;
if ($directory->saveOrFail()) {
return redirect()
->route('bo.directories.index')
->with('success', trans(
':model a été mis à jour',
['model' => Str::singular(trans('models.classes.directories'))]
));
return $directory;
}
return redirect()
->back()
->with('error', trans(
':model n\'a été mis à jour',
['model' => Str::singular(trans('models.classes.directories'))]
));
}
}

View file

@ -7,10 +7,13 @@ use App\Http\Requests\Bo\Documents\StoreDocumentRequest;
use App\Http\Requests\Bo\Documents\UpdateDocumentRequest;
use App\Models\Directory;
use App\Models\Document;
use App\Models\Tag;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Pion\Laravel\ChunkUpload\Exceptions\UploadMissingFileException;
use Pion\Laravel\ChunkUpload\Handler\HandlerFactory;
@ -30,6 +33,7 @@ class DocumentController extends Controller
{
/** @var \Illuminate\Database\Eloquent\Builder $documents */
$documents = Document::query();
$tags = Tag::get();
if ($request->search) {
$this->searchQuery(
@ -40,12 +44,23 @@ class DocumentController extends Controller
);
}
$documents->when($request->tag, function ($query) use ($request) {
$query->whereHas('tags', function (Builder $query) use ($request) {
$query->where('id', $request->tag);
});
});
$this->sortQuery($documents);
$searchFields = trans('Titre');
$documents = $documents->paginate(10);
return view('bo.pages.documents.index', compact('documents', 'searchFields'));
return view('bo.pages.documents.index', [
'documents' => $documents,
'searchFields' => $searchFields,
'searchTag' => $request->tag,
'tags' => $tags
]);
}
/**
@ -55,10 +70,11 @@ class DocumentController extends Controller
*/
public function create()
{
$documents = Document::get();
$documents = Document::where('lang', \App\Enums\Documents\LangEnum::fr())->get();
$directories = Directory::getChildrenDirectories();
$tags = Tag::get();
return view('bo.pages.documents.create', compact('documents', 'directories'));
return view('bo.pages.documents.create', compact('documents', 'directories', 'tags'));
}
/**
@ -72,8 +88,8 @@ class DocumentController extends Controller
return DB::transaction(function () use ($request) {
$document = new Document();
$document->fill($request->validated());
if ($document->saveOrFail()) {
$document->tags()->sync(collect($request->tags)->pluck('id'));
return redirect()
->route('bo.documents.edit', $document)
->with('success', trans(
@ -81,7 +97,6 @@ class DocumentController extends Controller
['model' => Str::singular(trans('models.classes.documents'))]
));
}
return redirect()
->back()
->with('error', trans(
@ -99,13 +114,15 @@ class DocumentController extends Controller
*/
public function edit(Document $document)
{
$documents = Document::get();
$documents = Document::where('lang', \App\Enums\Documents\LangEnum::fr())->get();
$directories = Directory::getChildrenDirectories();
$tags = Tag::get();
return view('bo.pages.documents.edit', [
'documents' => $documents,
'documentModel' => $document,
'directories' => $directories
'directories' => $directories,
'tags' => $tags
]);
}
@ -120,6 +137,7 @@ class DocumentController extends Controller
{
return DB::transaction(function () use ($request, $document) {
$document->fill($request->validated());
$document->tags()->sync(collect($request->tags)->pluck('id'));
if ($document->saveOrFail()) {
return redirect()
->route('bo.documents.edit', $document)
@ -145,6 +163,10 @@ class DocumentController extends Controller
*/
public function destroy(Document $document)
{
foreach ($document->children as $documentChild) {
Document::removeDocument($documentChild);
$documentChild->deleteOrFail();
}
if ($document->deleteOrFail()) {
return redirect()
->route('bo.documents.index')
@ -153,7 +175,6 @@ class DocumentController extends Controller
['model' => Str::singular(trans('models.classes.documents'))]
));
}
return redirect()
->back()
->with('error', trans(
@ -162,6 +183,19 @@ class DocumentController extends Controller
));
}
/**
* Download the document
*
* @param mixed $uuid
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function download(mixed $uuid)
{
$doc = Document::where('uuid', $uuid)->firstOrFail();
$pathToFile = public_path() . Storage::url('docs/' . $doc->uuid . '.' . $doc->type);
return response()->download($pathToFile, $doc->path);
}
/**
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse

View file

@ -6,43 +6,27 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Settings\UpdateSettingRequest;
use App\Models\Directory;
use App\Models\Setting;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class SettingController extends Controller
{
use ChangesModelOrder;
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
public function index()
{
$directories = Directory::renderDirectories(Directory::whereNull('directory_id')->get());
/** @var \Illuminate\Database\Eloquent\Builder $settings */
$settings = Setting::query();
if ($request->search) {
$this->searchQuery(
$settings,
$request->search,
null,
'title',
);
}
$this->sortQuery($settings);
$searchFields = trans('Titre');
$settings = $settings->get();
$settings = $settings->paginate(14);
return view('bo.pages.settings.index', compact('settings', 'searchFields', 'directories'));
return view('bo.pages.settings.index', compact('settings', 'directories'));
}
/**

View file

@ -0,0 +1,147 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Tags\StoreTagRequest;
use App\Http\Requests\Bo\Tags\UpdateTagRequest;
use App\Models\Tag;
use App\Traits\Controllers\ChangesModelOrder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class TagController extends Controller
{
use ChangesModelOrder;
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
/** @var \Illuminate\Database\Eloquent\Builder $tags */
$tags = Tag::query();
if ($request->search) {
$this->searchQuery(
$tags,
$request->search,
null,
'name',
);
}
$this->sortQuery($tags);
$searchFields = trans('Nom');
$tags = $tags->paginate(10);
return view('bo.pages.tags.index', compact('tags', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('bo.pages.tags.create');
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Tag\StoreTagRequest $request
* @return \Illuminate\Http\Response
*/
public function store(StoreTagRequest $request)
{
return DB::transaction(function () use ($request) {
$tag = new Tag();
$tag->fill($request->validated());
if ($tag->saveOrFail()) {
return redirect()
->route('bo.tags.edit', $tag)
->with('success', trans(
':model a été créé',
['model' => Str::singular(trans('models.classes.tags'))]
));
}
return redirect()
->back()
->with('error', trans(
':model n\'a pas été créé',
['model' => Str::singular(trans('models.classes.tags'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Tag $tag
* @return \Illuminate\Http\Response
*/
public function edit(Tag $tag)
{
return view('bo.pages.tags.edit', ['tagModel' => $tag]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Tag\UpdateTagRequest $request
* @param \App\Models\Tag $tag
* @return \Illuminate\Http\Response
*/
public function update(UpdateTagRequest $request, Tag $tag)
{
return DB::transaction(function () use ($request, $tag) {
$tag->fill($request->validated());
if ($tag->saveOrFail()) {
return redirect()
->route('bo.tags.edit', $tag)
->with('success', trans(
':model a été mis à jour',
['model' => Str::singular(trans('models.classes.tags'))]
));
}
return redirect()
->back()
->with('error', trans(
':model n\'a pas été mis à jour',
['model' => Str::singular(trans('models.classes.tags'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Tag $tag
* @return \Illuminate\Http\Response
*/
public function destroy(Tag $tag)
{
if ($tag->deleteOrFail()) {
return redirect()
->route('bo.tags.index')
->with('warning', trans(
':model a bien été supprimé',
['model' => Str::singular(trans('models.classes.tags'))]
));
}
return redirect()
->back()
->with('error', trans(
':model n\'a pas été supprimé',
['model' => Str::singular(trans('models.classes.tags'))]
));
}
}

View file

@ -64,5 +64,6 @@ class Kernel extends HttpKernel
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'htmlsanitize' => \App\Http\Middleware\HtmlSanitizer::class,
'api.token' => \App\Http\Middleware\CheckApiToken::class,
];
}

View file

@ -0,0 +1,24 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckApiToken
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if (isset($request->token) && $request->token == config('auth.API_TOKEN')) {
return $next($request);
}
return response()->json(['message' => 'Nope'], 401);
}
}

View file

@ -18,6 +18,18 @@ 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.
*
@ -26,16 +38,17 @@ class StoreDocumentRequest extends FormRequest
public function rules()
{
return [
'directory_id' => 'sometimes|nullable|integer',
'document_id' => 'sometimes|nullable|integer',
'uuid' => 'required|min:3|max:255',
'title' => 'required|min:3|max:255',
'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)
],
'status' => 'required|boolean'
];
}
@ -47,7 +60,14 @@ class StoreDocumentRequest extends FormRequest
public function attributes()
{
return [
'directory_id' => \trans('dossier à associer'),
'document_id' => \trans('document (FR) à associer'),
'title' => \trans('titre'),
'uuid' => \trans('document'),
'type' => \trans('type du document'),
'path' => \trans('chemin du document'),
'lang' => \trans('langue du document'),
'status' => \trans('état de publication du document'),
];
}
}

View file

@ -3,7 +3,6 @@
namespace App\Http\Requests\Bo;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class ImportRequest extends FormRequest
{
@ -14,7 +13,7 @@ class ImportRequest extends FormRequest
*/
public function authorize()
{
return Auth::check();
return auth('backend')->check();
}
/**

View file

@ -2,8 +2,11 @@
namespace App\Http\Requests\Bo\Settings;
use App\Enums\UserRolesEnum;
use App\Models\Setting;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class UpdateSettingRequest extends FormRequest
{
@ -16,7 +19,16 @@ class UpdateSettingRequest extends FormRequest
*/
public function authorize()
{
return auth('backend')->check();
if (
$this->key === "Button1" ||
$this->key === "Button2" ||
$this->key === "Button3" ||
$this->key === "ShowIsActive"
) {
return auth('backend')->check();
} else {
return (auth('backend')->check() && Auth::user()->role === UserRolesEnum::admin()->value);
}
}
/**
@ -27,9 +39,14 @@ class UpdateSettingRequest extends FormRequest
protected function prepareForValidation()
{
if ($this->key === "ShowIsActive") {
$this->merge(['value' => $this->value ? "true" : "false"]);
}
if (
$this->merge(['value' => intval($this->value) ? "true" : "false"]);
} elseif (
$this->key === "Button1" ||
$this->key === "Button2" ||
$this->key === "Button3"
) {
$this->merge(['value' => $this->value === "0" ? null : $this->value]);
} elseif (
$this->key === "SquaredLogo" ||
$this->key === "RectangleLogo" ||
$this->key === "BackgroundImage" ||
@ -46,22 +63,43 @@ class UpdateSettingRequest extends FormRequest
*/
public function rules()
{
$rules = [
'value' => 'required|string|min:1',
];
if (
$this->key === "Button1" ||
$this->key === "Button2" ||
$this->key === "Button3"
) {
$buttonsNullable = 0;
$buttons = Setting::where('key', 'Button1')
->orWhere('key', 'Button2')
->orWhere('key', 'Button3')
->get();
foreach ($buttons as $button) {
if ($button->value === null) {
if ($button->key !== $this->key) {
$buttonsNullable++;
}
};
}
return [
'value' => [
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
function ($attribute, $value, $fail) use ($buttonsNullable) {
if (!isset($value) && $buttonsNullable >= 2) {
$fail(\trans('Au moins 1 bouton doît être défini.'));
}
}
]
];
} elseif (
$this->key === "SquaredLogo" ||
$this->key === "RectangleLogo" ||
$this->key === "BackgroundImage" ||
$this->key === "HomeButtonImage"
) {
return \array_merge(
$rules,
$this->pictureRules('value', true, 100, 100, 1920, 1200),
);
return $this->pictureRules('value', true, 100, 100, 1920, 1200);
} else {
return $rules;
}
return ['value' => 'required|string|min:1'];
} //end if
}
/**
@ -74,6 +112,7 @@ class UpdateSettingRequest extends FormRequest
return [
'key' => \trans('clé'),
'value' => \trans('valeur'),
'type' => \trans('type'),
];
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace App\Http\Requests\Bo\Tags;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Str;
class StoreTagRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'slug' => Str::slug($this->name),
]);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|string|min:2|max:25',
];
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes(): array
{
return [
'name' => trans('name of the tag'),
'slug' => trans('slug of the tag'),
];
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace App\Http\Requests\Bo\Tags;
class UpdateTagRequest extends StoreTagRequest
{
}

View file

@ -0,0 +1,46 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ApiResponseResource extends JsonResource
{
/**
* Status
* @var string
*/
private $status;
/**
* Datas
* @var array
*/
private $datas;
/**
* Create a new resource instance.
*
* @param string $status
* @param array $datas
* @return void
*/
public function __construct(string $status, array $datas)
{
$this->status = $status;
$this->datas = $datas;
}
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'status' => $this->status,
'datas' => $this->datas
];
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class AppUserCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ContactsCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class DirectoriesCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class DocumentsCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}

View file

@ -2,8 +2,11 @@
namespace App\Imports;
use App\Mail\AccountCreated;
use App\Enums\AppUserRolesEnum;
use App\Models\AppUser;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithUpserts;
@ -43,11 +46,19 @@ class AppUserImport implements ToModel, WithUpserts, WithCustomCsvSettings
'email' => $row[3],
'lastname' => ucfirst(strtolower($row[1])),
'firstname' => ucfirst(strtolower($row[2])),
'password' => Str::random(10),
'password' => '',
'status' => 1,
'role' => AppUserRolesEnum::user(),
]);
if ($user) {
$password = Str::random(10);
$user->password = Hash::make($password);
$user->save();
Mail::to($user->email)->send(new AccountCreated($user, $password));
}
$user->saveOrFail();
return $user;

View file

@ -0,0 +1,47 @@
<?php
namespace App\Mail;
use App\Models\AppUser;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class AccountCreated extends Mailable
{
use Queueable;
use SerializesModels;
/**
* The app user instance
*
* @var \App\Models\AppUser;
*/
public $user;
/** @var string */
public $password;
/**
* Create a new message instance.
*
* @param \App\Models\AppUser $user
* @param string $password
* @return void
*/
public function __construct(AppUser $user, string $password)
{
$this->user = $user;
$this->password = $password;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->subject(__("Votre compte a été créé"))->view('emails.account-created');
}
}

40
app/Mail/SendFlyer.php Normal file
View file

@ -0,0 +1,40 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SendFlyer extends Mailable
{
use Queueable;
use SerializesModels;
/** @var object */
public $data;
/**
* Create a new message instance.
*
* @param mixed $data
* @return void
*/
public function __construct(mixed $data)
{
$this->data = (object)$data;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this
->from($this->data->from, $this->data->fromName)
->subject($this->data->subject)
->markdown('bo.mails.sendflyer');
}
}

View file

@ -0,0 +1,40 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SendFlyerFailed extends Mailable
{
use Queueable;
use SerializesModels;
/** @var object */
private $data;
/**
* Create a new message instance.
*
* @param mixed $data
* @return void
*/
public function __construct(mixed $data)
{
$this->data = (object)$data;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this
->from('noreply@ldc.fr', '[APP] ' . config('app.name'))
->subject('[MAIL] Une erreur est survenue')
->view('bo.mails.sendflyerfailed', ['data' => $this->data]);
}
}

View file

@ -103,6 +103,6 @@ class AppUser extends Model
*/
public function directories()
{
return $this->morphToMany(Directory::class, 'taggable');
return $this->morphToMany(Directory::class, 'directorable');
}
}

63
app/Models/Contact.php Normal file
View file

@ -0,0 +1,63 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Kwaadpepper\Enum\Traits\CastsEnums;
/**
* @property integer $app_user_id
* @property integer $id
* @property string $email
* @property string $type
* @property string $other
* @property string $select1
* @property string $select2
* @property string $name
* @property string $firstname
* @property string $company
* @property string $address
* @property string $phone
* @property string $products
* @property string $card_url
* @property string $notes
* @property string $visits
*/
class Contact extends Model
{
use CastsEnums;
/**
* fillable
* @var string[]
*/
protected $fillable = [
'app_user_id',
'email',
'type',
'other',
'select1',
'select2',
'name',
'firstname',
'company',
'address',
'phone',
'products',
'card_url',
'notes',
'visits',
];
// * RELATIONSHIPS
/**
* MorphToMany Directories
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function appUser()
{
return $this->belongsTo(AppUser::class, 'id', 'app_user_id');
}
}

View file

@ -16,13 +16,6 @@ class Directory extends Model
{
use HasFactory;
/**
* The accessors to append to the model's array form.
*
* @var string[]
*/
protected $appends = ['is_system'];
/**
* Fillable;
*
@ -32,7 +25,8 @@ class Directory extends Model
'name',
'directory_id',
'order',
'needAuthorization'
'needAuthorization',
'is_system'
];
/**
@ -52,6 +46,7 @@ class Directory extends Model
protected static function booted()
{
static::creating(function (self $model) {
self::setIsSystem($model);
self::setOrder($model);
});
static::deleting(function (self $model) {
@ -76,14 +71,14 @@ class Directory extends Model
}
/**
* Check if is directory system.
* 1 = Salon
* Set order after the last element of the list.
*
* @return boolean
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
public function getIsSystemAttribute()
private static function setIsSystem(Model $model): void
{
return $this->id === 1;
$model->is_system = ($model->is_system) ? $model->is_system : 0;
}
/**
@ -165,7 +160,7 @@ class Directory extends Model
*/
public function appusers()
{
return $this->morphedByMany(AppUser::class, 'taggable');
return $this->morphedByMany(AppUser::class, 'directorable');
}
/**

View file

@ -41,6 +41,15 @@ class Document extends Model
'order',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'status' => 'bool'
];
/**
* Map attribute names to enum classes.
*
@ -62,6 +71,12 @@ class Document extends Model
self::assertFieldIsUnique('title', $model->title);
self::setOrder($model);
});
static::updating(function (self $model) {
$path = \ltrim(\urldecode("docs/" . $model->getOriginal('uuid') . $model->getOriginal('type')), '/');
if (Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
});
static::deleting(function (self $model) {
self::removeDocument($model);
});
@ -94,24 +109,13 @@ class Document extends Model
$model->order = \intval(self::query()->max('order')) + 1;
}
/**
* Check if is directory system.
* 1 = Salon
*
* @return boolean
*/
public function getIsSystemAttribute()
{
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
public static function removeDocument(Model $model): void
{
$path = \ltrim(\urldecode("storage/docs/" . $model->uuid . $model->type), '/');
if (\strpos($path, 'storage') !== 0) {
@ -142,7 +146,7 @@ class Document extends Model
*/
public function parent()
{
return $this->belongsTo('App\Models\Documents', 'document_id');
return $this->belongsTo('App\Models\Document', 'document_id');
}
/**
@ -152,7 +156,7 @@ class Document extends Model
*/
public function children()
{
return $this->hasMany('App\Models\Documents', 'document_id');
return $this->hasMany('App\Models\Document', 'document_id');
}
/**
@ -164,4 +168,14 @@ class Document extends Model
{
return $this->morphedByMany(AppUser::class, 'taggable');
}
/**
* MorphToMany tags relation.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}

107
app/Models/Tag.php Normal file
View file

@ -0,0 +1,107 @@
<?php
namespace App\Models;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
/**
* @property integer $id
* @property string $name
* @property string $slug
* @property integer $order
*/
class Tag extends Model
{
use HasFactory;
/**
* Indicates if the model should be timestamped.
*
* @var boolean
*/
public $timestamps = false;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'slug',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $tag) {
static::setSlug($tag);
static::assertFieldIsUnique($tag->slug);
static::setOrder($tag);
});
static::updating(function (self $tag) {
static::assertFieldIsUnique($tag->slug, $tag->id);
});
static::deleting(function (self $tag) {
$tag->documents()->detach();
});
}
// * METHODS
/**
* Set the slug.
*
* @param \App\Models\Tag $tag
*
* @return void
*/
private static function setSlug(Tag $tag)
{
$tag->slug = Str::slug($tag->name);
}
/**
* Asserts using validation that the field is unique.
*
* @param string $slug
* @param integer|null $id
* @return void
* @throws \Illuminate\Validation\ValidationException If field already exists.
*/
private static function assertFieldIsUnique(string $slug, ?int $id = null)
{
$table = (new self())->getTable();
ToolboxHelper::assertFieldIsUnique($table, 'slug', $slug, $id);
}
/**
* Set order after the last element of the list.
*
* @param \App\Models\Tag $tag
* @return void
*/
private static function setOrder(Tag $tag): void
{
$tag->order = \intval(self::query()->max('order')) + 1;
}
// * RELATIONSHIPS
/**
* MorphToMany documents relation.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function documents()
{
return $this->morphedByMany(Document::class, 'taggable');
}
}

View file

@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use App\Enums\UserRolesEnum;
class User extends Authenticatable
{
@ -45,6 +46,14 @@ class User extends Authenticatable
'email_verified_at' => 'datetime',
];
/**
* cast enum
* @var string[]
*/
protected $enumCasts = [
'role' => UserRolesEnum::class
];
/**
* Perform any actions required after the model boots.
*

View file

@ -2,6 +2,7 @@
namespace App\Providers;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\URL;
@ -36,5 +37,7 @@ class AppServiceProvider extends ServiceProvider
\strtoupper(config('app.locale'))
));
Carbon::setLocale(config('app.locale'));
JsonResource::withoutWrapping();
}
}

View file

@ -4,6 +4,7 @@ namespace App\Providers;
use App\Models\AppUser;
use App\Models\Document;
use App\Models\Tag;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
@ -36,10 +37,16 @@ class RouteServiceProvider extends ServiceProvider
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web-bo.php'));
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
});
Route::model('appuser', AppUser::class);
Route::model('document', Document::class);
Route::model('tag', Tag::class);
}
/**

View file

@ -1,12 +1,7 @@
{
"name": "laravel/laravel",
"name": "uwil/com-app-bo",
"version": "1.0.0",
"type": "project",
"time": "2023-03-02",
"description": "The Laravel Framework.",
"support": {
"email": "equipe.web@ldc.fr"
},
"description": "Back-Office for Commercial App",
"keywords": [
"framework",
"laravel"
@ -15,7 +10,9 @@
"require": {
"php": "^7.3|^8.0",
"diglactic/laravel-breadcrumbs": "^6.1",
"erusev/parsedown": "^1.7",
"fruitcake/laravel-cors": "^2.0",
"google/cloud-vision": "^0.25.0",
"guzzlehttp/guzzle": "^7.0.1",
"kwaadpepper/enum": "^2.1",
"kwaadpepper/image-resizer": "^0.1.2",
@ -28,7 +25,8 @@
"mews/purifier": "^3.3",
"pion/laravel-chunk-upload": "^1.3",
"sentry/sentry-laravel": "^3.2",
"spatie/laravel-mix-preload": "^1.3"
"spatie/laravel-mix-preload": "^1.3",
"usmanhalalit/laracsv": "^2.0"
},
"require-dev": {
"facade/ignition": "^2.5",
@ -41,7 +39,7 @@
"slevomat/coding-standard": "^8.8"
},
"repositories": {
"lab.s-web.fr/23": {
"lab.s-web.fr": {
"type": "composer",
"url": "https://lab.s-web.fr/api/v4/group/23/-/packages/composer/packages.json"
}

1510
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,8 @@
return [
'BRAND' => env('BRAND', 'LDC'),
/*
|--------------------------------------------------------------------------
| Application Name

View file

@ -13,6 +13,8 @@ return [
|
*/
'API_TOKEN' => env('API_TOKEN'),
'defaults' => [
'guard' => 'frontend',
'passwords' => 'users',

View file

@ -33,6 +33,7 @@ class DirectoryFactory extends Factory
],
'directory_id' => null,
'needAuthorization' => $this->faker->boolean(50),
'is_system' => 0,
];
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace Database\Factories;
use App\Models\Tag;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends Factory<\App\Models\Tag>
*/
final class TagFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Tag::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
$name = $this->faker->unique()->word;
return [
'name' => $name,
'slug' => Str::slug($name),
];
}
}

View file

@ -14,7 +14,7 @@ class CreateFailedJobsTable extends Migration
public function up()
{
Schema::create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->bigIncrements('id');
$table->string('uuid')->unique();
$table->text('connection');
$table->text('queue');

View file

@ -1,34 +0,0 @@
<?php
use App\Enums\AppUserRolesEnum;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
class UpdateRoleAppUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::table('app_users')->where('role', 'USER')->update(['role' => AppUserRolesEnum::user()->value]);
DB::table('app_users')->where('role', 'TOTAL')->update(['role' => AppUserRolesEnum::total()->value]);
DB::statement("ALTER TABLE app_users CHANGE COLUMN role role TINYINT NOT NULL");
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
DB::statement("ALTER TABLE app_users CHANGE COLUMN role role VARCHAR(50) NOT NULL");
DB::table('app_users')->where('role', strval(AppUserRolesEnum::user()->value))->update(['role' => 'USER']);
DB::table('app_users')->where('role', strval(AppUserRolesEnum::total()->value))->update(['role' => 'TOTAL']);
}
}

View file

@ -1,27 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
class UpdatePasswordAppUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::statement("ALTER TABLE app_users CHANGE COLUMN password password VARCHAR(255) NOT NULL");
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
DB::statement("ALTER TABLE app_users CHANGE COLUMN password password BLOB NOT NULL");
}
}

View file

@ -1,32 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class UpdateSurnameAppUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('app_users', function (Blueprint $table) {
$table->renameColumn('surname', 'lastname');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('app_users', function (Blueprint $table) {
$table->renameColumn('lastname', 'surname');
});
}
}

View file

@ -0,0 +1,55 @@
<?php
use App\Models\Directory;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class UpdateDirectoryTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// * APP_USER->UPDATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `directories` CHANGE `updated_at` `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
Schema::table('directories', function (Blueprint $table) {
$table->renameColumn('parent', 'directory_id');
$table->json('name')->change();
$table->boolean('is_system')->after('needAuthorization')->comment('Le dossier est-il administrable ?');
$table->dateTime('created_at')->default('CURRENT_TIMESTAMP')->nullable()->change();
});
Directory::each(function (Directory $model) {
if ($model->name['fr'] === "Le Salon") {
$model->is_system = 1;
$model->saveOrFail();
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
// * APP_USER->CREATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `directories` CHANGE `created_at` `created_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
Schema::table('directories', function (Blueprint $table) {
$table->renameColumn('directory_id', 'parent');
$table->string('name')->change();
$table->dropColumn('is_system');
$table->dateTime('updated_at')->default('0000-00-00 00:00:00')->nullable()->change();
});
}
}

View file

@ -13,10 +13,10 @@ class AddPivotDirectoryTable extends Migration
*/
public function up()
{
Schema::create('taggables', function (Blueprint $table) {
Schema::create('directorables', function (Blueprint $table) {
$table->foreignId('directory_id')->references('id')->on('directories');
$table->bigInteger('taggable_id')->comment('Id du model associé');
$table->string('taggable_type', 60)->comment('Type du model associé');
$table->bigInteger('directorable_id')->comment('Id du model associé');
$table->string('directorable_type', 60)->comment('Type du model associé');
});
}
@ -27,6 +27,6 @@ class AddPivotDirectoryTable extends Migration
*/
public function down()
{
Schema::dropIfExists('taggables');
Schema::dropIfExists('directorables');
}
}

View file

@ -0,0 +1,86 @@
<?php
use App\Enums\AppUserRolesEnum;
use App\Models\AppUser;
use App\Models\Directory;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class UpdateAppUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// * APP_USER->UPDATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `app_users` CHANGE `updated_at` `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
// * APP_USER->ROLE
DB::table('app_users')->where('role', 'USER')->update(['role' => AppUserRolesEnum::user()->value]);
DB::table('app_users')->where('role', 'TOTAL')->update(['role' => AppUserRolesEnum::total()->value]);
DB::statement("ALTER TABLE app_users CHANGE COLUMN role role TINYINT NOT NULL");
// * APP_USER->PASSWORD
DB::statement("ALTER TABLE app_users CHANGE COLUMN password password VARCHAR(255) NOT NULL");
$appUsersOld = AppUser::get();
// * OTHERS
Schema::table('app_users', function (Blueprint $table) {
$table->dropUnique('email');
$table->unique(['email']);
$table->renameColumn('surname', 'lastname');
$table->renameColumn('activated', 'status');
$table->integer('order')->after('role')->comment('Ordonnance des utilisateurs de l\'applications.');
$table->dropColumn('authorizedFolders');
$table->dateTime('created_at')->default('CURRENT_TIMESTAMP')->nullable()->change();
});
AppUser::each(function (AppUser $appUserModel, int $key) use ($appUsersOld) {
foreach (json_decode($appUsersOld[$key]->authorizedFolders) as $directory) {
Directory::each(function (Directory $directoryModel) use ($appUserModel, $directory) {
if ($directoryModel->id == $directory->id) {
$appUserModel->directories()->save($directoryModel);
}
});
}
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
// * APP_USER->ROLE
DB::statement("ALTER TABLE app_users CHANGE COLUMN role role VARCHAR(50) NOT NULL");
DB::table('app_users')->where('role', strval(AppUserRolesEnum::user()->value))->update(['role' => 'USER']);
DB::table('app_users')->where('role', strval(AppUserRolesEnum::total()->value))->update(['role' => 'TOTAL']);
// * APP_USER->CREATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `app_users` CHANGE `created_at` `created_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
// * APP_USER->PASSWORD
DB::statement("ALTER TABLE app_users CHANGE COLUMN password password BLOB NOT NULL");
// * OTHERS
Schema::table('app_users', function (Blueprint $table) {
$table->dropUnique(['email']);
$table->unique('email');
$table->renameColumn('lastname', 'surname');
$table->renameColumn('status', 'activated');
$table->dropColumn('order');
$table->text('authorizedFolders')->nullable();
$table->dateTime('updated_at')->default('0000-00-00 00:00:00')->nullable()->change();
});
}
}

View file

@ -1,7 +1,9 @@
<?php
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class UpdateUsersTable extends Migration
@ -13,10 +15,23 @@ class UpdateUsersTable extends Migration
*/
public function up()
{
$usersOld = User::get();
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `users` CHANGE `updated_at` `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('name', 'firstname');
$table->string('lastname')->after('name');
$table->string('lastname')->nullable()->after('name');
$table->dateTime('created_at')->default('CURRENT_TIMESTAMP')->nullable()->change();
});
$usersNew = User::get();
foreach ($usersNew as $key => $userNew) {
$userName = explode(" ", $usersOld[$key]->name);
$userNew->firstname = $userName[0];
$userNew->lastname = $userName[1] ?? null;
$userNew->saveOrFail();
}
}
/**
@ -26,9 +41,22 @@ class UpdateUsersTable extends Migration
*/
public function down()
{
// * APP_USER->CREATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `users` CHANGE `created_at` `created_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
$usersOld = User::get();
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('firstname', 'name');
$table->dropColumn('lastname');
$table->dateTime('updated_at')->default('0000-00-00 00:00:00')->nullable()->change();
});
$usersNew = User::get();
foreach ($usersNew as $key => $userNew) {
$userNew->name = $usersOld[$key]->firstname . " " . $userNew[$key]->lastname;
$userNew->saveOrFail();
}
}
}

View file

@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class UpdateAppUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('app_users', function (Blueprint $table) {
$table->integer('order')->after('role')->comment('Ordonnance des utilisateurs de l\'applications.');
$table->dropColumn('authorizedFolders');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('app_users', function (Blueprint $table) {
$table->dropColumn('order');
$table->text('authorizedFolders')->nullable();
});
}
}

View file

@ -1,40 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class UpdateDirectoryTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('directories', function (Blueprint $table) {
$table->dropForeign('directories_parent_foreign');
$table->dropColumn('parent');
$table->unsignedBigInteger('directory_id')->index()->nullable()->after('id');
$table->foreign(['directory_id'])->references(['id'])->on('directories');
$table->json('name')->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('directories', function (Blueprint $table) {
$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();
});
}
}

View file

@ -1,11 +1,26 @@
<?php
use App\Enums\Documents\LangEnum;
use App\Models\Document;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class UpdateDocumentTable extends Migration
{
/**
* Collection of old Documents.
* @var object[]
*/
private $documentsOld;
/**
* Collection of new Documents.
* @var object[]
*/
private $documentsNew;
/**
* Run the migrations.
*
@ -13,18 +28,31 @@ class UpdateDocumentTable extends Migration
*/
public function up()
{
$this->documentsOld = Document::get();
$this->documentsNew = Document::get();
// * APP_USER->UPDATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `documents` CHANGE `updated_at` `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
self::updateData();
Schema::table('documents', function (Blueprint $table) {
$table->dropForeign('documents_directory_foreign');
$table->dropColumn('directory');
$table->unsignedBigInteger('directory_id')->index()->nullable()->after('id');
$table->foreign(['directory_id'])->references(['id'])->on('directories');
$table->bigInteger('parent')->unsigned()->change();
$table->renameColumn('directory', 'directory_id');
$table->dropColumn('parent');
$table->unsignedBigInteger('document_id')->index()->nullable()->after('directory_id');
$table->unsignedBigInteger('document_id')->index()->nullable()->after('directory');
$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');
$table->integer('lang')->nullable()->change();
$table->renameColumn('published', 'status');
$table->dateTime('created_at')->default('CURRENT_TIMESTAMP')->nullable()->change();
});
foreach ($this->documentsNew as $key => $documentNew) {
$documentNew->document_id =
($this->documentsOld[$key]->parent !== null) ? intval($this->documentsOld[$key]->parent) : null;
$documentNew->saveOrFail();
}
}
/**
@ -34,18 +62,65 @@ class UpdateDocumentTable extends Migration
*/
public function down()
{
$documentsOld = Document::get();
// * APP_USER->CREATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `documents` CHANGE `created_at` `created_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
Schema::table('documents', function (Blueprint $table) {
$table->dropForeign('documents_directory_id_foreign');
$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->renameColumn('directory_id', 'directory');
$table->renameColumn('document_id', 'parent');
$table->dropColumn('order');
$table->string('type', 3)->change();
$table->boolean('published');
$table->renameColumn('status', 'published');
$table->dateTime('updated_at')->default('0000-00-00 00:00:00')->nullable()->change();
});
$documentsNew = Document::get();
foreach ($documentsNew as $key => $documentNew) {
switch ($documentNew->lang) {
case LangEnum::fr()->value:
$documentNew->lang = 'fr';
break;
case LangEnum::en()->value:
$documentNew->lang = 'en';
break;
case LangEnum::de()->value:
$documentNew->lang = 'de';
break;
case LangEnum::nl()->value:
$documentNew->lang = 'nl';
break;
}
$documentNew->parent = strval($documentsOld[$key]->document_id);
$documentNew->saveOrFail();
}
}
/**
* Update data migrations.
*
* @return void
*/
public function updateData()
{
foreach ($this->documentsNew as $documentNew) {
switch ($documentNew->lang) {
case "fr":
$documentNew->lang = LangEnum::fr()->value;
break;
case "en":
$documentNew->lang = LangEnum::en()->value;
break;
case "de":
$documentNew->lang = LangEnum::de()->value;
break;
case "nl":
$documentNew->lang = LangEnum::nl()->value;
break;
}
$documentNew->saveOrFail();
}
}
}

View file

@ -0,0 +1,84 @@
<?php
use App\Models\Setting;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class UpdateSettingsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// * APP_USER->UPDATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `settings` CHANGE `updated_at` `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
Schema::table('settings', function (Blueprint $table) {
$table->dropUnique('data_key_unique');
$table->unique(['key']);
$table->text('value')->nullable()->default(null)->change();
$table->dateTime('created_at')->default('CURRENT_TIMESTAMP')->nullable()->change();
});
$settings = Setting::get();
foreach ($settings as $key => $setting) {
if ($setting->key === "ShowIsActive") {
$setting->type = 5;
} elseif ($setting->key === "MainColor") {
$setting->type = 6;
} elseif ($setting->key === "Button1" || $setting->key === "Button2" || $setting->key === "Button3") {
$setting->type = 7;
} elseif (
$setting->key === "FormSelect1" ||
$setting->key === "FormSelect2" ||
$setting->key === "FormCheck"
) {
$setting->type = 4;
}
$setting->saveOrFail();
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
// * APP_USER->CREATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `settings` CHANGE `created_at` `created_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
Schema::table('settings', function (Blueprint $table) {
$table->dropUnique('settings_key_unique');
$table->unique('data_key_unique');
$table->text('value')->change();
$table->dateTime('updated_at')->default('0000-00-00 00:00:00')->nullable()->change();
});
$settings = Setting::get();
foreach ($settings as $key => $setting) {
if ($setting->key === "ShowIsActive") {
$setting->type = 2;
} elseif ($setting->key === "MainColor") {
$setting->type = 1;
} elseif ($setting->key === "Button1" || $setting->key === "Button2" || $setting->key === "Button3") {
$setting->type = 2;
} elseif (
$setting->key === "FormSelect1" ||
$setting->key === "FormSelect2" ||
$setting->key === "FormCheck"
) {
$setting->type = 1;
}
$setting->saveOrFail();
}
}
}

View file

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTagsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('slug')->unique()->comment('Slug du nom de l\'étiquette.');
$table->string('name')->comment('Nom du tag qui sera unique.');
$table->integer('order')->comment('L\'ordre des étiquette.');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('tags');
}
}

View file

@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class RenameActivatedAppUsersTable extends Migration
class CreateTaggablesTable extends Migration
{
/**
* Run the migrations.
@ -13,8 +13,10 @@ class RenameActivatedAppUsersTable extends Migration
*/
public function up()
{
Schema::table('app_users', function (Blueprint $table) {
$table->renameColumn('activated', 'status');
Schema::create('taggables', function (Blueprint $table) {
$table->foreignId('tag_id')->references('id')->on('tags');
$table->foreignId('taggable_id')->references('id')->on('documents');
$table->string('taggable_type', 60);
});
}
@ -25,8 +27,6 @@ class RenameActivatedAppUsersTable extends Migration
*/
public function down()
{
Schema::table('app_users', function (Blueprint $table) {
$table->renameColumn('status', 'activated');
});
Schema::dropIfExists('taggables');
}
}

View file

@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class UpdateContactsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// * APP_USER->UPDATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `contacts` CHANGE `updated_at` `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
Schema::table('contacts', function (Blueprint $table) {
$table->renameColumn('user_id', 'app_user_id');
$table->renameColumn('name', 'lastname');
$table->dateTime('created_at')->default('CURRENT_TIMESTAMP')->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
// * APP_USER->CREATED_AT
//phpcs:ignore Generic.Files.LineLength.TooLong
DB::statement('ALTER TABLE `contacts` CHANGE `created_at` `created_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
Schema::table('contacts', function (Blueprint $table) {
$table->renameColumn('app_user_id', 'user_id');
$table->renameColumn('lastname', 'name');
$table->dateTime('updated_at')->default('0000-00-00 00:00:00')->nullable()->change();
});
}
}

View file

@ -17,6 +17,7 @@ class DatabaseSeeder extends Seeder
AppUserSeeder::class,
DirectorySeeder::class,
SettingSeeder::class,
TagSeeder::class,
]);
}
}

View file

@ -5,6 +5,7 @@ namespace Database\Seeders;
use App\Models\AppUser;
use App\Models\Directory;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class DirectorySeeder extends Seeder
{
@ -15,8 +16,22 @@ class DirectorySeeder extends Seeder
*/
public function run()
{
$i = 1;
Directory::factory(15)->make()->each(function (Directory $directory) use (&$i) {
$directory = new Directory();
$directory->name = [
"fr" => "Salon",
"en" => "Salon",
"de" => "Wohnzimmer",
"nl" => "Tentoonstelling",
];
$directory->directory_id = null;
$directory->needAuthorization = 0;
$directory->is_system = 1;
$directory->order = 1;
$directory->saveOrFail();
$i = 2;
Directory::factory(14)->make()->each(function (Directory $directory) use (&$i) {
$directory->order = $i;
$directory->saveOrFail();
$i = $i + 1;
@ -25,11 +40,9 @@ class DirectorySeeder extends Seeder
// Seeder for directory_authorizations table.
$directories = Directory::query()->where('needAuthorization', true)->get();
AppUser::each(function (AppUser $model) use ($directories) {
$offset = rand(1, 15);
$offset = rand(DB::table('directories')->min('id') ?? 1, DB::table('directories')->max('id') ?? 15);
$length = rand(1, 2);
if (Directory::query()->where('id', $offset)->firstOrFail()->needAuthorization) {
$model->directories()->saveMany($directories->slice($offset, $length));
}
$model->directories()->saveMany($directories->slice($offset, $length));
});
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class MigrationSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('migrations')->truncate();
DB::table('migrations')->insert([
['id' => 1, 'migration' => '2023_03_14_150900_create_app_users_table', 'batch' => 1],
['id' => 2, 'migration' => '2023_03_14_150900_create_contacts_table', 'batch' => 1],
['id' => 3, 'migration' => '2023_03_14_150900_create_directories_table', 'batch' => 1],
['id' => 4, 'migration' => '2023_03_14_150900_create_documents_table', 'batch' => 1],
['id' => 5, 'migration' => '2023_03_14_150900_create_settings_table', 'batch' => 1],
['id' => 6, 'migration' => '2023_03_14_150900_create_users_table', 'batch' => 1],
['id' => 7, 'migration' => '2023_03_14_150901_add_foreign_keys_to_contacts_table', 'batch' => 1],
['id' => 8, 'migration' => '2023_03_14_150901_add_foreign_keys_to_directories_table', 'batch' => 1],
['id' => 9, 'migration' => '2023_03_14_150901_add_foreign_keys_to_documents_table', 'batch' => 1]
]);
$this->command->warn('Seeding default Migration table.');
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace Database\Seeders;
use App\Models\Tag;
use Illuminate\Database\Seeder;
class TagSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$i = 1;
Tag::factory(15)->make()->each(function (Tag $tag) use (&$i) {
$tag->order = $i;
$tag->saveOrFail();
$i = $i + 1;
});
}
}

View file

@ -7,6 +7,7 @@ return [
'directories' => 'Directories',
'documents' => 'Documents',
'users' => 'Users',
'settings' => 'Settings'
'settings' => 'Settings',
'tags' => 'Tags'
]
];

View file

@ -7,6 +7,7 @@ return [
'directories' => 'Dossiers',
'documents' => 'Documents',
'users' => 'Utilisateurs',
'settings' => 'Paramètres'
'settings' => 'Paramètres',
'tags' => 'Étiquettes'
]
];

View file

@ -3,7 +3,7 @@
<Transition name="fade">
<p
v-if="message"
class="message"
class="text-danger mb-2"
>
{{ message }}
</p>
@ -249,10 +249,6 @@ export default defineComponent({
}
}
.message {
color: #ff0000;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;

View file

@ -20,6 +20,7 @@
v-for="(language, languageIndex) in intLanguages"
:key="languageIndex"
:value="language.value"
:selected="Number(intModel?.lang) === language.value ? true : false"
>
{{ language.label }}
</option>
@ -105,12 +106,16 @@
<option
v-for="(document, documentIndex) in intDocuments"
:key="documentIndex"
:value="documentIndex"
:value="document.id"
:selected="intModel?.document_id === document.id ? true : false"
>
{{ document.title }}
</option>
</select>
<p class="text-muted">
<p
v-else
class="text-muted"
>
{{ __("Aucun documents français n'est disponible") }}
</p>
<small class="form-text text-muted">
@ -125,7 +130,7 @@
>
<b>{{ __("Document à ajouter") }} *</b>
</label>
<div v-if="!intIsUploading">
<div :class="intIsUploading ? 'd-none' : ''">
<div class="input-group">
<button
class="btn btn-outline-secondary"
@ -160,8 +165,8 @@
</div>
</div>
<div
v-else
class="progress"
:class="!intIsUploading ? 'd-none' : ''"
>
<div
class="progress-bar progress-bar-striped progress-bar-animated"
@ -224,7 +229,7 @@ export default defineComponent({
value: number;
label: string;
}[];
intDocuments: { title: string }[];
intDocuments: { id: number; title: string }[];
intDirectories: LaravelModel[];
intIsDocFR: boolean;
intModel: LaravelModel | null;
@ -281,6 +286,7 @@ export default defineComponent({
this.intDocumentDatas.path = String(this.intModel.path);
this.intDocumentDatas.uuid = String(this.intModel.uuid);
this.intDocumentDatas.type = String(this.intModel.type);
this.intIsDocFR = this.intModel.lang === "1" ? true : false;
}
this.intCsrf = data.csrf;
this.$nextTick(() => {
@ -351,9 +357,9 @@ export default defineComponent({
this.intDocumentDatas.path = file.fileName;
this.intDocumentDatas.uuid = result.uid;
if (file.file.type === "application/pdf") {
this.intDocumentDatas.type = ".pdf";
this.intDocumentDatas.type = "pdf";
} else {
this.intDocumentDatas.type = ".mp4";
this.intDocumentDatas.type = "mp4";
}
this.intSuccess = true;
this.intMessage = "Fichier chargé.";

View file

@ -1,5 +1,21 @@
<template>
<div :class="`directories-${intId}`">
<div :class="`directories-${intId} position-relative`">
<Transition name="fade">
<p
v-if="intMessage"
class="d-flex align-items-center text-danger mb-2"
>
<span>{{ Object.values(intMessage)[0] }}&nbsp;</span>
<a
class="btn btn-sm btn-primary"
:href="getEditButtonRoute(Number(Object.keys(intMessage)[0]))"
:title="__('Modifier ce paramètre')"
data-bs="tooltip"
>
<FontAwesomeIcon icon="fa-solid fa-pencil" />
</a>
</p>
</Transition>
<vue-nestable
:value="intDirectories"
@change="updateOrderDirectories"
@ -47,16 +63,10 @@
<FontAwesomeIcon icon="fa-solid fa-arrow-up" />
</button>
</div>
<button
v-if="!item.is_system"
class="btn btn-sm border-0 disabled opacity-100"
>
<button class="btn btn-sm border-0 disabled opacity-100">
<FontAwesomeIcon icon="fa-solid fa-grip-vertical" />
</button>
<p
class="m-0"
:class="item.is_system ? 'ms-2' : ''"
>
<p class="m-0">
{{ item.name["fr" as keyof typeof item.name] }}
</p>
</div>
@ -65,33 +75,24 @@
class="d-flex justify-content-end align-items-center"
>
<div class="input-group">
<form
:action="getAuthorizationDirectoryRoute(item.id)"
method="POST"
class="d-inline btn-group"
<button
v-if="item.needAuthorization"
@click="updateAuthorization(item)"
class="btn btn-sm btn-warning"
:title="__('L\'accès à ce dossier est restreint')"
data-bs="tooltip"
>
<button
v-if="item.needAuthorization"
class="btn btn-sm btn-warning"
:title="__('L\'accès à ce dossier est restreint')"
data-bs="tooltip"
>
<FontAwesomeIcon icon="fa-solid fa-lock" />
</button>
<button
v-else
class="btn btn-sm btn-success"
:title="__('L\'accès à ce dossier est tout public')"
data-bs="tooltip"
>
<FontAwesomeIcon icon="fa-solid fa-lock-open" />
</button>
<input
type="hidden"
name="_token"
:value="intCsrf"
>
</form>
<FontAwesomeIcon icon="fa-solid fa-lock" />
</button>
<button
v-else
@click="updateAuthorization(item)"
class="btn btn-sm btn-success"
:title="__('L\'accès à ce dossier est tout public')"
data-bs="tooltip"
>
<FontAwesomeIcon icon="fa-solid fa-lock-open" />
</button>
<a
:href="getEditDirectoryRoute(item.id)"
class="btn btn-sm btn-primary"
@ -100,29 +101,33 @@
>
<FontAwesomeIcon icon="fa-solid fa-pencil" />
</a>
<form
:action="getDestroyDirectoryRoute(item.id)"
method="POST"
class="d-inline btn-group confirmDeleteJS"
<button
@click="deleteDirectory($event, item)"
class="btn btn-sm btn-danger confirmDelete"
:title="__('Supprimer le Dossier')"
data-bs="tooltip"
ref="confirmDelete"
>
<input
type="hidden"
name="_token"
:value="intCsrf"
>
<button
class="btn btn-sm btn-danger"
:title="__('Supprimer le Dossier')"
data-bs="tooltip"
>
<FontAwesomeIcon icon="fa-solid fa-trash" />
</button>
</form>
<FontAwesomeIcon icon="fa-solid fa-trash" />
</button>
</div>
</div>
</vue-nestable-handle>
</template>
</vue-nestable>
<div
v-if="intLoading"
class="loading position-absolute top-0 start-0 d-flex justify-content-center align-items-center rounded-1 w-100 h-100"
>
<div
class="spinner-border text-secondary"
role="status"
>
<span class="visually-hidden">
{{ __("form.image_input_viewer_loading") }}
</span>
</div>
</div>
</div>
</template>
@ -133,6 +138,7 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { Tooltip } from "bootstrap";
import route from "../../modules/route";
import trans from "../../modules/trans";
import sweetalertConfirm from "../../modules/sweetalertConfirm";
type DirectoryObject = {
id: number;
@ -153,13 +159,15 @@ export default defineComponent({
VueNestableHandle,
FontAwesomeIcon,
},
mixins: [route, trans],
mixins: [route, trans, sweetalertConfirm],
data(): {
intCsrf: string | null | undefined;
intId: String;
intDirectories: DirectoryObject[];
intMessage: object | object[] | null;
intDisplay: boolean[];
tooltipList: HTMLButtonElement[];
intLoading: boolean;
intTooltipList: HTMLButtonElement[];
} {
return {
intCsrf: document
@ -167,8 +175,10 @@ export default defineComponent({
?.getAttribute("content"),
intId: "",
intDirectories: [],
intMessage: null,
intDisplay: [],
tooltipList: [],
intLoading: false,
intTooltipList: [],
};
},
mounted() {
@ -277,30 +287,16 @@ export default defineComponent({
return route;
},
/**
* Return destroy route for a directory.
* Return edit route for a directory.
* @param id
* @return string
*/
getDestroyDirectoryRoute(id: number): string {
const route = this.route("bo.directories.destroy", {
getEditButtonRoute(id: number): string {
const route = this.route("bo.settings.edit", {
ID: id,
});
if (!route) {
throw new Error("Undefined route bo.directories.destroy");
}
return route;
},
/**
* Return authorization route for a directory.
* @param id
* @return string
*/
getAuthorizationDirectoryRoute(id: number): string {
const route = this.route("bo.directories.need-authorization", {
ID: id,
});
if (!route) {
throw new Error("Undefined route bo.directories.need-authorization");
throw new Error("Undefined route bo.settings.edit");
}
return route;
},
@ -317,6 +313,101 @@ export default defineComponent({
this.updateBootstrapTooltip();
});
},
/**
* Update authorization for a specific directory.
* @param LaravelModel model
*/
updateAuthorization(model: LaravelModel) {
this.intLoading = true;
const route = this.route("bo.directories.need-authorization", {
ID: model.id as number,
});
if (!route) {
throw new Error("Undefined route bo.directories.need-authorization");
}
window.axios
.post(route, { id: model.id })
.then((reponse) => {
this.intDirectories.forEach((directory, directoryindex) => {
if (directory.id === reponse.data.id) {
this.intDirectories[directoryindex] = reponse.data;
}
});
this.intLoading = false;
this.$nextTick(() => {
this.updateBootstrapTooltip();
});
})
.catch((error) => {
if (error.response) {
console.error(error.response.data);
} else if (error.request) {
console.error(error.request);
} else {
// Something happened in setting up the request that triggered an Error.
console.error("Error", error.message);
}
});
},
/**
* Update authorization for a specific directory.
* @param LaravelModel model
*/
deleteDirectory(e: Event, model: LaravelModel) {
const btnConfirmDelete = this.$refs.confirmDelete as HTMLButtonElement;
(async () => {
const promise = new Promise((resolve: (value: boolean) => void) => {
sweetalertConfirm.methods.confirm(
"Confirmez",
"Êtes vous sure ?",
btnConfirmDelete,
function (response) {
resolve(response.isConfirmed);
},
{ icon: "warning" }
);
return false;
});
if (await promise) {
this.intLoading = true;
const route = this.route("bo.directories.destroy", {
ID: model.id as number,
});
if (!route) {
throw new Error("Undefined route bo.directories.destroy");
}
window.axios
.post(route, { id: model.id, _method: "DELETE" })
.then((reponse) => {
if (reponse.data[0] !== undefined) {
this.intDirectories = this.recursiveDir(reponse.data);
} else {
this.intMessage = reponse.data;
setTimeout(() => {
this.intMessage = null;
this.$nextTick(() => {
this.updateBootstrapTooltip();
});
}, 6000);
}
this.intLoading = false;
this.$nextTick(() => {
this.updateBootstrapTooltip();
});
})
.catch((error) => {
if (error.response) {
console.error(error.response.data);
} else if (error.request) {
console.error(error.request);
} else {
// Something happened in setting up the request that triggered an Error.
console.error("Error", error.message);
}
});
}
})();
},
/**
* Update Bootstrap tooltips.
*/
@ -326,18 +417,18 @@ export default defineComponent({
".directories-" + this.intId + " [data-bs=\"tooltip\"]"
)
) as HTMLButtonElement[];
let tmp = newTooltipList.filter((x) => !this.tooltipList.includes(x));
let tmp = newTooltipList.filter((x) => !this.intTooltipList.includes(x));
tmp.map((tooltip) => {
return new Tooltip(tooltip);
});
this.closeBootstrapTooltip();
this.tooltipList = newTooltipList;
this.intTooltipList = newTooltipList;
},
/**
* Close all Bootstrap tooltips.
*/
closeBootstrapTooltip() {
this.tooltipList.forEach((tooltip) => {
this.intTooltipList.forEach((tooltip) => {
tooltip.blur();
Tooltip.getInstance(tooltip)?.hide();
});
@ -345,3 +436,19 @@ export default defineComponent({
},
});
</script>
<style lang="scss">
.loading {
background-color: rgba(0, 0, 0, 0.15);
z-index: 5;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

View file

@ -40,6 +40,8 @@ import {
faCircleCheck,
faCircleXmark,
faFloppyDisk,
faVideo,
faFile,
} from "@fortawesome/free-solid-svg-icons";
config.autoReplaceSvg = false;
@ -79,6 +81,8 @@ library.add(faLockOpen);
library.add(faCircleCheck);
library.add(faCircleXmark);
library.add(faFloppyDisk);
library.add(faFile);
library.add(faVideo);
// Front
library.add(faChevronLeft);

View file

@ -7,14 +7,14 @@
<body>
@include('bo.layouts.header')
<main class="container-fluid pt-2 @yield('bg-color')">
<main class="container-fluid pt-3 @yield('bg-color')">
<div class="row justify-content-center">
<div class="col col-md-6">
@include('modules.flash-message')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-8 mt-3">
<div class="col-12 col-md-10 col-lg-8">
@include('modules.breadcrumb.breadcrumb-body')
</div>
</div>

View file

@ -1,4 +1,4 @@
<nav class="navbar navbar-expand-md bg-light text-bg-light shadow-sm">
<nav class="navbar navbar-expand-lg bg-light text-bg-light shadow-sm">
<div class="container">
<a class="navbar-brand rounded py-1" href="{{ url('/') }}">
{{ config('app.name', 'Laravel') }}

View file

@ -32,6 +32,14 @@
{{ __(':model', ['model' => __('models.classes.documents')]) }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if(request()->routeIs('bo.tags.*')) active @endif"
href="{{ route('bo.tags.index') }}"
title="{{ __('Liste des :model', ['model' => __('models.classes.tags')]) }}"
data-bs-toggle="tooltip">
{{ __(':model', ['model' => __('models.classes.tags')]) }}
</a>
</li>
<li class="nav-item">
<a class="nav-link @if(request()->routeIs('bo.settings.*')) active @endif"
href="{{ route('bo.settings.index') }}"

View file

@ -0,0 +1,17 @@
@component('mail::message')
{{ $data->body }}
@if (count($data->attach) === 1)
<p>{{ __('Brochure :') }}</p>
@else
<p>{{ __('Brochures :') }}</p>
@endif
@for ($i = 0; $i < count($data->attach); $i++)
@component('mail::button', ['url' => $data->attach[$i], 'color' => 'success'])
{{ $data->filesName[$i] }}
@endcomponent
@endfor
@endcomponent

View file

@ -0,0 +1,11 @@
<p>
{{ __('Bonjour,') }}<br>
{{ __('Le mail suivant n\'a pas été envoyé car des fichiers ont été supprimés.') }}<br><br>
{{ __('Email : ') }}{{ $data->email }} <br>
{{ __('Objet : ') }}{{ $data->subject }} <br>
{{ __('Message : ') }}{{ $data->message }} <br>
@if (count($data->filesName) > 0)
{{ __('Fichier(s) existant(s) : ') }} @foreach($data->filesName as $text) {{ $text }} @if(!$loop->last), @endif @endforeach <br>
@endif
{{ __('Fichier(s) supprimé(s) : ') }} @foreach($data->noExists as $text) {{ $text }} @if(!$loop->last), @endif @endforeach
</p>

View file

@ -1,17 +1,17 @@
@if ($paginator->hasPages())
<nav>
<ul class="pagination d-flex justify-content-center align-items-center my-3">
<ul class="pagination d-flex justify-content-center align-items-center m-0">
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<li class="page-item disabled" data-bs-toggle="tooltip" data-bs-placement="top"
title="{{ __('Previous page') }}" aria-disabled="true" aria-label="@lang('Previous page')">
title="{{ __('Page précédente') }}" aria-disabled="true" aria-label="{{ __('Page précédente') }}">
<span class="page-link" aria-hidden="true">&lsaquo;</span>
</li>
@else
<li class="page-item">
<a class="page-link" data-bs-toggle="tooltip" data-bs-placement="top"
title="{{ __('Previous page') }}" href="{{ $paginator->previousPageUrl() }}"
rel="prev" aria-label="@lang('Previous page')">&lsaquo;</a>
title="{{ __('Page précédente') }}" href="{{ $paginator->previousPageUrl() }}"
rel="prev" aria-label="{{ __('Page précédente') }}">&lsaquo;</a>
</li>
@endif
@ -45,13 +45,13 @@
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<li class="page-item">
<a class="page-link" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Next page') }}"
<a class="page-link" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Page suivante') }}"
href="{{ $paginator->nextPageUrl() }}" rel="next"
aria-label="@lang('Next page')">&rsaquo;</a>
aria-label="{{ __('Page suivante') }}">&rsaquo;</a>
</li>
@else
<li class="page-item disabled" data-bs-toggle="tooltip" data-bs-placement="top"
title="{{ __('Next page') }}" aria-disabled="true" aria-label="@lang('Next page')">
title="{{ __('Page suivante') }}" aria-disabled="true" aria-label="{{ __('Page suivante') }}">
<span class="page-link" aria-hidden="true">&rsaquo;</span>
</li>
@endif

View file

@ -27,6 +27,14 @@
@endif
<input type="search" id="searchField" name="search" class="form-control"
value="{{ request()->search }}" placeholder="{{ __('Vos mots clés ici..') }}"/>
@if (request()->routeIs('bo.documents.*'))
<select id="searchTag" name="tag" class="form-select">
<option value="0">{{ __('Rechercher par tags') }}</option>
@foreach($tags as $key => $tag)
<option value="{{ $tag->id }}" @if (intval($searchTag) === $tag->id) selected @endif>{{ $tag->name }}</option>
@endforeach
</select>
@endif
<button type="submit" class="btn btn-primary" data-bs-toggle="tooltip" title="{{ __('Rechercher') }}">
<i class="fas fa-search"></i>
</button>
@ -38,6 +46,7 @@
<script nonce="{{ $nonce }}">
document.getElementById('searchDelete').addEventListener('click', function (e) {
document.getElementById('searchField').value = '';
document.getElementById('searchTag').selectedIndex = 0;
document.getElementById('searchForm').submit();
});
</script>

View file

@ -13,13 +13,13 @@ $ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
{{-- NO Sort for order column --}}
@if($col === 'order' or in_array($col, $ignore))
@if(!$noOrder or $rst)
<th scope="col" @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) class="d-none d-md-table-cell text-center" @endif>
<th scope="col" class="text-center @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) d-none d-md-table-cell text-center @endif">
<span>{{ $colname }}</span>
</th>
@endif
@continue
@endif
<th scope="col" @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) class="d-none d-md-table-cell text-center" @endif>
<th scope="col" class="text-center @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) d-none d-md-table-cell text-center @endif">
<span class="text-nowrap">
{{ $colname }}
</span>
@ -51,7 +51,7 @@ $ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
<th class="text-end" scope="col">
@if($noOrder and !$rst)
<a class="btn btn-sm btn-danger"
href="{{ request()->fullUrlWithQuery(['sort_col' => null, 'sort_way' => null, 'rst' => true, 'search' => null]) }}"
href="{{ request()->fullUrlWithQuery(['sort_col' => null, 'sort_way' => null, 'rst' => true, 'search' => null, 'tag' => null]) }}"
data-bs-toggle="tooltip"
title="{{ __('Supprimer le tri') }}">
<i class="fa fa-eraser"></i>

View file

@ -33,9 +33,8 @@
</div>
</div>
<div class="card-body bg-light">
<form action="{{ route('bo.app-users.store') }}" method="POST" enctype="multipart/form-data">
<form action="{{ route('bo.app-users.store') }}" method="POST">
@csrf
@method('PUT')
@include('bo.pages.app-users.form')
<div class="row">
<div class="col text-center">

View file

@ -44,7 +44,7 @@
</div>
</div>
<div class="card-body bg-light">
<form action="{{ route('bo.app-users.update', $app_userModel->id) }}" method="POST" enctype="multipart/form-data">
<form action="{{ route('bo.app-users.update', $app_userModel->id) }}" method="POST">
@csrf
@method('PUT')
@include('bo.pages.app-users.form', ['model' => $app_userModel])

View file

@ -20,21 +20,21 @@
<td>
<span>{{ $app_usersModel->lastname }}</span>
</td>
<td>
<td class="text-center">
<span>{{ $app_usersModel->firstname }}</span>
</td>
<td>
<td class="text-center">
<span>{{ $app_usersModel->email }}</span>
</td>
@if(!$noOrder or $rst)
<td class="d-flex">
<td class="align-middle d-flex justify-content-center align-items-center">
<form action="{{ route('bo.app-users.change-order', ['appuser' => $app_usersModel, 'action' => 'up']) }}"
method="POST"
class="text-center @if($loop->first and $app_users->onFirstPage()) invisible @endif">
@csrf
<button type="submit"
class="btn btn-sm btn-outline-dark @if(($loop->first and $app_users->onFirstPage())) disabled @endif"
title="{{ __('Change the order of appearance upwards') }}"
title="{{ __('Modifier l\'ordre d\'apparition vers le haut') }}"
data-bs-toggle="tooltip">
<i class="fas fa-arrow-up"></i>
</button>
@ -45,7 +45,7 @@
@csrf
<button type="submit"
class="btn btn-sm btn-outline-dark ms-1 @if($loop->last and $app_users->currentPage() === $app_users->lastPage()) disabled @endif"
title="{{ __('Change the order of appearance downwards') }}"
title="{{ __('Modifier l\'ordre d\'apparition vers le bas') }}"
data-bs-toggle="tooltip">
<i class="fas fa-arrow-down"></i>
</button>
@ -79,7 +79,7 @@
@endforeach
@else
<tr>
<td colspan="5" class="text-center">
<td colspan="{{ count($cols) + 1 }}" class="text-center">
<span class="h3">
{{ __('Aucun résultat pour les :models', ['models' => __('models.classes.users')]) }}
</span>

View file

@ -19,9 +19,13 @@
action="{{ route('bo.app-users.import') }}"
method="POST"
enctype="multipart/form-data">
<input class="form-control" type="file" name="import" accept="text/csv,.csv" required>
<input class="form-control" type="file" name="import" accept="text/csv,.csv"
title="{{ __('Sélectionner un fichier .csv') }}"
data-bs-toggle="tooltip" required>
@csrf
<button type="submit" class="btn btn-primary">
<button type="submit" class="btn btn-primary"
title="{{ __('Importer le fichier .csv') }}"
data-bs-toggle="tooltip">
{{ __('Importer') }}
</button>
</form>
@ -38,18 +42,13 @@
</div>
<div class="card-body">
@include('bo.modules.search-bar')
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0 p-md-3">
{{ $app_users->withQueryString()->onEachSide(1)->links() }}
</div>
</div>
<div class="row">
<div class="row mt-3">
<div class="col">
@include('bo.pages.app-users.index-list')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0 p-md-3">
<div class="col-12 col-md-6">
{{ $app_users->withQueryString()->onEachSide(1)->links() }}
</div>
</div>

View file

@ -5,11 +5,42 @@
@section('breadcrumb', 'no')
@section('content')
<div class="container">
<div class="row">
<div class="col">
<h1>{{ __('Panneau de bord') }}</h1>
<div class="container">
<div class="row">
<div class="col">
<div class="card text-center">
<div class="card-header fw-bold">
<h1 class="h2 fw-bold">{{ __('Dashboard') }}</h1>
</div>
<div class="card-body">
<h5 class="card-title">
{{ __('Bonjour :firstname :lastname !', [
'firstname' => Auth::user()->firstname,
'lastname' => Auth::user()->lastname
]) }}
</h5>
<p class="card-text m-0">
{{ __('Bienvenue dans le back-office, où vous pouvez gérer votre application web.') }}
</p>
<p class="card-text">
{{ __('Pour tout problème ou évolution souhaitée, veuillez nous contacter via notre outil : ') }}
<a href="https://supportweb.ldc.fr" target="blank"
title="{{ __('Accéder à notre outil de ticketing') }}"
data-bs-toggle="tooltip">
supportweb.ldc.fr
</a>.
</p>
</div>
<div class="card-footer">
<a href="{{ route('bo.dashboard.export-contacts') }}"
class="btn btn-primary"
title="{{ __('Exportation de tous les contacts enregistrés dans un fichier .csv') }}"
data-bs-toggle="tooltip">
{{ __('Exporter les contacts') }}
</a>
</div>
</div>
</div>
</div>
</div>
@endsection

View file

@ -44,7 +44,7 @@
</div>
</div>
<div class="card-body bg-light">
<form action="{{ route('bo.directories.update', $directoryModel->id) }}" method="POST" enctype="multipart/form-data">
<form action="{{ route('bo.directories.update', $directoryModel->id) }}" method="POST">
@csrf
@method('PUT')
@include('bo.pages.directories.form', ['model' => $directoryModel])

View file

@ -10,7 +10,7 @@
'label' => __('Nom du :model en français', ['model' => Str::singular(__('models.classes.directories'))]),
'hasWordCounter' => true,
'name' => 'name[fr]',
'value' => $directoryModel->name['fr'],
'value' => $directoryModel->name['fr'] ?? "",
'required' => true,
'model' => $directoryModel ?? null,
'helper' => __('Doit posséder 3 caractères minimum, 255 maximum.'),
@ -31,7 +31,7 @@
'label' => __('Nom du :model en anglais', ['model' => Str::singular(__('models.classes.directories'))]),
'hasWordCounter' => true,
'name' => 'name[en]',
'value' => $directoryModel->name['en'],
'value' => $directoryModel->name['en'] ?? "",
'required' => true,
'model' => $directoryModel ?? null,
'helper' => __('Doit posséder 3 caractères minimum, 255 maximum.'),
@ -52,7 +52,7 @@
'label' => __('Nom du :model en allemand', ['model' => Str::singular(__('models.classes.directories'))]),
'hasWordCounter' => true,
'name' => 'name[de]',
'value' => $directoryModel->name['de'],
'value' => $directoryModel->name['de'] ?? "",
'required' => true,
'model' => $directoryModel ?? null,
'helper' => __('Doit posséder 3 caractères minimum, 255 maximum.'),
@ -73,7 +73,7 @@
'label' => __('Nom du :model en néerlandais', ['model' => Str::singular(__('models.classes.directories'))]),
'hasWordCounter' => true,
'name' => 'name[nl]',
'value' => $directoryModel->name['nl'],
'value' => $directoryModel->name['nl'] ?? "",
'required' => true,
'model' => $directoryModel ?? null,
'helper' => __('Doit posséder 3 caractères minimum, 255 maximum.'),

View file

@ -20,14 +20,12 @@
<div class="row">
<form action="{{ route('bo.directories.store') }}"
class="pb-3 mb-3 border-bottom"
method="POST"
enctype="multipart/form-data">
method="POST">
@csrf
@method('PUT')
<div class="col-12 input-group">
<input
id="directoryName"
class="form-control @error('name[fr]') is-invalid @enderror"
class="form-control @error('name.fr') is-invalid @enderror"
name="name[fr]"
placeholder="{{ __('Ajouter un dossier (nom en français)') }}">
<button
@ -38,7 +36,7 @@
</button>
</div>
@include('modules.input-error', [
'inputName' => "name",
'inputName' => "name.fr",
'helperId' => 'directoryNameHelp',
'helper' => __('Doit posséder 3 caractères minimum, 255 maximum.'),
])

View file

@ -33,7 +33,7 @@
</div>
</div>
<div class="card-body bg-light">
<form action="{{ route('bo.documents.store') }}" method="POST" enctype="multipart/form-data">
<form action="{{ route('bo.documents.store') }}" method="POST">
@csrf
@method('PUT')
@include('bo.pages.documents.form')

View file

@ -27,7 +27,7 @@
@method('DELETE')
@csrf
<div class="btn-group" role="group">
<a href="{{ asset("storage/docs/" . $documentModel->uuid . $documentModel->type) }}"
<a href="{{ asset("storage/docs/" . $documentModel->uuid . "." . $documentModel->type) }}"
target="blank"
class="btn btn-warning"
role="button"
@ -52,7 +52,7 @@
</div>
</div>
<div class="card-body bg-light">
<form action="{{ route('bo.documents.update', $documentModel->id) }}" method="POST" enctype="multipart/form-data">
<form action="{{ route('bo.documents.update', $documentModel->id) }}" method="POST">
@csrf
@method('PUT')
@include('bo.pages.documents.form', ['model' => $documentModel])

View file

@ -16,6 +16,43 @@
<div class="crud-document-input" data-json='@json($data)'></div>
</fieldset>
</div>
{{-- TAGS --}}
<div class="col-12 mb-3">
<fieldset class="border h-100 bg-white p-3">
<legend>{{ __('Étiquettes') }}</legend>
<div class="row">
<div class="col-12 mb-3">
@include('bo.partials.inputs.pivot-belongs-to-many', [
'id' => 'app_userAuthorizedFolders',
'name' => 'tags',
'label' => __('Étiquettes associées'),
'model' => $documentModel ?? null,
'itemsList' => $tags,
'itemLimit' => [0,5],
'placeholder' => __('Recherchez une étiquette'),
'helper' => __('Sélectionner des étiquettes parmis la liste (0 minimum et 5 maximum).'),
])
</div>
</div>
</fieldset>
</div>
{{-- STATUS --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="border h-100 bg-white p-3">
<legend>{{ __('Publication') }}</legend>
<div class="row">
<div class="col-12">
@include('bo.partials.inputs.boolean-switch', [
'id' => 'documentStatus',
'name' => 'status',
'label' => __('État de publication'),
'model' => $documentModel ?? null,
'helper' => __('Le document est publié ou non.')
])
</div>
</div>
</fieldset>
</div>
</div>
@push('scripts')

View file

@ -4,59 +4,85 @@
@php
$rst = !is_null(request()->rst);
$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'), 'order' => __('Order')];
$cols = ['title' => __('Title'), 'directory_id' => __('Dossier'), 'document_id' => __('Document'), 'type' => __('Type'), 'order' => __('Order')];
@endphp
@include('bo.modules.table-col-sorter', [
'cols' => $cols,
'mobileHide' => [],
'mobileHide' => []
])
</thead>
<tbody>
@if ($documents->count())
@foreach ($documents as $documentModel)
<tr>
<td>
<td class="align-middle">
<span>{{ $documentModel->title }}</span>
</td>
<td>
@if(!$documentModel->directory->is_system)
<td class="text-center align-middle">
@if(isset($documentModel->directory->is_system) && !$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') }}"
title="{{ __('Accéder au dossier associé') }}"
data-bs-toggle="tooltip">
{{ \App\Models\Directory::renderDirectories([$documentModel->directory])[0]->name }}
{{ $documentModel->directory->name['fr'] }}
</button>
</a>
@endif
</td>
<td class="text-center align-middle">
@if(isset($documentModel->document_id))
<a href="{{ route('bo.documents.edit', ['document' => $documentModel->document_id]) }}">
<button class="btn btn-sm btn-outline-dark"
title="{{ __('Accéder au document associé') }}"
data-bs-toggle="tooltip">
{{ $documentModel->parent->title }}
</button>
</a>
@endif
</td>
<td class="text-center align-middle">
@switch($documentModel->type)
@case("mp4")
<span class="px1"
title="{{ __('Document de type .mp4') }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-video"></i>
</span>
@break
@case("pdf")
<span class="px1"
title="{{ __('Document de type .pdf') }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-file"></i>
</span>
@break
@endswitch
</td>
@if(!$noOrder or $rst)
<td class="align-middle">
<div class="d-flex justify-content-start align-items-center">
<form action="{{ route('bo.documents.change-order', ['document' => $documentModel, 'action' => 'up']) }}"
method="POST"
class="text-center @if($loop->first and $documents->onFirstPage()) invisible @endif">
@csrf
<button type="submit"
class="btn btn-sm btn-outline-dark @if(($loop->first and $documents->onFirstPage())) disabled @endif"
title="{{ __('Change the order of appearance upwards') }}"
data-bs-toggle="tooltip">
<i class="fas fa-arrow-up"></i>
</button>
</form>
<form action="{{ route('bo.documents.change-order', ['document' => $documentModel, 'action' => 'down']) }}"
method="POST"
class="text-center @if($loop->last and $documents->currentPage() === $documents->lastPage()) invisible @endif">
@csrf
<button type="submit"
class="btn btn-sm btn-outline-dark ms-1 @if($loop->last and $documents->currentPage() === $documents->lastPage()) disabled @endif"
title="{{ __('Change the order of appearance downwards') }}"
data-bs-toggle="tooltip">
<i class="fas fa-arrow-down"></i>
</button>
</form>
</div>
<td class="align-middle d-flex justify-content-center align-items-center">
<form action="{{ route('bo.documents.change-order', ['document' => $documentModel, 'action' => 'up']) }}"
method="POST"
class="text-center @if($loop->first and $documents->onFirstPage()) invisible @endif">
@csrf
<button type="submit"
class="btn btn-sm btn-outline-dark @if(($loop->first and $documents->onFirstPage())) disabled @endif"
title="{{ __('Modifier l\'ordre d\'apparition vers le haut') }}"
data-bs-toggle="tooltip">
<i class="fas fa-arrow-up"></i>
</button>
</form>
<form action="{{ route('bo.documents.change-order', ['document' => $documentModel, 'action' => 'down']) }}"
method="POST"
class="text-center @if($loop->last and $documents->currentPage() === $documents->lastPage()) invisible @endif">
@csrf
<button type="submit"
class="btn btn-sm btn-outline-dark ms-1 @if($loop->last and $documents->currentPage() === $documents->lastPage()) disabled @endif"
title="{{ __('Modifier l\'ordre d\'apparition vers le bas') }}"
data-bs-toggle="tooltip">
<i class="fas fa-arrow-down"></i>
</button>
</form>
</td>
@endif
<td>
@ -65,7 +91,7 @@
@method('DELETE')
@csrf
<div class="btn-group" role="group">
<a href="{{ asset("storage/docs/" . $documentModel->uuid . $documentModel->type) }}"
<a href="{{ asset("storage/docs/" . $documentModel->uuid . "." . $documentModel->type) }}"
target="blank"
class="btn btn-sm btn-warning"
role="button"
@ -94,7 +120,7 @@
@endforeach
@else
<tr>
<td colspan="5" class="text-center">
<td colspan="{{ count($cols) + 1 }}" class="text-center">
<span class="h3">
{{ __('Aucun résultat pour les :models', ['models' => __('models.classes.documents')]) }}
</span>

View file

@ -28,18 +28,13 @@
</div>
<div class="card-body">
@include('bo.modules.search-bar')
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0 p-md-3">
{{ $documents->withQueryString()->onEachSide(1)->links() }}
</div>
</div>
<div class="row">
<div class="row mt-3">
<div class="col">
@include('bo.pages.documents.index-list')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0 p-md-3">
<div class="col-12 col-md-6">
{{ $documents->withQueryString()->onEachSide(1)->links() }}
</div>
</div>

View file

@ -16,6 +16,13 @@
<tbody>
@if ($settings->count())
@foreach ($settings as $settingModel)
@if (
Auth::user()->role === 1 ||
$settingModel->key === "Button1" ||
$settingModel->key === "Button2" ||
$settingModel->key === "Button3" ||
$settingModel->key === "ShowIsActive"
)
<tr>
<td class="align-middle">
<span>{{ $settingModel->key }}</span>
@ -51,8 +58,11 @@
])
@break
@case(\App\Enums\SettingTypesEnum::directory())
@if ($settingModel->value != null)
<a href="{{ route('bo.directories.edit', ['directory' => $settingModel->value]) }}">
<button class="btn btn-sm btn-outline-dark">
<button class="btn btn-sm btn-outline-dark"
title="{{ __('Accéder au dossier associé') }}"
data-bs-toggle="tooltip">
@foreach ($directories as $directory)
@if ($directory->id == $settingModel->value)
{{ $directory->name }}
@ -60,6 +70,9 @@
@endforeach
</button>
</a>
@else
<p class="text-muted m-0">{{ __('Aucun dossier associé') }}</p>
@endif
@break
@endswitch
</td>
@ -76,10 +89,11 @@
</div>
</td>
</tr>
@endif
@endforeach
@else
<tr>
<td colspan="5" class="text-center">
<td colspan="{{ count($cols) + 1 }}" class="text-center">
<span class="h3">
{{ __('Aucun résultat pour les :models', ['models' => __('models.classes.settings')]) }}
</span>

View file

@ -22,11 +22,6 @@
@include('bo.pages.settings.index-list')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-6 p-0 p-md-3">
{{ $settings->withQueryString()->onEachSide(1)->links() }}
</div>
</div>
</div>
</div>
@endsection

View file

@ -0,0 +1,53 @@
@extends('bo.layout')
@section('title', sprintf('%s - %s', Str::singular(__('models.classes.tags')), Str::ucfirst(__('création'))))
@section('description', __('Page de création d\'un nouveau tag de l\'application.'))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="text-center text-md-start h2">
<a href="{{ route('bo.tags.index') }}"
class="btn btn-primary text-decoration-none m-0"
data-bs="tooltip"
data-bs-placement="top"
title="{{ __('Retourner sur la liste des :model', ['model' => __('models.classes.tags')]) }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ Str::singular(__('models.classes.tags')) }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('création')) }}</small>
</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"
title="{{ __('Sauvegarder l\':model', ['model' => Str::singular(__('models.classes.tags'))]) }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-floppy-disk"></i>
</button>
</div>
</div>
</div>
<div class="card-body bg-light">
<form action="{{ route('bo.tags.store') }}" method="POST">
@csrf
@include('bo.pages.tags.form')
<div class="row">
<div class="col text-center">
<button id="formSubmit"
type="submit"
class="btn btn-primary"
title="{{ __('Sauvegarder l\':model', ['model' => Str::singular(__('models.classes.tags'))]) }}"
data-bs-toggle="tooltip">
{{ __('Sauvegarder') }}
</button>
</div>
</div>
</form>
</div>
</div>
@endsection

View file

@ -0,0 +1,65 @@
@extends('bo.layout', ['brParam' => $tagModel])
@section('title', sprintf('%s - %s %s', Str::singular(__('models.classes.tags')), Str::ucfirst(__('édition')), $tagModel->title))
@section('description', __('Page d\'édition d\'un tag de l\'application.'))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="text-center text-md-start h2">
<a href="{{ route('bo.tags.index') }}"
class="btn btn-primary text-decoration-none m-0"
data-bs="tooltip"
data-bs-placement="top"
title="{{ __('Retourner sur la liste des :model', ['model' => __('models.classes.tags')]) }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-arrow-left"></i>
</a>
<span class="fw-bold">{{ Str::singular(__('models.classes.tags')) }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('édition')) }}</small>
</h1>
</div>
<div class="col-12 col-md-4 d-flex justify-content-center justify-content-md-end align-items-center">
<form action="{{ route('bo.tags.destroy', $tagModel->id) }}" method="POST" class="d-inline confirmDeleteJS">
@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.tags'))]) }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-floppy-disk"></i>
</button>
<button class="btn btn-danger"
title="{{ __('Supprimer l\':model', ['model' => Str::singular(__('models.classes.tags'))]) }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-trash"></i>
</button>
</div>
</form>
</div>
</div>
</div>
<div class="card-body bg-light">
<form action="{{ route('bo.tags.update', $tagModel->id) }}" method="POST">
@csrf
@method('PUT')
@include('bo.pages.tags.form', ['model' => $tagModel])
<div class="row">
<div class="col text-center">
<button id="formSubmit"
type="submit"
class="btn btn-primary"
title="{{ __('Sauvegarder l\':model', ['model' => Str::singular(__('models.classes.tags'))]) }}"
data-bs-toggle="tooltip">
{{ __('Sauvegarder') }}
</button>
</div>
</div>
</form>
</div>
</div>
@endsection

View file

@ -0,0 +1,36 @@
<div class="row">
{{-- NAME --}}
<div class="col-12 col-md-6 mb-3">
<fieldset class="border h-100 bg-white p-3">
<legend>{{ __('Nom') }}</legend>
<div class="row">
<div class="col-12 mb-3">
@include('bo.partials.inputs.varchar', [
'id' => 'tagName',
'label' => __('Nom de l\':model', ['model' => Str::singular(__('models.classes.tags'))]),
'hasWordCounter' => true,
'name' => 'name',
'required' => true,
'model' => $tagModel ?? null,
'helper' => __('Doit posséder 3 caractères minimum, 255 maximum.'),
'placeholder' => "Un beau nom"
])
</div>
</div>
</fieldset>
</div>
</div>
@push('scripts')
<script nonce="{{ $nonce }}">
document.addEventListener("DOMContentLoaded", () => {
// Submit button clone.
const submit = document.getElementById('formSubmit')
submitClone = document.getElementById('formSubmitClone');
submitClone.addEventListener('click', (event) => {
event.preventDefault();
submit.click('');
})
});
</script>
@endpush

View file

@ -0,0 +1,84 @@
<div class="table-responsive">
<table class="table fix-action">
<thead>
@php
$rst = !is_null(request()->rst);
$routeName = request()->route()->getName();
$noOrder = Session::get("$routeName.sort_col") !== '' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way"));
$cols = ['name' => __('Nom'), 'order' => __('Order')];
@endphp
@include('bo.modules.table-col-sorter', [
'cols' => $cols,
'mobileHide' => [],
])
</thead>
<tbody>
@if ($tags->count())
@foreach ($tags as $tagModel)
<tr>
<td class="align-middle">
<span>{{ $tagModel->name }}</span>
</td>
@if(!$noOrder or $rst)
<td class="align-middle d-flex justify-content-center align-items-center">
<form action="{{ route('bo.tags.change-order', ['tag' => $tagModel, 'action' => 'up']) }}"
method="POST"
class="text-center @if($loop->first and $tags->onFirstPage()) invisible @endif">
@csrf
<button type="submit"
class="btn btn-sm btn-outline-dark @if(($loop->first and $tags->onFirstPage())) disabled @endif"
title="{{ __('Modifier l\'ordre d\'apparition vers le haut') }}"
data-bs-toggle="tooltip">
<i class="fas fa-arrow-up"></i>
</button>
</form>
<form action="{{ route('bo.tags.change-order', ['tag' => $tagModel, 'action' => 'down']) }}"
method="POST"
class="text-center @if($loop->last and $tags->currentPage() === $tags->lastPage()) invisible @endif">
@csrf
<button type="submit"
class="btn btn-sm btn-outline-dark ms-1 @if($loop->last and $tags->currentPage() === $tags->lastPage()) disabled @endif"
title="{{ __('Modifier l\'ordre d\'apparition vers le bas') }}"
data-bs-toggle="tooltip">
<i class="fas fa-arrow-down"></i>
</button>
</form>
</td>
@endif
<td>
<div class="btn-group">
<form action="{{ route('bo.tags.destroy', $tagModel->id) }}" method="POST" class="d-inline confirmDeleteJS">
@method('DELETE')
@csrf
<div class="btn-group" role="group">
<a id="formSubmitClone"
href="{{ route('bo.tags.edit', $tagModel) }}"
class="btn btn-sm btn-primary"
role="button"
title="{{ __('Modifier l\':model', ['model' => Str::singular(__('models.classes.tags'))]) }}"
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.tags'))]) }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-trash"></i>
</button>
</div>
</form>
</div>
</td>
</tr>
@endforeach
@else
<tr>
<td colspan="{{ count($cols) + 1 }}" class="text-center">
<span class="h3">
{{ __('Aucun résultat pour les :models', ['models' => __('models.classes.tags')]) }}
</span>
</td>
</tr>
@endif
</tbody>
</table>
</div>

View file

@ -0,0 +1,43 @@
@extends('bo.layout')
@section('title', sprintf('%s - %s', __('models.classes.tags'), Str::ucfirst(__('liste'))))
@section('description', __('Page de contôle sur tous les tags de l\'application.'))
@section('breadcrumb', request()->route()->getName())
@section('content')
<div class="card">
<div class="card-header">
<div class="row">
<div class="col">
<h1 class="col h2">
<span class="fw-bold">{{ __('models.classes.tags') }}</span>&nbsp;<small class="text-muted">{{ Str::ucfirst(__('liste')) }}</small>
</h1>
</div>
<div class="col d-flex justify-content-end align-items-center">
<div class="ms-1 justify-content-end">
<a href="{{ route('bo.tags.create') }}"
class="btn btn-primary"
title="{{ __('Créer une :model', ['model' => Str::singular(__('models.classes.tags'))]) }}"
data-bs-toggle="tooltip">
<i class="fa-solid fa-plus"></i>
</a>
</div>
</div>
</div>
</div>
<div class="card-body">
@include('bo.modules.search-bar')
<div class="row mt-3">
<div class="col">
@include('bo.pages.tags.index-list')
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-md-6">
{{ $tags->withQueryString()->onEachSide(1)->links() }}
</div>
</div>
</div>
</div>
@endsection

View file

@ -2,14 +2,15 @@
<label for="{{ $name }}" class="col-form-label"><b>{{ $label }} *</b></label>
@endif
<select id="bigIntForeignId{{ $name }}" class="form-select" name="{{ $name }}" aria-describedby="{{ $id }}Help" @if(!empty($label))required @endif>
<option value="0" @if (old($name, $model->{$name} ?? null) == null) selected @endif>{{ __('Aucun dossier associé') }}</option>
@foreach ($associatedModels as $_associatedModel)
<option value="{{ $_associatedModel->id }}"@if (old($name, $model->{$name} ?? 1) == $_associatedModel->id) selected @endif>
<option value="{{ $_associatedModel->id }}" @if (old($name, $model->{$name} ?? null) == $_associatedModel->id) selected @endif>
{{ $_associatedModel->{$foreignLabel} }}
</option>
@endforeach
</select>
@include('modules.input-error', [
'inputName' => $name,
'helperId' => "{{ $id }}Help",
'helperId' => $id . "Help",
'helper' => $helper
])

View file

@ -7,8 +7,8 @@
$data = [
'name' => $name,
'value' => old($name, $model->{$name} ?? []) ?? [],
'placeholder' => $placeholder,
'itemsList' => $itemsList,
'placeholder' => $placeholder ?? "",
'itemsList' => $itemsList ?? [],
'itemLimit' => $itemLimit ?? null,
'errors' => $errors->getBag('default')->getMessages() ?? []
];
@ -16,6 +16,6 @@ $data = [
<div class="belongs-to-many-dropdown" data-json='@json($data)'></div>
@include('modules.input-error', [
'inputName' => $name,
'helperId' => "{$id}Help",
'helperId' => $id . "Help",
'helper' => $helper,
])

View file

@ -1,6 +1,6 @@
@if (isset($breadcrumbs))
@unless ($breadcrumbs->isEmpty())
<nav aria-label="breadcrumb" class="d-inline">
<nav aria-label="breadcrumb" class="d-inline mt-3">
<ol class="breadcrumb d-inline-flex">
@foreach ($breadcrumbs as $breadcrumb)
@if (!is_null($breadcrumb->url) && !$loop->last)

Some files were not shown because too many files have changed in this diff Show more