Compare commits
1 commit
develop
...
fix-produc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e12283fd12 |
275 changed files with 8263 additions and 17062 deletions
20
.env.example
20
.env.example
|
|
@ -43,21 +43,5 @@ GOOGLE_RECAPTCHA_PUBLIC=
|
|||
GOOGLE_RECAPTCHA_PRIVATE=
|
||||
GOOGLE_RECAPTCHA_VERSION=
|
||||
|
||||
# UWIL ADMIN SECURE
|
||||
# - LIST SEPARATED WITH ',' (Required)
|
||||
UWIL_ADMIN_SECURE_CIDR_LIST=""
|
||||
# - LIST SEPARATED WITH ',' (Optional)
|
||||
UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST=""
|
||||
|
||||
|
||||
# SAML
|
||||
SAML2_DEFAULT_TENANT_UUID=
|
||||
SAML2_SP_CERT_x509=
|
||||
SAML2_SP_CERT_PRIVATEKEY=
|
||||
SAML2_CONTACT_TECHNICAL_EMAIL=
|
||||
SAML2_CONTACT_SUPPORT_EMAIL=
|
||||
|
||||
# CRM
|
||||
CRM_ENDPOINT=
|
||||
CRM_PASSWORD=
|
||||
CRM_TOKEN=
|
||||
# LDC Web Admin Secure
|
||||
LDC_WEB_API_KEY="MY_KEY"
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -23,9 +23,6 @@ Homestead.yaml
|
|||
npm-debug.log
|
||||
yarn-error.log
|
||||
.npmrc
|
||||
.zshrc
|
||||
.npm/
|
||||
.composer/
|
||||
|
||||
# Ignore public favicon
|
||||
/public/android-chrome-192x192.png
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ include:
|
|||
file: 'security/security.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'build/docker-multistage.yml'
|
||||
file: 'build/build.yml'
|
||||
- project: 'ldc-web/shared-ci'
|
||||
ref: 'main'
|
||||
file: 'test/test.yml'
|
||||
|
|
|
|||
48
Dockerfile
48
Dockerfile
|
|
@ -1,47 +1,5 @@
|
|||
ARG PHP_8_5_TAG=latest
|
||||
|
||||
FROM composer:2.8 AS vendor
|
||||
|
||||
ARG GITLAB_USER
|
||||
ARG GITLAB_PASSWORD
|
||||
|
||||
COPY database/ database/
|
||||
|
||||
COPY composer.json composer.json
|
||||
COPY composer.lock composer.lock
|
||||
|
||||
RUN composer config gitlab-token.lab.s-web.fr ${GITLAB_USER} ${GITLAB_PASSWORD}
|
||||
RUN composer install \
|
||||
--ignore-platform-reqs \
|
||||
--no-interaction \
|
||||
--no-plugins \
|
||||
--no-scripts \
|
||||
--no-dev \
|
||||
--prefer-dist
|
||||
|
||||
FROM node:20.18 AS frontend
|
||||
|
||||
ARG GITLAB_PASSWORD
|
||||
|
||||
RUN mkdir -p /app/public/build
|
||||
|
||||
COPY package*.json tsconfig.json vite.config.ts .eslintrc.json .stylelintrc.json /app/
|
||||
COPY resources/ /app/resources/
|
||||
WORKDIR /app
|
||||
RUN npm config set @ldc-web:registry https://lab.s-web.fr/api/v4/packages/npm/
|
||||
RUN npm config set -- '//lab.s-web.fr/api/v4/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
|
||||
RUN npm ci && npm run prod
|
||||
|
||||
ARG PHP_8_5_TAG
|
||||
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.5:${PHP_8_5_TAG}
|
||||
|
||||
ARG USER=www-data
|
||||
|
||||
COPY --chown=${USER}:${USER} . /app/srcs
|
||||
COPY --chown=${USER}:${USER} ./resources/favicon /app/srcs/public
|
||||
COPY --from=vendor --chown=${USER}:${USER} /app/vendor/ /app/srcs/vendor/
|
||||
COPY --from=frontend --chown=${USER}:${USER} /app/public/build/ /app/srcs/public/build/
|
||||
|
||||
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/ldcweb-production-8.2:latest
|
||||
COPY --chown=www-data:www-data . /app/srcs
|
||||
USER root
|
||||
RUN chmod -R 755 /app/srcs/storage
|
||||
USER ${USER}
|
||||
USER www-data
|
||||
35
app/Console/Commands/TestMail.php
Normal file
35
app/Console/Commands/TestMail.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class TestMail extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'uwil:mail:test';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Send test email to equipe.web@ldc.fr';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Mail::raw(sprintf('UWIL mail-test from %s %s', \config('app.name'), \config('app.url')), function ($msg) {
|
||||
$msg->to('equipe.web@ldc.fr')->subject('Test Email');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
|
@ -44,6 +45,13 @@ class UserCreate extends Command
|
|||
*/
|
||||
protected $email;
|
||||
|
||||
/**
|
||||
* The password of the new user.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
|
|
@ -60,10 +68,16 @@ class UserCreate extends Command
|
|||
$this->email = null;
|
||||
$this->addEmail();
|
||||
|
||||
$this->password = null;
|
||||
$this->addPassword();
|
||||
|
||||
$user = new User([
|
||||
'firstname' => $this->firstname,
|
||||
'lastname' => $this->lastname,
|
||||
'email' => $this->email
|
||||
'email' => $this->email,
|
||||
'password' => $this->password,
|
||||
'published' => true,
|
||||
'published_at' => Carbon::now(),
|
||||
]);
|
||||
$user->saveOrFail();
|
||||
|
||||
|
|
@ -94,7 +108,7 @@ class UserCreate extends Command
|
|||
));
|
||||
continue;
|
||||
} //end try
|
||||
};
|
||||
}; //end while
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -119,7 +133,7 @@ class UserCreate extends Command
|
|||
));
|
||||
continue;
|
||||
} //end try
|
||||
};
|
||||
}; //end while
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,6 +158,22 @@ class UserCreate extends Command
|
|||
));
|
||||
continue;
|
||||
} //end try
|
||||
};
|
||||
}; //end while
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a password to the user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addPassword(): void
|
||||
{
|
||||
while (
|
||||
($this->password = $this->secret(
|
||||
(!\is_null($this->password) ? 'Failed to confirm, ' : '') . 'Type the wanted user password'
|
||||
)) !== $this->secret('Confirm the password')
|
||||
) {
|
||||
continue;
|
||||
}; //end while
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,18 +8,17 @@ enum ProductSpeciesEnum: int
|
|||
{
|
||||
use BaseEnum;
|
||||
|
||||
case caille = 0;
|
||||
case canard = 1;
|
||||
case canette = 2;
|
||||
case coq = 3;
|
||||
case coquelet = 4;
|
||||
case dinde = 5;
|
||||
case lapin = 6;
|
||||
case pigeonneau = 7;
|
||||
case pintade = 8;
|
||||
case poule = 9;
|
||||
case poulet = 10;
|
||||
case volaille_festive = 11;
|
||||
case caille = 0;
|
||||
case canard = 1;
|
||||
case canette = 2;
|
||||
case coq = 3;
|
||||
case coquelet = 4;
|
||||
case dinde = 5;
|
||||
case lapin = 6;
|
||||
case pigeonneau = 7;
|
||||
case pintade = 8;
|
||||
case poule = 9;
|
||||
case poulet = 10;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition.
|
||||
|
|
@ -27,17 +26,16 @@ enum ProductSpeciesEnum: int
|
|||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
private const LABELS = [
|
||||
self::caille->name => 'Caille',
|
||||
self::canard->name => 'Canard',
|
||||
self::canette->name => 'Canette',
|
||||
self::coq->name => 'Coq',
|
||||
self::coquelet->name => 'Coquelet',
|
||||
self::dinde->name => 'Dinde',
|
||||
self::lapin->name => 'Lapin',
|
||||
self::pigeonneau->name => 'Pigeonneau',
|
||||
self::pintade->name => 'Pintade',
|
||||
self::poule->name => 'Poule',
|
||||
self::poulet->name => 'Poulet',
|
||||
self::volaille_festive->name => 'Volaille festive'
|
||||
self::caille->name => 'Caille',
|
||||
self::canard->name => 'Canard',
|
||||
self::canette->name => 'Canette',
|
||||
self::coq->name => 'Coq',
|
||||
self::coquelet->name => 'Coquelet',
|
||||
self::dinde->name => 'Dinde',
|
||||
self::lapin->name => 'Lapin',
|
||||
self::pigeonneau->name => 'Pigeonneau',
|
||||
self::pintade->name => 'Pintade',
|
||||
self::poule->name => 'Poule',
|
||||
self::poulet->name => 'Poulet'
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ enum StaticPageType: int
|
|||
case expertise_chicken = 6;
|
||||
case expertise_duck = 7;
|
||||
case expertise_rabbit = 8;
|
||||
case sitemap = 9;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition.
|
||||
|
|
@ -32,6 +31,5 @@ enum StaticPageType: int
|
|||
self::expertise_chicken->name => 'Expertise poulet',
|
||||
self::expertise_duck->name => 'Expertise canard',
|
||||
self::expertise_rabbit->name => 'Expertise lapin',
|
||||
self::sitemap->name => 'Plan du site',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use App\Traits\Enums\BaseEnum;
|
||||
|
||||
enum TagTypeEnum: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case recipes = 1;
|
||||
case products = 2;
|
||||
|
||||
/**
|
||||
* Optionnal labels definition.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
private const LABELS = [
|
||||
self::recipes->name => 'Recettes / Astuces',
|
||||
self::products->name => 'Produits',
|
||||
];
|
||||
}
|
||||
|
|
@ -3,14 +3,12 @@
|
|||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\Advices\AdviceTypeEnum;
|
||||
use App\Enums\TagTypeEnum;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Advice\StoreAdviceRequest;
|
||||
use App\Http\Requests\Bo\Advice\UpdateAdviceRequest;
|
||||
use App\Models\Advice;
|
||||
use App\Models\Product;
|
||||
use App\Models\Tag;
|
||||
use App\Traits\Controllers\ManagesOrder;
|
||||
use App\Traits\Controllers\UpdateModelPublished;
|
||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -21,7 +19,6 @@ use Illuminate\Support\Str;
|
|||
class AdviceController extends Controller
|
||||
{
|
||||
use UpdateModelPublished;
|
||||
use ManagesOrder;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
|
|
@ -30,7 +27,7 @@ class AdviceController extends Controller
|
|||
* @param \App\Enums\Advices\AdviceTypeEnum|null $type
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request, AdviceTypeEnum|null $type = null): \Illuminate\Contracts\View\View
|
||||
public function index(Request $request, AdviceTypeEnum $type = null): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$type = $type ?: AdviceTypeEnum::all;
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $adviceModels */
|
||||
|
|
@ -73,7 +70,7 @@ class AdviceController extends Controller
|
|||
public function create(AdviceTypeEnum $type): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$advice = new Advice();
|
||||
$adviceTags = Tag::query()->where('type', TagTypeEnum::recipes)->select(['id', 'label', 'slug'])->get();
|
||||
$adviceTags = Tag::query()->select(['id', 'label', 'slug'])->get();
|
||||
$adviceProducts = Product::all();
|
||||
$recipeList = Advice::query()->where('type', '=', AdviceTypeEnum::recipes)->get();
|
||||
$tipList = Advice::query()->where('type', '=', AdviceTypeEnum::tips)->get();
|
||||
|
|
@ -152,7 +149,7 @@ class AdviceController extends Controller
|
|||
public function edit(Advice $advice): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$currentType = $advice->type;
|
||||
$adviceTags = Tag::query()->where('type', TagTypeEnum::recipes)
|
||||
$adviceTags = Tag::query()->whereNotIn('id', $advice->tags()->pluck('id'))
|
||||
->select(['id', 'label', 'slug'])->get();
|
||||
$adviceProducts = Product::all();
|
||||
$recipeList = Advice::query()->where([
|
||||
|
|
|
|||
|
|
@ -1,152 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Requests\Bo\BrigadeSections\StoreBrigadeSectionsRequest;
|
||||
use App\Http\Requests\Bo\BrigadeSections\UpdateBrigadeSectionsRequest;
|
||||
use App\Models\BrigadeSection;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Controllers\UpdateModelPublished;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Uwil\Laravel\Common\Controllers\Controller;
|
||||
|
||||
class BrigadeSectionController extends Controller
|
||||
{
|
||||
use UpdateModelPublished;
|
||||
use ChangesModelOrder;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $brigadeSectionModels */
|
||||
$brigadeSectionModels = BrigadeSection::query();
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
if ($search) {
|
||||
$this->searchQuery(
|
||||
$brigadeSectionModels,
|
||||
$search,
|
||||
null,
|
||||
'title',
|
||||
'content',
|
||||
'button_text',
|
||||
'button_url'
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Titre, Texte, CTA, Lien');
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($brigadeSectionModels);
|
||||
|
||||
/** Custom pagination */
|
||||
$brigadeSectionModels = $this->paginate($brigadeSectionModels);
|
||||
|
||||
return view('bo.pages.brigade_sections.index', compact('brigadeSectionModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param \App\Models\BrigadeSection $brigadeSection
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function create(BrigadeSection $brigadeSection): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$brigadeSection = $brigadeSection->exists() ? $brigadeSection : new BrigadeSection();
|
||||
|
||||
return view('bo.pages.brigade_sections.create', [
|
||||
'brigadeSectionModel' => $brigadeSection,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\BrigadeSections\StoreBrigadeSectionsRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreBrigadeSectionsRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$brigadeSection = new BrigadeSection();
|
||||
$brigadeSection->fill($request->validated());
|
||||
|
||||
if ($brigadeSection->saveOrFail()) {
|
||||
return redirect()->route('bo.brigade_sections.edit', $brigadeSection->id)
|
||||
->with('success', __('crud.messages.has_been_created', [
|
||||
'model' => trans_choice('models.classes.brigade_section', 1)
|
||||
]));
|
||||
}
|
||||
return redirect()->back()
|
||||
->with('error', __('crud.messages.cannot_be_created', [
|
||||
'model' => trans_choice('models.classes.brigade_section', 1)
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\BrigadeSection $brigadeSection
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(BrigadeSection $brigadeSection): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.brigade_sections.edit', [
|
||||
'brigadeSectionModel' => $brigadeSection,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\BrigadeSections\UpdateBrigadeSectionsRequest $request
|
||||
* @param \App\Models\BrigadeSection $brigadeSection
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateBrigadeSectionsRequest $request, BrigadeSection $brigadeSection): RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $brigadeSection) {
|
||||
$brigadeSection->fill($request->validated());
|
||||
|
||||
if ($brigadeSection->saveOrFail()) {
|
||||
return redirect()->route('bo.brigade_sections.edit', $brigadeSection->id)
|
||||
->with('success', __('crud.messages.has_been_updated', [
|
||||
'model' => trans_choice('models.classes.brigade_section', 1)
|
||||
]));
|
||||
}
|
||||
return redirect()->route('bo.brigade_sections.edit', $brigadeSection->id)
|
||||
->with('error', __('crud.messages.cannot_be_updated', [
|
||||
'model' => trans_choice('models.classes.brigade_section', 1)
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\BrigadeSection $brigadeSection
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(BrigadeSection $brigadeSection): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
if ($brigadeSection->deleteOrFail()) {
|
||||
return redirect()->route('bo.brigade_sections.index')
|
||||
->with('success', __('crud.messages.has_been_deleted', [
|
||||
'model' => trans_choice('models.classes.brigade_section', 1)
|
||||
]));
|
||||
}
|
||||
return redirect()->back()
|
||||
->with('error', __('crud.messages.cannot_be_deleted', [
|
||||
'model' => trans_choice('models.classes.brigade_section', 1)
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
|
@ -93,7 +93,7 @@ class NewsController extends Controller
|
|||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$news = new News();
|
||||
$news->fill($request->safe()->except(['categories', 'products', 'associated_news_list']));
|
||||
$news->fill($request->validated());
|
||||
|
||||
if ($news->saveOrFail()) {
|
||||
$news->categories()->sync($request->categories_list);
|
||||
|
|
@ -156,7 +156,7 @@ class NewsController extends Controller
|
|||
$news->products()->sync($request->products_list);
|
||||
$news->news()->sync($request->news_list);
|
||||
|
||||
$news->fill($request->safe()->except(['categories', 'products', 'associated_news_list']));
|
||||
$news->fill($request->validated());
|
||||
|
||||
if ($news->saveOrFail()) {
|
||||
return redirect()->route('bo.news.edit', $news->id)
|
||||
|
|
|
|||
|
|
@ -2,25 +2,22 @@
|
|||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\TagTypeEnum;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Products\StoreProductRequest;
|
||||
use App\Http\Requests\Bo\Products\UpdateProductRequest;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Models\Product;
|
||||
use App\Models\Range;
|
||||
use App\Models\Subrange;
|
||||
use App\Models\Tag;
|
||||
use App\Traits\Controllers\UpdateModelPublished;
|
||||
use App\Traits\Controllers\ManagesOrder;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use UpdateModelPublished;
|
||||
use ManagesOrder;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
|
|
@ -43,13 +40,6 @@ class ProductController extends Controller
|
|||
'label'
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->range) {
|
||||
$productModels->whereHas('subrange', function ($q) use ($request) {
|
||||
$q->where('subranges.range_id', '=', $request->range);
|
||||
})->get();
|
||||
}
|
||||
|
||||
$searchFields = trans('Label');
|
||||
|
||||
/** Sort columns with a query */
|
||||
|
|
@ -58,9 +48,7 @@ class ProductController extends Controller
|
|||
/** Custom pagination */
|
||||
$productModels = $this->paginate($productModels);
|
||||
|
||||
$ranges = Range::all();
|
||||
|
||||
return view('bo.pages.products.index', compact('productModels', 'search', 'searchFields', 'ranges'));
|
||||
return view('bo.pages.products.index', compact('productModels', 'search', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -73,12 +61,10 @@ class ProductController extends Controller
|
|||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $subrangeModels */
|
||||
$subrangeModels = Subrange::get();
|
||||
$productTags = Tag::query()->where('type', TagTypeEnum::products)->select(['id', 'label', 'slug'])->get();
|
||||
|
||||
return view('bo.pages.products.create', [
|
||||
'productModel' => $product,
|
||||
'subrangeModels' => $subrangeModels,
|
||||
'productTags' => $productTags,
|
||||
'subrangeModels' => $subrangeModels
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -92,11 +78,10 @@ class ProductController extends Controller
|
|||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$product = new Product();
|
||||
$product->fill($request->safe()->except('tags'));
|
||||
$product->fill($request->validated());
|
||||
$this->storePictures($request, $product);
|
||||
|
||||
if ($product->saveOrFail()) {
|
||||
$product->tags()->sync(collect($request->input('tags'))->pluck('id'));
|
||||
return redirect()->route('bo.products.edit', $product->id)
|
||||
->with('success', __('crud.messages.has_been_created', [
|
||||
'model' => Str::singular(__('models.classes.products'))
|
||||
|
|
@ -120,13 +105,9 @@ class ProductController extends Controller
|
|||
/** @var \Illuminate\Database\Eloquent\Builder $subrangeModels */
|
||||
$subrangeModels = Subrange::get();
|
||||
|
||||
$productTags = Tag::query()->where('type', TagTypeEnum::products)
|
||||
->select(['id', 'label', 'slug'])->get();
|
||||
|
||||
return view('bo.pages.products.edit', [
|
||||
'productModel' => $product,
|
||||
'subrangeModels' => $subrangeModels,
|
||||
'productTags' => $productTags,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -140,8 +121,7 @@ class ProductController extends Controller
|
|||
public function update(UpdateProductRequest $request, Product $product): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $product) {
|
||||
$product->tags()->sync(collect($request->input('tags'))->pluck('id'));
|
||||
$product->fill($request->safe()->except('tags'));
|
||||
$product->fill($request->validated());
|
||||
$this->storePictures($request, $product);
|
||||
|
||||
if ($product->saveOrFail()) {
|
||||
|
|
@ -167,7 +147,6 @@ class ProductController extends Controller
|
|||
{
|
||||
$product->advices()->sync([]);
|
||||
$product->news()->sync([]);
|
||||
$product->tags()->sync([]);
|
||||
|
||||
if ($product->deleteOrFail()) {
|
||||
return redirect()->route('bo.products.index')
|
||||
|
|
@ -192,7 +171,7 @@ class ProductController extends Controller
|
|||
{
|
||||
if (is_array($request->input('slider_pictures'))) {
|
||||
$product->slider_pictures = [];
|
||||
$product->slider_pictures = collect($request->file('slider_pictures'))
|
||||
$product->slider_pictures = collect($request->input('slider_pictures'))
|
||||
->map(function ($picture) use ($product) {
|
||||
return FileStorageHelper::storeFile($product, $picture, true);
|
||||
})->all();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use App\Http\Requests\Bo\Slides\StoreSlideRequest;
|
|||
use App\Http\Requests\Bo\Slides\UpdateSlideRequest;
|
||||
use App\Models\Slide;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use App\Traits\Controllers\UpdateModelPublished;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -15,7 +14,6 @@ use Illuminate\Support\Str;
|
|||
class SlideController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
use UpdateModelPublished;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\TagTypeEnum;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Tags\StoreTagRequest;
|
||||
use App\Http\Requests\Bo\Tags\UpdateTagRequest;
|
||||
|
|
@ -23,7 +22,6 @@ class TagController extends Controller
|
|||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $tagModels */
|
||||
$tagModels = Tag::query();
|
||||
$tagModels = $request->type ? $tagModels->where('type', TagTypeEnum::{$request->type}) : $tagModels;
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
|
|
@ -32,11 +30,10 @@ class TagController extends Controller
|
|||
$tagModels,
|
||||
$search,
|
||||
null,
|
||||
'label',
|
||||
'type',
|
||||
'label'
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Nom, Type');
|
||||
$searchFields = trans('Nom');
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($tagModels);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class Controller extends BaseController
|
|||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query The eloquent query builder.
|
||||
* @param string $search The query string.
|
||||
* @param callable|null $searchQuery The query string.
|
||||
* @param callable $searchQuery The query string.
|
||||
* @param string ...$fields Either a simple array or a string
|
||||
* in case of a string the two fields
|
||||
* would be concatenate to make the search.
|
||||
|
|
@ -38,7 +38,7 @@ class Controller extends BaseController
|
|||
protected function searchQuery(
|
||||
Builder $query,
|
||||
string $search,
|
||||
callable|null $searchQuery = null,
|
||||
callable $searchQuery = null,
|
||||
string ...$fields
|
||||
): \Illuminate\Database\Eloquent\Builder {
|
||||
if (count($fields)) {
|
||||
|
|
@ -203,7 +203,7 @@ class Controller extends BaseController
|
|||
*/
|
||||
protected function paginate(
|
||||
Builder $query,
|
||||
ItemsPerPaginationEnum|null $pagination = null
|
||||
ItemsPerPaginationEnum $pagination = null
|
||||
): \Illuminate\Contracts\Pagination\LengthAwarePaginator {
|
||||
$currentRoutePath = Str::slug(request()->route()->getName());
|
||||
$cacheKey = "pagination.{$currentRoutePath}";
|
||||
|
|
@ -237,7 +237,7 @@ class Controller extends BaseController
|
|||
*/
|
||||
protected function getProductQuery(string $search): Builder
|
||||
{
|
||||
return Product::query()->where('published', true)->where(function ($query) use ($search) {
|
||||
return Product::query()->where('status', true)->where(function ($query) use ($search) {
|
||||
// Par leur désignation.
|
||||
$query->where('label', 'like', "%{$search}%");
|
||||
// Par ingrédients.
|
||||
|
|
@ -257,7 +257,7 @@ class Controller extends BaseController
|
|||
// Par espèce.
|
||||
if (\strlen($search)) {
|
||||
/** @var \App\Enums\Products\ProductSpeciesEnum|null $specie */
|
||||
$specie = \collect(ProductSpeciesEnum::cases())
|
||||
$specie = \collect(ProductSpeciesEnum::toArray())
|
||||
->filter(function (ProductSpeciesEnum $specie) use ($search) {
|
||||
return \strpos(Str::lower($specie->label()), Str::lower($search)) !== false;
|
||||
})->first();
|
||||
|
|
@ -279,7 +279,7 @@ class Controller extends BaseController
|
|||
*/
|
||||
protected function getNewsQuery(string $search): Builder
|
||||
{
|
||||
return News::query()->where('published', true)->where(function ($query) use ($search) {
|
||||
return News::query()->where('status', true)->where(function ($query) use ($search) {
|
||||
$query->where('title', 'like', "%{$search}%");
|
||||
$query->orWhere('subtitle', 'like', "%{$search}%");
|
||||
$query->orWhere('content', 'like', "%{$search}%");
|
||||
|
|
@ -298,7 +298,7 @@ class Controller extends BaseController
|
|||
*/
|
||||
protected function getRecipeQuery(string $search): Builder
|
||||
{
|
||||
return Advice::query()->where('published', true)
|
||||
return Advice::query()->where('status', true)
|
||||
->where('type', '=', AdviceTypeEnum::recipes->value)
|
||||
->where(function ($query) use ($search) {
|
||||
$query->where('title', 'like', "%{$search}%");
|
||||
|
|
|
|||
|
|
@ -16,6 +16,16 @@ class AdnController extends Controller
|
|||
return view('fo.pages.adn.adn');
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function story(): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('fo.pages.adn.story');
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\BrigadeSection;
|
||||
|
||||
class BrigadeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$sections = BrigadeSection::query()
|
||||
->where('published', true)
|
||||
->orderBy('order')
|
||||
->get();
|
||||
|
||||
return view('fo.pages.brigade', compact(
|
||||
'sections',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -7,13 +7,8 @@ use App\Http\Controllers\Controller;
|
|||
use App\Http\Requests\Fo\Contact\ContactRequest;
|
||||
use App\Mail\ContactFormMail;
|
||||
use App\Models\StaticPage;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
use LDC\LDCCRM\Exceptions\CrmException;
|
||||
use LDC\LDCCRM\Models\SingleOptin;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
|
|
@ -37,63 +32,12 @@ class ContactController extends Controller
|
|||
*/
|
||||
public function contactSubmit(ContactRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$recipients = config('mail.contactsList.contactform');
|
||||
|
||||
if (empty($recipients)) {
|
||||
Log::warning('Aucun destinataire configuré pour le formulaire de contact.');
|
||||
return back()
|
||||
->withErrors(['global' => __('Une erreur est survenue, veuillez réessayer plus tard.')])
|
||||
->withInput();
|
||||
}
|
||||
$redirection = back()->with('success', trans(
|
||||
'Votre message a bien été envoyé, merci de votre intérêt, nous répondrons dans les meilleurs délais.'
|
||||
));
|
||||
|
||||
if ($request->opt_in) {
|
||||
try {
|
||||
SingleOptin::setStatus($request->email, true);
|
||||
} catch (ApiErrorException $e) {
|
||||
\report($e);
|
||||
$redirection = $redirection->withErrors([
|
||||
'opt_in' => trans('Une erreur est survenue,
|
||||
votre inscription à la newsletter n\'a pas été prise en compte.')
|
||||
]);
|
||||
} catch (CrmException $e) {
|
||||
\report($e);
|
||||
$redirection = $redirection->withErrors([
|
||||
'opt_in' => trans('Une erreur est survenue,
|
||||
votre inscription à la newsletter n\'a pas été prise en compte.')
|
||||
]);
|
||||
}
|
||||
} //end if
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
Mail::to($recipient)->send(new ContactFormMail($request));
|
||||
}
|
||||
Mail::to(config('mail.contactsList.contactform'))->send(new ContactFormMail($request));
|
||||
|
||||
Session::forget('saveProductInBasket');
|
||||
|
||||
Session::forget('contact_draft');
|
||||
|
||||
Session::flash('matomo_generate_lead');
|
||||
|
||||
return $redirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data form as draft
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function saveDraft(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$request->session()->put('contact_draft', $request->only([
|
||||
'firstname', 'lastname', 'email', 'phone',
|
||||
'activity', 'society', 'postcode', 'city',
|
||||
'message', 'callTime', 'opt_in',
|
||||
]));
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
return back()->with('success', trans(
|
||||
'Votre message a bien été envoyé, merci de votre intérêt, nous répondrons dans les meilleurs délais.'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class ExpertiseController extends Controller
|
|||
$productVipModels = ExpertiseProduct::query()->where('page', $enumExpertiseProductPage->value())->get();
|
||||
|
||||
/** @var \App\Models\Product $productModels */
|
||||
$productModels = Product::query()->where('published', true)
|
||||
$productModels = Product::query()->where('status', true)
|
||||
->where('species', $enumProductSpecies->value())
|
||||
->inRandomOrder()
|
||||
->limit(3)
|
||||
|
|
|
|||
|
|
@ -3,17 +3,10 @@
|
|||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Fo\Newsletter\SingleOptinRequest;
|
||||
use App\Http\Requests\Fo\Newsletter\UnsubscribeNewsletterRequest;
|
||||
use App\Models\News;
|
||||
use App\Models\Product;
|
||||
use App\Models\Range;
|
||||
use App\Models\Slide;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use LDC\LDCCRM\Enums\ApiError;
|
||||
use LDC\LDCCRM\Exceptions\ApiErrorException;
|
||||
use LDC\LDCCRM\Exceptions\CrmException;
|
||||
use LDC\LDCCRM\Models\SingleOptin;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
|
|
@ -27,31 +20,30 @@ class HomeController extends Controller
|
|||
// Get Slides.
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $slides */
|
||||
$slides = Slide::query()
|
||||
->where('published', true)
|
||||
->orderBy('order', 'DESC')
|
||||
->get();
|
||||
$slides = Slide::query();
|
||||
$slides->orderBy('order', 'DESC');
|
||||
$slides = $slides->get();
|
||||
|
||||
// Gammes.
|
||||
$ranges = Range::all();
|
||||
|
||||
// VIP Products.
|
||||
$threeproducts = Product::where('published', true)
|
||||
$threeproducts = Product::where('status', true)
|
||||
->where('is_vip', true)
|
||||
->take(3)
|
||||
->orderBy('priority_order', 'DESC')
|
||||
->orderBy('order', 'DESC')
|
||||
->with('subrange.range')
|
||||
->get();
|
||||
|
||||
// Get Agenda.
|
||||
// Events starting in the future.
|
||||
$events = News::query()->where('published', true)
|
||||
$events = News::query()->where('status', true)
|
||||
->where('event_start', '>', now())
|
||||
->orderBy('event_start', 'desc')
|
||||
->take(2)->get()->reverse();
|
||||
|
||||
// Get last 3 News.
|
||||
$news = News::query()->latest()->where('published', true)
|
||||
$news = News::query()->latest()->where('status', true)
|
||||
->take(3)->with('categories')->get();
|
||||
|
||||
return view('fo.pages.home', compact(
|
||||
|
|
@ -62,66 +54,4 @@ class HomeController extends Controller
|
|||
'news'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the CRM to add a single optin
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Newsletter\SingleOptinRequest $request
|
||||
* @return string|array|null|\Illuminate\Contracts\Translation\Translator
|
||||
* @throws \LDC\LDCCRM\Exceptions\ValidationException ValidationException.
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
|
||||
*/
|
||||
public function addOptIn(SingleOptinRequest $request)
|
||||
{
|
||||
try {
|
||||
SingleOptin::setStatus($request->email, true);
|
||||
return \response(trans("Votre inscription à la newsletter a été prise en compte"), 200);
|
||||
} catch (ApiErrorException $e) {
|
||||
\report($e);
|
||||
return \response(trans('Une erreur est survenue, merci de réessayer ultérieurement'), 500);
|
||||
} catch (CrmException $e) {
|
||||
\report($e);
|
||||
return \response(trans('Une erreur est survenue, merci de réessayer ultérieurement'), 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unsubscribeNewsletter method
|
||||
*
|
||||
* @param \App\Http\Requests\Fo\Newsletter\UnsubscribeNewsletterRequest $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function unsubscribeNewsletter(UnsubscribeNewsletterRequest $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$error = null;
|
||||
$hashcode = $request->hashcode;
|
||||
|
||||
try {
|
||||
SingleOptin::unsetStatusWithHashcode($hashcode);
|
||||
} catch (ApiErrorException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
if ($e->getApiError()->equals(ApiError::modelNotFound)) {
|
||||
abort(404);
|
||||
} else {
|
||||
if (app()->bound('sentry')) {
|
||||
app('sentry')->captureException($e);
|
||||
}
|
||||
$error = true;
|
||||
}
|
||||
} catch (CrmException $e) {
|
||||
Log::debug($e->getMessage());
|
||||
$error = true;
|
||||
if (app()->bound('sentry')) {
|
||||
app('sentry')->captureException($e);
|
||||
}
|
||||
} //end try
|
||||
|
||||
if (!is_null($error)) {
|
||||
return view('fo.pages.newsletter-unsubscribe')->with(
|
||||
'error',
|
||||
trans('Une erreur est survenue, merci de réessayer ultérieurement')
|
||||
);
|
||||
}
|
||||
return view('fo.pages.newsletter-unsubscribe');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ class NewsController extends Controller
|
|||
|
||||
$news = News::query()->with('categories')->when(
|
||||
$filters_activated->first() !== 'all',
|
||||
fn(Builder $q) => $q->with('categories')
|
||||
->whereRelation('categories', fn(Builder $q) =>
|
||||
fn (Builder $q) => $q->with('categories')
|
||||
->whereRelation('categories', fn (Builder $q) =>
|
||||
$q->where(function (Builder $q) use ($filters_activated) {
|
||||
foreach ($filters_activated as $value) {
|
||||
if (is_string($value)) {
|
||||
|
|
@ -35,7 +35,7 @@ class NewsController extends Controller
|
|||
}
|
||||
}
|
||||
}))
|
||||
)->where('published', true)->orderByDesc('created_at')->paginate(6);
|
||||
)->where('status', true)->orderBy('created_at')->paginate(6);
|
||||
|
||||
return view('fo.pages.news.index', compact('categories', 'news', 'filters_activated'));
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ class NewsController extends Controller
|
|||
{
|
||||
$news->load('categories', 'news.categories', 'products');
|
||||
$readingTime = $news->getReadingTime();
|
||||
$products = $news->products()->with(['subrange', 'subrange.range'])->get();
|
||||
$products = $news->products()->get();
|
||||
|
||||
return view('fo.pages.news.post', compact('news', 'readingTime', 'products'));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,7 @@ class ProductsController extends Controller
|
|||
$search = htmlspecialchars($request->query('search') ?? '');
|
||||
$productsQuery = !empty($search) ? $this->getProductQuery($search) : Product::query();
|
||||
$productsQuery->with('subrange.range');
|
||||
$productsQuery->where('published', true);
|
||||
$productsQuery->orderBy('priority_order', 'ASC');
|
||||
$productsQuery->where('status', true);
|
||||
|
||||
// * Range filter (obligatoire).
|
||||
$productsQuery->whereHas('subrange', function (Builder $q) use ($range) {
|
||||
|
|
@ -85,6 +84,7 @@ class ProductsController extends Controller
|
|||
if ($request->vip) {
|
||||
$productsQuery->where('is_vip', $request->vip);
|
||||
}
|
||||
|
||||
return \response()->json(new ProductPaginatedCollectionResource($productsQuery->paginate(6)));
|
||||
}
|
||||
|
||||
|
|
@ -97,12 +97,12 @@ class ProductsController extends Controller
|
|||
public function show(Product $publishedProduct): \Illuminate\Contracts\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Advice> */
|
||||
$recipes = $publishedProduct->recipesQuery()->where('published', true)->with('tags')->get();
|
||||
$recipes = $publishedProduct->recipesQuery()->where('status', true)->get();
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Advice> */
|
||||
$tips = $publishedProduct->tipsQuery()->where('published', true)->get();
|
||||
$tips = $publishedProduct->tipsQuery()->where('status', true)->get();
|
||||
|
||||
// Force load subrange and range.
|
||||
$publishedProduct->load(['subrange.range', 'tags']);
|
||||
$publishedProduct->load('subrange.range');
|
||||
|
||||
/** @var \App\Models\Subrange */
|
||||
$subrange = $publishedProduct->subrange;
|
||||
|
|
@ -113,7 +113,7 @@ class ProductsController extends Controller
|
|||
$randomProducts = Product::query()
|
||||
->with('subrange.range')
|
||||
->where('id', '!=', $publishedProduct->id)
|
||||
->where('published', true)
|
||||
->where('status', true)
|
||||
->whereHas('subrange', function (Builder $q) use ($range) {
|
||||
$q->whereHas('range', function (Builder $q) use ($range) {
|
||||
$q->where('id', $range->id);
|
||||
|
|
@ -136,13 +136,13 @@ class ProductsController extends Controller
|
|||
* @param \App\Models\Product $publishedProduct
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function printCommercialSheet(Product $publishedProduct): Response
|
||||
public function printCommericalSheet(Product $publishedProduct): Response
|
||||
{
|
||||
$title = trans('Fiche commerciale du produit : :label - :appname', [
|
||||
'label' => $publishedProduct->label,
|
||||
'appname' => \config('app.name', 'Le Gaulois Pro')
|
||||
]);
|
||||
$filename = trans('fiche-commerciale-:slug-:date.pdf', [
|
||||
$filename = trans('fiche-commerciale-:slug-:date', [
|
||||
'slug' => Str::slug($publishedProduct->label),
|
||||
'date' => \now()->format('Y-m-d')
|
||||
]);
|
||||
|
|
@ -153,15 +153,17 @@ class ProductsController extends Controller
|
|||
* ! apres avoir header et echo dans le corps de la réponse php (Nasty trick)
|
||||
*/
|
||||
return \response(
|
||||
$this->generateProductCommercialPdf($publishedProduct, $title)->download($filename),
|
||||
$this->generateProductCommercialPdf($publishedProduct, $title)->output(),
|
||||
200,
|
||||
[
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-disposition' => "inline; filename=\"{$filename}\"",
|
||||
'Cache-Control' => 'public, must-revalidate, max-age=0',
|
||||
'Pragma' => 'public',
|
||||
'Expires' => 'Sat, 26 Jul 1997 05:00:00 GMT',
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT',
|
||||
'Cache-Control' => 'public, must-revalidate, max-age=0',
|
||||
'Pragma' => 'public',
|
||||
// * For glory
|
||||
'X-Generator' => 'mPDF',
|
||||
'Expires' => 'Sat, 26 Jul 1997 05:00:00 GMT',
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,39 +43,39 @@ class RecipesController extends Controller
|
|||
/** @var \App\Enums\Advices\AdviceTimeEnum|null $cooking_time */
|
||||
/** @var \App\Enums\Advices\AdviceTimeEnum|null $preparation_time */
|
||||
|
||||
$query = Advice::query()->with('tags')->where('type', 1)->where('published', true)->when(
|
||||
$query = Advice::query()->where('type', 1)->where('status', true)->when(
|
||||
is_numeric($search_range),
|
||||
fn(Builder $q) =>
|
||||
fn (Builder $q) =>
|
||||
$q->whereHas(
|
||||
'products',
|
||||
fn(Builder $q) =>
|
||||
fn (Builder $q) =>
|
||||
$q->whereHas(
|
||||
'subrange',
|
||||
fn(Builder $q) =>
|
||||
fn (Builder $q) =>
|
||||
$q->whereHas(
|
||||
'range',
|
||||
fn(Builder $q) =>
|
||||
fn (Builder $q) =>
|
||||
$q->where('id', 'LIKE', $search_range)
|
||||
)
|
||||
)
|
||||
)
|
||||
)->when(
|
||||
$cooking_time,
|
||||
fn(Builder $q) =>
|
||||
fn (Builder $q) =>
|
||||
$q->whereBetween('cooking_time', [
|
||||
Arr::get($cooking_time->times(), 0),
|
||||
Arr::get($cooking_time->times(), 1)
|
||||
])
|
||||
)->when(
|
||||
$preparation_time,
|
||||
fn(Builder $q) =>
|
||||
fn (Builder $q) =>
|
||||
$q->whereBetween('preparation_time', [
|
||||
Arr::get($preparation_time->times(), 0),
|
||||
Arr::get($preparation_time->times(), 1)
|
||||
])
|
||||
);
|
||||
|
||||
$recipes = $query->orderBy('priority_order', 'ASC')->paginate(9);
|
||||
$recipes = $query->orderBy('slug', 'ASC')->paginate(9);
|
||||
|
||||
return view('fo.pages.ideas.recipes', compact(
|
||||
'ranges',
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Enums\StaticPageType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\StaticPage;
|
||||
use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
||||
|
||||
class StaticPageController extends Controller
|
||||
{
|
||||
/**
|
||||
* Legal show
|
||||
*
|
||||
* @param \App\Models\StaticPage $legalPage
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function legals(StaticPage $legalPage)
|
||||
{
|
||||
$legalPage = StaticPage::query()->where('type', StaticPageType::legals)->first();
|
||||
return view('fo.pages.legals', ['staticPageModel' => $legalPage]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Policies show
|
||||
*
|
||||
* @param \App\Models\StaticPage $policiesPage
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function policies(StaticPage $policiesPage)
|
||||
{
|
||||
$policiesPage = StaticPage::query()->where('type', StaticPageType::confidentiality)->first();
|
||||
return view('fo.pages.legals', ['staticPageModel' => $policiesPage]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sitemap show
|
||||
*
|
||||
* @param \App\Models\StaticPage $sitemap
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function sitemap(StaticPage $sitemap)
|
||||
{
|
||||
$sitemap = StaticPage::query()->where('type', StaticPageType::sitemap)->first();
|
||||
$singlePages = SitemapHelper::getSinglePages();
|
||||
return view('fo.pages.sitemap', ['staticPageModel' => $sitemap, 'singlePages' => $singlePages]);
|
||||
}
|
||||
}
|
||||
18
app/Http/Controllers/Fo/StoryController.php
Normal file
18
app/Http/Controllers/Fo/StoryController.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Fo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class StoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('fo.pages.story');
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ class TipsController extends Controller
|
|||
{
|
||||
$advices = Advice::query()->with('tags')
|
||||
->where('type', AdviceTypeEnum::tips)
|
||||
->where('published', true)
|
||||
->where('status', true)
|
||||
->paginate(9);
|
||||
return view('fo.pages.ideas.tips', \compact('advices'));
|
||||
}
|
||||
|
|
@ -31,9 +31,7 @@ class TipsController extends Controller
|
|||
public function show(Advice $publishedAdvice): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$publishedAdvice->load([
|
||||
'advices',
|
||||
'products.subrange.range',
|
||||
'tags'
|
||||
'advices', 'products.subrange.range', 'tags'
|
||||
]);
|
||||
return view('fo.pages.ideas.tip', [
|
||||
'adviceModel' => $publishedAdvice
|
||||
|
|
|
|||
|
|
@ -33,16 +33,12 @@ class Kernel extends HttpKernel
|
|||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\SecureHeaders::class
|
||||
],
|
||||
'saml' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ class SecureHeaders
|
|||
View::share('nonce', $nonce = Vite::useCspNonce());
|
||||
// * For VueJS dev tool to execute
|
||||
$jsDev = config('app.debug') ? "'unsafe-eval' 'unsafe-inline'" : "'nonce-{$nonce}' 'strict-dynamic'";
|
||||
$scheme = config('app.env') === 'local' ? 'http' : 'https';
|
||||
$reportUri = Route::has('cspReportUri') ?
|
||||
\sprintf(' report-uri %s ;', \parse_url(route('cspReportUri'), \PHP_URL_PATH)) : '';
|
||||
$this->removeUnwantedHeaders($this->unwantedHeaderList);
|
||||
|
|
@ -60,7 +61,6 @@ class SecureHeaders
|
|||
]) . ';',
|
||||
"img-src 'self' data: blob: " . implode(' ', [
|
||||
'https://yl.s-web.fr',
|
||||
'https://i3.ytimg.com/',
|
||||
// * VITE DEV
|
||||
config('app.debug') ? "https://{$host}:4443" : '',
|
||||
// * MESBR
|
||||
|
|
@ -99,6 +99,7 @@ class SecureHeaders
|
|||
'https: blob:',
|
||||
'https://www.googletagmanager.com',
|
||||
'https://cdnjs.cloudflare.com',
|
||||
"$scheme://www.google-analytics.com",
|
||||
// * VITE DEV
|
||||
config('app.debug') ? "https://{$host}:4443" : '',
|
||||
]) . ';'
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Http\Requests\Bo\Advice;
|
|||
|
||||
use App\Enums\Advices\AdviceDifficultyEnum;
|
||||
use App\Enums\Advices\AdviceTypeEnum;
|
||||
use App\Rules\WysiwygLength;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -36,7 +35,7 @@ class StoreAdviceRequest extends FormRequest
|
|||
//phpcs:enable
|
||||
$this->merge([
|
||||
'slug' => Str::slug(strip_tags($this->input('title'))),
|
||||
'published' => $this->boolean('published'),
|
||||
'status' => $this->boolean('status'),
|
||||
'tags' => $this->input('tags', []),
|
||||
'products' => $this->input('products', []),
|
||||
'associated_tips_list' => $this->input('associated_tips_list', []),
|
||||
|
|
@ -80,28 +79,18 @@ class StoreAdviceRequest extends FormRequest
|
|||
'sticker_title' => 'required_with:sticker|nullable|min:3|max:255',
|
||||
'sticker_sm_alt' => 'required_with:sticker_sm|nullable|min:3|max:255',
|
||||
'sticker_sm_title' => 'required_with:sticker_sm|nullable|min:3|max:255',
|
||||
'preparation' => [
|
||||
'required',
|
||||
'string',
|
||||
new WysiwygLength(15, 2500)
|
||||
],
|
||||
'advice' => [
|
||||
'nullable',
|
||||
'string',
|
||||
new WysiwygLength(15, 2500)
|
||||
],
|
||||
'preparation' => 'required|string|min:15',
|
||||
'advice' => 'nullable|string|min:15',
|
||||
'ingredients' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (count($value) < 1 || count($value) > 15) {
|
||||
$fail(\trans('Vous devez associer 1 à 15 lignes d\'ingrédients.'));
|
||||
}
|
||||
}
|
||||
],
|
||||
'ingredients.*' => 'required|array',
|
||||
'ingredients.*.value' => 'nullable|regex:/^\d*\.?\d{0,1}$/|between:0,65535',
|
||||
'ingredients.*.value' => 'nullable|numeric|max:65535',
|
||||
'ingredients.*.label' => [
|
||||
Rule::requiredIf(function () {
|
||||
return $this->type === AdviceTypeEnum::recipes->value();
|
||||
|
|
@ -129,22 +118,16 @@ class StoreAdviceRequest extends FormRequest
|
|||
) {
|
||||
$fail(\trans('Le nombre de convives est obligatoire'));
|
||||
}
|
||||
},
|
||||
'nullable',
|
||||
'numeric',
|
||||
'min:1',
|
||||
'max:99'
|
||||
}, 'nullable', 'numeric', 'min:1', 'max:99'
|
||||
],
|
||||
'youtube_title' => 'required_with:youtube_video_id|nullable|min:3|max:255',
|
||||
'youtube_video_id' => 'required_with:youtube_title|nullable|min:3|max:50|regex:%([^"&?\/\s]{11})%i',
|
||||
'cooking_time' => 'nullable|numeric|min:0|max:65535',
|
||||
'preparation_time' => [
|
||||
'youtube_title' => 'required_with:youtube_video_id|nullable|min:3|max:255',
|
||||
'youtube_video_id' => 'required_with:youtube_title|nullable|regex:%([^"&?\/\s]{11})%i',
|
||||
'cooking_time' => 'nullable|numeric|min:0|max:65535',
|
||||
'preparation_time' => [
|
||||
Rule::requiredIf(function () {
|
||||
return $this->type === AdviceTypeEnum::recipes->value();
|
||||
}),
|
||||
'numeric',
|
||||
'min:0',
|
||||
'max:65535'
|
||||
'numeric', 'min:0', 'max:65535'
|
||||
],
|
||||
'difficulty' => [
|
||||
Rule::requiredIf(function () {
|
||||
|
|
@ -152,12 +135,10 @@ class StoreAdviceRequest extends FormRequest
|
|||
}),
|
||||
new Enum(AdviceDifficultyEnum::class)
|
||||
],
|
||||
'published' => 'required|boolean',
|
||||
'status' => 'required|boolean',
|
||||
'tags' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (count($value) > 2) {
|
||||
$fail(\trans('Vous devez associer au maximum 2 tags.'));
|
||||
}
|
||||
|
|
@ -167,10 +148,8 @@ class StoreAdviceRequest extends FormRequest
|
|||
'tags.*.id' => 'required|numeric|exists:tags,id|distinct',
|
||||
'tags.*.label' => 'required|string',
|
||||
'products' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if ($this->type == AdviceTypeEnum::recipes->value()) {
|
||||
if (count($value) < 1 || count($value) > 3) {
|
||||
$fail(\trans('Vous devez associer 1 à 3 produits.'));
|
||||
|
|
@ -186,10 +165,8 @@ class StoreAdviceRequest extends FormRequest
|
|||
'products.*.value' => 'required|exists:products,id',
|
||||
'products.*.label' => 'required|string',
|
||||
'associated_tips_list' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (count($value) > 3) {
|
||||
$fail(\trans('Vous devez associer au maximum 3 astuces.'));
|
||||
}
|
||||
|
|
@ -199,10 +176,8 @@ class StoreAdviceRequest extends FormRequest
|
|||
'associated_tips_list.*.value' => 'required|exists:advice,id',
|
||||
'associated_tips_list.*.label' => 'required|string',
|
||||
'associated_recipes_list' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (count($value) > 3) {
|
||||
$fail(\trans('Vous devez associer au maximum 3 recettes.'));
|
||||
}
|
||||
|
|
@ -214,9 +189,9 @@ class StoreAdviceRequest extends FormRequest
|
|||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 650, 690, 650, 690, false),
|
||||
$this->pictureRules('sticker', 370, 300, 370, 300, false),
|
||||
$this->pictureRules('sticker_sm', 270, 145, 270, 145, false),
|
||||
$this->pictureRules('picture', 650, 690, 650, 690, true),
|
||||
$this->pictureRules('sticker', 370, 300, 370, 300, true),
|
||||
$this->pictureRules('sticker_sm', 270, 145, 270, 145, true),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\BrigadeSections;
|
||||
|
||||
use App\Rules\WysiwygLength;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreBrigadeSectionsRequest extends FormRequest
|
||||
{
|
||||
use HasPicture;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'published' => $this->boolean('published'),
|
||||
'button_display' => $this->boolean('button_display'),
|
||||
'button_newtab' => $this->boolean('button_newtab'),
|
||||
]);
|
||||
$this->mergePicture('picture');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'title' => 'required|string|min:3|max:500',
|
||||
'content' => [
|
||||
'required',
|
||||
'string',
|
||||
new WysiwygLength(15, 1500)
|
||||
],
|
||||
'picture_alt' => 'required|string|min:3|max:255',
|
||||
'picture_title' => 'required|string|min:3|max:255',
|
||||
'button_display' => 'required|boolean',
|
||||
'button_text' => 'required_if_accepted:button_display|nullable|string|min:3|max:255',
|
||||
'button_url' => 'required_if_accepted:button_display|nullable|url:https|min:3|max:255',
|
||||
'button_newtab' => 'required|boolean',
|
||||
'published' => 'required|boolean',
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 800, 535, 800, 535, false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'title' => trans('Titre'),
|
||||
'picture' => trans('Image'),
|
||||
'picture_alt' => trans('Attribut alt de l\'image'),
|
||||
'picture_title' => trans('Titre de l\'image'),
|
||||
'content' => trans('Contenu'),
|
||||
'button_text' => trans('Texte du CTA'),
|
||||
'button_url' => trans('URL du CTA'),
|
||||
'published' => trans('Statut'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\BrigadeSections;
|
||||
|
||||
class UpdateBrigadeSectionsRequest extends StoreBrigadeSectionsRequest
|
||||
{
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\News;
|
||||
|
||||
use App\Rules\WysiwygLength;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -32,7 +31,7 @@ class StoreNewsRequest extends FormRequest
|
|||
//phpcs:enable
|
||||
$this->merge([
|
||||
'slug' => Str::slug($this->title),
|
||||
'published' => $this->published ? true : false,
|
||||
'status' => $this->status ? true : false,
|
||||
'categories' => $this->categories ?? [],
|
||||
'products' => $this->products ?? [],
|
||||
'associated_news_list' => $this->associated_news_list ?? [],
|
||||
|
|
@ -67,18 +66,8 @@ class StoreNewsRequest extends FormRequest
|
|||
'picture_title' => 'required_with:picture|nullable|min:3|max:255',
|
||||
'picture2_alt' => 'required_with:picture2|nullable|min:3|max:255',
|
||||
'picture2_title' => 'required_with:picture2|nullable|min:3|max:255',
|
||||
'content' => [
|
||||
'required_with:picture',
|
||||
'nullable',
|
||||
'string',
|
||||
new WysiwygLength(15, 2500)
|
||||
],
|
||||
'content2' => [
|
||||
'required_with:picture2',
|
||||
'nullable',
|
||||
'string',
|
||||
new WysiwygLength(15, 2500)
|
||||
],
|
||||
'content' => 'required_with:picture|nullable|string|min:15',
|
||||
'content2' => 'required_with:picture2|nullable|string|min:15',
|
||||
'event_start' => 'nullable|date_format:Y-m-d',
|
||||
'event_end' => [
|
||||
'required_with:event_start',
|
||||
|
|
@ -92,12 +81,10 @@ class StoreNewsRequest extends FormRequest
|
|||
'min:3',
|
||||
'max:255'
|
||||
],
|
||||
'published' => 'required|boolean',
|
||||
'status' => 'required|boolean',
|
||||
'categories' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (count($value) < 1 || count($value) > 2) {
|
||||
$fail(\trans('Vous devez associer une actualité à 1 ou 2 catégories.'));
|
||||
}
|
||||
|
|
@ -107,10 +94,8 @@ class StoreNewsRequest extends FormRequest
|
|||
'categories.*.value' => 'required|exists:news_categories,id',
|
||||
'categories.*.label' => 'required|string',
|
||||
'products' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (count($value) > 3) {
|
||||
$fail(\trans('Vous devez associer au maximum 3 produits.'));
|
||||
}
|
||||
|
|
@ -120,10 +105,8 @@ class StoreNewsRequest extends FormRequest
|
|||
'products.*.value' => 'required|exists:products,id',
|
||||
'products.*.label' => 'required|string',
|
||||
'associated_news_list' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (count($value) > 3) {
|
||||
$fail(\trans('Vous devez associer au maximum 3 actualités.'));
|
||||
}
|
||||
|
|
@ -135,8 +118,8 @@ class StoreNewsRequest extends FormRequest
|
|||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('picture', 590, 645, 590, 645, false),
|
||||
$this->pictureRules('picture2', 590, 645, 590, 645, true, requiredWith: 'content2')
|
||||
$this->pictureRules('picture', 920, 1025, 920, 1025, true),
|
||||
$this->pictureRules('picture2', 920, 1025, 920, 1025, false)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +147,7 @@ class StoreNewsRequest extends FormRequest
|
|||
'event_start' => trans('Date de début de l\'évènement'),
|
||||
'event_end' => trans('Date de fin de l\'évènement'),
|
||||
'event_text' => trans('Description de l\'évènement'),
|
||||
'published' => trans('Status'),
|
||||
'status' => trans('Status'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Http\Requests\Bo\Products;
|
|||
|
||||
use App\Enums\NutriscoreEnum;
|
||||
use App\Enums\Products\ProductSpeciesEnum;
|
||||
use App\Rules\WysiwygLength;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -36,19 +35,9 @@ class StoreProductRequest extends FormRequest
|
|||
'is_frenchpoultry' => $this->is_frenchpoultry ? true : false,
|
||||
'is_vip' => $this->is_vip ? true : false,
|
||||
'is_egalim' => $this->is_egalim ? true : false,
|
||||
'published' => $this->published ? true : false,
|
||||
'tags' => $this->input('tags', []),
|
||||
// * For sync relations
|
||||
'tags_list' => \collect($this->input('tags'))->map(function ($value) {
|
||||
return \is_array($value) ? ($value['value'] ?? null) : null;
|
||||
})->filter()->all(),
|
||||
'status' => $this->status ? true : false
|
||||
]);
|
||||
$this->mergePicture('sticker_sm');
|
||||
($this->slider_pictures)
|
||||
? $this->mergePictures('slider_pictures')
|
||||
: $this->merge([
|
||||
'slider_pictures' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -67,26 +56,12 @@ class StoreProductRequest extends FormRequest
|
|||
'nutriscore' => ['required', new Enum(NutriscoreEnum::class)],
|
||||
'sticker_sm_alt' => 'required|min:3|max:255',
|
||||
'sticker_sm_title' => 'required|min:3|max:255',
|
||||
'ingredients' => [
|
||||
'required',
|
||||
'string',
|
||||
new WysiwygLength(15, 2500)
|
||||
],
|
||||
'advantage' => [
|
||||
'required',
|
||||
'string',
|
||||
new WysiwygLength(15, 2500)
|
||||
],
|
||||
'preparation' => [
|
||||
'required',
|
||||
'string',
|
||||
new WysiwygLength(15, 2500)
|
||||
],
|
||||
'ingredients' => 'required|string|min:15',
|
||||
'advantage' => 'required|string|min:15',
|
||||
'preparation' => 'required|string|min:15',
|
||||
'packaging' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (1 > count($value) || count($value) > 6) {
|
||||
$fail(\trans('Vous devez remplir au moins 1 ligne et au plus 6 lignes de conditionnement.'));
|
||||
}
|
||||
|
|
@ -95,10 +70,8 @@ class StoreProductRequest extends FormRequest
|
|||
'packaging.*' => 'required|array',
|
||||
'packaging.*.value' => 'required|string|min:2|max:255',
|
||||
'caliber' => [
|
||||
'present',
|
||||
'array',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (1 > count($value) || count($value) > 6) {
|
||||
$fail(\trans('Vous devez remplir au moins 1 ligne et au plus 6 lignes de calibre.'));
|
||||
}
|
||||
|
|
@ -106,29 +79,25 @@ class StoreProductRequest extends FormRequest
|
|||
],
|
||||
'caliber.*' => 'required|array',
|
||||
'caliber.*.value' => 'required|string|min:1|max:255',
|
||||
'is_frenchpoultry' => 'required|boolean',
|
||||
'is_vip' => 'required|boolean',
|
||||
'is_egalim' => 'required|boolean',
|
||||
'published' => 'required|boolean',
|
||||
// * TAGS
|
||||
'tags' => [
|
||||
'present',
|
||||
'array',
|
||||
'nutritionnal_values' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, array $value, $fail) {
|
||||
if (count($value) > 2) {
|
||||
$fail(\trans('Vous devez associer au maximum 2 tags.'));
|
||||
'present', 'array', function ($attribute, array $value, $fail) {
|
||||
if (count($value) != 9) {
|
||||
$fail(\trans('Vous devez remplir seulement 9 lignes de valeurs nutritionnelles.'));
|
||||
}
|
||||
}
|
||||
],
|
||||
'tags.*' => 'required|array',
|
||||
'tags.*.id' => 'required|numeric|exists:tags,id|distinct',
|
||||
'tags.*.label' => 'required|string',
|
||||
|
||||
'nutritionnal_values.*' => 'nullable|array',
|
||||
'nutritionnal_values.*.label' => 'nullable|string|min:3|max:255',
|
||||
'nutritionnal_values.*.value' => 'nullable|numeric|min:0',
|
||||
'is_frenchpoultry' => 'required|boolean',
|
||||
'is_vip' => 'required|boolean',
|
||||
'is_egalim' => 'required|boolean',
|
||||
'status' => 'required|boolean'
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
$this->pictureRules('sticker_sm', 206, 159, 206, 159, false),
|
||||
$this->pictureRules('sticker_sm', 206, 159, 206, 159, true),
|
||||
$this->picturesRules('slider_pictures', 396, 286, 396, 286, 1, 5, true),
|
||||
);
|
||||
}
|
||||
|
|
@ -141,30 +110,29 @@ class StoreProductRequest extends FormRequest
|
|||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'label' => trans('title'),
|
||||
'slug' => trans('slug'),
|
||||
'seo_title' => trans('title') . ' seo',
|
||||
'seo_description' => trans('description') . ' seo',
|
||||
'subrange_id' => trans('sous-gamme'),
|
||||
'species' => trans('Espèce du produit'),
|
||||
'nutriscore' => trans('Label Nutriscore'),
|
||||
'sticker_sm' => trans('miniature'),
|
||||
'sticker_sm_alt' => trans('attribut alt de la miniature'),
|
||||
'sticker_sm_title' => trans('titre de la miniature'),
|
||||
'slider_pictures' => trans('images du slider'),
|
||||
'slider_pictures.*' => trans('image du slider'),
|
||||
'packaging' => trans('conditionnement'),
|
||||
'packaging.*.value' => trans('valeur du conditionnement'),
|
||||
'caliber' => trans('calibre'),
|
||||
'caliber.*.value' => trans('valeur du calibre'),
|
||||
'is_frenchpoultry' => trans('Label volaille française'),
|
||||
'is_vip' => trans('Produit VIP'),
|
||||
'is_egalim' => trans('Produit Égalim'),
|
||||
'published' => trans('publish'),
|
||||
'tags' => trans('tag'),
|
||||
'tags.*' => trans('tag'),
|
||||
'tags.*.id' => trans('id du tag'),
|
||||
'tags.*.label' => trans('label du tag'),
|
||||
'label' => trans('title'),
|
||||
'slug' => trans('slug'),
|
||||
'seo_title' => trans('title') . ' seo',
|
||||
'seo_description' => trans('description') . ' seo',
|
||||
'subrange_id' => trans('sous-gamme'),
|
||||
'species' => trans('Espèce du produit'),
|
||||
'nutriscore' => trans('Label Nutriscore'),
|
||||
'sticker_sm' => trans('miniature'),
|
||||
'sticker_sm_alt' => trans('attribut alt de la miniature'),
|
||||
'sticker_sm_title' => trans('titre de la miniature'),
|
||||
'slider_pictures' => trans('images du slider'),
|
||||
'slider_pictures.*' => trans('image du slider'),
|
||||
'packaging' => trans('conditionnement'),
|
||||
'packaging.*.value' => trans('valeur du conditionnement'),
|
||||
'caliber' => trans('calibre'),
|
||||
'caliber.*.value' => trans('valeur du calibre'),
|
||||
'nutritionnal_values' => trans('valeurs nutritionnelles'),
|
||||
'nutritionnal_values.*.label' => trans('libellé de la valeur nutritionnelle'),
|
||||
'nutritionnal_values.*.value' => trans('valeur de la valeur nutritionnelle'),
|
||||
'is_frenchpoultry' => trans('Label volaille française'),
|
||||
'is_vip' => trans('Produit VIP'),
|
||||
'is_egalim' => trans('Produit Égalim'),
|
||||
'status' => trans('publish')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Slides;
|
||||
|
||||
use App\Rules\WysiwygLength;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
|
|
@ -28,9 +27,8 @@ class StoreSlideRequest extends FormRequest
|
|||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'button_display' => $this->boolean('button_display'),
|
||||
'button_targetblank' => $this->boolean('button_targetblank'),
|
||||
'published' => $this->boolean('published'),
|
||||
'button_display' => $this->button_display ? true : false,
|
||||
'button_targetblank' => $this->button_targetblank ? true : false,
|
||||
]);
|
||||
$this->mergePicture('picture');
|
||||
$this->mergePicture('picture_thumbnail');
|
||||
|
|
@ -45,11 +43,7 @@ class StoreSlideRequest extends FormRequest
|
|||
{
|
||||
$rules = [
|
||||
'title' => 'required|min:3|max:255',
|
||||
'content' => [
|
||||
'required',
|
||||
'string',
|
||||
new WysiwygLength(15, 2500)
|
||||
],
|
||||
'content' => 'required|string|min:15|max:540',
|
||||
'button_display' => 'required|boolean',
|
||||
'button_text' => 'nullable|min:3|max:45',
|
||||
'button_url' => 'nullable|min:3|max:255|url',
|
||||
|
|
@ -57,8 +51,7 @@ class StoreSlideRequest extends FormRequest
|
|||
'picture_alt' => 'required|min:3|max:255',
|
||||
'picture_title' => 'required|min:3|max:255',
|
||||
'picture_thumbnail_alt' => 'required|min:3|max:255',
|
||||
'picture_thumbnail_title' => 'required|min:3|max:255',
|
||||
'published' => 'required|boolean',
|
||||
'picture_thumbnail_title' => 'required|min:3|max:255'
|
||||
];
|
||||
return \array_merge(
|
||||
$rules,
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Tags;
|
||||
|
||||
use App\Enums\TagTypeEnum;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreTagRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -40,10 +38,6 @@ class StoreTagRequest extends FormRequest
|
|||
{
|
||||
return [
|
||||
'label' => 'required|min:2|max:30',
|
||||
'type' => [
|
||||
'required',
|
||||
Rule::enum(TagTypeEnum::class),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +51,6 @@ class StoreTagRequest extends FormRequest
|
|||
return [
|
||||
'label' => trans('libellé'),
|
||||
'slug' => trans('slug'),
|
||||
'type' => trans('type'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use App\Interfaces\OrderableInterface;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateOrderRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Attribute model needed.
|
||||
*
|
||||
* @var Model $orderable
|
||||
*/
|
||||
private Model $orderable;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->orderable = collect($this->route()->parameters())
|
||||
->first(fn($param) => $param instanceof Model);
|
||||
|
||||
$groupField = $this->orderable->getOrderGroupField();
|
||||
|
||||
if ($groupField) {
|
||||
$this->orderable::query()->where($groupField, $this->orderable->{$groupField});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'priority_order' => [
|
||||
'required',
|
||||
'integer',
|
||||
'min:1',
|
||||
sprintf('max:%s', $this->orderable->max('priority_order')),
|
||||
function ($value, $fail) {
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
if ($this->orderable instanceof OrderableInterface && intval($value) === $this->orderable->getPriorityOrder()) {
|
||||
$fail(trans('validation.custom.same_priority'));
|
||||
}
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -20,18 +20,6 @@ class ContactRequest extends FormRequest
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'opt_in' => $this->boolean('opt_in'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
|
|
@ -48,12 +36,11 @@ class ContactRequest extends FormRequest
|
|||
'phone' => 'required|max:255|phone:' . implode(',', $this->isoCodes()),
|
||||
'activity' => ['required', new Enum(ContactActivityEnum::class)],
|
||||
'society' => 'nullable|string|max:255',
|
||||
'postcode' => 'required|postal_code:' . implode(',', $this->isoCodes()),
|
||||
'postcode' => 'nullable|postal_code:' . implode(',', $this->isoCodes()),
|
||||
'city' => 'nullable|string|max:255',
|
||||
'message' => 'required|string|min:20|max:255',
|
||||
'callTime' => ['required', new Enum(ContactTimeEnum::class)],
|
||||
'brigade' => 'nullable|boolean',
|
||||
'opt_in' => 'required|boolean',
|
||||
'rgpd' => 'accepted'
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -94,8 +81,7 @@ class ContactRequest extends FormRequest
|
|||
'city' => trans('ville'),
|
||||
'message' => trans('message'),
|
||||
'callTime' => trans('préférence de rappel'),
|
||||
'brigade' => trans('La Brigade'),
|
||||
'opt_in' => trans('newsletter'),
|
||||
'rgpd' => trans('condition d\'utilisation'),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Fo\Newsletter;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class SingleOptinRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'email' => 'required|email:rfc,dns,spoof',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Fo\Newsletter;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UnsubscribeNewsletterRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'hashcode' => 'required|uuid'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ class AjaxAddProductBasket extends FormRequest
|
|||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'packaging' => 'array',
|
||||
'packaging' => 'required|array|min:1',
|
||||
'packaging.*' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
|
|
@ -37,7 +37,7 @@ class AjaxAddProductBasket extends FormRequest
|
|||
}
|
||||
}
|
||||
],
|
||||
'caliber' => 'array',
|
||||
'caliber' => 'required|array|min:1',
|
||||
'caliber.*' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class ProductCommercialSheetResource extends JsonResource
|
|||
'ingredients' => '',
|
||||
'preparation' => '',
|
||||
'sticker_sm' => '',
|
||||
'nutritionnal_values' => [],
|
||||
'slider_pictures' => [],
|
||||
'subrange' => null,
|
||||
];
|
||||
|
|
@ -64,6 +65,7 @@ class ProductCommercialSheetResource extends JsonResource
|
|||
'caliber' => $this->product->caliber,
|
||||
'ingredients' => $this->product->ingredients,
|
||||
'preparation' => $this->product->preparation,
|
||||
'nutritionnal_values' => $this->product->nutritionnal_values,
|
||||
'sticker_sm' => $this->product->sticker_sm,
|
||||
'slider_pictures' => $this->product->slider_pictures,
|
||||
'subrange' => (new SubrangeResource($this->product->subrange))->toArray($request),
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Interfaces;
|
||||
|
||||
interface OrderableInterface
|
||||
{
|
||||
/**
|
||||
* Returns the priority order value.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getPriorityOrder(): int;
|
||||
|
||||
/**
|
||||
* Returns the grouping field used for ordering.
|
||||
* Returns null if the order is global.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getOrderGroupField(): ?string;
|
||||
}
|
||||
37
app/Lib/CompleteSitemapWith.php
Normal file
37
app/Lib/CompleteSitemapWith.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib;
|
||||
|
||||
use App\Enums\Advices\AdviceTypeEnum;
|
||||
use App\Models\Advice;
|
||||
use App\Models\Product;
|
||||
use LDC\SitemapGenerator\Lib\Sitemap;
|
||||
|
||||
class CompleteSitemapWith
|
||||
{
|
||||
/**
|
||||
* Use this method to append a list of links to the sitemap
|
||||
*
|
||||
* * Please call $sitemap->mergeUrls to append url for any specific route name.
|
||||
*
|
||||
* @param \LDC\SitemapGenerator\Lib\Sitemap $sitemap
|
||||
* @return void
|
||||
*/
|
||||
public static function append(Sitemap $sitemap): void
|
||||
{
|
||||
// * Ajouts des éléments qui sont affichés en random
|
||||
$sitemap->mergeUrls(Product::query()->where('status', true)->pluck('slug')->transform(function (string $slug) {
|
||||
return \route('fo.product.show', $slug);
|
||||
}));
|
||||
$sitemap->mergeUrls(Advice::query()
|
||||
->where('status', true)->where('type', AdviceTypeEnum::recipes)
|
||||
->pluck('slug')->transform(function (string $slug) {
|
||||
return \route('fo.recipes.show', $slug);
|
||||
}));
|
||||
$sitemap->mergeUrls(Advice::query()
|
||||
->where('status', true)->where('type', AdviceTypeEnum::tips)
|
||||
->pluck('slug')->transform(function (string $slug) {
|
||||
return \route('fo.tips.show', $slug);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -63,20 +63,6 @@ class FileStorageHelper
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy files associate with the attribute.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param array $array
|
||||
* @return void
|
||||
*/
|
||||
public static function removeFiles(Model $model, array $array): void
|
||||
{
|
||||
foreach ($array as $item) {
|
||||
self::removeFile($model, $item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the file associate with the attribute old value (before updated to DB).
|
||||
*
|
||||
|
|
@ -119,7 +105,7 @@ class FileStorageHelper
|
|||
Model $model,
|
||||
$file,
|
||||
bool $slugify = false,
|
||||
string|null $filename = null,
|
||||
string $filename = null,
|
||||
bool $private = false
|
||||
): string {
|
||||
// phpcs:enable
|
||||
|
|
@ -180,7 +166,7 @@ class FileStorageHelper
|
|||
public static function storeModelFilesFromHtml(
|
||||
Model $model,
|
||||
string $htmlString,
|
||||
string|null $oldHtmlString = null
|
||||
string $oldHtmlString = null
|
||||
): string {
|
||||
\collect(self::onlyUploadedFilesWithFileManager(self::findFilesInHtml($htmlString)))
|
||||
->each(function (string $path) use ($model, &$htmlString) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class ContactFormMail extends Mailable
|
|||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->from(config('mail.from.address'))
|
||||
return $this->from(config('mail.contactsList.contactform'))
|
||||
->subject(sprintf("%s : %s", config('app.name'), trans("Nouveau contact")))
|
||||
->markdown('fo.emails.contact-form', $this->request->toArray());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,25 +2,18 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Interfaces\OrderableInterface;
|
||||
use App\Enums\Advices\AdviceDifficultyEnum;
|
||||
use App\Enums\Advices\AdviceTypeEnum;
|
||||
use App\Enums\Advices\AdviceDifficultyEnum;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\Orderable;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Spatie\Sitemap\Contracts\Sitemapable;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
use Uwil\Laravel\Redirections\Interfaces\RedirectableInterface;
|
||||
use Uwil\Laravel\Redirections\Traits\IsRedirectable;
|
||||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
|
||||
/**
|
||||
* @property integer $id Id.
|
||||
|
|
@ -47,8 +40,7 @@ use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
|||
* @property integer|null $cooking_time Time of cooking.
|
||||
* @property integer|null $preparation_time Time of preparation.
|
||||
* @property \App\Enums\Advices\AdviceDifficultyEnum|null $difficulty Difficulty.
|
||||
* @property boolean $published Status.
|
||||
* @property integer $priority_order Priority Order.
|
||||
* @property boolean $status Status.
|
||||
* @property-read \Illuminate\Support\Carbon $created_at Created date.
|
||||
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
|
||||
*
|
||||
|
|
@ -63,12 +55,10 @@ use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
|||
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Tag> $tags
|
||||
* Tags Morph-To-Many relationship.
|
||||
*/
|
||||
class Advice extends Authenticatable implements SeoInterface, Sitemapable, RedirectableInterface, OrderableInterface
|
||||
class Advice extends Authenticatable implements SeoInterface
|
||||
{
|
||||
use HasFactory;
|
||||
use SeoTrait;
|
||||
use IsRedirectable;
|
||||
use Orderable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
|
@ -99,8 +89,7 @@ class Advice extends Authenticatable implements SeoInterface, Sitemapable, Redir
|
|||
'cooking_time',
|
||||
'preparation_time',
|
||||
'difficulty',
|
||||
'published',
|
||||
'priority_order'
|
||||
'status'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -110,7 +99,7 @@ class Advice extends Authenticatable implements SeoInterface, Sitemapable, Redir
|
|||
*/
|
||||
protected $casts = [
|
||||
'ingredients' => 'array',
|
||||
'published' => 'bool',
|
||||
'status' => 'bool',
|
||||
'type' => AdviceTypeEnum::class,
|
||||
'difficulty' => AdviceDifficultyEnum::class,
|
||||
];
|
||||
|
|
@ -124,7 +113,6 @@ class Advice extends Authenticatable implements SeoInterface, Sitemapable, Redir
|
|||
{
|
||||
static::creating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
self::bootOrderable();
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
|
|
@ -139,7 +127,6 @@ class Advice extends Authenticatable implements SeoInterface, Sitemapable, Redir
|
|||
FileStorageHelper::removeFile($model, 'picture');
|
||||
FileStorageHelper::removeFile($model, 'sticker');
|
||||
FileStorageHelper::removeFile($model, 'sticker_sm');
|
||||
self::setOrder($model);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +268,7 @@ class Advice extends Authenticatable implements SeoInterface, Sitemapable, Redir
|
|||
protected function recipes(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn() => $this->recipesQuery(),
|
||||
get: fn () => $this->recipesQuery(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -303,24 +290,10 @@ class Advice extends Authenticatable implements SeoInterface, Sitemapable, Redir
|
|||
protected function tips(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn() => $this->tipsQuery(),
|
||||
get: fn () => $this->tipsQuery(),
|
||||
);
|
||||
}
|
||||
|
||||
// * REDIRECTIONS.
|
||||
|
||||
/**
|
||||
* Get the front url of this model.
|
||||
* Should return the model.show route, with all binded elements if needed.
|
||||
*
|
||||
* @param string $modelKey
|
||||
* @return string
|
||||
*/
|
||||
public function getFrontUrl(string $modelKey): string
|
||||
{
|
||||
return route('fo.tips.show', $modelKey);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -364,33 +337,9 @@ class Advice extends Authenticatable implements SeoInterface, Sitemapable, Redir
|
|||
\trans($this->getTable()),
|
||||
$this->seo_title,
|
||||
$this->seo_description,
|
||||
$this->published ?? false,
|
||||
$this->status ?? false,
|
||||
\route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this),
|
||||
$this->type === AdviceTypeEnum::recipes ? route('fo.recipes.show', $this) : route('fo.tips.show', $this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* toSitemapTag method
|
||||
*
|
||||
* @return Url|string|array
|
||||
*/
|
||||
public function toSitemapTag(): Url | string | array
|
||||
{
|
||||
$model = $this;
|
||||
$route = $this->type === AdviceTypeEnum::tips ? 'fo.tips.show' : 'fo.recipes.show';
|
||||
$params = ['publishedAdvice' => $model];
|
||||
return SitemapHelper::generateUrl($route, $params, $model);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Group ordering by type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOrderGroupField(): string
|
||||
{
|
||||
return 'type';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Uwil\Laravel\Common\Helpers\ToolboxHelper;
|
||||
|
||||
class BrigadeSection extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'content',
|
||||
'picture',
|
||||
'picture_alt',
|
||||
'picture_title',
|
||||
'button_display',
|
||||
'button_text',
|
||||
'button_url',
|
||||
'button_newtab',
|
||||
'published',
|
||||
'order'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array<string,string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'button_display' => 'bool',
|
||||
'button_newtab' => 'bool',
|
||||
'published' => 'bool',
|
||||
];
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::setOrder($model);
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::deleting(function (self $model) {
|
||||
self::assertLimitPublishedSections($model, true);
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Common methods function.
|
||||
*
|
||||
* @param self $model
|
||||
* @return void
|
||||
*/
|
||||
private static function manageFields(self $model): void
|
||||
{
|
||||
self::assertLimitPublishedSections($model);
|
||||
|
||||
ToolboxHelper::assertNoInternalBoUrls('content', $model->content);
|
||||
ToolboxHelper::assertNoInternalBoUrls('button_url', $model->content);
|
||||
|
||||
$model->content = clean($model->content);
|
||||
$model->picture = FileStorageHelper::storeFile($model, $model->picture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param self $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(self $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the limit of published element is reached.
|
||||
*
|
||||
* @param self $model
|
||||
* @param boolean $isDeletion
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException Returns if fails.
|
||||
*/
|
||||
private static function assertLimitPublishedSections(self $model, bool $isDeletion = false)
|
||||
{
|
||||
$count = self::query()->where('published', true)->count();
|
||||
if (
|
||||
(!$model->published && $count <= 1) ||
|
||||
($model->published && $count >= 5) ||
|
||||
($isDeletion && $count === 1)
|
||||
) {
|
||||
throw ValidationException::withMessages([
|
||||
'Il doit y avoir entre 1 et 5 sections publiées simultanément.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ class ExpertiseProduct extends Model
|
|||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'page',
|
||||
|
|
|
|||
|
|
@ -2,22 +2,16 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
use Spatie\CalendarLinks\Link;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use Spatie\Sitemap\Contracts\Sitemapable;
|
||||
use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
||||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Uwil\Laravel\Redirections\Traits\IsRedirectable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Uwil\Laravel\Redirections\Interfaces\RedirectableInterface;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Spatie\CalendarLinks\Link;
|
||||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
|
@ -39,7 +33,7 @@ use Uwil\Laravel\Redirections\Interfaces\RedirectableInterface;
|
|||
* @property \Illuminate\Support\Carbon|null $event_start Start of the event.
|
||||
* @property \Illuminate\Support\Carbon|null $event_end End of the event.
|
||||
* @property string|null $event_text Text of the event.
|
||||
* @property boolean $published Status.
|
||||
* @property boolean $status Status.
|
||||
* @property-read string $reading_time Time reading of a news' page
|
||||
* @property-read \Illuminate\Support\Carbon $created_at Created date.
|
||||
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
|
||||
|
|
@ -53,11 +47,10 @@ use Uwil\Laravel\Redirections\Interfaces\RedirectableInterface;
|
|||
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Tags> $categories
|
||||
* Categories Morph-To-Many relationship.
|
||||
*/
|
||||
class News extends Authenticatable implements SeoInterface, Sitemapable, RedirectableInterface
|
||||
class News extends Authenticatable implements SeoInterface
|
||||
{
|
||||
use HasFactory;
|
||||
use SeoTrait;
|
||||
use IsRedirectable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
|
@ -81,7 +74,7 @@ class News extends Authenticatable implements SeoInterface, Sitemapable, Redirec
|
|||
'event_start',
|
||||
'event_end',
|
||||
'event_text',
|
||||
'published',
|
||||
'status',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -92,7 +85,7 @@ class News extends Authenticatable implements SeoInterface, Sitemapable, Redirec
|
|||
protected $casts = [
|
||||
'event_start' => 'datetime',
|
||||
'event_end' => 'datetime',
|
||||
'published' => 'bool',
|
||||
'status' => 'bool',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -131,7 +124,7 @@ class News extends Authenticatable implements SeoInterface, Sitemapable, Redirec
|
|||
public function calLink(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn() => (
|
||||
get: fn () => (
|
||||
$this->exists() and
|
||||
($this->event_start && $this->event_end && $this->event_text)
|
||||
) ? Link::create(
|
||||
|
|
@ -249,20 +242,6 @@ class News extends Authenticatable implements SeoInterface, Sitemapable, Redirec
|
|||
return ($time < 1) ? round(($allWords / 140) * 60, 0) . " seconde(s)" : $time . " minute(s)";
|
||||
}
|
||||
|
||||
// * REDIRECTIONS.
|
||||
|
||||
/**
|
||||
* Get the front url of this model.
|
||||
* Should return the model.show route, with all binded elements if needed.
|
||||
*
|
||||
* @param string $modelKey
|
||||
* @return string
|
||||
*/
|
||||
public function getFrontUrl(string $modelKey): string
|
||||
{
|
||||
return route('fo.news.show', $modelKey);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -296,34 +275,4 @@ class News extends Authenticatable implements SeoInterface, Sitemapable, Redirec
|
|||
{
|
||||
return $this->belongsToMany(NewsCategory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* toSitemapTag method
|
||||
*
|
||||
* @return Url|string|array
|
||||
*/
|
||||
public function toSitemapTag(): Url | string | array
|
||||
{
|
||||
$model = $this;
|
||||
$route = 'fo.news.show';
|
||||
$params = ['actu' => $model];
|
||||
return SitemapHelper::generateUrl($route, $params, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform to seoModel
|
||||
*
|
||||
* @return \Uwil\Seo\Laravel\Objects\SeoItem
|
||||
*/
|
||||
public function toSeoItem(): SeoItem
|
||||
{
|
||||
return new SeoItem(
|
||||
\trans($this->getTable()),
|
||||
$this->seo_title,
|
||||
$this->seo_description,
|
||||
$this->published ?? false,
|
||||
\route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this),
|
||||
route('fo.news.show', $this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,24 +2,16 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Interfaces\OrderableInterface;
|
||||
use App\Enums\Advices\AdviceTypeEnum;
|
||||
use App\Enums\NutriscoreEnum;
|
||||
use App\Enums\Products\ProductSpeciesEnum;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\Orderable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Sitemap\Contracts\Sitemapable;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
use Uwil\Laravel\Redirections\Interfaces\RedirectableInterface;
|
||||
use Uwil\Laravel\Redirections\Traits\IsRedirectable;
|
||||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
||||
|
||||
/**
|
||||
* @property integer $id Id.
|
||||
|
|
@ -36,15 +28,15 @@ use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
|||
* @property array<string> $slider_pictures Array of paths of pictures.
|
||||
* @property array<array<string,string>> $packaging Packaging.
|
||||
* @property array<array<string,string>> $caliber Caliber.
|
||||
* @property array<array<string,string>> $nutritionnal_values Nutritionnal values.
|
||||
* @property string $ingredients Ingredients.
|
||||
* @property string $advantage Advantage.
|
||||
* @property string $preparation Preparation.
|
||||
* @property boolean $is_frenchpoultry Is frenchpoultry or not.
|
||||
* @property boolean $is_vip Is vip or not.
|
||||
* @property boolean $is_egalim Is egalim or not.
|
||||
* @property boolean $published Status.
|
||||
* @property boolean $status Status.
|
||||
* @property integer $order Order.
|
||||
* @property integer $priority_order Priority Order.
|
||||
* @property-read \Illuminate\Support\Carbon $created_at Created date.
|
||||
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
|
||||
*
|
||||
|
|
@ -54,17 +46,15 @@ use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
|||
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\News> $news
|
||||
* News Belongs-To-Many relation.
|
||||
*/
|
||||
class Product extends Model implements SeoInterface, Sitemapable, RedirectableInterface, OrderableInterface
|
||||
class Product extends Model implements SeoInterface
|
||||
{
|
||||
use HasFactory;
|
||||
use SeoTrait;
|
||||
use IsRedirectable;
|
||||
use Orderable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'label',
|
||||
|
|
@ -83,11 +73,11 @@ class Product extends Model implements SeoInterface, Sitemapable, RedirectableIn
|
|||
'slider_pictures',
|
||||
'packaging',
|
||||
'caliber',
|
||||
'nutritionnal_values',
|
||||
'is_frenchpoultry',
|
||||
'is_vip',
|
||||
'is_egalim',
|
||||
'published',
|
||||
'priority_order',
|
||||
'status'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -96,15 +86,16 @@ class Product extends Model implements SeoInterface, Sitemapable, RedirectableIn
|
|||
* @var array<string,string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'slider_pictures' => 'array',
|
||||
'packaging' => 'array',
|
||||
'caliber' => 'array',
|
||||
'is_frenchpoultry' => 'bool',
|
||||
'is_vip' => 'bool',
|
||||
'is_egalim' => 'bool',
|
||||
'published' => 'bool',
|
||||
'species' => ProductSpeciesEnum::class,
|
||||
'nutriscore' => NutriscoreEnum::class
|
||||
'slider_pictures' => 'array',
|
||||
'packaging' => 'array',
|
||||
'caliber' => 'array',
|
||||
'nutritionnal_values' => 'array',
|
||||
'is_frenchpoultry' => 'bool',
|
||||
'is_vip' => 'bool',
|
||||
'is_egalim' => 'bool',
|
||||
'status' => 'bool',
|
||||
'species' => ProductSpeciesEnum::class,
|
||||
'nutriscore' => NutriscoreEnum::class
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -117,25 +108,16 @@ class Product extends Model implements SeoInterface, Sitemapable, RedirectableIn
|
|||
// * EVENT CLOSURES.
|
||||
static::creating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
self::bootOrderable();
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
self::manageFields($model);
|
||||
});
|
||||
static::updated(function (self $model) {
|
||||
FileStorageHelper::removeOldFile($model, 'sticker_sm');
|
||||
FileStorageHelper::removeOldFiles(
|
||||
!is_array($model->getOriginal('slider_pictures')) ? [] : $model->getOriginal('slider_pictures'),
|
||||
$model->slider_pictures
|
||||
);
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'sticker_sm');
|
||||
FileStorageHelper::removeFiles(
|
||||
$model,
|
||||
!is_array($model->getOriginal('slider_pictures')) ? [] : $model->getOriginal('slider_pictures'),
|
||||
);
|
||||
self::setOrder($model);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -160,16 +142,22 @@ class Product extends Model implements SeoInterface, Sitemapable, RedirectableIn
|
|||
foreach ($model->caliber as $calib) {
|
||||
ToolboxHelper::assertNoInternalBoUrls('caliber', $calib['value']);
|
||||
}
|
||||
foreach ($model->nutritionnal_values as $nutritionnal_value) {
|
||||
if (!empty($nutritionnal_value['value'])) {
|
||||
ToolboxHelper::assertNoInternalBoUrls('nutritionnal_values', $nutritionnal_value['value']);
|
||||
}
|
||||
}
|
||||
|
||||
// * TRANSFORMATIONS
|
||||
$model->slug = Str::slug($model->label);
|
||||
$model->sticker_sm = FileStorageHelper::storeFile($model, $model->sticker_sm, true);
|
||||
$model->ingredients = clean($model->ingredients);
|
||||
$model->advantage = clean($model->advantage);
|
||||
$model->preparation = clean($model->preparation);
|
||||
$model->slider_pictures = clean($model->slider_pictures);
|
||||
$model->packaging = clean($model->packaging);
|
||||
$model->caliber = clean($model->caliber);
|
||||
$model->slug = Str::slug($model->label);
|
||||
$model->sticker_sm = FileStorageHelper::storeFile($model, $model->sticker_sm, true);
|
||||
$model->ingredients = clean($model->ingredients);
|
||||
$model->advantage = clean($model->advantage);
|
||||
$model->preparation = clean($model->preparation);
|
||||
$model->slider_pictures = clean($model->slider_pictures);
|
||||
$model->packaging = clean($model->packaging);
|
||||
$model->caliber = clean($model->caliber);
|
||||
$model->nutritionnal_values = clean($model->nutritionnal_values);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -228,20 +216,6 @@ class Product extends Model implements SeoInterface, Sitemapable, RedirectableIn
|
|||
return $this->recipesQuery()->get();
|
||||
}
|
||||
|
||||
// * REDIRECTIONS.
|
||||
|
||||
/**
|
||||
* Get the front url of this model.
|
||||
* Should return the model.show route, with all binded elements if needed.
|
||||
*
|
||||
* @param string $modelKey
|
||||
* @return string
|
||||
*/
|
||||
public function getFrontUrl(string $modelKey): string
|
||||
{
|
||||
return route('fo.product.show', $modelKey);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -273,44 +247,4 @@ class Product extends Model implements SeoInterface, Sitemapable, RedirectableIn
|
|||
{
|
||||
return $this->belongsToMany(News::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags Morph-To-Many relationship.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||
*/
|
||||
public function tags(): \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||
{
|
||||
return $this->morphToMany(Tag::class, 'taggable');
|
||||
}
|
||||
|
||||
/**
|
||||
* toSitemapTag method
|
||||
*
|
||||
* @return Url|string|array
|
||||
*/
|
||||
public function toSitemapTag(): Url | string | array
|
||||
{
|
||||
$model = $this;
|
||||
$route = 'fo.product.show';
|
||||
$params = ['publishedProduct' => $model];
|
||||
return SitemapHelper::generateUrl($route, $params, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform to seoModel
|
||||
*
|
||||
* @return \Uwil\Seo\Laravel\Objects\SeoItem
|
||||
*/
|
||||
public function toSeoItem(): SeoItem
|
||||
{
|
||||
return new SeoItem(
|
||||
\trans($this->getTable()),
|
||||
$this->seo_title,
|
||||
$this->seo_description,
|
||||
$this->published ?? false,
|
||||
\route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this),
|
||||
route('fo.product.show', $this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,6 @@ use Illuminate\Support\Str;
|
|||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
use Spatie\Sitemap\Contracts\Sitemapable;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
use Uwil\Laravel\Redirections\Interfaces\RedirectableInterface;
|
||||
use Uwil\Laravel\Redirections\Traits\IsRedirectable;
|
||||
use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
||||
|
||||
/**
|
||||
* @property integer $id Id.
|
||||
|
|
@ -37,16 +32,15 @@ use Uwil\SitemapGenerator\Lib\SitemapHelper;
|
|||
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Subrange> $subranges
|
||||
* Subranges Has-Many relationship.
|
||||
*/
|
||||
class Range extends Model implements SeoInterface, Sitemapable, RedirectableInterface
|
||||
class Range extends Model implements SeoInterface
|
||||
{
|
||||
use HasFactory;
|
||||
use SeoTrait;
|
||||
use IsRedirectable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'label',
|
||||
|
|
@ -114,30 +108,6 @@ class Range extends Model implements SeoInterface, Sitemapable, RedirectableInte
|
|||
ToolboxHelper::assertFieldIsUnique($table, 'slug', Str::slug($label), $id);
|
||||
}
|
||||
|
||||
// * REDIRECTIONS.
|
||||
|
||||
/**
|
||||
* All models that belongs to it.
|
||||
*
|
||||
* @return array<string>
|
||||
*/
|
||||
protected function getRouteChildrenModels(): array
|
||||
{
|
||||
return ['App\Models\Subrange'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the front url of this model.
|
||||
* Should return the model.show route, with all binded elements if needed.
|
||||
*
|
||||
* @param string $modelKey
|
||||
* @return string
|
||||
*/
|
||||
public function getFrontUrl(string $modelKey): string
|
||||
{
|
||||
return route('fo.products.range-products', $modelKey);
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -168,17 +138,4 @@ class Range extends Model implements SeoInterface, Sitemapable, RedirectableInte
|
|||
\route('fo.products.range-products', $this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* toSitemapTag method
|
||||
*
|
||||
* @return Url|string|array
|
||||
*/
|
||||
public function toSitemapTag(): Url | string | array
|
||||
{
|
||||
$model = $this;
|
||||
$route = 'fo.products.range-products';
|
||||
$params = ['range' => $model];
|
||||
return SitemapHelper::generateUrl($route, $params, $model);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ use Illuminate\Validation\ValidationException;
|
|||
* @property string $picture_thumbnail_alt Thumbnail picture's attribute alt.
|
||||
* @property string $picture_thumbnail_title Thumbnail picture's attribute title.
|
||||
* @property integer $order Order.
|
||||
* @property boolean $published Is the slide published ?
|
||||
* @property-read \Illuminate\Support\Carbon $created_at Created date.
|
||||
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
|
||||
*/
|
||||
|
|
@ -34,7 +33,7 @@ class Slide extends Model
|
|||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
|
|
@ -49,8 +48,7 @@ class Slide extends Model
|
|||
'picture_thumbnail',
|
||||
'picture_thumbnail_alt',
|
||||
'picture_thumbnail_title',
|
||||
'order',
|
||||
'published'
|
||||
'order'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -59,9 +57,8 @@ class Slide extends Model
|
|||
* @var array<string,string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'button_display' => 'bool',
|
||||
'button_targetblank' => 'bool',
|
||||
'published' => 'bool'
|
||||
'button_display' => 'bool',
|
||||
'button_targetblank' => 'bool'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -72,6 +69,9 @@ class Slide extends Model
|
|||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
if (count(self::get()) >= 4) {
|
||||
self::assertNumberOfSlides();
|
||||
}
|
||||
self::manageFields($model);
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
});
|
||||
|
|
@ -82,8 +82,10 @@ class Slide extends Model
|
|||
FileStorageHelper::removeOldFile($model, 'picture');
|
||||
FileStorageHelper::removeOldFile($model, 'picture_thumbnail');
|
||||
});
|
||||
static::deleting(function (self $model) {
|
||||
self::assertNumberOfSlides($model, true);
|
||||
static::deleting(function () {
|
||||
if (1 >= count(self::get())) {
|
||||
self::assertNumberOfSlides();
|
||||
}
|
||||
});
|
||||
static::deleted(function (self $model) {
|
||||
FileStorageHelper::removeFile($model, 'picture');
|
||||
|
|
@ -102,7 +104,6 @@ class Slide extends Model
|
|||
private static function manageFields(self $model): void
|
||||
{
|
||||
self::assertTitleIsUnique($model->title, $model->id);
|
||||
self::assertNumberOfSlides($model);
|
||||
ToolboxHelper::assertNoInternalBoUrls($model->content, 'content');
|
||||
$model->content = clean($model->content);
|
||||
if ($model->button_url) {
|
||||
|
|
@ -116,31 +117,14 @@ class Slide extends Model
|
|||
/**
|
||||
* Asserts the number of slides in the slider.
|
||||
*
|
||||
* @param self $model
|
||||
* @param boolean $isDeleting
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException If there is less 1 or more than 4 slides.
|
||||
*/
|
||||
private static function assertNumberOfSlides(self $model, bool $isDeleting = false): void
|
||||
private static function assertNumberOfSlides(): void
|
||||
{
|
||||
if (
|
||||
$isDeleting &&
|
||||
$model->published &&
|
||||
self::query()->where('published', true)->count() <= 1
|
||||
) {
|
||||
throw ValidationException::withMessages(
|
||||
[trans('Minimum 1 slide doit être publiée, la slide n\'a pas été supprimée.')]
|
||||
);
|
||||
}
|
||||
if ($model->published !== $model->getOriginal('published')) {
|
||||
if (self::query()->where('published', true)->count() + 1 > 4 && $model->published) {
|
||||
$model->published = false;
|
||||
\session()->flash('info', \trans('Maximum 4 slides peuvent être publiées, la slide a été dépubliée.'));
|
||||
} elseif (self::query()->where('published', true)->count() <= 1 && !$model->published) {
|
||||
$model->published = true;
|
||||
\session()->flash('info', \trans('Minimum 1 slide doit être publiée, la slide a été publiée.'));
|
||||
}
|
||||
}
|
||||
throw ValidationException::withMessages([
|
||||
'Opération impossible, minimum un et maximum quatre slides doivent être présentes.'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class Subrange extends Model
|
|||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'label',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\TagTypeEnum;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -12,7 +11,6 @@ use Illuminate\Support\Str;
|
|||
* @property integer $id Id.
|
||||
* @property string $slug Slug.
|
||||
* @property string $label Label.
|
||||
* @property \App\Enums\TagTypeEnum $type Type (ENUM).
|
||||
* @property-read \Illuminate\Support\Carbon $created_at Created date.
|
||||
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
|
||||
*
|
||||
|
|
@ -26,20 +24,10 @@ class Tag extends Model
|
|||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'label',
|
||||
'type',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array<string,string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'type' => TagTypeEnum::class,
|
||||
'label'
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -90,14 +78,4 @@ class Tag extends Model
|
|||
{
|
||||
return $this->morphedByMany(Advice::class, 'taggable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Product Morphed-By-Many relation.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||
*/
|
||||
public function products(): \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||
{
|
||||
return $this->morphedByMany(Product::class, 'taggable');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,16 @@ use App\Lib\Helpers\ToolboxHelper;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @property integer $id Id.
|
||||
* @property string $firstname Firstname.
|
||||
* @property string $lastname Lastname.
|
||||
* @property string $email Email.
|
||||
* @property \Illuminate\Support\Carbon|null $email_verified_at Email_verified_at.
|
||||
* @property string $password Password.
|
||||
* @property string $remember_token Remember_token.
|
||||
* @property \Carbon\Carbon $last_connection Last_connection.
|
||||
* @property-read \Illuminate\Support\Carbon $created_at Created date.
|
||||
|
|
@ -30,7 +34,8 @@ class User extends Authenticatable
|
|||
protected $fillable = [
|
||||
'firstname',
|
||||
'lastname',
|
||||
'email'
|
||||
'email',
|
||||
'password',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -39,7 +44,8 @@ class User extends Authenticatable
|
|||
* @var array<int, string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'remember_token'
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -48,7 +54,8 @@ class User extends Authenticatable
|
|||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'last_connection' => 'date',
|
||||
'email_verified_at' => 'datetime',
|
||||
'last_connection' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -61,9 +68,17 @@ class User extends Authenticatable
|
|||
// * EVENT CLOSURES.
|
||||
static::creating(function (self $user) {
|
||||
self::assertEmailIsUnique($user->email);
|
||||
if (Hash::needsRehash($user->password)) {
|
||||
$user->password = Hash::make($user->password);
|
||||
}
|
||||
$user->remember_token = Str::random(10);
|
||||
});
|
||||
static::updating(function (self $user) {
|
||||
self::assertEmailIsUnique($user->email, $user->id);
|
||||
if (Hash::needsRehash($user->password)) {
|
||||
$user->password = Hash::make($user->password);
|
||||
}
|
||||
$user->remember_token = Str::random(10);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use LDC\LDCCRM\CrmApiV4;
|
||||
|
||||
class CrmApiServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
App::singleton('crmAPI', function () {
|
||||
return new CrmApiV4(
|
||||
config('crm.endpoint'),
|
||||
config('crm.token'),
|
||||
config('crm.password')
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,6 @@
|
|||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Slides\Saml2\Events\SignedIn;
|
||||
use Slides\Saml2\Events\SignedOut;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
|
@ -27,41 +20,5 @@ class EventServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot()
|
||||
{
|
||||
Event::listen('Slides\Saml2\Events\SignedIn', function (SignedIn $event) {
|
||||
|
||||
$messageId = $event->getAuth()->getLastMessageId();
|
||||
|
||||
$fromCache = Cache::get(config('cache.prefix') . "_saml_message_id_" . $messageId);
|
||||
if ($fromCache) {
|
||||
logger()->error(
|
||||
'SAML MESSAGE ID HANDLER',
|
||||
['error' => 'Message ID : ' . $messageId . " replayed !"]
|
||||
);
|
||||
abort(403);
|
||||
} else {
|
||||
Cache::put(config('cache.prefix') . "_saml_message_id_" . $messageId, $messageId, 28800);
|
||||
// Cache for 8h.
|
||||
}
|
||||
|
||||
$user = $event->getSaml2User();
|
||||
$email = $user->getNameId();
|
||||
|
||||
$lUser = User::where('email', '=', $email)->first();
|
||||
|
||||
if (!$lUser) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
Auth::guard('backend')->login($lUser);
|
||||
session(['sessionIndex' => $user->getSessionIndex()]);
|
||||
$lUser->last_connection = now();
|
||||
$lUser->saveQuietly();
|
||||
});
|
||||
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
|
||||
Event::listen('Slides\Saml2\Events\SignedOut', function (SignedOut $event) {
|
||||
Auth::guard('backend')->logout();
|
||||
Session::save();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Providers;
|
||||
|
||||
use App\Models\Advice;
|
||||
use App\Models\BrigadeSection;
|
||||
use App\Models\ExpertiseProduct;
|
||||
use App\Models\News;
|
||||
use App\Models\NewsCategory;
|
||||
|
|
@ -58,7 +57,6 @@ class RouteServiceProvider extends ServiceProvider
|
|||
Route::model('range', Range::class);
|
||||
Route::model('product', Product::class);
|
||||
Route::model('advice', Advice::class);
|
||||
Route::model('brigade_section', BrigadeSection::class);
|
||||
}
|
||||
|
||||
Route::bind('actu', function ($value) {
|
||||
|
|
@ -67,7 +65,7 @@ class RouteServiceProvider extends ServiceProvider
|
|||
|
||||
// * Front binded Models
|
||||
Route::bind('publishedAdvice', function ($value) {
|
||||
return Advice::where('slug', $value)->where('published', true)->firstOrFail();
|
||||
return Advice::where('slug', $value)->where('status', true)->firstOrFail();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -112,11 +110,8 @@ class RouteServiceProvider extends ServiceProvider
|
|||
})->all();
|
||||
// * Filter array keys
|
||||
$cspReport = collect(array_intersect_key($cspReport, [
|
||||
'blocked-uri' => '',
|
||||
'document-uri' => '',
|
||||
'original-policy' => '',
|
||||
'referrer' => '',
|
||||
'violated-directive' => ''
|
||||
'blocked-uri' => '', 'document-uri' => '', 'original-policy' => '',
|
||||
'referrer' => '', 'violated-directive' => ''
|
||||
]));
|
||||
\Illuminate\Support\Facades\Log::warning(sprintf(
|
||||
"CSP REPORT for %s : \n %s",
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Check the length of a Wysiwyg field, excluding tags and end spaces.
|
||||
*
|
||||
* @package App\Rules
|
||||
*/
|
||||
class WysiwygLength implements ValidationRule
|
||||
{
|
||||
/**
|
||||
* Construct method.
|
||||
*
|
||||
* @param integer $min The minimum length of the content (excluding tags). Default is 15.
|
||||
* @param integer|null $max The maximum length of the content (excluding tags).
|
||||
* Default is null (max will be defined by the type of the column in DB).
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException If $max < $min.
|
||||
*/
|
||||
public function __construct(private int $min = 15, private int|null $max = null)
|
||||
{
|
||||
if ($max !== null && $max < $min && $min < 0) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'$max should be higher than $min. $max = %d. $min = %d.',
|
||||
$max,
|
||||
$min
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
* @param \Closure $fail
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, \Closure $fail): void
|
||||
{
|
||||
$length = Str::length(\strip_tags($value));
|
||||
|
||||
$translatedAttribute = self::getTranslatedAttribute($attribute);
|
||||
if (!\is_null($this->max) and !($length >= $this->min && $length <= $this->max)) {
|
||||
$fail(trans('validation.between.string', [
|
||||
'attribute' => $translatedAttribute,
|
||||
'min' => $this->min,
|
||||
'max' => $this->max
|
||||
]));
|
||||
return;
|
||||
}
|
||||
if ($length < $this->min) {
|
||||
$fail(trans('validation.min.string', [
|
||||
'attribute' => $translatedAttribute,
|
||||
'min' => $this->min
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the correct translation for the given attrribute.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @return string
|
||||
*/
|
||||
private static function getTranslatedAttribute(string $attribute): string
|
||||
{
|
||||
/** @var \Illuminate\Translation\Translator $trans */
|
||||
$trans = trans();
|
||||
if ($trans->has('validation.attributes.' . $attribute)) {
|
||||
return trans('validation.attributes.' . $attribute);
|
||||
}
|
||||
if ($trans->has('validation.custom.' . $attribute)) {
|
||||
return trans('validation.custom.' . $attribute);
|
||||
}
|
||||
return $attribute;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
namespace App\Traits\Controllers;
|
||||
|
||||
use App\Http\Requests\Bo\UpdateChangeOrderRequest;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -14,16 +14,15 @@ trait ChangesModelOrder
|
|||
* Change order.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\UpdateChangeOrderRequest $request
|
||||
* @param mixed ...$params
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \RuntimeException Si le nom du parametre de la route ne correspond pas au model utilisé.
|
||||
*/
|
||||
public function changeOrder(UpdateChangeOrderRequest $request, mixed ...$params): \Illuminate\Http\RedirectResponse
|
||||
public function changeOrder(UpdateChangeOrderRequest $request, Model $model): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$paramNames = collect(request()->route()->parameterNames);
|
||||
$className = Str::of($paramNames->get($paramNames->count() - 2))->lower()->studly();
|
||||
$className = "\\App\\Models\\$className";
|
||||
$model = Arr::get($params, $paramNames->count() - 2);
|
||||
$params = collect(request()->route()->parameterNames);
|
||||
$className = Str::ucfirst(Str::lower($params->get($params->count() - 2)));
|
||||
$className = "\\App\\Models\\$className";
|
||||
|
||||
if (!class_exists($className)) {
|
||||
throw new \RuntimeException("The $className class doesn't exist.");
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Traits\Controllers;
|
||||
|
||||
use App\Http\Requests\Bo\UpdateOrderRequest;
|
||||
use App\Interfaces\OrderableInterface;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
trait ManagesOrder
|
||||
{
|
||||
/**
|
||||
* Updates the order of a model and reorders all impacted elements.
|
||||
*
|
||||
* Shifts by +1 or -1 all elements located between the old
|
||||
* and new position of the model, then assigns the new position
|
||||
* to the target model. The whole operation runs inside a
|
||||
* database transaction to ensure data consistency.
|
||||
*
|
||||
* @param UpdateOrderRequest $request The validated request containing the 'priority' field.
|
||||
* @param Model&OrderableInterface $model The model to reorder (must use the Orderable trait).
|
||||
* @return RedirectResponse
|
||||
*
|
||||
* @throws \Throwable Returns if save fail.
|
||||
*/
|
||||
public function changeOrderPriority(UpdateOrderRequest $request, Model&OrderableInterface $model): RedirectResponse
|
||||
{
|
||||
$newPriority = (int) $request->validated('priority_order');
|
||||
|
||||
return DB::transaction(function () use ($model, $newPriority): RedirectResponse {
|
||||
|
||||
$query = $model::query()
|
||||
->whereKeyNot($model)
|
||||
->whereBetween('priority_order', [
|
||||
min($model->getPriorityOrder(), $newPriority),
|
||||
max($model->getPriorityOrder(), $newPriority),
|
||||
]);
|
||||
|
||||
$groupField = $model->getOrderGroupField();
|
||||
if ($groupField) {
|
||||
$query->where($groupField, $model->{$groupField});
|
||||
}
|
||||
|
||||
$model->getPriorityOrder() < $newPriority
|
||||
? $query->decrement('priority_order', 1)
|
||||
: $query->increment('priority_order', 1);
|
||||
|
||||
$model->setAttribute('priority_order', $newPriority);
|
||||
$model->saveOrFail();
|
||||
|
||||
return redirect()->back()->with('success', trans('crud.messages.order_changed'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,6 @@ trait UpdateModelPublished
|
|||
public function changePublished(Model $model)
|
||||
{
|
||||
$model->update(['published' => !$model->getOriginal('published')]);
|
||||
return redirect()->back()->with('success', trans('crud.messages.publish_status_saved'));
|
||||
return redirect()->back()->with('success', trans(__('crud.messages.publish_status_saved')));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Traits\Models;
|
||||
|
||||
use App\Interfaces\OrderableInterface;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
trait Orderable
|
||||
{
|
||||
/**
|
||||
* @property int $priority_order
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the grouping field used for ordering.
|
||||
* Returns null if the order is global
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getOrderGroupField(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority order value of the model.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getPriorityOrder(): int
|
||||
{
|
||||
return $this->priority_order ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* shifts down by 1 all elements positioned after the delete.
|
||||
*
|
||||
* @param Model&OrderableInterface $model
|
||||
* @return void
|
||||
*/
|
||||
public static function setOrder(OrderableInterface $model): void
|
||||
{
|
||||
$groupField = $model->getOrderGroupField();
|
||||
$query = $model::query()->where('priority_order', '>', $model->getPriorityOrder());
|
||||
|
||||
if ($groupField) {
|
||||
$query->where($groupField, $model->{$groupField});
|
||||
}
|
||||
|
||||
$query->each(function (Model $item): void {
|
||||
/** @var Model&OrderableInterface $item */
|
||||
$item->setAttribute('priority_order', $item->getPriorityOrder() - 1);
|
||||
$item->saveOrFail();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the next order value on creation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function bootOrderable(): void
|
||||
{
|
||||
static::creating(function (Model $model): void {
|
||||
/** @var Model&OrderableInterface $model */
|
||||
if (!$model->getPriorityOrder()) {
|
||||
$groupField = $model->getOrderGroupField();
|
||||
$query = static::query();
|
||||
|
||||
if ($groupField) {
|
||||
$query->where($groupField, $model->{$groupField});
|
||||
}
|
||||
|
||||
$model->setAttribute('priority_order', ($query->max('priority_order') ?? 0) + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -112,7 +112,8 @@ trait HasPicture
|
|||
];
|
||||
return [
|
||||
$name => [!$nullable ? 'required' : 'nullable', 'array', "between:{$limitMin},{$limitMax}"],
|
||||
"{$name}.*" => [
|
||||
"{$name}Validate" => "required_with:{$name}|array",
|
||||
"{$name}Validate.*" => [
|
||||
'required',
|
||||
function (string $attribute, $value, callable $fail) use ($sizes) {
|
||||
ToolboxHelper::validatePicture($attribute, $value, $fail, $sizes);
|
||||
|
|
|
|||
|
|
@ -12,28 +12,24 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.5",
|
||||
"24slides/laravel-saml2": "^2.4",
|
||||
"php": "^8.2",
|
||||
"axlon/laravel-postal-code-validation": "^3.4",
|
||||
"carlos-meneses/laravel-mpdf": "^2.1.13",
|
||||
"diglactic/laravel-breadcrumbs": "^9.0",
|
||||
"diglactic/laravel-breadcrumbs": "^8.1.1",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"kaishiyoku/laravel-color-validation": "*",
|
||||
"laravel/framework": "^11.0",
|
||||
"kaishiyoku/laravel-color-validation": "^2.1.1",
|
||||
"kwaadpepper/image-resizer": "^2.1.0",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/tinker": "^2.8",
|
||||
"laravel/ui": "^4.2",
|
||||
"ldc/ldccrmv4client": "^4.0",
|
||||
"ldc/sitemap-generator": "^2.0",
|
||||
"ldc/web-admin-secure-laravel": "^2.0.0",
|
||||
"mews/purifier": "^3.4",
|
||||
"propaganistas/laravel-phone": "^5.0.3",
|
||||
"sentry/sentry-laravel": "^4.9",
|
||||
"sentry/sentry-laravel": "^3.8",
|
||||
"spatie/calendar-links": "^1.8.5",
|
||||
"uwil/admin-secure-laravel": "^5.0",
|
||||
"uwil/k8s-laravel": "^1.2",
|
||||
"uwil/laravel-common": "^2.0",
|
||||
"uwil/laravel-redirections": "^2.0",
|
||||
"uwil/seo-laravel": "^3.0",
|
||||
"uwil/sitemap-generator": "^3.0",
|
||||
"verschuur/laravel-robotstxt": "^5.1"
|
||||
"uwil/seo-laravel": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/dbal": "^3.3",
|
||||
|
|
@ -43,7 +39,7 @@
|
|||
"laravel/pint": "^1.0",
|
||||
"laravel/sail": "^1.18",
|
||||
"mockery/mockery": "^1.4.4",
|
||||
"nunomaduro/collision": "^8.1",
|
||||
"nunomaduro/collision": "^7.0",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"slevomat/coding-standard": "^8.10",
|
||||
"spatie/laravel-ignition": "^2.3"
|
||||
|
|
@ -94,10 +90,7 @@
|
|||
"pestphp/pest-plugin": true,
|
||||
"php-http/discovery": true,
|
||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||
},
|
||||
"gitlab-domains": [
|
||||
"lab.s-web.fr"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
|
|
|
|||
6123
composer.lock
generated
6123
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -179,7 +179,6 @@ return [
|
|||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
App\Providers\ViewServiceProvider::class,
|
||||
App\Providers\CrmApiServiceProvider::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'endpoint' => env('CRM_ENDPOINT'),
|
||||
'token' => env('CRM_TOKEN'),
|
||||
'password' => env('CRM_PASSWORD')
|
||||
];
|
||||
|
|
@ -5,7 +5,7 @@ return [
|
|||
* The php image driver to use
|
||||
* this can be 'imagick' or 'gd'
|
||||
*/
|
||||
'driver' => 'imagick',
|
||||
'driver' => 'gd',
|
||||
|
||||
/**
|
||||
* The cache driver to use as defined
|
||||
|
|
@ -57,9 +57,6 @@ return [
|
|||
* ]
|
||||
*/
|
||||
'templates' => [
|
||||
'toWebp' => [
|
||||
'format' => 'webp'
|
||||
],
|
||||
'tipsBigCard' => [
|
||||
'height' => 300,
|
||||
'width' => 370,
|
||||
|
|
|
|||
|
|
@ -120,6 +120,6 @@ return [
|
|||
*/
|
||||
|
||||
'contactsList' => [
|
||||
'contactform' => array_filter(explode(',', env('MAIL_LIST_CONTACTFORM', '') ?? '')),
|
||||
'contactform' => env('MAIL_LIST_CONTACTFORM')
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'environments' => [
|
||||
'production' => [
|
||||
'paths' => [
|
||||
'*' => [
|
||||
'disallow' => [
|
||||
'/bo',
|
||||
'*.pdf$'
|
||||
],
|
||||
'allow' => []
|
||||
],
|
||||
],
|
||||
'sitemaps' => [
|
||||
'sitemap.xml'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
397
config/saml2.php
397
config/saml2.php
|
|
@ -1,397 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Tenant Model
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This will allow you to override the tenant model with your own.
|
||||
|
|
||||
*/
|
||||
|
||||
'tenantModel' => \Slides\Saml2\Models\Tenant::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Use built-in routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If "useRoutes" set to true, the package defines five new routes:
|
||||
|
|
||||
| Method | URI | Name
|
||||
| -------|---------------------------------|------------------
|
||||
| POST | {routesPrefix}/{uuid}/acs | saml.acs
|
||||
| GET | {routesPrefix}/{uuid}/login | saml.login
|
||||
| GET | {routesPrefix}/{uuid}/logout | saml.logout
|
||||
| GET | {routesPrefix}/{uuid}/metadata | saml.metadata
|
||||
| GET | {routesPrefix}/{uuid}/sls | saml.sls
|
||||
|
|
||||
*/
|
||||
|
||||
'useRoutes' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Built-in routes prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the prefix for built-in routes.
|
||||
|
|
||||
*/
|
||||
|
||||
'routesPrefix' => '/saml2',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Middle groups to use for the SAML routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Note, Laravel 5.2 requires a group which includes StartSession
|
||||
|
|
||||
*/
|
||||
|
||||
'routesMiddleware' => ['saml'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Signature validation
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set to true if you want to use parameters from $_SERVER to validate the signature.
|
||||
|
|
||||
*/
|
||||
|
||||
'retrieveParametersFromServer' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Login redirection URL.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The redirection URL after successful login.
|
||||
|
|
||||
*/
|
||||
|
||||
'loginRoute' => '/bo',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Logout redirection URL.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The redirection URL after successful logout.
|
||||
|
|
||||
*/
|
||||
|
||||
'logoutRoute' => '/bo',
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Login error redirection URL.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The redirection URL after login failing.
|
||||
|
|
||||
*/
|
||||
|
||||
'errorRoute' => '/bo/login-error',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Strict mode.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If 'strict' is True, then the PHP Toolkit will reject unsigned
|
||||
| or unencrypted messages if it expects them signed or encrypted
|
||||
| Also will reject the messages if not strictly follow the SAML
|
||||
| standard: Destination, NameId, Conditions... are validated too.
|
||||
|
|
||||
*/
|
||||
|
||||
'strict' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Debug mode.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When enabled, errors must be printed.
|
||||
|
|
||||
*/
|
||||
|
||||
'debug' => env('SAML2_DEBUG', env('APP_DEBUG', false)),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Whether to use `X-Forwarded-*` headers to determine port/domain/protocol.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If 'proxyVars' is True, then the Saml lib will trust proxy headers
|
||||
| e.g X-Forwarded-Proto / HTTP_X_FORWARDED_PROTO. This is useful if
|
||||
| your application is running behind a load balancer which terminates SSL.
|
||||
|
|
||||
*/
|
||||
|
||||
'proxyVars' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Service Provider configuration.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| General setting of the service provider.
|
||||
|
|
||||
*/
|
||||
|
||||
'sp' => [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| NameID format.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specifies constraints on the name identifier to be used to
|
||||
| represent the requested subject.
|
||||
|
|
||||
*/
|
||||
|
||||
'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| SP Certificates.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Usually x509cert and privateKey of the SP are provided by files placed at
|
||||
| the certs folder. But we can also provide them with the following parameters.
|
||||
|
|
||||
*/
|
||||
|
||||
'x509cert' => env('SAML2_SP_CERT_x509', ''),
|
||||
'privateKey' => env('SAML2_SP_CERT_PRIVATEKEY', ''),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Identifier (URI) of the SP entity.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Leave blank to use the 'saml.metadata' route.
|
||||
|
|
||||
*/
|
||||
|
||||
'entityId' => env('SAML2_SP_ENTITYID', ''),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| The Assertion Consumer Service (ACS) URL.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| URL Location where the <Response> from the IdP will be returned, using HTTP-POST binding.
|
||||
| Leave blank to use the 'saml.acs' route.
|
||||
|
|
||||
*/
|
||||
|
||||
'assertionConsumerService' => [
|
||||
'url' => '',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| The Single Logout Service URL.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Specifies info about where and how the <Logout Response> message MUST be
|
||||
| returned to the requester, in this case our SP.
|
||||
|
|
||||
| URL Location where the <Response> from the IdP will be returned, using HTTP-Redirect binding.
|
||||
| Leave blank to use the 'saml.sls' route.
|
||||
|
|
||||
*/
|
||||
|
||||
'singleLogoutService' => [
|
||||
'url' => ''
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| OneLogin security settings.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
|
|
||||
|
|
||||
*/
|
||||
|
||||
'security' => [
|
||||
|
||||
'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
|
||||
'digestAlgorithm' => 'http://www.w3.org/2001/04/xmlenc#sha256',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| NameId encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
|
||||
| will be encrypted.
|
||||
|
|
||||
*/
|
||||
|
||||
'nameIdEncrypted' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| AuthnRequest signage
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Indicates whether the <samlp:AuthnRequest> messages sent by
|
||||
| this SP will be signed. The Metadata of the SP will offer this info
|
||||
|
|
||||
*/
|
||||
|
||||
'authnRequestsSigned' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Logout request signage
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Indicates whether the <samlp:logoutRequest> messages sent by this SP
|
||||
| will be signed.
|
||||
|
|
||||
*/
|
||||
|
||||
'logoutRequestSigned' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Logout response signage
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Indicates whether the <samlp:logoutResponse> messages sent by this SP
|
||||
| will be signed.
|
||||
|
|
||||
*/
|
||||
|
||||
'logoutResponseSigned' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Whether need to sign metadata.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The possible values:
|
||||
| - false
|
||||
| - true (use certs)
|
||||
| - array:
|
||||
| ```
|
||||
| [
|
||||
| 'keyFileName' => 'metadata.key',
|
||||
| 'certFileName' => 'metadata.crt'
|
||||
| ]
|
||||
| ```
|
||||
|
|
||||
*/
|
||||
|
||||
'signMetadata' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Requirement to sign messages.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> and
|
||||
| <samlp:LogoutResponse> elements received by this SP to be signed.
|
||||
|
|
||||
*/
|
||||
|
||||
'wantMessagesSigned' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Requirement to sign assertion elements.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Indicates a requirement for the <saml:Assertion> elements received by
|
||||
| this SP to be signed.
|
||||
|
|
||||
*/
|
||||
|
||||
'wantAssertionsSigned' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Requirement to encrypt NameID.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Indicates a requirement for the NameID received by this SP to be encrypted.
|
||||
|
|
||||
*/
|
||||
|
||||
'wantNameIdEncrypted' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication context.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set to false and no AuthContext will be sent in the AuthNRequest,
|
||||
|
|
||||
| Set true or don't present this parameter and you will get an
|
||||
| AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
|
||||
|
|
||||
| Set an array with the possible auth context values:
|
||||
| ['urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509']
|
||||
|
|
||||
*/
|
||||
|
||||
'requestedAuthnContext' => true,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Contact information.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| It is recommended to supply a technical and support contacts.
|
||||
|
|
||||
*/
|
||||
|
||||
'contactPerson' => [
|
||||
'technical' => [
|
||||
'givenName' => env('SAML2_CONTACT_TECHNICAL_NAME', env('APP_NAME', 'Technical')),
|
||||
'emailAddress' => env('SAML2_CONTACT_TECHNICAL_EMAIL', 'no@reply.com')
|
||||
],
|
||||
'support' => [
|
||||
'givenName' => env('SAML2_CONTACT_SUPPORT_NAME', env('APP_NAME', 'Support')),
|
||||
'emailAddress' => env('SAML2_CONTACT_SUPPORT_EMAIL', 'no@reply.com')
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Organization information.
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The info in en_US lang is recommended, add more if required.
|
||||
|
|
||||
*/
|
||||
|
||||
'organization' => [
|
||||
'en-US' => [
|
||||
'name' => env('SAML2_ORGANIZATION_NAME', env('APP_NAME', 'Name')),
|
||||
'displayname' => env('SAML2_ORGANIZATION_NAME', env('APP_NAME', 'Name')),
|
||||
'url' => env('SAML2_ORGANIZATION_URL', env('APP_URL', 'http://url'))
|
||||
],
|
||||
],
|
||||
|
||||
/**
|
||||
* Default tenant UUID
|
||||
*/
|
||||
|
||||
'default_tenant_uuid' => env('SAML2_DEFAULT_TENANT_UUID', null)
|
||||
|
||||
];
|
||||
|
|
@ -51,14 +51,10 @@ return [
|
|||
'missing_routes' => false,
|
||||
],
|
||||
|
||||
/**
|
||||
* @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii.
|
||||
*/
|
||||
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii.
|
||||
'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
|
||||
|
||||
/**
|
||||
* @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate.
|
||||
*/
|
||||
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate.
|
||||
'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float)env('SENTRY_TRACES_SAMPLE_RATE'),
|
||||
|
||||
'before_send' => [\App\Lib\Helpers\ExceptionsHelper::class, 'sentryEventHandler'],
|
||||
|
|
|
|||
|
|
@ -1,88 +1,77 @@
|
|||
<?php
|
||||
|
||||
use App\Lib\CompleteSitemapWith;
|
||||
use Spatie\Sitemap\Tags\Url;
|
||||
|
||||
return [
|
||||
|
||||
/**
|
||||
* Single route names
|
||||
* A list of url to ignore
|
||||
* These are hard coded
|
||||
* Each url does not have to be exhaustive
|
||||
*
|
||||
* Ex:
|
||||
* For example, if you want to ignore all routes
|
||||
* of the backoffice group
|
||||
* just add 'bo' into this table
|
||||
*
|
||||
* 'singlePages' => [
|
||||
* 'homepage',
|
||||
* ],
|
||||
* * Note that this can take route names (both partially or full)
|
||||
* * You can use a wild card just as for routeIs method
|
||||
*/
|
||||
'singlePages' => [
|
||||
'fo.homepage',
|
||||
'fo.adn.adn',
|
||||
'fo.adn.btob',
|
||||
'fo.adn.breeder',
|
||||
'fo.engagments.francais',
|
||||
'fo.engagments.eleverdurablement',
|
||||
'fo.engagments.biennourrir',
|
||||
'fo.engagments.respecterlaterre',
|
||||
'fo.engagments.vivreensemble',
|
||||
'fo.expertise.canard',
|
||||
'fo.expertise.dinde',
|
||||
'fo.expertise.lapin',
|
||||
'fo.expertise.pintade',
|
||||
'fo.expertise.poulet',
|
||||
'fo.ideas.ideas',
|
||||
'fo.ideas.tips.index',
|
||||
'fo.ideas.recipes.index',
|
||||
'fo.products.index',
|
||||
'fo.news.index',
|
||||
'fo.contact.show',
|
||||
'fo.group',
|
||||
'fo.trade',
|
||||
'fo.dealer',
|
||||
'fo.baker',
|
||||
'fo.policies',
|
||||
'fo.legals',
|
||||
'fo.search'
|
||||
'ignoreRoutes' => [
|
||||
'back.*',
|
||||
'bo.*',
|
||||
'front.frame',
|
||||
'cspReportUri',
|
||||
],
|
||||
|
||||
/**
|
||||
* Model namespaces with filters
|
||||
* This should be filled using the command `php artisan sitemap:install-completer`
|
||||
*
|
||||
* Ex:
|
||||
* 'cruds' => [
|
||||
* [
|
||||
* 'model' => 'App\Models\Product',
|
||||
* 'filters' => [
|
||||
* ['published', '=', true]
|
||||
* ]
|
||||
* ],
|
||||
* [
|
||||
* 'model' => 'App\Models\Article',
|
||||
* 'filters' => []
|
||||
* ]
|
||||
* ],
|
||||
* 'completeWith' => [CLASS, 'METHOD'],
|
||||
* eg : 'completeWith' => [CompleteSitemapWith::class, 'append'],
|
||||
*
|
||||
* This should point to a static method which will be called with the folowing parameter
|
||||
* (LDC\SitemapGenerator\Lib\Sitemap $sitemap)
|
||||
*
|
||||
* You may now use $sitemap->addLinks('route.myRouteName', string[] $links)
|
||||
*/
|
||||
'cruds' => [
|
||||
[
|
||||
'model' => 'App\Models\Advice',
|
||||
'filters' => [
|
||||
['published', '=', true]
|
||||
]
|
||||
],
|
||||
[
|
||||
'model' => 'App\Models\Range',
|
||||
'filters' => []
|
||||
],
|
||||
[
|
||||
'model' => 'App\Models\Product',
|
||||
'filters' => [
|
||||
['published', '=', true]
|
||||
]
|
||||
],
|
||||
[
|
||||
'model' => 'App\Models\News',
|
||||
'filters' => [
|
||||
['published', '=', true]
|
||||
]
|
||||
]
|
||||
'completeWith' => [CompleteSitemapWith::class, 'append'],
|
||||
|
||||
/**
|
||||
* The default route frequency to use with sitemap generator
|
||||
*/
|
||||
'routeDefaultFrequency' => Url::CHANGE_FREQUENCY_DAILY,
|
||||
|
||||
/**
|
||||
* The default route priority to use with sitemap generator
|
||||
*
|
||||
* priority should be a number between 0 and 1
|
||||
* https://www.sitemaps.org/protocol.html
|
||||
*/
|
||||
'routeDefaultPriority' => 0.5,
|
||||
|
||||
/**
|
||||
* Frequencies for routes
|
||||
* use the full or partial route name as index
|
||||
* and a frequency within \Spatie\Sitemap\Tags\Url constants
|
||||
*
|
||||
* eg: 'engagments.*' => \Spatie\Sitemap\Tags\Url::CHANGE_FREQUENCY_HOURLY
|
||||
*/
|
||||
'routeFrequencies' => [
|
||||
'news.show' => Url::CHANGE_FREQUENCY_HOURLY
|
||||
],
|
||||
|
||||
/**
|
||||
* Priorities for routes
|
||||
* use the full or partial route name as index
|
||||
* and a priority in 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, and 0.0.
|
||||
*
|
||||
* 1.0 is the Highest
|
||||
*
|
||||
* eg: 'engagments.*' => 1.0
|
||||
*/
|
||||
'routePriorities' => [],
|
||||
|
||||
/**
|
||||
* Enable or disable schedule for the job
|
||||
* If set to true the sitemap generator will be run
|
||||
|
|
@ -101,4 +90,13 @@ return [
|
|||
* Default is every day at 15:45
|
||||
*/
|
||||
'cron' => '45 15 * * *',
|
||||
|
||||
/**
|
||||
* The sitemap generator can execute JavaScript on each page so it will
|
||||
* discover links that are generated by your JS scripts. This feature
|
||||
* is powered by headless Chrome.
|
||||
*
|
||||
* ! This needs pupetter installed with npm : npm i puppeteer (not to put in dev dependencies)
|
||||
*/
|
||||
'executeJavascript' => false,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class AdviceFactory extends Factory
|
|||
'cooking_time' => $cooking_time,
|
||||
'preparation_time' => $preparation_time,
|
||||
'difficulty' => $difficulty,
|
||||
'published' => $this->faker->boolean(75)
|
||||
'status' => $this->faker->boolean(75)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class NewsFactory extends Factory
|
|||
'event_start' => $eventStart,
|
||||
'event_end' => $eventEnd,
|
||||
'event_text' => $eventText,
|
||||
'published' => $this->faker->boolean(75)
|
||||
'status' => $this->faker->boolean(75)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@ class ProductFactory extends Factory
|
|||
]);
|
||||
}
|
||||
|
||||
$nutritionnal_values = [];
|
||||
for ($jj = 1; $jj <= 9; $jj++) {
|
||||
array_push($nutritionnal_values, [
|
||||
"label" => $this->faker->unique()->words(rand(2, 8), true),
|
||||
"value" => $this->faker->numberBetween(6, 30)
|
||||
]);
|
||||
}
|
||||
|
||||
$label = $this->faker->unique()->words(rand(2, 4), true);
|
||||
|
||||
return [
|
||||
|
|
@ -51,13 +59,14 @@ class ProductFactory extends Factory
|
|||
'sticker_sm_alt' => $this->faker->words(8, true),
|
||||
'packaging' => $packaging,
|
||||
'caliber' => $caliber,
|
||||
'nutritionnal_values' => $nutritionnal_values,
|
||||
'ingredients' => $this->faker->unique()->words(rand(15, 25), true),
|
||||
'advantage' => $this->faker->unique()->words(rand(15, 25), true),
|
||||
'preparation' => $this->faker->unique()->words(rand(15, 25), true),
|
||||
'is_frenchpoultry' => $this->faker->boolean(75),
|
||||
'is_vip' => $this->faker->boolean(25),
|
||||
'is_egalim' => $this->faker->boolean(25),
|
||||
'published' => $this->faker->boolean(75)
|
||||
'status' => $this->faker->boolean(75)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,7 @@ class SlideFactory extends Factory
|
|||
'picture_alt' => $picture_alt,
|
||||
'picture_title' => $picture_title,
|
||||
'picture_thumbnail_alt' => $picture_alt,
|
||||
'picture_thumbnail_title' => $picture_title,
|
||||
'published' => $this->faker->boolean(),
|
||||
'picture_thumbnail_title' => $picture_title
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('email_verified_at');
|
||||
$table->dropColumn('password');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->timestamp('email_verified_at')->nullable()->after('email');
|
||||
$table->string('password')->after('email_verified_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Slide;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('slides', function (Blueprint $table) {
|
||||
$table->boolean('published')->comment('Is the slide published ?')
|
||||
->after('order');
|
||||
});
|
||||
Slide::query()->update(['published' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('slides', function (Blueprint $table) {
|
||||
$table->dropColumn('published');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('advice', function (Blueprint $table) {
|
||||
$table->renameColumn('status', 'published');
|
||||
});
|
||||
Schema::table('news', function (Blueprint $table) {
|
||||
$table->renameColumn('status', 'published');
|
||||
});
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->renameColumn('status', 'published');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('advice', function (Blueprint $table) {
|
||||
$table->renameColumn('published', 'status');
|
||||
});
|
||||
Schema::table('news', function (Blueprint $table) {
|
||||
$table->renameColumn('published', 'status');
|
||||
});
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->renameColumn('published', 'status');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->dropColumn('nutritionnal_values');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->json('nutritionnal_values')->comment('Valeurs nutritionnelles du produit')->nullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Product;
|
||||
use App\Models\Range;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Range::with('subranges.products')->get()->map(function ($range) {
|
||||
$range->subranges->flatMap(function ($subrange) {
|
||||
return $subrange->products;
|
||||
})->map(function ($product, $productIndex) {
|
||||
$product->order = $productIndex + 1;
|
||||
$product->saveQuietly();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Product::query()->get()->map(function ($product, $productIndex) {
|
||||
$product->order = $productIndex + 1;
|
||||
$product->saveQuietly();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('tags', function (Blueprint $table) {
|
||||
// Default is 'recipes' because actually, it is only used for this model.
|
||||
$table->unsignedTinyInteger('type')->default(1)->comment('ENUM - Type of the tag')->after('slug');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tags', function (Blueprint $table) {
|
||||
$table->dropColumn('type');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('brigade_sections', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title', 500)->comment('Title of the section');
|
||||
$table->text('content')->comment('WYSIWYG - Content of the section');
|
||||
$table->string('picture')->comment('Picture of the section');
|
||||
$table->string('picture_alt')->comment('Alt attribute for the picture');
|
||||
$table->string('picture_title')->comment('Title attribute for the picture');
|
||||
$table->string('button_text')->nullable()->comment('Text of the CTA');
|
||||
$table->string('button_url')->nullable()->comment('URL the CTA');
|
||||
$table->boolean('button_newtab')->comment('Should the URL be opened in a new tab ?');
|
||||
$table->boolean('button_display')->comment('Should the CTA be displayed ?');
|
||||
$table->unsignedTinyInteger('order')->comment('Order of the section');
|
||||
$table->boolean('published')->comment('Is the section visible ?');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('brigade_sections');
|
||||
}
|
||||
};
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Product;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->unsignedInteger('priority_order')->comment('Ordre de priorite')->default(0)->after('order');
|
||||
});
|
||||
|
||||
$order = 1;
|
||||
|
||||
Product::query()
|
||||
->orderBy('order')
|
||||
->each(function (Product $product) use (&$order) {
|
||||
$product->priority_order = $order++;
|
||||
$product->saveOrFail();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->dropColumn('priority_order');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\Advices\AdviceTypeEnum;
|
||||
use App\Models\Advice;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('advice', function (Blueprint $table) {
|
||||
$table->unsignedInteger('priority_order')->comment('Ordre de priorite')->default(0)->after('published');
|
||||
});
|
||||
|
||||
// loop through all types and in each type we order
|
||||
Advice::query()->select('type')->pluck('type')
|
||||
->each(function (AdviceTypeEnum $type) {
|
||||
$order = 1;
|
||||
Advice::query()
|
||||
->where('type', $type)
|
||||
->orderBy('created_at')
|
||||
->each(function (Advice $advice) use (&$order) {
|
||||
$advice->priority_order = $order++;
|
||||
$advice->saveOrFail();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('advice', function (Blueprint $table) {
|
||||
$table->dropColumn('priority_order');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('products', function (Blueprint $table) {
|
||||
$table->dropColumn('order');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$table->integer('order')->comment('Ordre du slide');
|
||||
}
|
||||
};
|
||||
|
|
@ -21,7 +21,7 @@ class ExpertiseProductSeeder extends Seeder
|
|||
ExpertiseProduct::factory(rand(0, 3))->make()->each(
|
||||
// @phpstan-ignore-next-line
|
||||
function (ExpertiseProduct $expertiseProduct) use ($enum) {
|
||||
$expertiseProduct->page = ExpertiseProductPageEnum::make($enum->value);
|
||||
$expertiseProduct->page = $enum;
|
||||
$expertiseProduct->saveQuietly();
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -647,18 +647,5 @@ class StaticPageSeeder extends Seeder
|
|||
viande désossée et goûteuse, aux atouts nutritionnels indiscutables.</p>',
|
||||
]
|
||||
);
|
||||
// Sitemap.
|
||||
StaticPage::query()->updateOrCreate(
|
||||
[
|
||||
'type' => StaticPageType::sitemap,
|
||||
],
|
||||
[
|
||||
'seo_title' => 'Plan du site',
|
||||
'seo_description' => 'Plan du site internet Le Gaulois Professionnel',
|
||||
'title' => 'Plan du site',
|
||||
'type' => StaticPageType::sitemap,
|
||||
'content' => '',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
114
manifest.yaml
114
manifest.yaml
|
|
@ -8,9 +8,9 @@ data:
|
|||
APP_ENV: "${APP_APP_ENV}"
|
||||
APP_KEY: "${APP_APP_KEY}"
|
||||
APP_DEBUG: "${APP_APP_DEBUG}"
|
||||
APP_URL: "https://${REDIRECT}${APP_DOMAIN}"
|
||||
APP_URL: "https://www.${APP_DOMAIN}"
|
||||
LOG_CHANNEL: "k8s"
|
||||
DB_HOST: "${APP_DB_HOST}"
|
||||
DB_HOST: "mariadb-service.common-services"
|
||||
DB_DATABASE: "${APP_DB_DATABASE}"
|
||||
DB_USERNAME: "${APP_DB_USERNAME}"
|
||||
DB_PASSWORD: "${APP_DB_PASSWORD}"
|
||||
|
|
@ -22,20 +22,12 @@ data:
|
|||
MAIL_FROM_ADDRESS: "${APP_MAIL_FROM_ADDRESS}"
|
||||
MAIL_FROM_NAME: "${APP_APP_NAME}"
|
||||
MAIL_LIST_CONTACTFORM: "${APP_MAIL_LIST_CONTACTFORM}"
|
||||
LDC_WEB_API_KEY: "${APP_LDC_WEB_API_KEY}"
|
||||
GOOGLE_RECAPTCHA_PRIVATE: "${APP_GOOGLE_RECAPTCHA_PRIVATE}"
|
||||
GOOGLE_RECAPTCHA_PUBLIC: "${APP_GOOGLE_RECAPTCHA_PUBLIC}"
|
||||
GOOGLE_RECAPTCHA_VERSION: "${APP_GOOGLE_RECAPTCHA_VERSION}"
|
||||
SENTRY_LARAVEL_DSN: "${APP_SENTRY_LARAVEL_DSN}"
|
||||
MATOMO_SITE_ID: "${APP_MATOMO_SITE_ID}"
|
||||
SAML2_SP_CERT_x509: "${APP_SAML2_SP_CERT_x509}"
|
||||
SAML2_SP_CERT_PRIVATEKEY: "${APP_SAML2_SP_CERT_PRIVATEKEY}"
|
||||
SAML2_CONTACT_TECHNICAL_EMAIL: "${APP_SAML2_CONTACT_TECHNICAL_EMAIL}"
|
||||
SAML2_CONTACT_SUPPORT_EMAIL: "${APP_SAML2_CONTACT_SUPPORT_EMAIL}"
|
||||
SAML2_DEFAULT_TENANT_UUID: "${APP_SAML2_DEFAULT_TENANT_UUID}"
|
||||
CRM_ENDPOINT: "${APP_CRM_ENDPOINT}"
|
||||
CRM_PASSWORD: "${APP_CRM_PASSWORD}"
|
||||
CRM_TOKEN: "${APP_CRM_TOKEN}"
|
||||
UWIL_ADMIN_SECURE_CIDR_LIST: "${APP_GLOBAL_UWIL_ADMIN_SECURE_CIDR_LIST}"
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
|
@ -71,28 +63,22 @@ spec:
|
|||
envFrom:
|
||||
- configMapRef:
|
||||
name: ${CI_PROJECT_PATH_SLUG}-config-map
|
||||
resources:
|
||||
limits:
|
||||
cpu: "${APP_CI_CPU_LIMIT}"
|
||||
memory: "${APP_CI_MEMORY_LIMIT}"
|
||||
requests:
|
||||
cpu: "${APP_CI_CPU_REQUEST}"
|
||||
memory: "${APP_CI_MEMORY_REQUEST}"
|
||||
volumeMounts:
|
||||
- name: storage
|
||||
mountPath: /app/srcs/storage
|
||||
imagePullSecrets:
|
||||
- name: docker-registry-credentials
|
||||
securityContext:
|
||||
runAsUser: 82
|
||||
runAsGroup: 82
|
||||
fsGroup: 82
|
||||
runAsUser: 33
|
||||
runAsGroup: 33
|
||||
fsGroup: 33
|
||||
fsGroupChangePolicy: "OnRootMismatch"
|
||||
volumes:
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
|
||||
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
|
|
@ -103,10 +89,10 @@ spec:
|
|||
app: ${CI_PROJECT_PATH_SLUG}-app
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
targetPort: 443
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: ${CI_PROJECT_PATH_SLUG}-ingress-route
|
||||
|
|
@ -115,15 +101,30 @@ spec:
|
|||
- web
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`${APP_DOMAIN}`) || Host(`www.${APP_DOMAIN}`)
|
||||
- match: Host(`${APP_DOMAIN}`, `www.${APP_DOMAIN}`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: ${CI_PROJECT_PATH_SLUG}-service
|
||||
port: 80
|
||||
middlewares:
|
||||
- name: redirect-no-www-to-www
|
||||
namespace: common-services
|
||||
tls:
|
||||
secretName: ${CRT_TLS_NAME}
|
||||
secretName: $APP_DOMAIN
|
||||
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: $APP_DOMAIN
|
||||
spec:
|
||||
dnsNames:
|
||||
- $APP_DOMAIN
|
||||
- www.${APP_DOMAIN}
|
||||
secretName: $APP_DOMAIN
|
||||
issuerRef:
|
||||
name: $APP_CERT_ISSUER
|
||||
kind: ClusterIssuer
|
||||
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
|
|
@ -132,9 +133,6 @@ metadata:
|
|||
name: ${CI_PROJECT_PATH_SLUG}-cronjob
|
||||
spec:
|
||||
schedule: "* * * * *"
|
||||
successfulJobsHistoryLimit: 1
|
||||
failedJobsHistoryLimit: 1
|
||||
concurrencyPolicy: Forbid
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
|
|
@ -142,38 +140,38 @@ spec:
|
|||
affinity:
|
||||
podAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- ${CI_PROJECT_PATH_SLUG}-app
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
namespaces: [$KUBE_NAMESPACE]
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- ${CI_PROJECT_PATH_SLUG}-app
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
namespaces: [$KUBE_NAMESPACE]
|
||||
containers:
|
||||
- name: ${CI_PROJECT_PATH_SLUG}-scheduled
|
||||
image: $IMAGE_TAG
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- "php"
|
||||
args:
|
||||
- "artisan"
|
||||
- "schedule:run"
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: ${CI_PROJECT_PATH_SLUG}-config-map
|
||||
volumeMounts:
|
||||
- name: storage
|
||||
mountPath: /app/srcs/storage
|
||||
imagePullSecrets:
|
||||
- name: docker-registry-credentials
|
||||
volumes:
|
||||
- name: ${CI_PROJECT_PATH_SLUG}-scheduled
|
||||
image: $IMAGE_TAG
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- "php"
|
||||
args:
|
||||
- "artisan"
|
||||
- "schedule:run"
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: ${CI_PROJECT_PATH_SLUG}-config-map
|
||||
volumeMounts:
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
|
||||
mountPath: /app/srcs/storage
|
||||
imagePullSecrets:
|
||||
- name: docker-registry-credentials
|
||||
volumes:
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
|
||||
securityContext:
|
||||
runAsUser: 82
|
||||
runAsGroup: 82
|
||||
fsGroup: 82
|
||||
runAsUser: 33
|
||||
runAsGroup: 33
|
||||
fsGroup: 33
|
||||
fsGroupChangePolicy: "OnRootMismatch"
|
||||
restartPolicy: OnFailure
|
||||
|
|
|
|||
5771
package-lock.json
generated
5771
package-lock.json
generated
File diff suppressed because it is too large
Load diff
32
package.json
32
package.json
|
|
@ -22,7 +22,7 @@
|
|||
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.5",
|
||||
"@ldc-web/cookie-notice": "^6.1.0",
|
||||
"@ldc-web/cookie-notice": "^4.0.0",
|
||||
"@sipec/vue3-tags-input": "^3.0.4",
|
||||
"@types/bootstrap": "^5.2.7",
|
||||
"@types/node": "^20.8.2",
|
||||
|
|
@ -30,23 +30,23 @@
|
|||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.36.2",
|
||||
"@vitejs/plugin-basic-ssl": "^1.0.1",
|
||||
"@vitejs/plugin-vue": "^4.5",
|
||||
"@vue/compiler-sfc": "^3.3",
|
||||
"@vue/eslint-config-typescript": "^12.0",
|
||||
"@vitejs/plugin-vue": "latest",
|
||||
"@vue/compiler-sfc": "latest",
|
||||
"@vue/eslint-config-typescript": "latest",
|
||||
"@vue/tsconfig": "^0.4.0",
|
||||
"axios": "^1.5.1",
|
||||
"bootstrap": "^5.3.2",
|
||||
"cropperjs": "^1.6.1",
|
||||
"eslint": "^8.56",
|
||||
"eslint": "latest",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-vue": "^9.19",
|
||||
"eslint-plugin-vue": "latest",
|
||||
"laravel-vite-plugin": "^0.8.1",
|
||||
"meow": "^9.0.0",
|
||||
"postcss-discard-comments": "^6.0.0",
|
||||
"prettier": "^3.1",
|
||||
"prettier": "latest",
|
||||
"print-js": "^1.6.0",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"rollup-plugin-copy": "^3.5.0",
|
||||
"sass": "^1.69",
|
||||
"sass": "latest",
|
||||
"slugify": "^1.6.6",
|
||||
"stylelint": "^15.11.0",
|
||||
"stylelint-config-idiomatic-order": "github:ream88/stylelint-config-idiomatic-order",
|
||||
|
|
@ -55,17 +55,17 @@
|
|||
"stylelint-scss": "^5.3.2",
|
||||
"sweetalert2": "^11.7.31",
|
||||
"swiper": "^11.0.5",
|
||||
"terser": "^5.26",
|
||||
"terser": "latest",
|
||||
"toastify-js": "^1.12.0",
|
||||
"ts-loader": "^9.3.1",
|
||||
"typescript": ">=3.3.1 <5.2.0",
|
||||
"typescript-eslint": "0.0.1-alpha.0",
|
||||
"typescript-eslint": "latest",
|
||||
"vite": "^4.5.1",
|
||||
"vite-plugin-babel": "^1.2",
|
||||
"vite-plugin-checker": "^0.6",
|
||||
"vite-plugin-eslint": "^1.8",
|
||||
"vite-plugin-stylelint": "^5.3",
|
||||
"vue": "^3.3",
|
||||
"vite-plugin-babel": "latest",
|
||||
"vite-plugin-checker": "latest",
|
||||
"vite-plugin-eslint": "latest",
|
||||
"vite-plugin-stylelint": "latest",
|
||||
"vue": "latest",
|
||||
"vue-eslint-parser": "^9.3.2",
|
||||
"vue-loader": "^17.3.1",
|
||||
"vue-tsc": "1.8.11"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
<rule ref="Generic.Files.LineLength"/>
|
||||
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
|
||||
<rule ref="Generic.Formatting.MultipleStatementAlignment"/>
|
||||
<rule ref="Generic.Formatting.NoSpaceAfterCast"/>
|
||||
<rule ref="Generic.Functions.CallTimePassByReference"/>
|
||||
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
|
||||
<rule ref="Generic.Metrics.CyclomaticComplexity"/>
|
||||
<rule ref="Generic.Metrics.NestingLevel"/>
|
||||
|
|
@ -42,6 +44,9 @@
|
|||
<rule ref="Generic.Strings.UnnecessaryStringConcat"/>
|
||||
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
|
||||
<rule ref="Generic.WhiteSpace.ScopeIndent"/>
|
||||
<rule ref="MySource.PHP.EvalObjectFactory"/>
|
||||
<rule ref="MySource.PHP.GetRequestData"/>
|
||||
<rule ref="MySource.PHP.AjaxNullComparison"/>
|
||||
<rule ref="PEAR.Classes.ClassDeclaration"/>
|
||||
<rule ref="PEAR.Commenting.InlineComment"/>
|
||||
<rule ref="PSR1.Classes.ClassDeclaration"/>
|
||||
|
|
@ -74,6 +79,7 @@
|
|||
<rule ref="Squiz.Scope.MemberVarScope"/>
|
||||
<rule ref="Squiz.Scope.MethodScope"/>
|
||||
<rule ref="Squiz.Scope.StaticThisUsage"/>
|
||||
<rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
|
||||
<rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
|
||||
<rule ref="Squiz.WhiteSpace.MemberVarSpacing">
|
||||
<properties>
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: $APP_DOMAIN
|
||||
spec:
|
||||
dnsNames:
|
||||
- $APP_DOMAIN
|
||||
- www.${APP_DOMAIN}
|
||||
secretName: $APP_DOMAIN
|
||||
issuerRef:
|
||||
name: $APP_CERT_ISSUER
|
||||
kind: ClusterIssuer
|
||||
---
|
||||
# Redirect with domain replacement
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: redirect-lglpronet-to-lglprofr
|
||||
spec:
|
||||
redirectRegex:
|
||||
regex: ^https://(.*)legauloisprofessionnel.net/(.*)
|
||||
replacement: https://${REDIRECT}${APP_DOMAIN}
|
||||
permanent: true
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: redirect-lglpronet-to-lglprofr
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`legauloisprofessionnel.net`) || Host(`www.legauloisprofessionnel.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: api@internal
|
||||
kind: TraefikService
|
||||
middlewares:
|
||||
- name: redirect-lglpronet-to-lglprofr
|
||||
tls:
|
||||
secretName: legauloisprofessionnel.net
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: legauloisprofessionnel.net
|
||||
spec:
|
||||
dnsNames:
|
||||
- legauloisprofessionnel.net
|
||||
- www.legauloisprofessionnel.net
|
||||
secretName: legauloisprofessionnel.net
|
||||
issuerRef:
|
||||
name: $APP_CERT_ISSUER
|
||||
kind: ClusterIssuer
|
||||
|
|
@ -14,10 +14,6 @@
|
|||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [L,R=301]
|
||||
|
||||
# Redirect /index.php/anything to /anything
|
||||
RewriteCond %{THE_REQUEST} /index\.php/([^\s?]*) [NC]
|
||||
RewriteRule ^index\.php/(.*)$ /$1 [L,R=301,NC]
|
||||
|
||||
# Send Requests To Front Controller...
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 602 KiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue