Compare commits

...
Sign in to create a new pull request.

46 commits

Author SHA1 Message Date
K Muller
baaa5b7fd6 fix: 🐛 alpine permissions 33->82 2026-10-23 18:00:14 +02:00
Noix
b013fc3bed Merge branch 'meooooooooooooow' into 'develop'
chore: ➕ add meow dependency

See merge request ldc-web/projets/tregalette!41
2026-10-22 15:57:20 +00:00
Corentin Huet
3b3ac352cf chore: ➕ add meow dependency 2026-10-22 17:49:55 +02:00
Noix
cc95950d83 Merge branch 'update-dockerfile' into 'develop'
chore: 💚 add php 8.5 arg

See merge request ldc-web/projets/tregalette!40
2026-10-22 13:17:14 +00:00
Corentin Huet
63af7b4c54 chore: 💚 add php 8.5 arg 2026-10-22 15:13:49 +02:00
Noix
cd2d35e305 Merge branch 'bump-php8.5' into 'develop'
chore: ⬆️ Bump to php8.5 + laravel13 + added saml2

See merge request ldc-web/projets/tregalette!36
2026-04-27 14:02:39 +00:00
Noah Lancien
84d1ec9578 fix: 🐛 Use the packaged admin-secure middleware 2026-04-20 09:51:06 +02:00
Noah Lancien
7aa5af78ef chore: ⬆️ Bump to php8.5 + laravel13 + added saml2 2026-04-17 16:50:06 +02:00
Noix
fbdd7d7f70 Merge branch '85-fix-verify' into 'develop'
fix: 🐛 remove auth middleware from email verification

See merge request ldc-web/projets/tregalette!35
2026-04-16 07:27:28 +00:00
Corentin Huet
e7e7210be3 fix: 🐛 remove auth middleware from email verification 2026-04-10 10:27:56 +02:00
Noah Lancien
9dd0473359 fix: handmade admin-secure while waiting for bump/remake 2026-03-24 16:02:15 +01:00
Noah Lancien
eff3e4e9a5 ci: updated image version + target port 80 + added staging-resources.yaml + define pod resources + limit cronjobs 2026-01-23 10:03:59 +01:00
karl.muller
ab2cfd8fd1 Merge branch 'issue-81' into 'develop'
fix: 🐛 error on productController@productFiltered from sentry

See merge request ldc-web/projets/tregalette!33
2025-04-03 13:22:15 +00:00
Karl Muller
e339369118 fix: 🐛 error on productController@productFiltered from sentry 2025-04-03 13:18:48 +00:00
Noah Lancien
818c6f3481 Merge branch 'issue-49-feedback' into develop 2025-03-28 11:25:30 +01:00
Noah Lancien
c1bad194ff style: reduce space between pictos in commitments page 2025-03-28 11:25:07 +01:00
Noah Lancien
f3fadfd9e5 fix: style in registration form 2025-03-25 12:03:10 +01:00
Noah Lancien
13ef97b332 fix: wording on privacy policy link in footer 2025-03-25 11:48:56 +01:00
Noah Lancien
cdf05264b0 fix: wording on registration form 2025-03-25 11:40:40 +01:00
noah.lancien
355f0d8681 Merge branch 'issue-80-game-rules' into 'develop'
feat: add static page game rules

See merge request ldc-web/projets/tregalette!32
2025-03-25 08:44:10 +00:00
Corentin Huet
ccb71ad66d feat: add static page game rules 2025-03-24 16:21:57 +01:00
Vincent BRIDIER
4ab26676a6 Merge branch 'issue-49' into 'develop'
Issue 49

See merge request ldc-web/projets/tregalette!31
2025-03-06 08:12:46 +00:00
Vincent BRIDIER
60372ed206 Merge branch 'issue-35' into 'develop'
fix: 💄 center logo Regalette in footer

See merge request ldc-web/projets/tregalette!29
2025-03-06 08:12:17 +00:00
Vincent BRIDIER
5e4d617582 Merge branch 'issue-33' into 'develop'
fix: 🍱 change the suzette-contact image

See merge request ldc-web/projets/tregalette!30
2025-03-05 13:29:57 +00:00
Nicolas Demangeat
45a178e12e fix: 🔥 remove unuse scss 2025-03-05 11:38:03 +01:00
Nicolas Demangeat
5da6dc8051 fix: 💄 change the size and place of the commitments picto 2025-03-05 11:35:49 +01:00
Nicolas Demangeat
be58c744bf fix: 🍱 change the suzette-contact image 2025-03-05 11:10:23 +01:00
Nicolas Demangeat
c015e7d0ed fix: 💄 center logo Regalette in footer 2025-03-05 10:54:03 +01:00
Vincent BRIDIER
bed470c915 Merge branch 'issue-79-wording' into 'develop'
fix: 💬 wording on commitments page

See merge request ldc-web/projets/tregalette!28
2025-03-04 09:20:56 +00:00
Vincent BRIDIER
848c1007fa Merge branch 'issue-76-mail-display' into 'develop'
fix: characters were still encoded in the sended mail

See merge request ldc-web/projets/tregalette!27
2025-03-04 09:20:49 +00:00
Vincent BRIDIER
cb91fe413b Merge branch 'rgpd-issues' into 'develop'
fix: Updated cookie-notice and added recaptcha on contact + register forms. #71 #72 #73 #74

See merge request ldc-web/projets/tregalette!26
2025-03-04 09:20:41 +00:00
Noah Lancien
2dc19cba29 fix: 💬 wording on commitments page 2025-03-04 10:00:02 +01:00
Noah Lancien
fff92acbb9 fix: characters were still encoded in the sended mail 2025-03-03 17:44:00 +01:00
Noah Lancien
80813ab9e5 fix: Updated cookie-notice and added recaptcha on contact + register forms. #71 #72 #73 #74 2025-03-03 12:31:26 +01:00
Vincent BRIDIER
f37a549e9f Merge branch 'newsletter' into 'develop'
feat: Add Newsletter 01-2025

See merge request ldc-web/projets/tregalette!25
2025-01-23 14:49:58 +00:00
Sebastien Hattry
d961eaadca feat: Add Newsletter 01-2025 2025-01-23 12:03:57 +01:00
Karl Muller
71ca13a16b fix: composer update to fix CVE 2025-01-13 13:23:54 +00:00
noah.lancien
4c10b43d54 Merge branch 'newsletter' into 'develop'
fix: change wording

See merge request ldc-web/projets/tregalette!24
2024-10-21 07:54:45 +00:00
Sebastien Hattry
bee7b69635 fix: change wording 2024-10-21 09:24:38 +02:00
Vincent BRIDIER
3f20647e1e Merge branch 'unsubscribe-nl' into 'develop'
feat: ✨ add unsubscribe from newsletter

See merge request ldc-web/projets/tregalette!23
2024-10-15 17:37:00 +00:00
Sebastien Hattry
7b259943c4 feat: ✨ add unsubscribe from newsletter 2024-10-15 17:46:47 +02:00
noah.lancien
f4592947a4 Merge branch 'newsletter' into 'develop'
feat: ✨ add assets

See merge request ldc-web/projets/tregalette!22
2024-10-04 13:50:51 +00:00
Sebastien Hattry
640932ea3c feat: ✨ add assets 2024-10-04 15:41:42 +02:00
Noah Lancien
489bf1d909 Updated manifest.yaml 2024-07-31 09:41:36 +02:00
Noah Lancien
0044a56921 Updated production-resources.yaml 2024-07-31 09:37:40 +02:00
Noah Lancien
0b316ab818 Updated manifest.yaml 2024-07-31 09:22:36 +02:00
88 changed files with 9294 additions and 3170 deletions

View file

@ -61,6 +61,15 @@ GOOGLE_RECAPTCHA_PUBLIC=
GOOGLE_RECAPTCHA_PRIVATE=
GOOGLE_RECAPTCHA_VERSION=
# ADMIN SECURE
# - API KEY
LDC_WEB_API_KEY=""
# 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=

View file

@ -1,5 +1,6 @@
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/ldcweb-production-8.2:latest
ARG PHP_8_5_TAG=latest
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.5:${PHP_8_5_TAG}
COPY --chown=www-data:www-data . /app/srcs
USER root
RUN chmod -R 755 /app/srcs/storage
USER www-data
USER www-data

View file

@ -19,6 +19,7 @@ enum StaticPageType: int
case history = 9;
case commitments = 10;
case news = 11;
case rules = 12;
/**
* Optionnal labels definition.
@ -35,5 +36,6 @@ enum StaticPageType: int
self::history->name => 'Notre Histoire',
self::commitments->name => 'Nos Engagements',
self::news->name => 'Actualités',
self::rules->name => 'Règlement du jeu',
];
}

View file

@ -28,7 +28,7 @@ class VerificationController extends Controller
*/
public function __construct()
{
$this->middleware('auth:frontend');
$this->middleware('auth:frontend')->except('verify');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
@ -58,7 +58,7 @@ class VerificationController extends Controller
public function verify(Request $request): JsonResponse|RedirectResponse
{
/** @var \App\Models\Customer */
$user = $request->user('frontend');
$user = Customer::findOrFail($request->route('id'));
if (!hash_equals((string)$request->route('id'), (string)$user->getKey())) {
throw new AuthorizationException();

View file

@ -4,10 +4,18 @@ namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\UnsubscribeNewsletterRequest;
use App\Models\KlubBloc;
use App\Models\News;
use App\Models\Range;
use App\Models\StaticPage;
use Illuminate\Support\Facades\Log;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
use LDC\LDCCRM\Exceptions\ValidationException;
use LDC\LDCCRM\Models\Customer;
use LDC\LDCCRM\Models\SingleOptin;
class HomeController extends Controller
{
@ -27,4 +35,54 @@ class HomeController extends Controller
return view('fo.pages.home', compact('staticPageModel', 'rangeModels', 'klubBloc', 'newsModels'));
}
/**
* unsubscribeNewsletter method
*
* @param \App\Http\Requests\Fo\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)) {
if ($customer = Customer::find($hashcode)) {
$customer->opt_in = false;
// ! Les données peuvent être parsés en retour de la crm et inconsitantes (Héritage vielle crm).
try {
$customer->save();
} catch (ValidationException $e) {
$error = null;
}
} else {
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');
}
}

View file

@ -46,6 +46,10 @@ class ProductController extends Controller
*/
public function productsFiltered(): \Illuminate\Http\JsonResponse
{
if (!request()->has('range_id') or !request()->has('page')) {
abort(404);
}
$productModels = Product::query()
->where('published', true)
->where('range_id', request()->range_id)

View file

@ -23,6 +23,19 @@ class StaticPageController extends Controller
return view('fo.pages.legals', ['staticPageModel' => $legalPage]);
}
/**
* Game rules show
*
* @param \App\Models\StaticPage $rulesPage
* @return \Illuminate\Contracts\View\View
*/
public function rules(StaticPage $rulesPage)
{
$rulesPage = StaticPage::query()->where('type', StaticPageType::rules)->firstOrFail();
return view('fo.pages.rules', ['staticPageModel' => $rulesPage]);
}
/**
* Policies show
*

View file

@ -40,6 +40,12 @@ class Kernel extends HttpKernel
\App\Http\Middleware\SecureHeaders::class
],
'saml' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
],
'api' => [
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
@ -66,5 +72,6 @@ class Kernel extends HttpKernel
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'htmlsanitize' => \App\Http\Middleware\HtmlSanitizer::class,
'crm_questions' => \App\Http\Middleware\CrmMiddlewareQuestions::class,
'json_only' => \App\Http\Middleware\JsonOnly::class,
];
}

View file

@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
class JsonOnly
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, \Closure $next)
{
if (
(!($request->isJson() or $request->expectsJson()))
) {
abort(400, 'Invalid JSON');
}
return $next($request);
}
}

View file

@ -27,8 +27,6 @@ class ContactFormRequest extends FormRequest
'city' => Str::of($this->post('city'))->value(),
'postal_code' => Str::of($this->post('postal_code'))->value(),
'message' => Str::of($this->post('message'))->value(),
// * boolean
'terms' => $this->post('terms') ? true : false,
// * integer
'batch_number' => $this->post('batch_number') ? intval($this->post('batch_number')) : null,
]);
@ -66,8 +64,6 @@ class ContactFormRequest extends FormRequest
'postal_code' => 'present|min:0|postal_code:FR|max:25',
'message' => 'present|min:20|max:35656',
'file' => 'nullable|file|mimes:jpg,jpeg,png,pdf|max:2048',
// * obligatoire
'terms' => 'required|boolean|accepted',
// * Conditional fields
// * obligatoire si type == product
@ -99,7 +95,6 @@ class ContactFormRequest extends FormRequest
return [
'subject' => trans('validation.attributes.subject'),
'file' => trans('validation.custom.attachment'),
'terms' => trans('validation.attributes.terms'),
'expiration_date' => trans('validation.custom.expiration_date'),
'batch_number' => trans('validation.custom.batch_number'),
'job_title' => trans('validation.custom.job_title'),
@ -115,7 +110,8 @@ class ContactFormRequest extends FormRequest
{
return [
'postal_code' => trans('validation.custom.postal_code', [
'countries' => Country::france->label(), 'examples' => 72000
'countries' => Country::france->label(),
'examples' => 72000
]),
'phone.phone' => trans('validation.custom.phone'),
];

View file

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Fo;
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'
];
}
}

View file

@ -5,14 +5,11 @@ namespace App\Mail;
use App\Enums\Contact\ObjectEnum;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Mail\Markdown;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Str;
class SendContactMail extends Mailable
{
@ -34,33 +31,6 @@ class SendContactMail extends Mailable
public function __construct(\stdClass $data)
{
$this->data = clone $data;
$this->sanitizeStringInputs();
}
/**
* Sanitizes user message
*
* ! This is not recursive !
* * Prevent xss injection via markdown interpretation.
*
* La solution devrai etre de filtrer en sortie, mais il n'est pas possible de
*
* @return void
*/
private function sanitizeStringInputs(): void
{
$this->data = (object)Arr::map((array)$this->data, function ($el) {
if (is_string($el)) {
$el = \htmlspecialchars(\strip_tags(Blade::render(
(string)Markdown::parse($el)
)));
$el = Str::of($el)->replaceMatches(
'/[^\p{L}0-9\n\s\@\.\:\-\_\?\!\;\(\)\+\-\/\\\=]+/us',
''
)->trim()->wordWrap(75, "\n", true)->toString();
}
return $el;
});
}
/**
@ -71,8 +41,13 @@ class SendContactMail extends Mailable
public function envelope(): \Illuminate\Mail\Mailables\Envelope
{
return new Envelope(
from: new Address(\config('mail.from.address'), \config('mail.from.name')),
subject: sprintf('%s - %s', ObjectEnum::make($this->data->type)->label() ??
__('Nouveau message'), config('app.name')),
replyTo: [new Address(
$this->data->email,
sprintf('%s %s', $this->data->first_name, $this->data->last_name)
)],
);
}

View file

@ -3,10 +3,16 @@
namespace App\Providers;
use App\Listeners\PasswordHasReset;
use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Session;
use Slides\Saml2\Events\SignedIn;
class EventServiceProvider extends ServiceProvider
{
@ -33,4 +39,45 @@ class EventServiceProvider extends ServiceProvider
{
return false;
}
/**
* Register any events for your application.
*
* @return void
*/
public function boot(): void
{
Event::listen('Slides\Saml2\Events\SignedIn', function (SignedIn $event) {
$messageId = $event->getAuth()->getLastMessageId();
if (Cache::get(config('cache.prefix') . "_saml_message_id_" . $messageId)) {
logger()->error(
'SAML MESSAGE ID HANDLER',
['error' => 'Message ID : ' . $messageId . " replayed !"]
);
abort(403);
} else {
// Cache for 8h.
Cache::put(config('cache.prefix') . "_saml_message_id_" . $messageId, $messageId, 28800);
}
$user = $event->getSaml2User();
$email = $user->getNameId();
$lUser = User::query()->where('email', $email)->first();
if (!$lUser) {
abort(403);
}
Auth::guard('backend')->login($lUser);
session(['sessionIndex' => $user->getSessionIndex()]);
$lUser->last_connection = now();
$lUser->saveQuietly();
});
Event::listen('Slides\Saml2\Events\SignedOut', function () {
Auth::guard('backend')->logout();
Session::save();
});
}
}

View file

@ -18,6 +18,8 @@ trait ActivityLog
*/
public static function bootActivityLog(): void
{
static::observe(ModelObserver::class);
static::whenBooted(function () {
static::observe(ModelObserver::class);
});
}
}

View file

@ -4,33 +4,34 @@
"type": "project",
"description": "Tregalette website.",
"require": {
"php": "^8.2",
"php": "^8.5",
"axlon/laravel-postal-code-validation": "^3.4",
"diglactic/laravel-breadcrumbs": "^8.0",
"diglactic/laravel-breadcrumbs": "*",
"dxw/cidr": "^3.2",
"guzzlehttp/guzzle": "^7.2",
"jenssegers/agent": "^2.6",
"laravel/framework": "^10.0",
"laravel/tinker": "^2.8",
"laravel/framework": "^13.0",
"laravel/tinker": "^3.0",
"laravel/ui": "^4.2",
"ldc/ldccrmv4client": "^4.0",
"ldc/sitemap-generator": "^2.0",
"ldc/web-admin-secure-laravel": "^2.0",
"mews/purifier": "^3.4",
"propaganistas/laravel-phone": "^5.0",
"propaganistas/laravel-phone": "^6.0",
"scaler-tech/laravel-saml2": "^2.7",
"sentry/sentry-laravel": "*",
"uwil/k8s-laravel": "*"
"uwil/admin-secure-laravel": "^5.1",
"uwil/k8s-laravel": "*",
"uwil/sitemap-generator": "^7.0"
},
"require-dev": {
"fakerphp/faker": "^1.9.1",
"laravel-lang/common": "^4.0",
"laravel-lang/common": "^6.0",
"laravel/pint": "^1.0",
"laravel/sail": "^1.18",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^7.0",
"phpunit/phpunit": "^10.0",
"nunomaduro/collision": "^8.0",
"phpunit/phpunit": "^12.0",
"slevomat/coding-standard": "^8.10",
"spatie/laravel-ignition": "^2.0",
"thedoctor0/laravel-factory-generator": "^1.2"
"spatie/laravel-ignition": "^2.0"
},
"autoload": {
"psr-4": {

6390
composer.lock generated

File diff suppressed because it is too large Load diff

6
config/admin-secure.php Normal file
View file

@ -0,0 +1,6 @@
<?php
return [
'cidrList' => env('UWIL_ADMIN_SECURE_CIDR_LIST'),
'cidrProjectAllowedList' => env('UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST')
];

397
config/saml2.php Normal file
View file

@ -0,0 +1,397 @@
<?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)
];

View file

@ -0,0 +1,38 @@
<?php
use App\Enums\Users\RoleEnum;
use App\Models\User;
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');
$table->date('last_connection')->nullable()->after('role');
});
}
/**
* 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');
$table->dropColumn('last_connection');
});
}
};

View file

@ -129,5 +129,15 @@ class StaticPageSeeder extends Seeder
'content' => \clean(\fake()->randomHtml(2, 3)),
]
)->saveQuietly();
StaticPage::query()->make(
[
'seo_title' => 'Seo title pour la page Règlement du jeu',
'seo_description' => 'Seo description pour la page Règlement du jeu',
'title' => 'Règlement du jeu',
'slug' => Str::slug('Règlement du jeu'),
'type' => StaticPageType::rules,
'content' => \clean(\fake()->randomHtml(2, 3)),
]
)->saveQuietly();
}
}

View file

@ -8,9 +8,9 @@ data:
APP_ENV: "${APP_APP_ENV}"
APP_KEY: "${APP_APP_KEY}"
APP_DEBUG: "${APP_APP_DEBUG}"
APP_URL: "https://www.${APP_DOMAIN}"
APP_URL: "https://${REDIRECT}${APP_DOMAIN}"
LOG_CHANNEL: "k8s"
DB_HOST: "mariadb-service.common-services"
DB_HOST: "${APP_DB_HOST}"
DB_DATABASE: "${APP_DB_DATABASE}"
DB_USERNAME: "${APP_DB_USERNAME}"
DB_PASSWORD: "${APP_DB_PASSWORD}"
@ -27,7 +27,6 @@ data:
MESBR_REF_SITE: "${APP_MESBR_REF_SITE}"
MESBR_REF_CAMP: "${APP_MESBR_REF_CAMP}"
MESBR_ENDPOINT: "${APP_MESBR_ENDPOINT}"
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}"
@ -39,6 +38,12 @@ data:
MAIL_CONTACT_PARTNERSHIP: "${APP_MAIL_CONTACT_PARTNERSHIP}"
MAIL_CONTACT_COMMERCIAL: "${APP_MAIL_CONTACT_COMMERCIAL}"
MAIL_CONTACT_VARIOUS: "${APP_MAIL_CONTACT_VARIOUS}"
UWIL_ADMIN_SECURE_CIDR_LIST: "${APP_GLOBAL_UWIL_ADMIN_SECURE_CIDR_LIST}"
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}"
---
apiVersion: v1
@ -74,22 +79,28 @@ 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: 33
runAsGroup: 33
fsGroup: 33
runAsUser: 82
runAsGroup: 82
fsGroup: 82
fsGroupChangePolicy: "OnRootMismatch"
volumes:
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
---
apiVersion: v1
kind: Service
@ -100,10 +111,10 @@ spec:
app: ${CI_PROJECT_PATH_SLUG}-app
ports:
- port: 80
targetPort: 443
targetPort: 80
---
apiVersion: traefik.containo.us/v1alpha1
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ${CI_PROJECT_PATH_SLUG}-ingress-route
@ -112,30 +123,15 @@ spec:
- web
- websecure
routes:
- match: Host(`${APP_DOMAIN}`, `www.${APP_DOMAIN}`)
- match: Host(`${APP_DOMAIN}`) || Host(`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: $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
secretName: ${CRT_TLS_NAME}
---
apiVersion: batch/v1
@ -144,6 +140,9 @@ metadata:
name: ${CI_PROJECT_PATH_SLUG}-cronjob
spec:
schedule: "* * * * *"
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
@ -151,38 +150,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
- 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
- name: docker-registry-credentials
volumes:
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
- name: storage
persistentVolumeClaim:
claimName: ${CI_PROJECT_PATH_SLUG}-pvc-storage
securityContext:
runAsUser: 33
runAsGroup: 33
fsGroup: 33
runAsUser: 82
runAsGroup: 82
fsGroup: 82
fsGroupChangePolicy: "OnRootMismatch"
restartPolicy: OnFailure

152
package-lock.json generated
View file

@ -5,6 +5,9 @@
"packages": {
"": {
"name": "srcs",
"dependencies": {
"meow": "^9.0.0"
},
"devDependencies": {
"@babel/core": "^7.22.11",
"@babel/types": "^7.21.2",
@ -12,7 +15,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": "^3.1.2",
"@ldc-web/cookie-notice": "^6.1.0",
"@sipec/vue3-tags-input": "^3.0.4",
"@types/bootstrap": "^5.2.7",
"@types/node": "^20.8.2",
@ -88,7 +91,6 @@
"version": "7.23.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
"integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.23.4",
"chalk": "^2.4.2"
@ -269,7 +271,6 @@
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
@ -301,7 +302,6 @@
"version": "7.23.4",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
"integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
@ -1050,9 +1050,9 @@
"dev": true
},
"node_modules/@ldc-web/cookie-notice": {
"version": "3.1.3",
"resolved": "https://lab.s-web.fr/api/v4/projects/50/packages/npm/@ldc-web/cookie-notice/-/@ldc-web/cookie-notice-3.1.3.tgz",
"integrity": "sha1-+VPwI1VOhD+nWZeutLhT+on02CU=",
"version": "6.1.0",
"resolved": "https://lab.s-web.fr/api/v4/projects/50/packages/npm/@ldc-web/cookie-notice/-/@ldc-web/cookie-notice-6.1.0.tgz",
"integrity": "sha1-bzewvM6mGuWr3Ju8/HWkxXm60+A=",
"dev": true
},
"node_modules/@nodelib/fs.scandir": {
@ -1202,8 +1202,7 @@
"node_modules/@types/minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
"dev": true
"integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag=="
},
"node_modules/@types/node": {
"version": "20.10.5",
@ -1217,8 +1216,7 @@
"node_modules/@types/normalize-package-data": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
"dev": true
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="
},
"node_modules/@types/semver": {
"version": "7.5.6",
@ -2273,7 +2271,6 @@
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
},
@ -2427,7 +2424,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
"integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -2608,9 +2604,6 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=6"
}
@ -2619,9 +2612,6 @@
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
"integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"camelcase": "^5.3.1",
"map-obj": "^4.0.0",
@ -2658,7 +2648,6 @@
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
@ -2733,7 +2722,6 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": {
"color-name": "1.1.3"
}
@ -2741,8 +2729,7 @@
"node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
},
"node_modules/colord": {
"version": "2.9.3",
@ -2899,7 +2886,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -2908,7 +2894,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz",
"integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==",
"dev": true,
"dependencies": {
"decamelize": "^1.1.0",
"map-obj": "^1.0.0"
@ -2924,7 +2909,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
"integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -3039,7 +3023,6 @@
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"dev": true,
"dependencies": {
"is-arrayish": "^0.2.1"
}
@ -3198,7 +3181,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
@ -3887,7 +3869,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -4119,7 +4100,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
"integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
"dev": true,
"engines": {
"node": ">=6"
}
@ -4138,7 +4118,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": {
"node": ">=4"
}
@ -4208,7 +4187,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.2"
},
@ -4229,7 +4207,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
"integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
@ -4241,7 +4218,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
@ -4252,8 +4228,7 @@
"node_modules/hosted-git-info/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/html-tags": {
"version": "3.3.1",
@ -4320,9 +4295,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -4382,8 +4354,7 @@
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"dev": true
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
},
"node_modules/is-bigint": {
"version": "1.0.4",
@ -4444,7 +4415,6 @@
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
"integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
"dev": true,
"dependencies": {
"hasown": "^2.0.0"
},
@ -4549,7 +4519,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
"integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -4711,8 +4680,7 @@
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/js-yaml": {
"version": "4.1.0",
@ -4747,8 +4715,7 @@
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
@ -4796,7 +4763,6 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -4839,8 +4805,7 @@
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
"node_modules/loader-runner": {
"version": "4.3.0",
@ -4936,7 +4901,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
"dev": true,
"engines": {
"node": ">=8"
},
@ -4964,9 +4928,7 @@
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz",
"integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==",
"dev": true,
"optional": true,
"peer": true,
"license": "MIT",
"dependencies": {
"@types/minimist": "^1.2.0",
"camelcase-keys": "^6.2.2",
@ -4992,9 +4954,6 @@
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
"integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
},
@ -5056,7 +5015,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
"dev": true,
"engines": {
"node": ">=4"
}
@ -5087,7 +5045,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
"integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
"dev": true,
"dependencies": {
"arrify": "^1.0.1",
"is-plain-obj": "^1.1.0",
@ -5156,7 +5113,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
"integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
"dev": true,
"dependencies": {
"hosted-git-info": "^4.0.1",
"is-core-module": "^2.5.0",
@ -5171,7 +5127,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
@ -5183,7 +5138,6 @@
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
@ -5197,8 +5151,7 @@
"node_modules/normalize-package-data/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/normalize-path": {
"version": "3.0.0",
@ -5381,9 +5334,6 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=6"
}
@ -5404,7 +5354,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1",
@ -5428,7 +5377,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -5454,9 +5402,7 @@
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"peer": true
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/path-type": {
"version": "4.0.0",
@ -5676,9 +5622,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -5697,9 +5640,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
"integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"@types/normalize-package-data": "^2.4.0",
"normalize-package-data": "^2.5.0",
@ -5714,9 +5654,6 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
"integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"find-up": "^4.1.0",
"read-pkg": "^5.2.0",
@ -5733,9 +5670,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
@ -5748,9 +5682,6 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"p-locate": "^4.1.0"
},
@ -5762,9 +5693,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"p-try": "^2.0.0"
},
@ -5779,9 +5707,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"p-limit": "^2.2.0"
},
@ -5793,9 +5718,6 @@
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -5803,18 +5725,12 @@
"node_modules/read-pkg/node_modules/hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true,
"optional": true,
"peer": true
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
},
"node_modules/read-pkg/node_modules/normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"hosted-git-info": "^2.1.4",
"resolve": "^1.10.0",
@ -5826,9 +5742,6 @@
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"optional": true,
"peer": true,
"bin": {
"semver": "bin/semver"
}
@ -5837,9 +5750,6 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
"integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -5860,9 +5770,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"indent-string": "^4.0.0",
"strip-indent": "^3.0.0"
@ -5908,8 +5815,6 @@
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"dev": true,
"peer": true,
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
@ -6341,7 +6246,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
"integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
"dev": true,
"dependencies": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
@ -6350,14 +6254,12 @@
"node_modules/spdx-exceptions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
"dev": true
"integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
},
"node_modules/spdx-expression-parse": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
"integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
"dev": true,
"dependencies": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
@ -6366,8 +6268,7 @@
"node_modules/spdx-license-ids": {
"version": "3.0.16",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz",
"integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==",
"dev": true
"integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw=="
},
"node_modules/string-width": {
"version": "4.2.3",
@ -6457,9 +6358,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"min-indent": "^1.0.0"
},
@ -6907,7 +6805,6 @@
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
},
@ -6953,8 +6850,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"peer": true,
"engines": {
"node": ">= 0.4"
},
@ -7140,9 +7035,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
"integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -7530,7 +7422,6 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"dev": true,
"dependencies": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
@ -8419,7 +8310,6 @@
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
"engines": {
"node": ">=10"
}

View file

@ -20,7 +20,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": "^3.1.2",
"@ldc-web/cookie-notice": "^6.1.0",
"@sipec/vue3-tags-input": "^3.0.4",
"@types/bootstrap": "^5.2.7",
"@types/node": "^20.8.2",
@ -68,5 +68,8 @@
"vue-eslint-parser": "^9.3.2",
"vue-loader": "^17.3.1",
"vue-tsc": "1.8.11"
},
"dependencies": {
"meow": "^9.0.0"
}
}

View file

@ -30,8 +30,6 @@
<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"/>
@ -45,9 +43,6 @@
<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"/>
@ -80,7 +75,6 @@
<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>

13
production-resources.yaml Normal file
View file

@ -0,0 +1,13 @@
---
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View file

@ -1,26 +1,26 @@
<?php
// * Version 3.1.2
// phpcs:disable
return [
'button_customize_cookies' => 'Customize cookies',
'button_close_cookies' => 'Close cookie window',
'button_forbid' => 'Prohibit',
'button_allow' => 'Allow',
'button_forbid_all' => 'Reject all',
'button_toggle_cookie' => 'Accept or refuse',
'button_forbid_all' => 'Refuse all',
'button_allow_all' => 'Accept all',
'button_allow' => 'Accept',
'button_forbid_all_title' => 'Refuse all cookies and close the cookies panel',
'button_allow_all_title' => 'Accept all cookies and close the cookies panel',
'button_customize' => 'Customize',
'button_back' => 'Back',
'button_validate_and_close' => 'Confirm and close',
'button_title_open_new_tab' => 'Open link in new tab',
'banner_title' => 'The :site_name website uses cookies!',
'banner_text' => 'We use cookies to ensure the proper functioning of our site and for analytical purposes.
You can change your mind at any time by clicking on the icon on any page of our site.
By authorizing these third-party services, you agree to the deposit and reading of cookies and the use of tracking technologies necessary for their proper operation.',
'panel_title' => 'Cookie management panel',
'modal_title' => 'Cookie management window',
'panel_content' => 'Cookie management panel content',
'panel_subtitle' => 'Your privacy is our priority',
'panel_details' => 'The functionalities of this site are based on services provided by third parties. If you accept, these third parties will deposit cookies that will enable you to view content on the site hosted by these third parties. Through these cookies, these third parties will collect and use your browsing data for their own purposes, in accordance with their privacy policy (link below). This page allows you to give or withdraw your consent, either globally or service by service.',
'picture_cookie_title' => 'Image of a nice big cookie',
'navigation_title' => 'Cookies panel navigation',
'custom' => [
'matomo' => [
'title' => 'Matomo',
@ -31,7 +31,8 @@ return [
'title' => 'reCAPTCHA',
'description' => 'The purpose of the cookies placed on forms via the recaptcha is to prevent them from being submitted by robots.',
'labelLink' => 'Learn more',
'warning' => 'You must accept cookies to send the form',
'warning' => 'You must accept reCAPTCHA cookies to send the form',
'accept' => 'Accept this cookie to use the forms'
]
]
];

View file

@ -1,37 +1,38 @@
<?php
// * Version 3.1.2
// phpcs:disable
return [
'button_customize_cookies' => 'Personnaliser les cookies',
'button_close_cookies' => 'Fermer la fenêtre des cookies',
'button_forbid' => 'Interdire',
'button_allow' => 'Autoriser',
'button_toggle_cookie' => 'Autoriser ou refuser',
'button_forbid_all' => 'Tout refuser',
'button_allow_all' => 'Tout accepter',
'button_allow' => 'Autoriser',
'button_forbid_all_title' => 'Refuser tous les cookies et fermer le panneau des cookies',
'button_allow_all_title' => 'Accepter tous les cookies et fermer le panneau des cookies',
'button_customize' => 'Personnaliser',
'button_back' => 'Retour',
'button_validate_and_close' => 'Valider et fermer',
'button_title_open_new_tab' => 'Ouvrir le lien dans un nouvel onglet',
'banner_title' => 'Le site internet :site_name utilise des cookies !',
'banner_text' => 'Nous utilisons des cookies pour nous assurer du bon fonctionnement de notre site et à des fins analytiques.
Vous pouvez changer d\'avis à tout moment en cliquant sur l\'icône présente sur chaque page de notre site.
En autorisant ces services tiers, vous acceptez le dépôt et la lecture de cookies et l\'utilisation de technologies de suivi nécessaires à leur bon fonctionnement.',
'panel_title' => 'Panneau de gestion des cookies',
Vous pouvez changer d’avis à tout moment en cliquant sur l’icône présente sur chaque page de notre site.
En autorisant ces services tiers, vous acceptez le dépôt et la lecture de cookies et l’utilisation de technologies de suivi nécessaires à leur bon fonctionnement.',
'modal_title' => 'Fenêtre de gestion de cookies',
'panel_content' => 'Contenu du panneau des cookies',
'panel_subtitle' => 'Le respect de votre vie privée est notre priorité',
'panel_details' => 'Les fonctionnalités de ce site s’appuient sur des services proposés par des tiers. Si vous acceptez, ces tiers déposeront des cookies qui vous permettront de visualiser sur le site du contenu hébergé par ces tiers. Via ces cookies, ces tiers collecteront et utiliseront vos données de navigation pour des finalités qui leur sont propres, conformément à leur politique de confidentialité (lien ci-dessous). Cette page vous permet de donner ou de retirer votre consentement, soit globalement soit service par service.',
'picture_cookie_title' => 'Image d’un bon gros cookie',
'navigation_title' => 'Navigation du panneau des cookies',
'custom' => [
'matomo' => [
'title' => 'Matomo',
'description' => 'Les services de mesure d\'audience permettent de générer des statistiques de fréquentation utiles à l\'amélioration du site.',
'description' => 'Les services de mesure d’audience permettent de générer des statistiques de fréquentation utiles à l’amélioration du site.',
'labelLink' => 'En apprendre plus',
],
'recaptcha' => [
'title' => 'reCAPTCHA',
'description' => 'Les cookies qui sont déposés via le recaptcha sur les formulaires ont pour finalité d\'empêcher que ceux-ci ne soient soumis par des robots.',
'description' => 'Les cookies qui sont déposés via le recaptcha sur les formulaires ont pour finalité d’empêcher que ceux-ci ne soient soumis par des robots.',
'labelLink' => 'En apprendre plus',
'warning' => 'Vous devez accepter les cookies pour envoyer le formulaire',
'warning' => 'Vous devez accepter les cookies reCAPTCHA pour envoyer le formulaire',
'accept' => 'Acceptez ce cookie pour utiliser les formulaires'
]
]
];

View file

@ -34,30 +34,6 @@
position: relative;
}
}
.pictogram {
position:relative;
margin-top: 2rem;
margin-bottom: 2rem;
&:last-of-type {
float: right;
}
@include media-breakpoint-up(md) {
position:absolute;
top: 0;
&:first-of-type {
left: -4rem;
}
&:last-of-type {
right: -4rem;
float: inherit;
}
}
}
}
.bg-environment {

View file

@ -210,18 +210,6 @@ document.addEventListener("DOMContentLoaded", function () {
animateSeagull();
}
// document.addEventListener("scroll", () => {
// const seagullsScroll = document.getElementById("seagulls-scroll");
// if (seagullsScroll) {
// // Animate the seagulls on scroll
// const seagullsOffset = Number.parseInt(String(seagullsScroll.dataset.offset ?? 16));
// const percent = (- (100 * seagullsScroll.getBoundingClientRect().top / window.innerHeight - 100) );
// if (percent > 0 && percent < 100) {
// seagullsScroll.style.top = `calc(${percent}% - ${(seagullsOffset + seagullsScroll.getBoundingClientRect().height) * percent / 100}px)`;
// }
// }
// });
// * Keyboard navigation for news slider
const newsSlider = document.getElementById("swiper-news");
if (newsSlider) {

View file

@ -1,6 +1,8 @@
import CookieNotice from "@ldc-web/cookie-notice";
import axios from "axios";
import * as bootstrap from "bootstrap";
import bsTooltips from "./../../modules/bsTooltips";
import recaptcha from "./../../modules/recaptcha";
/**
* We'll load the axios HTTP library which allows us to easily issue requests
@ -19,3 +21,6 @@ window.axios = axios;
window.bootstrap = bootstrap;
bsTooltips.methods.initTooltips();
window.CookieNotice = CookieNotice;
window.Recaptcha = recaptcha;

View file

@ -2,6 +2,7 @@ export { };
import CookieNotice from "@ldc-web/cookie-notice";
import type VueTagsInput from "@sipec/vue3-tags-input";
import { AxiosStatic } from "axios";
import { type recaptcha } from "./modules/recaptcha";
// * Enum
interface EnumInterface {
@ -76,6 +77,10 @@ declare global {
Swal: Function;
vueDebug: boolean | undefined;
CookieNotice: typeof CookieNotice;
__CN_Recaptcha: Function;
__CN_Recaptcha_Reset: Function;
__CN_Recaptcha_Loaded: Function;
Recaptcha: recaptcha;
__SYSTEM: {
_asset: string;
_locale: string;

View file

@ -0,0 +1,46 @@
export default {
methods: {
// * Set recaptcha window variables and init it.
init(forms: Array<HTMLFormElement>) {
if(forms.length) {
window.__CN_Recaptcha = function () {
forms.map((form) => {
if (!form.querySelector(".r_captcha > div")) {
const newDiv = document.createElement("div");
newDiv.classList.add("g-recaptcha");
form.querySelector(".r_captcha")?.appendChild(newDiv);
}
form.inert = true;
});
(function(d, t) {
const g = d.createElement(t) as HTMLIFrameElement,
s = d.getElementsByTagName(t)[0];
g.src = "https://www.google.com/recaptcha/api.js?render=explicit&onload=__CN_Recaptcha_Loaded";
s.parentNode?.insertBefore(g, s);
}(document, "script"));
};
window.__CN_Recaptcha_Reset = function() {
forms.map((form) => {
form.querySelector(".r_captcha > div")?.remove();
form.inert = true;
});
};
window.__CN_Recaptcha_Loaded = function() {
forms.map((form) => {
form.inert = false;
if (form.querySelector(".r_captcha > div") !== null) {
// @ts-ignore
grecaptcha.render(document.querySelector(".r_captcha > div"), {
"sitekey": form.dataset.recaptchaKey ?? ""
});
}
});
};
// @ts-ignore
if (window.WebCookieNotice.getCnCookieStatus("recaptcha") === "true") {
window.__CN_Recaptcha();
}
}
},
},
};

View file

@ -3,65 +3,29 @@
@section('description', __('Formulaire d\'authentification au back-office.'))
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8 p-0">
<div class="card">
<div class="card-header">{{ __('Connexion') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('bo.login') }}">
@csrf
<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Adresse Email') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email"
value="{{ old('email') }}" autocomplete="email" autofocus required>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Mot de passe') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror"
name="password" autocomplete="current-password" required>
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label user-select-none" for="remember">
{{ __('Se souvenir de moi') }}
</label>
</div>
</div>
</div>
<div class="row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
<span>{{ __('Connexion') }}</span>
<div class="container">
<div class="row justify-content-center">
<div class="col-12 p-2 text-center">
<img class="logo img-fluid" src="{{ Vite::asset('resources/assets/images/logo.png') }}" alt="{{ config('app.name') }}">
</div>
<div class="col-md-8 p-0">
<div class="mt-2">
@include('modules.flash-messages')
</div>
<div class="card">
<div class="card-header fw-bold">{{ __('Connexion') }}</div>
<div class="card-body">
<div class="row">
<div class="col text-center">
<a class="btn btn-primary" href="{{ route('saml.login', ['uuid' => config('saml2.default_tenant_uuid')]) }}">
<span>{{ __('Connexion avec UWIL Support') }}</span>
<i class="fa-solid fa-arrow-right-from-bracket"></i>
</button>
@if (Route::has('bo.password.request'))
<a class="btn btn-link" href="{{ route('bo.password.request') }}">
{{ __('Mot de passe oublié ?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View file

@ -0,0 +1,41 @@
<div data-cookie-name="recaptcha" @class([
'fw-bold rounded-4 cn-cookie-activate d-flex flex-column flex-md-row mx-3 mb-3 mt-4 border p-3 text-start',
'bg-white' => !$shouldBeDark,
'bg-primary' => $shouldBeDark,
])>
<span class="d-flex flex-column w-md-75 w-100">
<strong @class([
'text-underline text-bold fs-5 mb-2',
'text-primary' => !$shouldBeDark,
'text-tertiary' => $shouldBeDark,
])>
{{ __('cookie-notice.custom.recaptcha.warning') }}
</strong>
<br><br>
<small @class([
'fw-normal fs-5',
'text-success' => !$shouldBeDark,
'text-white' => $shouldBeDark,
])>
{{ __('cookie-notice.custom.recaptcha.accept') }}
</small>
</span>
<button id="recaptcha-accept" @class([
'btn btn-primary w-lg-25 h-50 fs-5 rounded-4 mt-md-0 mt-3 border-0',
'btn-primary' => !$shouldBeDark,
'btn-white' => $shouldBeDark,
])>
{{ __('cookie-notice.button_allow') }}
</button>
</div>
@push('scripts')
<script nonce="{{ $nonce }}">
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("recaptcha-accept")?.addEventListener("click", function(e) {
e.preventDefault();
window.WebCookieNotice.acceptCookie("recaptcha");
});
});
</script>
@endpush

View file

@ -32,7 +32,7 @@
@component('mail::panel')
```
{{ $data->message }}
{!! $data->message !!}
```
@endcomponent

View file

@ -2,8 +2,7 @@
@section('title', __($staticPageModel->seo_title))
@section('description', __($staticPageModel->seo_description))
@section('breadcrumb',
request()->route()->getName())
@section('breadcrumb', request()->route()->getName())
@section('main-bg-class', 'bg-textured')
@ -15,7 +14,12 @@
<img class="img-fluid flex-shrink-1 mb-3 flex-grow-0"
src="{{ Vite::asset('resources/assets/images/global/underline-yellow.svg') }}" alt="{{ __('Trait souligné') }}">
<form method="POST" action="{{ route('fo.register') }}">
<div class="px-xl-3">
<x-fo.contact.need-recaptcha-banner :shouldBeDark="true" />
</div>
<form class="recaptcha-form" data-recaptcha-key="{{ config('services.google.recaptcha.public') }}" inert
enctype="multipart/form-data" method="POST" action="{{ route('fo.register') }}">
@csrf
<fieldset class="container-fluid p-md-5 pt-md-1">
@ -43,8 +47,10 @@
<input class="form-check-input @if ($errors->has('ok_cgv')) is-invalid @endif me-1" id="check-cgv"
name="ok_cgv" type="checkbox" required />
<label class="form-check-label w-fit" for="check-cgv" role="button">
J'ai lu et accepte les <a class="text-primary" href="{{ route('fo.policies.show') }}" target="_blank">
{{ __('conditions générales d\'utilisation du site Tre Galette et du Klub Tre Galette') }}</a>.
{{ __('J\'accepte les conditions générales d’utilisation du site et autorise le Responsable de Traitement à traiter mes données personnelles conformément à la') }}
<a class="text-primary" href="{{ route('fo.policies.show') }}" target="_blank">
{{ __('Charte de confidentialité') }}
</a>.
</label>
</div>
@foreach ($errors->get('ok_cgv') as $message)
@ -59,6 +65,18 @@
</div>
</div>
{{-- RECAPTCHA --}}
<div class="col-12 text-center">
<div class="d-flex flex-column justify-content-center align-items-center my-3">
<div class="r_captcha"></div>
@if ($errors->has('g-recaptcha-response'))
<div class="mb-6">
<span class="text-danger">{{ $errors->first('g-recaptcha-response') }}</span>
</div>
@endif
</div>
</div>
<div class="row justify-content-center mb-3">
<div class="col col-md-10 col-lg-8 mb-2 py-2 text-end">
<button class="btn btn-primary text-tertiary btn-lg rounded-0 px-5 py-2" type="submit">
@ -72,6 +90,14 @@
</div>
</fieldset>
</form>
<div class="col col-md-8 offset-md-2 text-primary lh-sm px-0 py-2">
<p>
{{ __('Les informations recueillies à partir de ce formulaire sont traitées par le Responsable de Traitement pour la création de votre compte utilisateur. Pour connaître vos droits, vous pouvez consulter la') }}
<a href="{{ route('fo.policies.show') }}"
title="{{ __('Accéder à la Charte de confidentialité') }}">{{ __('Charte de confidentialité') }}</a>
</p>
</div>
</div>
</div>
</div>

View file

@ -18,7 +18,7 @@
{{-- Tre Galette --}}
<div class="col-12 col-md-4 mb-3">
<div class="d-flex flex-column align-items-center align-items-md-start">
<div class="d-flex flex-column align-items-center">
<span class="h1 f-intro-script-b text-primary d-inline-block mb-4">{{ __('Tre Galette') }}</span>
<ul class="list-unstyled text-center">
<li>
@ -53,8 +53,8 @@
<div class="col-12 col-md-4 my-5">
<div class="d-flex justify-content-center">
<div class="bg-primary d-inline-block rounded-3 regalette-block p-4">
<a class="h-0 w-0" href="https://www.regalette.bzh/" title="{{ __('Aller sur le site Regalette') }}"
target="_blank">
<a class="d-flex justify-content-center h-0 w-0" href="https://www.regalette.bzh/"
title="{{ __('Aller sur le site Regalette') }}" target="_blank">
<img class="img-fluid" src="{{ Vite::asset('resources/assets/images/logo-regalette.png') }}"
href="https://www.regalette.bzh/" alt="{{ __('Logo Régalette') }}" width="122">
</a>
@ -81,11 +81,13 @@
<div class="col d-flex flex-column d-sm-block">
<span class="text-secondary">©2023 Tre Galette</span>
<a class="text-secondary" href="{{ route('fo.legals.show') }}"
title="{{ __('Aller sur la page mentions légales') }}">{{ __('Mentions légales') }}</a>
title="{{ __('Aller sur la page mentions légales et CGU') }}">{{ __('Mentions légales et CGU') }}</a>
<a class="text-secondary" href="{{ route('fo.policies.show') }}"
title="{{ __('Aller sur la page politique de confidentialités') }}">{{ __('Politique de confidentialités') }}</a>
title="{{ __('Aller sur la page charte de confidentialités') }}">{{ __('Charte de confidentialité') }}</a>
<a class="text-secondary cn-cookie-link" href="#" title="{{ __('Afficher le panneau de gestion des cookies') }}"
role="button">{{ __('Cookies') }}</a>
<a class="text-secondary" href="{{ route('fo.rules.show') }}" title="{{ __('Règlement du jeu') }}"
role="button">{{ __('Règlement du jeu') }}</a>
</div>
</div>
</div>

View file

@ -2,8 +2,7 @@
@section('title', __($staticPageModel->seo_title))
@section('description', __($staticPageModel->seo_description))
@section('breadcrumb',
request()->route()->getName())
@section('breadcrumb', request()->route()->getName())
@section('main-bg-class', 'has-banner commitments')
@ -135,20 +134,23 @@
src="{{ Vite::asset('resources/assets/images/global/underline-yellow.svg') }}"
alt="{{ __('Trait souligné') }}">
</div>
<div class="ck-content">{!! clean($commitmentPageModel->quality_text) !!}</div>
{{-- Pictogram 1 --}}
@if ($commitmentPageModel->pictos->get(0))
<img class="img-fluid pictogram" src="{{ asset($commitmentPageModel->pictos->get(0)->picture) }}"
title="{{ $commitmentPageModel->pictos->get(0)->picture_title }}"
alt="{{ $commitmentPageModel->pictos->get(0)->picture_alt }}">
@endif
{{-- Pictogram 2 --}}
@if ($commitmentPageModel->pictos->get(1))
<img class="img-fluid pictogram" src="{{ asset($commitmentPageModel->pictos->get(1)->picture) }}"
title="{{ $commitmentPageModel->pictos->get(1)->picture_title }}"
alt="{{ $commitmentPageModel->pictos->get(1)->picture_alt }}">
@endif
<div class="ck-content">
{!! clean($commitmentPageModel->quality_text) !!}
</div>
<div class="d-flex justify-content-center">
{{-- Pictogram 1 --}}
@if ($commitmentPageModel->pictos->get(0))
<img class="img-fluid mx-2" src="{{ asset($commitmentPageModel->pictos->get(0)->picture) }}"
title="{{ $commitmentPageModel->pictos->get(0)->picture_title }}"
alt="{{ $commitmentPageModel->pictos->get(0)->picture_alt }}">
@endif
{{-- Pictogram 2 --}}
@if ($commitmentPageModel->pictos->get(1))
<img class="img-fluid mx-2" src="{{ asset($commitmentPageModel->pictos->get(1)->picture) }}"
title="{{ $commitmentPageModel->pictos->get(1)->picture_title }}"
alt="{{ $commitmentPageModel->pictos->get(1)->picture_alt }}">
@endif
</div>
</div>
</div>
</div>
@ -207,7 +209,8 @@
<div class="col-12 col-md-6 g-0">
<ul class="rounded-handmade list-unstyled d-flex flex-column justify-content-center align-items-center mx-auto p-5">
<li class="my-2">
<span class="h5 f-intro-head-b-base">{{ __('Sans sels nitrités ajoutés dans nos jambons et lardons') }}</span>
<span
class="h5 f-intro-head-b-base">{{ __('Présence de bouillon de légumes et ferments qui génèrent des nitrites naturels, participant à la conservation des charcuteries') }}</span>
</li>
<li class="my-2">
<span class="h5 f-intro-head-b-base">{{ __('Sans arôme artificiel') }}</span>
@ -215,9 +218,6 @@
<li class="my-2">
<span class="h5 f-intro-head-b-base">{{ __('Sans antioxydants') }}</span>
</li>
<li class="my-2">
<span class="h5 f-intro-head-b-base">{{ __('Sans gomme de xanthane') }}</span>
</li>
</ul>
</div>
{{-- Product 2 --}}

View file

@ -2,8 +2,7 @@
@section('title', __($staticPageModel->seo_title))
@section('description', __($staticPageModel->seo_description))
@section('breadcrumb',
request()->route()->getName())
@section('breadcrumb', request()->route()->getName())
@section('main-bg-class', 'has-banner')
@ -78,7 +77,10 @@
</div>
@endif
<form id="contact-page-form" method="POST" action="{{ route('fo.contact-submit') }}" enctype="multipart/form-data">
<x-fo.contact.need-recaptcha-banner :shouldBeDark="false" />
<form class="recaptcha-form" id="contact-page-form" data-recaptcha-key="{{ config('services.google.recaptcha.public') }}" inert
method="POST" action="{{ route('fo.contact-submit') }}" enctype="multipart/form-data">
@csrf
<fieldset class="container-fluid p-md-5 pt-md-1 pb-md-0">
@ -270,25 +272,14 @@
</div>
<div class="row">
{{-- TERMS --}}
<div class="col-12 col-md-8 py-2">
<div class="d-flex">
<input
class="form-check-input border-tertiary @if ($errors->has('terms')) is-invalid @endif mx-auto me-1"
id="terms" name="terms" type="checkbox" value="1"
aria-label="{{ __('validation.attributes.terms') }}" autocomplete="disabled" required />
<label class="form-check-label ms-1" for="terms">*
{{ Str::ucfirst(__('Les informations recueillies à partir de ce formulaire sont traitées par le Responsable de Traitement pour donner suite à votre demande de contact. Pour connaître vos droits, vous pouvez consulter la')) }}
<a class="text-white" href="{{ route('fo.policies.show') }}"
target="_blank">{{ __('Charte de confidentialité') }}</a>.</label>
</div>
@foreach ($errors->get('terms') as $message)
<div class="invalid-feedback d-block">{{ $message }}</div>
@endforeach
</div>
<p>
{{ __('Les informations recueillies à partir de ce formulaire sont traitées par le Responsable de Traitement pour donner suite à votre demande de contact. Pour connaître vos droits, vous pouvez consulter la') }}
<a class="text-white" href="{{ route('fo.policies.show') }}"
title="{{ __('Accéder à la Charte de confidentialité') }}">{{ __('Charte de confidentialité') }}</a>
</p>
{{-- FILE --}}
<div class="col-12 col-md-4 py-2">
<div class="col-12 col-md-4 mx-auto py-2">
<div class="mb-3">
<label class="btn btn-lg btn-tertiary f-intro-head-b-base px-3 py-2" id="fileAddon" for="file"
role="button" tabindex="0">
@ -314,23 +305,21 @@
</div>
</div>
<div class="row mb-3" id="recaptcha-warning">
<div class="col text-center">
<strong
class="text-danger">{{ __('Vous devez activer les cookies recaptcha pour utiliser le formulaire de contact.') }}</strong>
</div>
</div>
<div class="row mb-3">
<div class="col d-flex justify-content-center">
<div id="r_captcha"></div>
{{-- RECAPTCHA --}}
<div class="col-12 text-center">
<div class="d-flex flex-column justify-content-center align-items-center my-3">
<div class="r_captcha"></div>
@if ($errors->has('g-recaptcha-response'))
<div class="mb-6">
<span class="text-danger">{{ $errors->first('g-recaptcha-response') }}</span>
</div>
@endif
</div>
</div>
<div class="row" id="submit-btn-row">
<div class="col text-center">
<button class="g-recaptcha btn btn-tertiary btn-lg rounded-0 fs-4 px-5 py-3"
data-sitekey="{{ config('services.google.recaptcha.public') }}" type="submit" render="explicit">
<button class="btn btn-tertiary btn-lg rounded-0 fs-4 px-5 py-3" type="submit" render="explicit">
{{ __('Envoyer') }}
</button>
</div>
@ -344,25 +333,3 @@
</div>
</div>
@endsection
@push('scripts')
<script nonce="{{ $nonce }}">
document.addEventListener('DOMContentLoaded', function() {
window.__CN_Recaptcha = function() {
(function(d, t) {
let g = d.createElement(t),
s = d.getElementsByTagName(t)[0];
g.src = 'https://www.google.com/recaptcha/api.js?render=explicit&onload=__CN_Recaptcha_Loaded';
s.parentNode.insertBefore(g, s)
}(document, 'script'));
};
window.__CN_Recaptcha_Loaded = function() {
grecaptcha.render('r_captcha', {
'sitekey': '{{ config('services.google.recaptcha.public') }}'
});
document.getElementById('recaptcha-warning').remove();
document.getElementById('contact-page-form').inert = false;
};
});
</script>
@endpush

View file

@ -0,0 +1,26 @@
@extends('fo.layout')
@section('title', __('Désincription à la newsletter'))
@section('description', __('Page de désincription à la newsletter du site le Gaulois'))
@section('breadcrumb', request()->route()->getName())
@section('bg-offset', true)
@section('content')
<div class="container mb-3 mt-5 pt-5">
<div class="row mb-5">
<div @class([
'col-6 mx-auto alert fw-medium',
'alert-danger' => isset($error),
'alert-success' => !isset($error),
])>
<p>
@isset($error)
{{ $error }}
@else
{{ __("Votre désinscription a été effectuée avec succès. Si vous changez d'avis, n'hésitez pas à vous réinscrire !") }}
@endisset
</p>
</div>
</div>
</div>
@endsection

View file

@ -0,0 +1,23 @@
@extends('fo.layout')
@section('title', __($staticPageModel->seo_title))
@section('description', __($staticPageModel->seo_description))
@section('breadcrumb',
request()->route()->getName())
@section('content')
<div class="container">
<div class="row">
<div class="col">
<h1 class="f-intro-head-h-base text-center">{{ __($staticPageModel->title) }}</h1>
</div>
</div>
</div>
<div class="container">
<div class="row mb-5">
<div class="col ck-content">
{!! clean($staticPageModel->content) !!}
</div>
</div>
</div>
@endsection

View file

@ -7,37 +7,43 @@ $logo_title_text = __('Logo du site :name', ['name' => $site_name]);
$logo_alt_text = __('Logo :name', ['name' => $site_name]);
$strings = (object)[
'modal_title' => __('Fenêtre de gestion de cookies'),
'modal_title' => __('cookie-notice.modal_title'),
'button_customize_cookies' => __('cookie-notice.button_customize_cookies'),
'button_close_cookies' => __('cookie-notice.button_close_cookies'),
'button_title_open_new_tab' => __('Ouvrir le lien dans un nouvel onglet'),
'button_forbid' => __('cookie-notice.button_forbid'),
'button_allow' => __('cookie-notice.button_allow'),
'button_forbid_all' => Str::upper(__('cookie-notice.button_forbid_all')),
'button_allow_all' => Str::upper(__('cookie-notice.button_allow_all')),
'button_customize' => Str::upper(__('cookie-notice.button_customize')),
'button_title_open_new_tab' => __('cookie-notice.button_title_open_new_tab'),
'button_toggle_cookie' => __('cookie-notice.button_toggle_cookie'),
'button_forbid_all' => str(__('cookie-notice.button_forbid_all'))->upper(),
'button_allow_all' => str(__('cookie-notice.button_allow_all'))->upper(),
'button_customize' => str(__('cookie-notice.button_customize'))->upper(),
'button_forbid_all_title' => __('cookie-notice.button_forbid_all_title'),
'button_allow_all_title' => __('cookie-notice.button_allow_all_title'),
'button_back' => Str::upper(__('cookie-notice.button_back')),
'button_validate_and_close' => str(__('cookie-notice.button_validate_and_close'))->upper(),
'banner_title' => __('cookie-notice.banner_title', ['site_name' => $site_name]),
'banner_text' => __('cookie-notice.banner_text'),
'banner_text' => sprintf(
"%s<br><br>%s",
"Nous utilisons des cookies pour nous assurer du bon fonctionnement de notre site et à des fins analytiques. Vous pouvez changer d'avis à tout moment en cliquant sur l'icône présente sur chaque page de notre site. En autorisant ces services tiers, vous acceptez le dépôt et la lecture de cookies et l'utilisation de technologies de suivi nécessaires à leur bon fonctionnement.",
sprintf(
"<a href=\"%s\">Charte de confidentialité</a>",
route('fo.policies.show')
)
),
'panel_title' => __('cookie-notice.panel_title'),
'panel_content' => __('cookie-notice.panel_content'),
'panel_subtitle' => __('cookie-notice.panel_subtitle'),
'panel_details' => __('cookie-notice.panel_details'),
'picture_cookie_title' => __('Image d\'un bon gros cookie'),
'navigation_title' => __('Navigation du panneau des cookie'),
'picture_cookie_title' => __('cookie-notice.picture_cookie_title'),
'navigation_title' => __('cookie-notice.navigation_title'),
];
$cookies = [];
// RECAPTCHA
$cookies['recaptcha'] = [
'name' => __('cookie-notice.custom.recaptcha.title'),
'description' => __('cookie-notice.custom.recaptcha.description'),
'link' => 'https://policies.google.com/privacy',
'labelLink' => __('En savoir +'),
'cookies' => ['NID', '__Secure-3PAPISID', '__Secure-3PSID', '__Secure-3PSIDCC']
'name' => __('cookie-notice.custom.recaptcha.title'),
'description' => __('cookie-notice.custom.recaptcha.description'),
'link' => 'https://policies.google.com/privacy',
'labelLink' => __('En savoir +'),
'cookies' => ['NID', '__Secure-3PAPISID', '__Secure-3PSID', '__Secure-3PSIDCC']
];
$cookies['recaptcha']['script'] = <<<SCRIPT
@ -45,8 +51,25 @@ function () {
if (window.__CN_Recaptcha) {
window.__CN_Recaptcha();
}
[...document.getElementsByClassName('cn-cookie-activate')].forEach(function(el) {
if (el.dataset.cookieName === 'recaptcha') {
el.classList.add('d-none');
}
});
}
SCRIPT;
$cookies['recaptcha']['fallback'] = <<<FALLBACK
function () {
if (window.__CN_Recaptcha_Reset) {
window.__CN_Recaptcha_Reset();
}
[...document.getElementsByClassName('cn-cookie-activate')].forEach(function(el) {
if (el.dataset.cookieName === 'recaptcha') {
el.classList.remove('d-none');
}
});
}
FALLBACK;
// MATOMO
$cookies['matomo'] = [
@ -106,6 +129,7 @@ document.addEventListener('DOMContentLoaded', function () {
window.WebCookieNotice['{{ $index_name }}'] = window.WebCookieNotice['{{ $index_name }}'].conf;
@endforeach
window.WebCookieNotice = new window.CookieNotice(window.WebCookieNotice);
window.Recaptcha.methods.init([].slice.call(document.querySelectorAll(".recaptcha-form")));
});
</script>
@endpush

View file

@ -1,4 +1,4 @@
<div class="position-relative" id="cn-wrapper" title="{{ $strings->modal_title }}" role="alertdialog" tabindex="-1">
<div id="cn-wrapper" title="{{ $strings->modal_title }}" role="alertdialog" tabindex="-1">
<button id="cn-cookie-btn" title="{{ $strings->button_customize_cookies }}">
{{-- COOKIE SVG --}}
<svg viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg">
@ -30,18 +30,15 @@
</div>
<div class="cn-banner-text">
<div class="cn-banner-title">
<span class="fw-normal">{!! nl2br(e($strings->banner_title)) !!}</span>
<span>{!! nl2br(e($strings->banner_title)) !!}</span>
</div>
<div class="cn-banner-para-p">
<p>{!! nl2br(e($strings->banner_text)) !!}</p>
<p>{!! clean($strings->banner_text) !!}</p>
</div>
</div>
</div>
{{-- 2ND PAGE CUSTOMIZE PANEL --}}
<div class="cn-modal-container d-none">
<p class="cn-modal-title" aria-level="h2">{{ $strings->panel_title }}</p>
<p class="cn-modal-subtitle">{!! nl2br(e($strings->panel_subtitle)) !!}</p>
<p class="cn-modal-description">{!! nl2br(e($strings->panel_details)) !!}</p>
<div class="cn-modal-wrapper">
{{-- COOKIES LIST --}}
<ul id="cn-modal-list"></ul>
@ -54,7 +51,7 @@
title="{{ $strings->button_forbid_all_title }}">{{ $strings->button_forbid_all }}</button>
<button class="cn-banner-btn cn-accept" id="cn-accept-banner"
title="{{ $strings->button_allow_all_title }}">{{ $strings->button_allow_all }}</button>
<button class="cn-banner-btn cn-custom" id="cn-settings-banner" data-open-modal="{{ $strings->button_back }}"
<button class="cn-banner-btn cn-custom" id="cn-settings-banner" data-open-modal="{{ $strings->button_validate_and_close }}"
data-close-modal="{{ $strings->button_customize }}">{{ $strings->button_customize }}</button>
</div>
@ -67,14 +64,11 @@
<a class="cn-cookie-link" title="{{ $strings->button_title_open_new_tab }}" target="blank">#link</a>
</div>
<div class="cn-cookie-buttons">
<div class="deny">
<input id="" name="" data-name="" data-status="false" type="radio">
<label for="" role="button" tabindex="0">{{ $strings->button_forbid }}</label>
</div>
<div class="accept">
<input id="" name="" data-name="" data-status="true" type="radio">
<label for="" role="button" tabindex="0">{{ $strings->button_allow }}</label>
</div>
<label class="cn-switch" title="{{ $strings->button_toggle_cookie }}" role="checkbox"
aria-label="{{ $strings->button_toggle_cookie }}" aria-checked="undefined" tabindex="0">
<input type="checkbox" tabindex="-1" />
<span></span>
</label>
</div>
</div>
</div>

View file

@ -2,11 +2,9 @@
<td class="header">
<a href="{{ $url }}" style="display: inline-block;">
@if (trim($slot) === 'Laravel')
<img src="https://laravel.com/img/notification-logo.png" class="logo" alt="Laravel Logo">
<img class="logo" src="https://laravel.com/img/notification-logo.png" alt="Laravel Logo">
@else
{{-- FIXME: Personaliser ca --}}
<img src="{{ Vite::asset('resources/assets/images/logo.png') }}" class="logo img-fluid" alt="{{ config('app.name') }}">
{{ $slot }}
<img class="logo img-fluid" src="{{ Vite::asset('resources/assets/images/logo.png') }}" alt="{{ config('app.name') }}">
@endif
</a>
</td>

View file

@ -0,0 +1,17 @@
<table class="panel" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="panel-content">
<table width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td class="panel-item">
{!! clean(nl2br(str($slot)->markdown([
'html_input' => 'strip',
'allow_unsafe_links' => false,
]))) !!}
</td>
</tr>
</table>
</td>
</tr>
</table>

View file

@ -47,7 +47,8 @@ Route::middleware(['throttle:credentials'])->name('fo.')->group(function () {
Route::get('/securite/identification/motdepasse', [CustomerController::class, 'password'])
->name('password');
Route::post('/securite/identification/motdepasse', [
CustomerController::class, 'passwordSubmit'
CustomerController::class,
'passwordSubmit'
])->name('passwordSubmit');
// * BR
@ -65,7 +66,11 @@ Route::middleware(['throttle:credentials'])->name('fo.')->group(function () {
Route::get('/gamme/{slug}', [RangeController::class, 'show'])->name('ranges.show');
// * PRODUCTS
Route::get('/produit/filtered', [ProductController::class, 'productsFiltered'])->name('products.filtered');
Route::middleware('json_only')->get(
'/produit/filtered',
[ProductController::class, 'productsFiltered']
)->name('products.filtered');
Route::get('/produit/{slug}', [ProductController::class, 'show'])->name('products.show');
// * COMMITMENTS
@ -74,6 +79,7 @@ Route::middleware(['throttle:credentials'])->name('fo.')->group(function () {
// * LEGALS
Route::get('/mentions-legales', [StaticPageController::class, 'legals'])->name('legals.show');
Route::get('/charte-de-confidentialite', [StaticPageController::class, 'policies'])->name('policies.show');
Route::get('/reglement-du-jeu', [StaticPageController::class, 'rules'])->name('rules.show');
// * CONTACT
Route::get('contact', [ContactController::class, 'contact'])->name('contact');
@ -81,4 +87,9 @@ Route::middleware(['throttle:credentials'])->name('fo.')->group(function () {
// * HISTORY
Route::get('/notre-histoire', [StaticPageController::class, 'ourHistory'])->name('history.show');
// * Unsubscribe from newsletter
Route::get('/{unsubscribe}', [HomeController::class, 'unsubscribeNewsletter'])
->where('unsubscribe', 'unsubscribe|unsubscribe.php|unsubscribe.html|newsletter')
->name('unsubscribeNewsletter');
});

20
staging-resources.yaml Normal file
View file

@ -0,0 +1,20 @@
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ${CI_PROJECT_PATH_SLUG}-ingress-route
spec:
entryPoints:
- web
- websecure
routes:
- match: Host(`${APP_DOMAIN}`)
kind: Rule
services:
- name: ${CI_PROJECT_PATH_SLUG}-service
port: 80
middlewares:
- name: admin-ldc-whitelist
namespace: common-services
tls:
secretName: ${CRT_TLS_NAME}