Compare commits

..

No commits in common. "brandPage" and "master" have entirely different histories.

603 changed files with 61311 additions and 157907 deletions

View file

@ -1,5 +0,0 @@
# Browsers that we support
last 3 version
> 0.3%
not dead # no browsers without security updates

12
.dockerignore Normal file
View file

@ -0,0 +1,12 @@
.git
*.md
node_modules/
npm-debug.log
.npmrc
tests/
Dockerfile*
.dockerignore
.gitignore
LICENSE
.vscode
auth.json

View file

@ -3,19 +3,13 @@ root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4
[*.vue]
[*.yml]
indent_size = 2

View file

@ -5,31 +5,31 @@ APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_HOST=dev-mysql
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_DRIVER=smtp
MAIL_HOST=dev-mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
MAIL_FROM_ADDRESS=
MAIL_FROM_NAME=
# CRM
CRM_ENDPOINT=
# Sentry
SENTRY_LARAVEL_DSN=
SENTRY_LARAVEL_DSN=

View file

@ -1,55 +0,0 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:vue/vue3-strongly-recommended",
"@vue/eslint-config-typescript"
],
"overrides": [
{
"files": ["*.ts", "*.vue"],
"rules": {
"no-undef": "off"
}
},
{
"files": ["*.vue"],
"rules": {
"indent": "off"
}
}
],
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "@typescript-eslint/parser",
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["vue", "@typescript-eslint"],
"ignorePatterns": ["webpack.mix.js", "**/vendor/*.js", "**/vendor/**/*.js"],
"rules": {
"indent": ["error", 4, { "SwitchCase": 1 }],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "double"],
"semi": ["error", "always"],
"vue/script-indent": ["error", 2, { "baseIndent": 0, "switchCase": 1 }],
"vue/one-component-per-file": "off"
},
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".vue", ".ts", ".d.ts"]
},
"alias": {
"extensions": [".vue", ".js", ".ts", ".scss", ".d.ts"],
"map": [
["~", "./resources/assets"],
["@", "./node_modules"]
]
}
}
}
}

14
.gitattributes vendored
View file

@ -1,11 +1,5 @@
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore
.styleci.yml export-ignore

14
.gitignore vendored
View file

@ -1,5 +1,6 @@
.env
.env.backup
.env.testing
.env.production
.phpunit.result.cache
.stylelintcache
@ -8,11 +9,14 @@
/.phpunit.cache
/.vscode
/node_modules
/bootstrap
/public/build
/public/cache
/public/hot
/public/sitemap.xml
/public/storage
/public/export/*
!/public/export/.gitkeep
/storage/*.key
/vendor
auth.json
@ -21,3 +25,13 @@ Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
.npmrc
/tests/coverage
/.npm
.zshrc
/.composer
/public/images/

View file

@ -1,24 +1,23 @@
include:
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'lint/lint.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'security/security.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'build/build.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'test/test.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'deploy/deploy.yml'
- project: "ldc-web/shared-ci"
ref: "main"
file: "lint/lint.yml"
- project: "ldc-web/shared-ci"
ref: "main"
file: "security/security.yml"
- project: "ldc-web/shared-ci"
ref: "main"
file: "build/build.yml"
- project: "ldc-web/shared-ci"
ref: "main"
file: "test/test.yml"
- project: "ldc-web/shared-ci"
ref: "main"
file: "deploy/deploy.yml"
stages:
- lint
- security
- build
- test
- deploy
- lint
- security
- build
- test
- deploy

View file

@ -0,0 +1,24 @@
👤 **Formulation**
<!-- réferencer des labels avec tilde ~ -->
**En tant que** ~"persona:: Marie"
**Je veux** <!-- action / fonctionnalité souhaitée en utilisant les objets métier entre backticks (ex: `Brand`, `Campaign`) -->
**Afin de** <!-- bénéfice métier / valeur ajoutée -->
🎯 **Contexte métier & Objectif**
<!-- Préciser le contexte métier, les impacts et les règles de gestion principales -->
🧪 **Critères d'acceptation**
- [ ] **Scénario :** Cas nominal
* **Étant donné** <!-- contexte initial -->
* **Quand** <!-- action déclenchée -->
* **Alors** <!-- résultat attendu et vérifiable -->
- [ ] **Scénario :** Cas d'erreur / alternatif
* **Étant donné** <!-- contexte limite ou données erronées -->
* **Quand** <!-- action déclenchée -->
* **Alors** <!-- comportement attendu / blocage / message d'erreur -->

View file

@ -1,43 +0,0 @@
{
"extends": [
"stylelint-config-standard-scss",
"stylelint-config-sass-guidelines",
"stylelint-config-idiomatic-order"
],
"plugins": ["stylelint-scss"],
"files": ["**/*.css", "**/*.scss"],
"ignoreFiles": [
"**/vendor/*.css",
"**/vendor/**/*.css",
"**/vendor/*.scss",
"**/vendor/**/*.scss",
"**/vendor/*.sass",
"**/vendor/**/*.sass",
"**/vendor/*.less",
"**/vendor/**/*.less"
],
"customSyntax": "postcss-scss",
"rules": {
"indentation": 4,
"string-quotes": "double",
"selector-max-id": null,
"color-no-invalid-hex": true,
"order/properties-alphabetical-order": null,
"max-nesting-depth": 5,
"selector-max-compound-selectors": 5,
"declaration-colon-space-after": "always-single-line",
"function-parentheses-space-inside": "never-single-line",
"declaration-colon-newline-after": null,
"value-list-comma-newline-after": null,
"scss/double-slash-comment-empty-line-before": [
"always",
{
"ignore": [
"between-comments",
"stylelint-commands",
"inside-block"
]
}
]
}
}

6
Dockerfile Normal file
View file

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

View file

@ -1 +1,14 @@
# MesBR
# MesBR
## Tests unitaires
```bash
cp .env .env.testing
// Update db vars
php artisan test
```
## Gestion du Legacy
Au moment de la suppression du legacy, ne pas oublier de refaire les factory au propre pour les models

View file

@ -0,0 +1,51 @@
<?php
namespace App\Console\Commands;
use App\Jobs\ArchiveStatsJob;
use App\Models\ArchiveSite;
use App\Models\ArchiveStat;
use App\Models\Statistique;
use Illuminate\Console\Command;
class ArchiveStatsCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:stats:archive';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Archives mesbr stats';
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$baseArchiveStatCount = ArchiveStat::count();
$baseStatCount = Statistique::count();
new ArchiveStatsJob()->handle();
$this->info(sprintf(
'%s archive(s) created',
ArchiveStat::count() - $baseArchiveStatCount
));
$this->info(sprintf(
'%s stat(s) deleted',
$baseStatCount - Statistique::count()
));
$this->info('Stats archived 👌');
}
}

View file

@ -1,177 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class CreateAdmin extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'user:create';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a backend admin user';
/**
* The firstname of the new user.
*
* @var string
*/
protected $firstname;
/**
* The lastname of the new user.
*
* @var string
*/
protected $lastname;
/**
* The email of the new user.
*
* @var string
*/
protected $email;
/**
* The password of the new user.
*
* @var string
*/
protected $password;
/**
* Execute the console command.
*
* @return integer
*/
public function handle(): int
{
$this->firstname = null;
$this->addFirstname();
$this->lastname = null;
$this->addLastname();
$this->email = null;
$this->addEmail();
$this->password = null;
$this->addPassword();
$user = new User([
'firstname' => $this->firstname,
'lastname' => $this->lastname,
'email' => $this->email,
'password' => $this->password,
]);
$user->saveOrFail();
$this->info('User created 👌');
return 0;
}
/**
* Add a firstname to the user.
*
* @return void
*/
private function addFirstname(): void
{
while (is_null($this->firstname)) {
try {
$tmp = $this->ask('Type the wanted user firstname', 'Admin');
$validator = Validator::make(['firstname' => $tmp], [
'firstname' => 'required|min:3|max:255'
]);
$validator->validate();
$this->firstname = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid firstname %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
/**
* Add a lastname to the user.
*
* @return void
*/
private function addLastname(): void
{
while (is_null($this->lastname)) {
try {
$tmp = $this->ask('Type the wanted user lastname', 'Saïtama');
$validator = Validator::make(['lastname' => $tmp], [
'lastname' => 'required|min:3|max:255'
]);
$validator->validate();
$this->lastname = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid lastname %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
/**
* Add an email to the user.
*
* @return void
*/
private function addEmail(): void
{
while (is_null($this->email)) {
try {
$tmp = $this->ask('Type the wanted user email', 'equipe.web@ldc.fr');
$validator = Validator::make(['email' => $tmp], [
'email' => 'required|unique:users,email|email:rfc,dns'
]);
$validator->validate();
$this->email = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid email %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
/**
* Add a password to the user.
*
* @return void
*/
private function addPassword(): void
{
while (
($this->password = $this->secret(
(!\is_null($this->password) ? 'Failed to confirm, ' : '') . 'Type the wanted user password'
)) !== $this->secret('Confirm the password')
) {
continue;
}; //end while
}
}

View file

@ -0,0 +1,123 @@
<?php
namespace App\Console\Commands;
use App\Models\Basket;
use App\Models\Campagne;
use App\Models\Contact;
use App\Models\Coupon;
use App\Models\Customers;
use App\Models\Site;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Validator;
class CustomersClaims extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'customers:claims {--siteId=?} {destCampaignId} {destCouponId}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$destCampaignId = $this->argument('destCampaignId');
$destCampaign = Campagne::findOrFail($destCampaignId);
$destCouponId = $this->argument('destCouponId');
$destCoupon = Coupon::findOrFail($destCouponId);
$siteIdArg = $this->option('siteId');
if (is_null($siteIdArg)) {
$this->table(
['ID', 'Site ID', 'Label'],
Site::all(['id', 'site_id', 'site_nom'])->toArray()
);
$site = $this->validateInput(fn() => $this->ask('Enter site model id'), 'required|numeric|min:1|max:50|exists:site,id');
$site = Site::find($site);
} else {
$site = Site::find($siteIdArg);
}
$email = $this->validateInput(fn() => $this->ask('Enter customer email'), 'required|email|min:1|max:255');
$crmHashcode = $this->validateInput(fn() => $this->ask('Enter customer hashcode'), 'required|string|min:1|max:36');
$crmCountry = $this->validateInput(fn() => $this->ask('Enter customer country ISO code'), 'required|numeric|in:56,250,442');
$date = $this->validateInput(fn() => $this->ask('Enter claim date'), 'required|date_format:d/m/Y');
$contacts = Contact::where('contact_email', $email)
->where('contact_siteId', '=', $site->site_id)
->get();
$toAdd = 0;
foreach ($contacts as $contact) {
$claimDate = \Illuminate\Support\Facades\Date::createFromFormat('d/m/Y', $date)->format('Y-m-d');
// On vient chercher les paniers dont la date de création est >= à la date de la récla
$paniers = $contact->paniers()->where('panier_createdate', '>=', $claimDate)->get();
foreach ($paniers as $panier) {
foreach ($panier->panierContents as $content) {
$toAdd += $content->panier_content_printed;
}
}
}
$qty = $this->validateInput(fn() => $this->ask('Enter quantity to add', $toAdd), 'required|numeric|max:20');
$customer = Customers::firstOrNew([
'hashcode' => $crmHashcode,
'email' => $email,
'country' => $crmCountry,
]);
$customer->saveOrFail();
$basket = Basket::updateContent($destCampaign, [$destCoupon->coupon_id => $qty], $customer);
$this->info(url()->route("fo.basket.show", $basket));
return 0;
}
private function validateInput($method, $rules)
{
$value = $method(); // Ask user input
$validator = Validator::make(['input' => $value], ['input' => $rules]);
if ($validator->fails()) {
foreach ($validator->errors()->all() as $error) {
$this->warn($error);
}
return $this->validateInput($method, $rules); // Retry
}
return $value;
}
}

View file

@ -0,0 +1,58 @@
<?php
namespace App\Console\Commands;
use App\Models\Coupon;
use App\Traits\GenerateBR;
use Illuminate\Console\Command;
use Illuminate\Http\Request;
class RegenBRBase extends Command
{
use GenerateBR;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'coupons:regen-base';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Re-generate coupons base image';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$publishedCoupons = Coupon::where('coupon_published', 1)->get();
foreach ($publishedCoupons as $coupon)
{
$br_path = $this->generateBase(new Request(), $coupon);
$coupon->coupon_image = $br_path;
$coupon->save();
}
return 0;
}
}

View file

@ -1,36 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class TestMail extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:mail-test';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send test email to equipe.web@ldc.fr';
/**
* Execute the console command.
*
* @return integer
*/
public function handle()
{
Mail::raw(sprintf('UWIL mail-test from %s %s', \config('app.name'), \config('app.url')), function ($msg) {
$msg->to('equipe.web@ldc.fr')->subject('Test Email');
});
return 0;
}
}

View file

@ -4,9 +4,32 @@ namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\Models\Site;
use App\Models\Campagne;
use App\Jobs\ArchiveStatsJob;
use App\Jobs\CleanOldDatasJob;
use App\Models\User;
use App\Models\Notification;
use App\Mail\AlertBr;
use App\Mail\AlertBrAdmin;
use Illuminate\Support\Facades\Mail;
use App\Traits\CouponTrait;
class Kernel extends ConsoleKernel
{
use CouponTrait;
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
\App\Console\Commands\CustomersClaims::class,
\App\Console\Commands\ArchiveStatsCommand::class,
\App\Console\Commands\RegenBRBase::class,
];
/**
* Define the application's command schedule.
*
@ -15,17 +38,78 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule)
{
}
// Archive stats every day at 2:00 AM (to prevent time difference between the server and the reality).
$schedule->job(ArchiveStatsJob::class)->dailyAt('2:00');
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__ . '/Commands');
// Clean datas older than 3 years every day at midnight.
$schedule->job(CleanOldDatasJob::class)->daily();
require base_path('routes/console.php');
// ---- Commande d'alerte appelé tt les jours de la semaine a 7h00
$schedule->call(function (): void {
$sites = Site::all();
$couponSeuilGlobal = [];
$couponDiffusionGlobal = [];
$sendGlobal = false;
foreach ($sites as $site) {
// ---- Pour chaque site
$campagnes = Campagne::where(['camp_siteId' => $site->site_id])->get();
foreach ($campagnes as $campagne) {
$sendMail = false;
$users = [];
$couponSeuil = [];
$couponDiffusion = [];
$coupons = $campagne->coupons()->get();
foreach ($coupons as $coupon) {
$couponAlert = false;
if ($coupon->coupon_published) {
$coupon->coupon_left = $this->getFullQuantity($coupon) - $this->getUsedQuantity($coupon);
if ($coupon->coupon_left < $coupon->coupon_seuil_alert) {
array_push($couponSeuil, $coupon);
array_push($couponSeuilGlobal, [$site->site_nom, $coupon]);
$sendGlobal = true;
$couponAlert = true;
}
// --- Check MaxDateDiffusion
if ($coupon->coupon_maxdatediffusion != null && strtotime($coupon->coupon_maxdatediffusion) < (time() + (30 * 24 * 60 * 60))) {
// Fin de diffusion dans moins de 30jours
array_push($couponDiffusion, $coupon);
array_push($couponDiffusionGlobal, [$site->site_nom, $coupon]);
$sendGlobal = true;
$couponAlert = true;
}
if ($couponAlert) {
$notifications = Notification::where(['notif_campId' => $campagne->camp_id])->get();
foreach ($notifications as $notification) {
if (!array_key_exists($notification->notif_id, $users)) {
$userObject = [];
$userObject['email'] = $notification->notif_email;
$userObject['name'] = $notification->notif_name;
$users[$notification->notif_id] = (object)$userObject;
}
}
$sendMail = true;
}
} //end if
} //end foreach
if ($sendMail) {
Mail::to($users)->send(new AlertBr($couponSeuil, $couponDiffusion, $site->site_nom));
}
} //end foreach
} //end foreach
if ($sendGlobal) {
$superadmins = [];
$admins = User::where(['roles' => 'superadmin'])->get();
foreach ($admins as $admin) {
$adminObject = [];
$adminObject['email'] = $admin->email;
$adminObject['name'] = $admin->name;
array_push($superadmins, (object)$adminObject);
}
Mail::to($superadmins)->send(new AlertBrAdmin($couponSeuilGlobal, $couponDiffusionGlobal));
}
})->weekdays()->at('7:00');
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnum;
/**
* @method static self mur()
* value 0 Mur (POUR LES MURS)
* @method static self panier()
* value 1 Panier (POUR LES PANIERS)
* @method static self murss()
* value 2 Mur sans sélection (POUR LES MURS SANS SELECTION)
* @method static self paniers()
* value 3 Panier Sélectionnable (POUR LES PANIERS AVEC SELECTION)
*/
class CampaignTypes extends BaseEnum
{
protected static function values(): array
{
return [
'mur' => 0,
'panier' => 1,
'murss' => 2,
'paniers' => 3,
];
}
protected static function labels(): array
{
return [
'mur' => trans('Mur'),
'panier' => trans('Panier'),
'murss' => trans('Mur sans sélection'),
'paniers' => trans('Panier Sélectionnable'),
];
}
}

32
app/Enums/Countries.php Normal file
View file

@ -0,0 +1,32 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnum;
/**
* @method static self france()
* @method static self belgique()
* @method static self luxembourg()
*/
class Countries extends BaseEnum
{
protected static function values(): array
{
return [
'france' => 250,
'belgique' => 56,
'luxembourg' => 442,
];
}
protected static function labels(): array
{
return [
'france' => 'France',
'belgique' => 'Belgique',
'luxembourg' => 'Luxembourg',
];
}
}

View file

@ -1,623 +0,0 @@
<?php
namespace App\Enums;
use App\Traits\Enums\BaseEnum;
enum Country: int
{
use BaseEnum;
case afghanistan = 1;
case alandIslands = 2;
case albania = 3;
case algeria = 4;
case americanSamoa = 5;
case andorra = 6;
case angola = 7;
case anguilla = 8;
case antarctica = 9;
case antiguaAndBarbuda = 10;
case argentina = 11;
case armenia = 12;
case aruba = 13;
case australia = 14;
case austria = 15;
case azerbaijan = 16;
case bahrain = 17;
case bahamas = 18;
case bangladesh = 19;
case barbados = 20;
case belarus = 21;
case belgium = 22;
case belize = 23;
case benin = 24;
case bermuda = 25;
case bhutan = 26;
case boliviaPlurinationalStateOf = 27;
case bonaireSintEustatiusAndSaba = 28;
case bosniaAndHerzegovina = 29;
case botswana = 30;
case bouvetIsland = 31;
case brazil = 32;
case britishIndianOceanTerritory = 33;
case bruneiDarussalam = 34;
case bulgaria = 35;
case burkinaFaso = 36;
case burundi = 37;
case cambodia = 38;
case cameroon = 39;
case canada = 40;
case capeVerde = 41;
case caymanIslands = 42;
case centralAfricanRepublic = 43;
case chad = 44;
case chile = 45;
case china = 46;
case christmasIsland = 47;
case cocosKeelingIslands = 48;
case colombia = 49;
case comoros = 50;
case congo = 51;
case congoTheDemocraticRepublicOfThe = 52;
case cookIslands = 53;
case costaRica = 54;
case coteDivoire = 55;
case croatia = 56;
case cuba = 57;
case curacao = 58;
case cyprus = 59;
case czechRepublic = 60;
case denmark = 61;
case djibouti = 62;
case dominica = 63;
case dominicanRepublic = 64;
case ecuador = 65;
case egypt = 66;
case elSalvador = 67;
case equatorialGuinea = 68;
case eritrea = 69;
case estonia = 70;
case ethiopia = 71;
case falklandIslandsMalvinas = 72;
case faroeIslands = 73;
case fiji = 74;
case finland = 75;
case france = 76;
case frenchGuiana = 77;
case frenchPolynesia = 78;
case frenchSouthernTerritories = 79;
case gabon = 80;
case gambia = 81;
case georgia = 82;
case germany = 83;
case ghana = 84;
case gibraltar = 85;
case greece = 86;
case greenland = 87;
case grenada = 88;
case guadeloupe = 89;
case guam = 90;
case guatemala = 91;
case guernsey = 92;
case guinea = 93;
case guineaBissau = 94;
case guyana = 95;
case haiti = 96;
case heardIslandAndMcdonaldIslands = 97;
case holySeeVaticanCityState = 98;
case honduras = 99;
case hongKong = 100;
case hungary = 101;
case iceland = 102;
case india = 103;
case indonesia = 104;
case iranIslamicRepublicOf = 105;
case iraq = 106;
case ireland = 107;
case isleOfMan = 108;
case israel = 109;
case italy = 110;
case jamaica = 111;
case japan = 112;
case jersey = 113;
case jordan = 114;
case kazakhstan = 115;
case kenya = 116;
case kiribati = 117;
case koreaDemocraticPeoplesRepublicOf = 118;
case koreaRepublicOf = 119;
case kuwait = 120;
case kyrgyzstan = 121;
case laoPeoplesDemocraticRepublic = 122;
case latvia = 123;
case lebanon = 124;
case lesotho = 125;
case liberia = 126;
case libya = 127;
case liechtenstein = 128;
case lithuania = 129;
case luxembourg = 130;
case macao = 131;
case macedoniaTheFormerYugoslavRepublicOf = 132;
case madagascar = 133;
case malawi = 134;
case malaysia = 135;
case maldives = 136;
case mali = 137;
case malta = 138;
case marshallIslands = 139;
case martinique = 140;
case mauritania = 141;
case mauritius = 142;
case mayotte = 143;
case mexico = 144;
case micronesiaFederatedStatesOf = 145;
case moldovaRepublicOf = 146;
case monaco = 147;
case mongolia = 148;
case montenegro = 149;
case montserrat = 150;
case morocco = 151;
case mozambique = 152;
case myanmar = 153;
case namibia = 154;
case nauru = 155;
case nepal = 156;
case netherlands = 157;
case newCaledonia = 158;
case newZealand = 159;
case nicaragua = 160;
case niger = 161;
case nigeria = 162;
case niue = 163;
case norfolkIsland = 164;
case northernMarianaIslands = 165;
case norway = 166;
case oman = 167;
case pakistan = 168;
case palau = 169;
case palestineStateOf = 170;
case panama = 171;
case papuaNewGuinea = 172;
case paraguay = 173;
case peru = 174;
case philippines = 175;
case pitcairn = 176;
case poland = 177;
case portugal = 178;
case puertoRico = 179;
case qatar = 180;
case reunion = 181;
case romania = 182;
case russianFederation = 183;
case rwanda = 184;
case saintBarthelemy = 185;
case saintHelenaAscensionAndTristanDaCunha = 186;
case saintKittsAndNevis = 187;
case saintLucia = 188;
case saintMartinFrenchPart = 189;
case saintPierreAndMiquelon = 190;
case saintVincentAndTheGrenadines = 191;
case samoa = 192;
case sanMarino = 193;
case saoTomeAndPrincipe = 194;
case saudiArabia = 195;
case senegal = 196;
case serbia = 197;
case seychelles = 198;
case sierraLeone = 199;
case singapore = 200;
case sintMaartenDutchPart = 201;
case slovakia = 202;
case slovenia = 203;
case solomonIslands = 204;
case somalia = 205;
case southAfrica = 206;
case southGeorgiaAndTheSouthSandwichIslands = 207;
case southSudan = 208;
case spain = 209;
case sriLanka = 210;
case sudan = 211;
case suriname = 212;
case svalbardAndJanMayen = 213;
case swaziland = 214;
case sweden = 215;
case switzerland = 216;
case syrianArabRepublic = 217;
case taiwanProvinceOfChina = 218;
case tajikistan = 219;
case tanzaniaUnitedRepublicOf = 220;
case thailand = 221;
case timorLeste = 222;
case togo = 223;
case tokelau = 224;
case tonga = 225;
case trinidadAndTobago = 226;
case tunisia = 227;
case turkey = 228;
case turkmenistan = 229;
case turksAndCaicosIslands = 230;
case tuvalu = 231;
case uganda = 232;
case ukraine = 233;
case unitedArabEmirates = 234;
case unitedKingdom = 235;
case unitedStates = 236;
case unitedStatesMinorOutlyingIslands = 237;
case uruguay = 238;
case uzbekistan = 239;
case vanuatu = 240;
case venezuelaBolivarianRepublicOf = 241;
case vietNam = 242;
case virginIslandsBritish = 243;
case virginIslandsUs = 244;
case wallisAndFutuna = 245;
case westernSahara = 246;
case yemen = 247;
case zambia = 248;
case zimbabwe = 249;
/**
* Optionnal labels definition
*/
private const LABELS = [
self::afghanistan->name => 'Afghanistan',
self::alandIslands->name => 'Åland Islands',
self::albania->name => 'Albania',
self::algeria->name => 'Algeria',
self::americanSamoa->name => 'American Samoa',
self::andorra->name => 'Andorra',
self::angola->name => 'Angola',
self::anguilla->name => 'Anguilla',
self::antarctica->name => 'Antarctica',
self::antiguaAndBarbuda->name => 'Antigua and Barbuda',
self::argentina->name => 'Argentina',
self::armenia->name => 'Armenia',
self::aruba->name => 'Aruba',
self::australia->name => 'Australia',
self::austria->name => 'Austria',
self::azerbaijan->name => 'Azerbaijan',
self::bahrain->name => 'Bahrain',
self::bahamas->name => 'Bahamas',
self::bangladesh->name => 'Bangladesh',
self::barbados->name => 'Barbados',
self::belarus->name => 'Belarus',
self::belgium->name => 'Belgium',
self::belize->name => 'Belize',
self::benin->name => 'Benin',
self::bermuda->name => 'Bermuda',
self::bhutan->name => 'Bhutan',
self::boliviaPlurinationalStateOf->name => 'Bolivia, Plurinational State of',
self::bonaireSintEustatiusAndSaba->name => 'Bonaire, Sint Eustatius and Saba',
self::bosniaAndHerzegovina->name => 'Bosnia and Herzegovina',
self::botswana->name => 'Botswana',
self::bouvetIsland->name => 'Bouvet Island',
self::brazil->name => 'Brazil',
self::britishIndianOceanTerritory->name => 'British Indian Ocean Territory',
self::bruneiDarussalam->name => 'Brunei Darussalam',
self::bulgaria->name => 'Bulgaria',
self::burkinaFaso->name => 'Burkina Faso',
self::burundi->name => 'Burundi',
self::cambodia->name => 'Cambodia',
self::cameroon->name => 'Cameroon',
self::canada->name => 'Canada',
self::capeVerde->name => 'Cape Verde',
self::caymanIslands->name => 'Cayman Islands',
self::centralAfricanRepublic->name => 'Central African Republic',
self::chad->name => 'Chad',
self::chile->name => 'Chile',
self::china->name => 'China',
self::christmasIsland->name => 'Christmas Island',
self::cocosKeelingIslands->name => 'Cocos (Keeling) Islands',
self::colombia->name => 'Colombia',
self::comoros->name => 'Comoros',
self::congo->name => 'Congo',
self::congoTheDemocraticRepublicOfThe->name => 'Congo, the Democratic Republic of the',
self::cookIslands->name => 'Cook Islands',
self::costaRica->name => 'Costa Rica',
self::coteDivoire->name => 'Côte d\'Ivoire',
self::croatia->name => 'Croatia',
self::cuba->name => 'Cuba',
self::curacao->name => 'Curaçao',
self::cyprus->name => 'Cyprus',
self::czechRepublic->name => 'Czech Republic',
self::denmark->name => 'Denmark',
self::djibouti->name => 'Djibouti',
self::dominica->name => 'Dominica',
self::dominicanRepublic->name => 'Dominican Republic',
self::ecuador->name => 'Ecuador',
self::egypt->name => 'Egypt',
self::elSalvador->name => 'El Salvador',
self::equatorialGuinea->name => 'Equatorial Guinea',
self::eritrea->name => 'Eritrea',
self::estonia->name => 'Estonia',
self::ethiopia->name => 'Ethiopia',
self::falklandIslandsMalvinas->name => 'Falkland Islands (Malvinas)',
self::faroeIslands->name => 'Faroe Islands',
self::fiji->name => 'Fiji',
self::finland->name => 'Finland',
self::france->name => 'France',
self::frenchGuiana->name => 'French Guiana',
self::frenchPolynesia->name => 'French Polynesia',
self::frenchSouthernTerritories->name => 'French Southern Territories',
self::gabon->name => 'Gabon',
self::gambia->name => 'Gambia',
self::georgia->name => 'Georgia',
self::germany->name => 'Germany',
self::ghana->name => 'Ghana',
self::gibraltar->name => 'Gibraltar',
self::greece->name => 'Greece',
self::greenland->name => 'Greenland',
self::grenada->name => 'Grenada',
self::guadeloupe->name => 'Guadeloupe',
self::guam->name => 'Guam',
self::guatemala->name => 'Guatemala',
self::guernsey->name => 'Guernsey',
self::guinea->name => 'Guinea',
self::guineaBissau->name => 'GuineaBissau',
self::guyana->name => 'Guyana',
self::haiti->name => 'Haiti',
self::heardIslandAndMcdonaldIslands->name => 'Heard Island and McDonald Islands',
self::holySeeVaticanCityState->name => 'Holy See (Vatican City State)',
self::honduras->name => 'Honduras',
self::hongKong->name => 'Hong Kong',
self::hungary->name => 'Hungary',
self::iceland->name => 'Iceland',
self::india->name => 'India',
self::indonesia->name => 'Indonesia',
self::iranIslamicRepublicOf->name => 'Iran, Islamic Republic of',
self::iraq->name => 'Iraq',
self::ireland->name => 'Ireland',
self::isleOfMan->name => 'Isle of Man',
self::israel->name => 'Israel',
self::italy->name => 'Italy',
self::jamaica->name => 'Jamaica',
self::japan->name => 'Japan',
self::jersey->name => 'Jersey',
self::jordan->name => 'Jordan',
self::kazakhstan->name => 'Kazakhstan',
self::kenya->name => 'Kenya',
self::kiribati->name => 'Kiribati',
self::koreaDemocraticPeoplesRepublicOf->name => 'Korea, Democratic People\'s Republic of',
self::koreaRepublicOf->name => 'Korea, Republic of',
self::kuwait->name => 'Kuwait',
self::kyrgyzstan->name => 'Kyrgyzstan',
self::laoPeoplesDemocraticRepublic->name => 'Lao People\'s Democratic Republic',
self::latvia->name => 'Latvia',
self::lebanon->name => 'Lebanon',
self::lesotho->name => 'Lesotho',
self::liberia->name => 'Liberia',
self::libya->name => 'Libya',
self::liechtenstein->name => 'Liechtenstein',
self::lithuania->name => 'Lithuania',
self::luxembourg->name => 'Luxembourg',
self::macao->name => 'Macao',
self::macedoniaTheFormerYugoslavRepublicOf->name => 'Macedonia, the Former Yugoslav Republic of',
self::madagascar->name => 'Madagascar',
self::malawi->name => 'Malawi',
self::malaysia->name => 'Malaysia',
self::maldives->name => 'Maldives',
self::mali->name => 'Mali',
self::malta->name => 'Malta',
self::marshallIslands->name => 'Marshall Islands',
self::martinique->name => 'Martinique',
self::mauritania->name => 'Mauritania',
self::mauritius->name => 'Mauritius',
self::mayotte->name => 'Mayotte',
self::mexico->name => 'Mexico',
self::micronesiaFederatedStatesOf->name => 'Micronesia, Federated States of',
self::moldovaRepublicOf->name => 'Moldova, Republic of',
self::monaco->name => 'Monaco',
self::mongolia->name => 'Mongolia',
self::montenegro->name => 'Montenegro',
self::montserrat->name => 'Montserrat',
self::morocco->name => 'Morocco',
self::mozambique->name => 'Mozambique',
self::myanmar->name => 'Myanmar',
self::namibia->name => 'Namibia',
self::nauru->name => 'Nauru',
self::nepal->name => 'Nepal',
self::netherlands->name => 'Netherlands',
self::newCaledonia->name => 'New Caledonia',
self::newZealand->name => 'New Zealand',
self::nicaragua->name => 'Nicaragua',
self::niger->name => 'Niger',
self::nigeria->name => 'Nigeria',
self::niue->name => 'Niue',
self::norfolkIsland->name => 'Norfolk Island',
self::northernMarianaIslands->name => 'Northern Mariana Islands',
self::norway->name => 'Norway',
self::oman->name => 'Oman',
self::pakistan->name => 'Pakistan',
self::palau->name => 'Palau',
self::palestineStateOf->name => 'Palestine, State of',
self::panama->name => 'Panama',
self::papuaNewGuinea->name => 'Papua New Guinea',
self::paraguay->name => 'Paraguay',
self::peru->name => 'Peru',
self::philippines->name => 'Philippines',
self::pitcairn->name => 'Pitcairn',
self::poland->name => 'Poland',
self::portugal->name => 'Portugal',
self::puertoRico->name => 'Puerto Rico',
self::qatar->name => 'Qatar',
self::reunion->name => 'Réunion',
self::romania->name => 'Romania',
self::russianFederation->name => 'Russian Federation',
self::rwanda->name => 'Rwanda',
self::saintBarthelemy->name => 'Saint Barthélemy',
self::saintHelenaAscensionAndTristanDaCunha->name => 'Saint Helena, Ascension and Tristan da Cunha',
self::saintKittsAndNevis->name => 'Saint Kitts and Nevis',
self::saintLucia->name => 'Saint Lucia',
self::saintMartinFrenchPart->name => 'Saint Martin (French part)',
self::saintPierreAndMiquelon->name => 'Saint Pierre and Miquelon',
self::saintVincentAndTheGrenadines->name => 'Saint Vincent and the Grenadines',
self::samoa->name => 'Samoa',
self::sanMarino->name => 'San Marino',
self::saoTomeAndPrincipe->name => 'Sao Tome and Principe',
self::saudiArabia->name => 'Saudi Arabia',
self::senegal->name => 'Senegal',
self::serbia->name => 'Serbia',
self::seychelles->name => 'Seychelles',
self::sierraLeone->name => 'Sierra Leone',
self::singapore->name => 'Singapore',
self::sintMaartenDutchPart->name => 'Sint Maarten (Dutch part)',
self::slovakia->name => 'Slovakia',
self::slovenia->name => 'Slovenia',
self::solomonIslands->name => 'Solomon Islands',
self::somalia->name => 'Somalia',
self::southAfrica->name => 'South Africa',
self::southGeorgiaAndTheSouthSandwichIslands->name => 'South Georgia and the South Sandwich Islands',
self::southSudan->name => 'South Sudan',
self::spain->name => 'Spain',
self::sriLanka->name => 'Sri Lanka',
self::sudan->name => 'Sudan',
self::suriname->name => 'Suriname',
self::svalbardAndJanMayen->name => 'Svalbard and Jan Mayen',
self::swaziland->name => 'Swaziland',
self::sweden->name => 'Sweden',
self::switzerland->name => 'Switzerland',
self::syrianArabRepublic->name => 'Syrian Arab Republic',
self::taiwanProvinceOfChina->name => 'Taiwan, Province of China',
self::tajikistan->name => 'Tajikistan',
self::tanzaniaUnitedRepublicOf->name => 'Tanzania, United Republic of',
self::thailand->name => 'Thailand',
self::timorLeste->name => 'TimorLeste',
self::togo->name => 'Togo',
self::tokelau->name => 'Tokelau',
self::tonga->name => 'Tonga',
self::trinidadAndTobago->name => 'Trinidad and Tobago',
self::tunisia->name => 'Tunisia',
self::turkey->name => 'Turkey',
self::turkmenistan->name => 'Turkmenistan',
self::turksAndCaicosIslands->name => 'Turks and Caicos Islands',
self::tuvalu->name => 'Tuvalu',
self::uganda->name => 'Uganda',
self::ukraine->name => 'Ukraine',
self::unitedArabEmirates->name => 'United Arab Emirates',
self::unitedKingdom->name => 'United Kingdom',
self::unitedStates->name => 'United States',
self::unitedStatesMinorOutlyingIslands->name => 'United States Minor Outlying Islands',
self::uruguay->name => 'Uruguay',
self::uzbekistan->name => 'Uzbekistan',
self::vanuatu->name => 'Vanuatu',
self::venezuelaBolivarianRepublicOf->name => 'Venezuela, Bolivarian Republic of',
self::vietNam->name => 'Viet Nam',
self::virginIslandsBritish->name => 'Virgin Islands, British',
self::virginIslandsUs->name => 'Virgin Islands, U.S.',
self::wallisAndFutuna->name => 'Wallis and Futuna',
self::westernSahara->name => 'Western Sahara',
self::yemen->name => 'Yemen',
self::zambia->name => 'Zambia',
self::zimbabwe->name => 'Zimbabwe',
];
/**
* Get Valid Shipping Countries
*
* @return array
*/
public static function validShippingCountries(): array
{
return [
self::france,
/**
* // * DROM COM .
// self::guadeloupe,
// self::martinique,
// self::frenchGuiana,
// self::reunion,
// self::saintPierreAndMiquelon,
// self::mayotte,
// self::saintBarthelemy,
// self::saintMartinFrenchPart,
// self::wallisAndFutuna,
// self::frenchPolynesia,
// self::newCaledonia
*/
];
}
/**
* Get Valid Shipping Countries
*
* @return array
*/
public static function validBillingCountries(): array
{
return [
self::france,
// * DROM COM.
self::guadeloupe,
self::martinique,
self::frenchGuiana,
self::reunion,
self::saintPierreAndMiquelon,
self::mayotte,
self::saintBarthelemy,
self::saintMartinFrenchPart,
self::wallisAndFutuna,
self::frenchPolynesia,
self::newCaledonia
];
}
/**
* Get Alpha 2 ISO code of valid shipping countries
*
* @return array
*/
public static function getValidShippingCountriesIsoAplha2Codes(): array
{
return ['FR'];
}
/**
* Get Alpha 2 ISO code of valid billing countries
*
* @return array
*/
public static function getValidBillingCountriesIsoAplha2Codes(): array
{
return \array_values(self::ISOCODES);
}
/**
* Custom added ISOCODES definition
*/
private const ISOCODES = [
self::france->name => 'FR',
self::guadeloupe->name => 'GP',
self::martinique->name => 'MQ',
self::frenchGuiana->name => 'GF',
self::reunion->name => 'RE',
self::saintPierreAndMiquelon->name => 'PM',
self::mayotte->name => 'YT',
self::saintBarthelemy->name => 'BL',
self::saintMartinFrenchPart->name => 'MF',
self::wallisAndFutuna->name => 'WF',
self::frenchPolynesia->name => 'PF',
self::newCaledonia->name => 'NC',
];
/**
* Get ISOCODE
*
* @return string
*/
public function iso(): string
{
return self::ISOCODES[$this->name];
}
/**
* Get enum ISOCODES
*
* @return array<string>
*/
public static function toIsoCodes(): array
{
return self::ISOCODES;
}
}

View file

@ -1,30 +0,0 @@
<?php
namespace App\Enums;
use App\Traits\Enums\BaseEnum;
enum InputType: int
{
use BaseEnum;
case boolean = 1;
case dropdownArray = 2;
case email = 3;
case image = 4;
case imageArray = 5;
case labelArray = 6;
case miniblocArray = 7;
case number = 8;
case selectEnum = 9;
case password = 10;
case string = 11;
case text = 12;
case url = 13;
/** Vimeo only */
case videoVimeo = 14;
/** Youtube only */
case videoYoutube = 15;
/** Youtube or Vimeo. */
case video = 16;
}

32
app/Enums/LogActions.php Normal file
View file

@ -0,0 +1,32 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnum;
/**
* @method static self updatebasket()
* @method static self impression()
* @method static self updatecontact()
*/
class LogActions extends BaseEnum
{
protected static function values(): array
{
return [
'updatebasket' => 1,
'impression' => 3,
'updatecontact' => 4,
];
}
protected static function labels(): array
{
return [
'updatebasket' => 'Mise à jour du panier',
'impression' => 'Impression',
'updatecontact' => 'Mise à jour du contact',
];
}
}

32
app/Enums/UserRoles.php Normal file
View file

@ -0,0 +1,32 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnum;
/**
* @method static self superadmin()
* @method static self admin()
* @method static self marketing()
*/
class UserRoles extends BaseEnum
{
protected static function values(): array
{
return [
'superadmin' => 'superadmin',
'admin' => 'admin',
'marketing' => 'marketing'
];
}
protected static function labels(): array
{
return [
'superadmin' => trans('Super-Admin'),
'admin' => trans('Admin'),
'marketing' => trans('Marketing')
];
}
}

View file

@ -2,6 +2,8 @@
namespace App\Exceptions;
use App\Http\Resources\StatusResource;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
@ -19,6 +21,7 @@ class Handler extends ExceptionHandler
*
* @var array<int, class-string<\Throwable>>
*/
protected $dontReport = [];
/**
@ -26,6 +29,7 @@ class Handler extends ExceptionHandler
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
@ -39,10 +43,25 @@ class Handler extends ExceptionHandler
*/
public function register()
{
$this->reportable(function (Throwable $e) {
$this->reportable(function (Throwable $e): void {
if (app()->bound('sentry')) {
app('sentry')->captureException($e);
resolve('sentry')->captureException($e);
}
});
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Throwable $exception
* @return \Symfony\Component\HttpFoundation\Response
*/
public function render($request, Throwable $exception)
{
if ($request->wantsJson() && $exception instanceof ModelNotFoundException) {
return response()->json(new StatusResource(['status' => 'KO', 'code' => 404, 'message' => 'Resource not found.']), 404);
}
return parent::render($request, $exception);
}
}

View file

@ -0,0 +1,302 @@
<?php
namespace App\Http\Controllers;
use App\Models\Campagne;
use App\Models\Coupon;
use App\Enums\CampaignTypes;
use App\Models\PanierContent;
use App\Models\Statistique;
use App\Models\Mur;
use App\Models\Log;
use Illuminate\Http\Request;
use App\Traits\GenerateBR;
use App\Traits\CouponTrait;
class AjaxController extends Controller
{
use GenerateBR;
use CouponTrait;
// ---- Ajoute des coupons à une campagne
public function add_coupons_ajax(Request $request)
{
$camp_id = $request->input('campid');
$campagne = Campagne::where('camp_id', $camp_id)->first();
$ids = $request->input('ids');
$coupons = Coupon::find($ids);
$campagne->coupons()->attach($coupons);
return json_encode($coupons);
}
// ---- Efface des coupons d'une campagne
public function remove_coupons_ajax(Request $request)
{
$camp_id = $request->input('campid');
$campagne = Campagne::where('camp_id', $camp_id)->first();
$coupon_id = $request->input('couponid');
$coupon = Coupon::find($coupon_id);
$campagne->coupons()->detach($coupon_id);
return json_encode($coupon);
}
// ---- Dépublie un coupon
public function unpublishCouponsAjax(Request $request)
{
$coupon_id = $request->input('couponid');
$coupon = Coupon::find($coupon_id);
$coupon->coupon_published = 0;
$coupon->save();
return json_encode($coupon);
}
// ---- Publie un coupon
public function publishCouponsAjax(Request $request)
{
$coupon_id = $request->input('couponid');
$coupon = Coupon::find($coupon_id);
$coupon->coupon_published = 1;
$coupon->save();
return json_encode($coupon);
}
// ---- Impression des BR
public function impressionAjax(Request $request)
{
if ($request->session()->has('coupons')) {
$couponsToPrint = $request->session()->get('coupons');
}
if ($request->session()->has('campagne')) {
$campagne = $request->session()->get('campagne');
} else {
die();
}
if ($request->session()->has('contact')) {
$contact = $request->session()->get('contact');
} else {
die();
}
if ($request->session()->has('panier')) {
$panier = $request->session()->get('panier');
}
if ($contact->contact_ref == "DEMO") {
$source = 'ADMIN';
} else {
$source = 'API';
}
// ---- INIT du log
$log = new Log();
$log->log_action = config('constants.impression');
$log->log_source = $source;
$log->log_contactId = $contact->contact_id;
$log->log_refsite = $campagne->camp_siteId;
$log->log_params = json_encode(['refcamp' => $campagne->camp_id]);
$couponsPrinted = [];
$coupons = '<TABLE width="100%" align="center" cellpadding="0" cellspacing="0" border="0">';
$coupons .= '<TR><TD width="100%" align="center"><div>';
if ($campagne->camp_type->equals(CampaignTypes::mur())) {
// ---- POUR LES MURS
if (!isset($couponsToPrint)) {
die();
}
$nbCoupon = 0;
foreach ($couponsToPrint as $coupon_code) {
$cp = Coupon::where(['coupon_code' => $coupon_code])->first();
if ($this->isAvailable($cp, $campagne, $contact) && $this->isAvailableToPrint($cp, $campagne)) {
array_push($couponsPrinted, ['cp_code' => $cp->coupon_code, 'qty' => 1]);
$imgCoupon = $this->printCp($cp, $contact);
$coupons .= '<img src="' . $imgCoupon . '" border="0" style="display:block;width:165mm;"/>';
$nbCoupon++;
if ($nbCoupon % 3 == 0) {
$coupons .= '</div><div>';
}
// ----- mémorise l'impression
$mur = new Mur();
$mur->mur_campid = $campagne->camp_id;
$mur->mur_contactId = $contact->contact_id;
$mur->mur_couponId = $cp->coupon_id;
$mur->save();
// Sauvegarde de stat
$this->saveStat($campagne, $cp);
}//end if
}//end foreach
} elseif ($campagne->camp_type->equals(CampaignTypes::panier())) {
// ---- POUR LES PANIERS
if (!isset($panier)) {
die();
}
$allPanierContent = $panier->panierContents()->get();
if (count($allPanierContent) == 0) {
die("error");
}
$nbCoupon = 0;
foreach ($allPanierContent as $panierContent) {
$cp = Coupon::where(['coupon_id' => $panierContent->panier_content_couponId])->first();
if ($cp && $this->isAvailableToPrint($cp, $campagne)) {
$imgCoupon = $this->printCp($cp, $contact);
// ---- Création du html du contenu à imprimer
if ($campagne->camp_limitedPrinting == 0) {
for ($i = 0; $i < $panierContent->panier_content_quantity; $i++) {
$coupons .= '<img src="' . $imgCoupon . '" border="0" style="display:block;width:165mm;"/>';
$nbCoupon++;
if ($nbCoupon % 3 == 0) {
$coupons .= '</div><div>';
}
}
$newQtyAvailable = 0;
$newQtyPrinted = $panierContent->panier_content_quantity + $panierContent->panier_content_printed;
array_push($couponsPrinted, ['cp_code' => $cp->coupon_code, 'qty' => $panierContent->panier_content_quantity]);
// Sauvegarde de stat
$this->saveStat($campagne, $cp);
} else {
if ($panierContent->panier_content_quantity > 0) {
$coupons .= '<img src="' . $imgCoupon . '" border="0" style="display:block;width:165mm;"/>';
$nbCoupon++;
if ($nbCoupon % 3 == 0) {
$coupons .= '</div><div>';
}
$newQtyAvailable = $panierContent->panier_content_quantity - 1;
$newQtyPrinted = $panierContent->panier_content_printed + 1;
array_push($couponsPrinted, ['cp_code' => $cp->coupon_code, 'qty' => 1]);
// Sauvegarde de stat
$this->saveStat($campagne, $cp);
}
}//end if
// ---- Mémorise l'impression
$panierContent->panier_content_quantity = $newQtyAvailable;
$panierContent->panier_content_printed = $newQtyPrinted;
$panierContent->save();
}//end if
}//end foreach
// ---- Update du status du panier
$qty = $panier->panierContents()->sum('panier_content_quantity');
if ($qty == 0) {
$panier->panier_pending = 0;
} else {
$panier->panier_pending = 1;
}
$panier->save();
} elseif ($campagne->camp_type->equals(CampaignTypes::murss())) {
// ---- POUR LES MURS SANS SELECTION
$nbCoupon = 0;
$cps = $campagne->coupons()->get();
foreach ($cps as $cp) {
// ---- Contrôle si le BR a déjà fait l'objet d'une impression
if ($this->isAvailable($cp, $campagne, $contact) && $this->isAvailableToPrint($cp, $campagne)) {
// ---- Génère l'image du BR à imprimer
$imgCoupon = $this->printCp($cp, $contact);
$coupons .= '<img src="' . $imgCoupon . '" border="0" style="display:block;width:165mm;"/>';
$nbCoupon++;
if ($nbCoupon % 3 == 0) {
$coupons .= '</div><div>';
}
array_push($couponsPrinted, ['cp_code' => $cp->coupon_code, 'qty' => 1]);
// ----- mémorise l'impression
$mur = new Mur();
$mur->mur_campid = $campagne->camp_id;
$mur->mur_contactId = $contact->contact_id;
$mur->mur_couponId = $cp->coupon_id;
$mur->save();
// Sauvegarde de stat
$this->saveStat($campagne, $cp);
}//end if
}//end foreach
} elseif ($campagne->camp_type->equals(CampaignTypes::paniers())) {
// ---- POUR LES PANIERS AVEC SELECTION
if (!isset($couponsToPrint)) {
die();
}
$nbCoupon = 0;
if (!isset($panier)) {
die();
}
foreach ($couponsToPrint as $coupon_code) {
$cp = Coupon::where(['coupon_code' => $coupon_code])->first();
if ($this->isAvailable($cp, $campagne, $contact) && $this->isAvailableToPrint($cp, $campagne)) {
$imgCoupon = $this->printCp($cp, $contact);
$panierContent = PanierContent::where(['panier_content_couponId' => $cp->coupon_id, 'panier_content_panierId' => $panier->panier_id])->first();
if ($panierContent->panier_content_quantity > 0) {
$coupons .= '<img src="' . $imgCoupon . '" border="0" style="display:block;width:165mm;"/>';
$nbCoupon++;
if ($nbCoupon % 3 == 0) {
$coupons .= '</div><div>';
}
$newQtyAvailable = $panierContent->panier_content_quantity - 1;
$newQtyPrinted = $panierContent->panier_content_printed + 1;
// Sauvegarde de stat
$this->saveStat($campagne, $cp);
// ---- Mémorise l'impression
$panierContent->panier_content_quantity = $newQtyAvailable;
$panierContent->panier_content_printed = $newQtyPrinted;
$panierContent->save();
}
array_push($couponsPrinted, ['cp_code' => $cp->coupon_code, 'qty' => 1]);
}//end if
}//end foreach
// ---- Update du status du panier
$qty = $panier->panierContents()->sum('panier_content_quantity');
if ($qty == 0) {
$panier->panier_pending = 0;
} else {
$panier->panier_pending = 1;
}
$panier->save();
}//end if
$coupons .= '</div></TD></TR>';
$coupons .= '</TABLE>';
$log->log_statut = 'OK';
$log->log_message = json_encode(['Message' => 'Impressions réussies', 'Coupons' => $couponsPrinted], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$log->save();
return $coupons;
}
// ---- Retour au bon index une fois l'impression faite
public function backToIndex(Request $request)
{
if ($request->session()->has('campagne')) {
$campagne = $request->session()->get('campagne');
} else {
die();
}
if ($campagne->camp_type->equals(CampaignTypes::panier()) || $campagne->camp_type->equals(CampaignTypes::paniers())) {
if ($request->session()->has('panier')) {
$panier = $request->session()->get('panier');
} else {
die();
}
return redirect(url('/') . '/?basketid=' . $panier->panier_ref);
}
}
}

View file

@ -0,0 +1,114 @@
<?php
namespace App\Http\Controllers\Api\v0;
use App\Models\Contact;
use App\Http\Controllers\Controller;
use App\Models\Site;
use App\Traits\CouponTrait;
use Illuminate\Http\Request;
class ContactController extends Controller
{
use CouponTrait;
public function updateContact(Request $request)
{
// Validation des paramètres requis
$requiredFields = [
'refadherent' => 'string',
'nom' => 'string',
'refsite' => 'string',
'prenom' => 'string',
'email' => 'email',
'code_postal' => 'string',
'commune' => 'string',
];
$validated = [];
foreach ($requiredFields as $field => $type) {
$value = $request->input($field);
if (empty($value)) {
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Des paramètres de la requête sont mal renseignés ou non présents'
]);
}
$validated[$field] = $value;
}
// Validation spécifique pour l'email
if (!filter_var($validated['email'], FILTER_VALIDATE_EMAIL)) {
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'L\'email fourni n\'est pas valide'
]);
}
// Validation du pays (entier ou par défaut)
$pays = $request->input('pays');
if ($pays !== null && $pays !== '') {
if (!filter_var($pays, FILTER_VALIDATE_INT)) {
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Le pays doit être un entier'
]);
}
$validated['pays'] = $pays;
} else {
$validated['pays'] = 250;
}
// Recherche du contact existant
$contact = Contact::where([
'contact_siteId' => $validated['refsite'],
'contact_ref' => $validated['refadherent']
])->first();
// Si le contact n'existe pas, on vérifie le site
if (!$contact) {
$site = Site::where('site_id', $validated['refsite'])->first();
if (!$site) {
return response()->json([
'Statut' => 'KO',
'Code' => 102,
'Message' => 'Le site spécifié n\'existe pas'
]);
}
$contact = new Contact();
$contact->contact_ref = $validated['refadherent'];
$contact->contact_siteId = $validated['refsite'];
$contact->contact_hash = $request->input('hashcode') ?: strtoupper(md5(uniqid(time(), true)));
}
// Mise à jour des champs
$contact->contact_prenom = $validated['prenom'];
$contact->contact_nom = $validated['nom'];
$contact->contact_email = $validated['email'];
$contact->contact_cp = $validated['code_postal'];
$contact->contact_ville = $validated['commune'];
$contact->contact_country = $validated['pays'];
$contact->contact_updatedate = now();
if ($request->filled('hashcode')) {
$contact->contact_hash = $request->hashcode;
}
// Sauvegarde et réponse
if ($contact->save()) {
return response()->json([
'Statut' => 'OK',
'contact' => $contact
]);
}
return response()->json([
'Statut' => 'KO',
'Code' => 109,
'Message' => 'Une erreur est survenue'
]);
}
}

View file

@ -0,0 +1,509 @@
<?php
namespace App\Http\Controllers\Api\v0;
use Illuminate\Http\Request;
use App\Models\Panier;
use App\Models\Campagne;
use App\Models\Coupon;
use App\Models\Contact;
use App\Http\Controllers\Controller;
use App\Models\Site;
use App\Models\Log;
use App\Models\PanierContent;
use App\Traits\CouponTrait;
use App\Traits\ThanksTrait;
class PanierController extends Controller
{
use ThanksTrait;
use CouponTrait;
public function updateBasket(Request $request)
{
if (isset($request->admin)) {
$source = 'ADMIN';
} else {
$source = 'API';
}
// ---- INIT du log
$log = new Log();
$log->log_action = config('constants.updatebasket');
$log->log_source = $source;
if (isset($request->basketid)) {
$basketid = $request->basketid;
if ($basketid != '') {
$panier = Panier::where('panier_ref', $basketid)->first();
if (!$panier) {
$log->log_params = json_encode(['basketid' => $basketid]);
$log->log_statut = 'NOK';
$log->log_message = "Le panier n'existe pas";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 106,
'Message' => 'Le panier n\'existe pas'
]);
}
if (isset($request->panier) && $request->panier != "") {
$panier = $request->panier;
$panierTab = explode(",", $panier);
$coupons = [];
foreach ($panierTab as $panier) {
$pos = strpos($panier, ")");
if ($pos === false || substr_count($panier, ")") != 1) {
$log->log_params = json_encode(['basketid' => $basketid, 'panier' => $panier]);
$log->log_statut = 'NOK';
$log->log_message = "Des paramètres de la requête sont mal renseignés ou non présents";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Des paramètres de la requête sont mal renseignés ou non présents'
]);
}
$quantity = substr($panier, 0, $pos);
$quantity = str_replace("(", "", $quantity);
$couponCode = substr($panier, $pos + 1);
if (is_numeric($quantity) && is_numeric($couponCode)) {
if (isset($coupons[$couponCode])) {
$coupons[$couponCode] = $coupons[$couponCode] + $quantity;
} else {
$coupons[$couponCode] = $quantity;
}
} else {
$log->log_params = json_encode(['basketid' => $basketid, 'panier' => $panier]);
$log->log_statut = 'NOK';
$log->log_message = "Des paramètres de la requête sont mal renseignés ou non présents";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Des paramètres de la requête sont mal renseignés ou non présents'
]);
}
}//end foreach
// ---- Préparation message de log avec coupons
$panierCoupons = [];
foreach ($coupons as $code => $qty) {
array_push($panierCoupons, ['cp_code' => $code, 'qty' => $qty]);
}
if (count($coupons) == 0) {
die();
}
} else {
$log->log_params = json_encode(['basketid' => $basketid, 'panier' => $panier]);
$log->log_statut = 'NOK';
$log->log_message = "Des paramètres de la requête sont mal renseignés ou non présents";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Des paramètres de la requête sont mal renseignés ou non présents'
]);
}//end if
// ---- MAJ du panier
$panier = Panier::where('panier_ref', $basketid)->first();
if ($panier) {
foreach ($coupons as $couponCode => $quantity) {
$cp = Coupon::where('coupon_code', $couponCode)->first();
$exists = $cp->campagnes->contains($panier->panier_campId);
if ($cp && $exists) {
$site = $cp->coupon_siteId;
$panierContent = PanierContent::where(['panier_content_panierId' => $panier->panier_id, 'panier_content_couponId' => $cp->coupon_id])->first();
if ($panierContent) {
$quantity += $panierContent->panier_content_quantity;
if ($quantity <= 0) {
$quantity = 0;
}
// MAJ du contenu
$panierContent->panier_content_quantity = $quantity;
$panierContent->save();
} else {
// Ajout du contenu
if ($quantity > 0) {
$panierNewContent = new PanierContent();
$panierNewContent->panier_content_panierId = $panier->panier_id;
$panierNewContent->panier_content_couponId = $cp->coupon_id;
$panierNewContent->panier_content_quantity = $quantity;
$panierNewContent->save();
}
}
} else {
$log->log_params = json_encode(['refcamp' => $request->refcamp, 'refadherent' => $request->refadherent, 'refsite' => $request->refsite, 'nom' => $request->nom, 'prenom' => $request->prenom, 'email' => $request->email, 'code postal' => $request->code_postal, 'commune' => $request->commune, 'panier' => $request->panier]);
$log->log_statut = 'NOK';
$log->log_message = "Le coupon ne correspond pas aux coupons liés a la campagne";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 110,
'Message' => 'Le coupon ne correspond pas aux coupons liés a la campagne'
]);
}//end if
}//end foreach
// MAJ du status du panier
$qty = $panier->panierContents()->sum('panier_content_quantity');
if ($qty == 0) {
$panier_pending = 0;
} else {
$panier_pending = 1;
}
$panier->panier_pending = $panier_pending;
$panier->save();
$campagne = Campagne::where(['camp_id' => $panier->panier_campId])->first();
$log->log_refsite = $campagne->camp_siteId;
$log->log_contactId = $panier->panier_contactId;
$log->log_params = json_encode(['refcamp' => $panier->panier_campId, 'basketid' => $basketid, 'panier' => $panier]);
$log->log_statut = 'OK';
$log->log_message = json_encode(['Message' => 'Le panier a bien été créé/mis à jour', 'Coupons' => $panierCoupons], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$log->save();
$contact = Contact::where(['contact_id' => $panier->panier_contactId])->first();
$site = Site::where(['site_id' => $campagne->camp_siteId])->first();
if (isset($contact->contact_nom) && isset($site->site_nom)) {
if ($panier->panier_pending == 1) {
$encours = "oui";
} else {
$encours = "non";
}
$response = new \stdClass();
$response->Site = $site->site_nom . " (" . $site->site_id . ")";
$response->Campagne = $campagne->camp_name . " (" . $campagne->camp_id . ")";
$response->Panier = $panier->panier_ref;
$response->DateCreation = date("d/m/Y", strtotime($panier->panier_createdate));
$response->EnCours = $encours;
$response->Nom = $contact->contact_nom;
$response->Prenom = $contact->contact_prenom;
$response->Email = $contact->contact_email;
$response->CodePostal = $contact->contact_cp;
$response->Commune = $contact->contact_ville;
$allPanierContent = $panier->panierContents()->get();
foreach ($allPanierContent as $panierContent) {
$panCont = [];
$coupon = Coupon::where(['coupon_id' => $panierContent->panier_content_couponId])->first();
if ($coupon) {
array_push($panCont, $coupon->coupon_code . " - " . $coupon->coupon_name . " (x" . $panierContent->panier_content_quantity . ")");
}
}
$response->panierContent = $panCont;
return response()->json([
'Statut' => 'OK',
'Panier' => $response
]);
} else {
return response()->json([
'Statut' => 'OK',
'Panier' => $panier
]);
}//end if
} else {
$log->log_params = json_encode(['basketid' => $basketid, 'panier' => $panier]);
$log->log_statut = 'NOK';
$log->log_message = "Le panier n'existe pas";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 106,
'Message' => 'Le panier n\'existe pas'
]);
}//end if
} else {
$log->log_params = json_encode(['basketid' => $basketid, 'panier' => $panier]);
$log->log_statut = 'NOK';
$log->log_message = "Le panier n'existe pas";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 106,
'Message' => 'Le panier n\'existe pas'
]);
}//end if
} else {
// ---- Contrôle des paramètres
$error = false;
if (isset($request->refcamp) && $request->refcamp != "") {
$refcamp = $request->refcamp;
$campagne = Campagne::where(['camp_id' => $refcamp])->first();
if (!$campagne || $campagne->camp_published == 0 || ($campagne->camp_type->value != 1 && $campagne->camp_type->value != 3)) {
$log->log_params = json_encode(['refcamp' => $refcamp]);
$log->log_statut = 'NOK';
$log->log_message = "La campagne n'existe pas ou n'est pas un panier";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 103,
'Message' => 'La campagne n\'existe pas ou n\'est pas un panier'
]);
}
} else {
$error = true;
}
if (isset($request->refadherent) && $request->refadherent != "") {
$refadherent = $request->refadherent;
} else {
$error = true;
}
if (isset($request->nom) && $request->nom != "") {
$nom = $request->nom;
} else {
$error = true;
}
if (isset($request->refsite) && $request->refsite != "") {
$refsite = $request->refsite;
if ($refsite != $campagne->camp_siteId) {
return response()->json([
'Statut' => 'KO',
'Code' => 103,
'Message' => 'La campagne ne correspond à aucune campagnes du site'
]);
}
} else {
$error = true;
}
if (isset($request->prenom) && $request->prenom != "") {
$prenom = $request->prenom;
} else {
$error = true;
}
if (isset($request->email) && $request->email != "" && filter_var($request->email, FILTER_VALIDATE_EMAIL)) {
$email = $request->email;
} else {
$error = true;
}
if (isset($request->code_postal) && $request->code_postal != "") {
$code_postal = $request->code_postal;
} else {
$error = true;
}
if (isset($request->commune) && $request->commune != "") {
$commune = $request->commune;
} else {
$error = true;
}
if (isset($request->pays) && $request->pays != "") {
if (filter_var($request->pays, FILTER_VALIDATE_INT)) {
$pays = $request->pays;
} else {
$error = true;
}
} else {
$pays = 250;
}
if (isset($request->panier) && $request->panier != "") {
$panier = $request->panier;
$panierTab = explode(",", $panier);
$coupons = [];
foreach ($panierTab as $panier) {
$pos = strpos($panier, ")");
if ($pos === false) {
$error = true;
}
$quantity = substr($panier, 0, $pos);
$quantity = str_replace("(", "", $quantity);
$couponCode = substr($panier, $pos + 1);
if (is_numeric($quantity) && is_numeric($couponCode) && $quantity > 0) {
if (isset($coupons[$couponCode])) {
$coupons[$couponCode] = $coupons[$couponCode] + $quantity;
} else {
$coupons[$couponCode] = $quantity;
}
}
}
if (count($coupons) == 0) {
die();
}
} else {
$error = true;
}//end if
// ---- Préparation message de log avec coupons
if (isset($coupons)) {
$panierCoupons = [];
foreach ($coupons as $code => $qty) {
array_push($panierCoupons, ['cp_code' => $code, 'qty' => $qty]);
}
}
if ($error) {
$log->log_params = json_encode(['refcamp' => $request->refcamp, 'refadherent' => $request->refadherent, 'refsite' => $request->refsite, 'nom' => $request->nom, 'prenom' => $request->prenom, 'email' => $request->email, 'code postal' => $request->code_postal, 'commune' => $request->commune, 'panier' => $request->panier]);
$log->log_statut = 'NOK';
$log->log_message = "Des paramètres de la requête sont mal renseignés ou non présents";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Des paramètres de la requête sont mal renseignés ou non présents'
]);
}
// ---- Ajout/MAJ du contact
$contact = Contact::where(['contact_siteId' => $refsite, 'contact_ref' => $refadherent])->first();
if ($contact) {
// ---- Mise à jour du contact
$contact->contact_prenom = $prenom;
$contact->contact_nom = $nom;
$contact->contact_email = $email;
$contact->contact_cp = $code_postal;
$contact->contact_ville = $commune;
$contact->contact_country = $pays;
$contact->contact_updatedate = date('Y-m-d H:i:s');
} else {
// ---- Création du contact
$site = Site::where('site_id', $refsite)->first();
if ($site) {
$contact = new Contact();
$contact->contact_nom = $nom;
$contact->contact_prenom = $prenom;
$contact->contact_ref = $refadherent;
$contact->contact_email = $email;
$contact->contact_cp = $code_postal;
$contact->contact_ville = $commune;
$contact->contact_country = $pays;
$contact->contact_siteId = $refsite;
$contact->contact_hash = strtoupper(md5(uniqid(time(), true)));
} else {
$log->log_params = json_encode(['refcamp' => $request->refcamp, 'refadherent' => $request->refadherent, 'refsite' => $request->refsite, 'nom' => $request->nom, 'prenom' => $request->prenom, 'email' => $request->email, 'code postal' => $request->code_postal, 'commune' => $request->commune, 'panier' => $request->panier]);
$log->log_statut = 'NOK';
$log->log_message = "Le site spécifié n'existe pas";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 102,
'Message' => 'Le site spécifié n\'existe pas'
]);
}//end if
}//end if
if (!$contact->save()) {
$log->log_params = json_encode(['refcamp' => $request->refcamp, 'refadherent' => $request->refadherent, 'refsite' => $request->refsite, 'nom' => $request->nom, 'prenom' => $request->prenom, 'email' => $request->email, 'code postal' => $request->code_postal, 'commune' => $request->commune, 'panier' => $request->panier]);
$log->log_statut = 'NOK';
$log->log_message = "Une erreur est survenue";
$log->save();
return response()->json([
'Statut' => 'KO',
'Code' => 109,
'Message' => 'Une erreur est survenue'
]);
}
// ---- Ajout/MAJ du panier
$panier = Panier::where(['panier_campId' => $refcamp, 'panier_contactId' => $contact->contact_id, 'panier_pending' => 1])->first();
if ($panier) {
foreach ($coupons as $couponCode => $quantity) {
$camp = Campagne::where('camp_id', $panier->panier_campId)->first();
$cp = $camp->coupons()->where('coupon_code', $couponCode)->first();
if ($cp) {
$panierContent = PanierContent::where(['panier_content_panierId' => $panier->panier_id, 'panier_content_couponId' => $cp->coupon_id])->first();
if ($panierContent) {
// $quantity += $panierContent->panier_content_quantity;
$panierContent->panier_content_quantity = $quantity + $panierContent->panier_content_quantity;
// MAJ du contenu
$panierContent->save();
// $panierContent->update(['panier_content_quantity', $quantity]);
} else {
// Ajout du contenu
if ($quantity > 0) {
$panierNewContent = new PanierContent();
$panierNewContent->panier_content_panierId = $panier->panier_id;
$panierNewContent->panier_content_couponId = $cp->coupon_id;
$panierNewContent->panier_content_quantity = $quantity;
$panierNewContent->save();
}
}
}
}//end foreach
} else {
// Ajout du panier et du contenu
$panierRef = strtoupper(md5(uniqid(time(), true)));
$panier = new Panier();
$panier->panier_ref = $panierRef;
$panier->panier_campId = $refcamp;
$panier->panier_contactId = $contact->contact_id;
$panier->panier_createdate = date('Y-m-d H:i:s');
$panier->save();
foreach ($coupons as $couponCode => $quantity) {
$cp = $campagne->coupons()->where('coupon_code', $couponCode)->first();
if ($cp) {
// Ajout du contenu
if ($quantity > 0) {
$panierNewContent = new PanierContent();
$panierNewContent->panier_content_panierId = $panier->panier_id;
$panierNewContent->panier_content_couponId = $cp->coupon_id;
$panierNewContent->panier_content_quantity = $quantity;
$panierNewContent->save();
}
}
}
}//end if
$log->log_params = json_encode(['refcamp' => $request->refcamp, 'refadherent' => $request->refadherent, 'refsite' => $request->refsite, 'nom' => $request->nom, 'prenom' => $request->prenom, 'email' => $request->email, 'code postal' => $request->code_postal, 'commune' => $request->commune, 'panier' => $request->panier]);
$log->log_contactId = $panier->panier_contactId;
$log->log_refsite = $request->refsite;
$log->log_statut = 'OK';
$log->log_message = json_encode(['Message' => 'Le panier a bien été créé/mis à jour', 'Coupons' => $panierCoupons], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$log->save();
$contact = Contact::where(['contact_id' => $panier->panier_contactId])->first();
$site = Site::where(['site_id' => $campagne->camp_siteId])->first();
if (isset($contact->contact_nom) && isset($site->site_nom)) {
if ($panier->panier_pending == 1) {
$encours = "oui";
} else {
$encours = "non";
}
$response = new \stdClass();
$response->Site = $site->site_nom . " (" . $site->site_id . ")";
$response->Campagne = $campagne->camp_name . " (" . $campagne->camp_id . ")";
$response->Panier = $panier->panier_ref;
$response->DateCreation = date("d/m/Y", strtotime($panier->panier_createdate));
$response->EnCours = $encours;
$response->Nom = $contact->contact_nom;
$response->Prenom = $contact->contact_prenom;
$response->Email = $contact->contact_email;
$response->CodePostal = $contact->contact_cp;
$response->Commune = $contact->contact_ville;
$allPanierContent = $panier->panierContents()->get();
$panCont = [];
foreach ($allPanierContent as $panierContent) {
$coupon = Coupon::where(['coupon_id' => $panierContent->panier_content_couponId])->first();
if ($coupon) {
array_push($panCont, $coupon->coupon_code . " - " . $coupon->coupon_name . " (x" . $panierContent->panier_content_quantity . ")");
}
}
$response->panierContent = $panCont;
return response()->json([
'Statut' => 'OK',
'Panier' => $response
]);
} else {
return response()->json([
'Statut' => 'OK',
'Panier' => $panier
]);
}//end if
}//end if
}
}

View file

@ -0,0 +1,140 @@
<?php
namespace App\Http\Controllers\Api\v1;
use Illuminate\Http\Request;
use App\Models\Campagne;
use App\Enums\LogActions;
use App\Http\Controllers\Controller;
use App\Models\Basket;
use App\Models\Coupon;
use App\Models\Customers;
use App\Traits\CouponTrait;
use App\Traits\ThanksTrait;
use App\Traits\LogTrait;
class BasketController extends Controller
{
use ThanksTrait, CouponTrait, LogTrait;
protected $logSource;
protected $logAction;
public function __construct()
{
$this->logAction = LogActions::updatebasket();
$this->logSource = 'API';
}
public function updateBasket(Request $request)
{
// Validate required parameters
$requiredParams = ['customer_hashcode', 'refcamp', 'refsite', 'panier'];
$error = array_any($requiredParams, fn($param) => empty($request->{$param}));
if ($error) {
$this->writeLogErrorWrongRequestParameters(
$request->refcamp ?? null,
$request->customer_hashcode ?? null,
$request->refsite ?? null,
$request->panier ?? null
);
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Des paramètres de la requête sont mal renseignés ou non présents'
]);
}
// Validate campaign
$refcamp = $request->refcamp;
$campagne = Campagne::where('camp_id', $refcamp)->first();
if (!$campagne || $campagne->camp_published == 0 || !in_array($campagne->camp_type->value, [1, 3])) {
$this->writeLogErrorIncorrectCampaign($refcamp);
return response()->json([
'Statut' => 'KO',
'Code' => 103,
'Message' => 'La campagne n\'existe pas ou n\'est pas un panier'
]);
}
$refsite = $request->refsite;
if ($refsite != $campagne->camp_siteId) {
return response()->json([
'Statut' => 'KO',
'Code' => 103,
'Message' => 'La campagne ne correspond à aucune campagnes du site'
]);
}
// Parse panier
$panierTab = explode(",", $request->panier);
$coupons = [];
foreach ($panierTab as $item) {
$pos = strpos($item, ")");
if ($pos === false) {
$error = true;
break;
}
$quantity = str_replace("(", "", substr($item, 0, $pos));
$couponCode = substr($item, $pos + 1);
if (is_numeric($quantity) && is_numeric($couponCode) && $quantity > 0) {
$coupon = Coupon::where('coupon_code', $couponCode)->first();
if (isset($coupons[$coupon->coupon_id])) {
$coupons[$coupon->coupon_id] += $quantity;
} else {
$coupons[$coupon->coupon_id] = $quantity;
}
}
}
if (empty($coupons)) {
die();
}
if ($error) {
$this->writeLogErrorWrongRequestParameters(
$refcamp,
$request->customer_hashcode,
$campagne->camp_siteId,
$request->panier
);
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Des paramètres de la requête sont mal renseignés ou non présents'
]);
}
// Prepare panierCoupons for logging
$panierCoupons = [];
foreach ($coupons as $coupon_id => $qty) {
$panierCoupons[] = ['coupon_id' => $coupon_id, 'qty' => $qty];
}
// Retrieve customer
$customer = Customers::where('hashcode', $request->customer_hashcode)->first();
// Retrieve or create basket
$basket = Basket::updateContent($campagne, $coupons, $customer);
// Log success
$this->writeLogSuccessBasketCreated(
$refcamp,
$request->customer_hashcode,
$refsite,
$request->panier,
$panierCoupons
);
return response()->json([
'Statut' => 'OK',
'Panier' => $basket
]);
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace App\Http\Controllers\Api\v1;
use App\Models\Campagne;
use App\Models\Coupon;
use App\Enums\CampaignTypes;
use App\Http\Controllers\Controller;
use App\Http\Requests\Coupons\PrintRequest;
use App\Http\Resources\StatusResource;
use App\Models\Customers;
use App\Traits\CouponTrait;
use App\Traits\GenerateBR;
use PDF;
use LDC\LDCCRM\CrmApiV4;
class CouponsController extends Controller
{
use CouponTrait;
use GenerateBR;
public function print(PrintRequest $request)
{
$datas = $request->validated();
$campagne = Campagne::find($datas['refcamp']);
$customer = Customers::find($datas['hashcode']);
$couponsToPrint = explode(",", $datas['coupons']);
$type = $request->validated()['type'] ?? 'stream';
if ($campagne->site->crm_token === null) {
return new StatusResource(['status' => 'KO', 'code' => 500, 'message' => 'CRM Token is missing for site_id : ' . $campagne->site->site_id]);
}
if ($campagne->site->crm_password === null) {
return new StatusResource(['status' => 'KO', 'code' => 500, 'message' => 'CRM Password is missing for site_id : ' . $campagne->site->site_id]);
}
if (empty($couponsToPrint)) {
return new StatusResource(['status' => 'KO', 'code' => 422, 'message' => 'Coupons not found.']);
}
$crm = new CrmApiV4(config('services.crm.endpoint'), $campagne->site->crm_token, $campagne->site->crm_password);
try {
/**
* @var \LDC\LDCCRM\Models\Customer
*/
$crmInfos = $crm->getCustomer($customer->hashcode);
} catch (\Exception) {
// TODO : Update error message
return new StatusResource(['status' => 'KO', 'code' => 422, 'message' => 'Customer not found.']);
}
if (is_null($crmInfos)) {
return new StatusResource(['status' => 'KO', 'code' => 422, 'message' => 'Customer not found.']);
}
// TODO : Vérifier si les coupons sont dans la campagne
// TODO : Logs
$coupons = [];
if ($campagne->camp_type->equals(CampaignTypes::mur())) {
// ---- POUR LES MURS
foreach ($couponsToPrint as $coupon_code) {
$cp = Coupon::where(['coupon_code' => $coupon_code])->first();
if (!$this->isUsed($cp, $campagne, $customer)) {
$coupons[] = $this->printCoupon($cp, $customer, $crmInfos, $campagne);
}
}//end foreach
}//end if
// $coupons contains all printed coupons
$pdf = PDF::loadView('pdf.coupons', ['coupons' => $coupons]);
if ($type === 'dl') {
return $pdf->download(sprintf("coupons_%s_%s_%s.pdf", $crmInfos->firstname, $crmInfos->lastname, date('d-m-Y')));
}
return new StatusResource(['status' => 'OK', 'pdf' => base64_encode($pdf->stream(sprintf("coupons_%s_%s_%s.pdf", $crmInfos->firstname, $crmInfos->lastname, date('d-m-Y'))))]);
}
}

View file

@ -0,0 +1,250 @@
<?php
namespace App\Http\Controllers\Api\v1;
use App\Models\Calendrier;
use App\Models\Campagne;
use App\Enums\CampaignTypes;
use App\Http\Requests\Customers\StoreRequest;
use App\Http\Resources\CustomersResource;
use App\Http\Resources\StatusResource;
use App\Models\Customers;
use App\Http\Controllers\Controller;
use App\Http\Requests\Customers\BasketRequest;
use App\Http\Requests\Customers\MurRequest;
use App\Http\Resources\CouponsResource;
use App\Traits\CouponTrait;
use App\Traits\GenerateBR;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
class CustomerController extends Controller
{
use CouponTrait;
use GenerateBR;
/**
* Display a listing of the resource.
*
* @return StatusResource
*/
public function index()
{
return new StatusResource(['status' => 'KO', 'code' => '501', 'message' => 'Not Implemented']);
}
/**
* Show the form for creating a new resource.
*
* @return StatusResource
*/
public function create()
{
return new StatusResource(['status' => 'KO', 'code' => '501', 'message' => 'Not Implemented']);
}
/**
* Store a newly created resource in storage.
*
* @param StoreRequest $request
* @return CustomersResource | StatusResource
*/
public function store(StoreRequest $request)
{
$datas = $request->validated();
try {
$customer = Customers::where([
['hashcode', $datas['hashcode']],
['email', $datas['email']]
])->firstOrNew();
$customer->fill($datas);
$customer->saveOrFail();
return new CustomersResource($customer);
} catch (\Throwable $e) {
Log::critical($e->getMessage());
return new StatusResource(['status' => 'KO', 'code' => '500', 'message' => 'Server Error.']);
}
}
/**
* Display the specified resource.
*
* @param integer $id
* @return StatusResource
*/
public function show($id)
{
return new StatusResource(['status' => 'KO', 'code' => '501', 'message' => 'Not Implemented']);
}
/**
* Show the form for editing the specified resource.
*
* @param integer $id
* @return StatusResource
*/
public function edit($id)
{
return new StatusResource(['status' => 'KO', 'code' => '501', 'message' => 'Not Implemented']);
}
/**
* Update the specified resource in storage.
*
* @param Request $request
* @return StatusResource
*/
public function update(Request $request)
{
return new StatusResource(['status' => 'KO', 'code' => '501', 'message' => 'Not Implemented']);
}
/**
* Remove the specified resource from storage.
*
* @param integer $id
* @return StatusResource
*/
public function destroy($id)
{
return new StatusResource(['status' => 'KO', 'code' => '501', 'message' => 'Not Implemented']);
}
/**
* Recupere le contenu d'un mur pour une campagne et un user
* @param MurRequest $request
* @return StatusResource
* @throws ValidationException
*/
public function mur(MurRequest $request)
{
$datas = $request->validated();
$customer = Customers::where('hashcode', $datas['hashcode'])->first();
$campagne = Campagne::find($datas['refcamp']);
if (!$campagne->camp_type->equals(CampaignTypes::mur())) {
return new StatusResource(['status' => 'KO', 'code' => 404, 'message' => 'Campaign is not mur.']);
}
if ($campagne->camp_published === 0) {
return new StatusResource(['status' => 'KO', 'code' => 404, 'message' => 'Campaign not found.']);
}
$coupons = $campagne->coupons()->whereRaw("coupon_published = 1 AND (coupon_mindatediffusion IS NULL OR coupon_mindatediffusion <= NOW()) AND (coupon_maxdatediffusion IS NULL OR coupon_maxdatediffusion >= NOW()) AND (coupon_maxdatevalidity IS NULL OR coupon_maxdatevalidity >= NOW())")->get();
$montantDispo = 0;
$montantTotal = 0;
// TODO : Improve
foreach ($coupons as $key => $coupon) {
// ---- Contrôle des calendriers de diffusion
$calendars = Calendrier::where(['calendrier_couponId' => $coupon->coupon_id])->get();
if (!$calendars->isEmpty()) {
$pub = false;
foreach ($calendars as $calendar) {
if ($calendar->isPublished()) {
$pub = true;
}
}
if (!$pub) {
$coupons->forget($key);
continue;
}
}
// Available for user
$coupon->isUsed = $this->isUsed($coupon, $campagne, $customer);
$montantTotal += $coupon->coupon_value;
if (!$coupon->isUsed) {
$montantDispo += $coupon->coupon_value;
}
}//end foreach
return new StatusResource([
'status' => "OK",
'name' => $campagne->camp_name,
'limited_printing' => $campagne->camp_limitedPrinting,
'total' => count($coupons),
'available_amount' => $montantDispo,
'total_amount' => $montantTotal,
'coupons' => CouponsResource::collection($coupons)
]);
}
/**
* Recupere le contenu d'un panier pour une campagne et un user
* @param BasketRequest $request
* @return StatusResource
* @throws ValidationException
*/
public function basket(BasketRequest $request)
{
$montantDispo = 0;
$montantTotal = 0;
$nbCoupons = 0;
$couponTotal = 0;
$coupons = [];
$datas = $request->validated();
$customer = Customers::where('hashcode', $datas['hashcode'])->first();
$campagne = Campagne::find($datas['refcamp']);
if (!$campagne->camp_type->equals(CampaignTypes::panier())) {
return new StatusResource(['status' => 'KO', 'code' => 404, 'message' => 'Campaign is not basket.']);
}
if ($campagne->camp_published === 0) {
return new StatusResource(['status' => 'KO', 'code' => 404, 'message' => 'Campaign not found.']);
}
$basket = $customer->baskets()->where('campagne_id', $campagne->camp_id)->first();
if (is_null($basket)) {
return new StatusResource(['status' => 'KO', 'code' => 404, 'message' => 'Basket not found.']);
}
foreach ($basket->contents as $content)
{
$published = true;
$nbCoupons += $content->quantity;
$couponTotal += $content->printed;
$montantTotal += ($content->coupon->coupon_value * $content->printed);
$coupon = $content->coupon()->whereRaw("coupon_published = 1 AND (coupon_mindatediffusion IS NULL OR coupon_mindatediffusion <= NOW()) AND (coupon_maxdatediffusion IS NULL OR coupon_maxdatediffusion >= NOW()) AND (coupon_maxdatevalidity IS NULL OR coupon_maxdatevalidity >= NOW())")->first();
if (!is_null($coupon))
{
// ---- Contrôle des calendriers de diffusion
$calendars = Calendrier::where(['calendrier_couponId' => $coupon->coupon_id])->get();
if (!$calendars->isEmpty()) {
$published = false;
foreach ($calendars as $calendar) {
if ($calendar->isPublished()) {
$published = true;
}
}
}
if ($published){
$montantDispo += ($coupon->coupon_value * $content->quantity);
$montantTotal += ($coupon->coupon_value * $content->quantity);
$couponTotal += $content->quantity;
$coupons[] = [
'quantity' => $content->quantity,
'printed' => $content->printed,
'coupon' => new CouponsResource($coupon)
];
}
}
}
return new StatusResource([
'status' => "OK",
'ref' => $basket->uuid,
'name' => $campagne->camp_name,
'limited_printing' => $campagne->camp_limitedPrinting,
'available_coupon' => $nbCoupons,
'available_amount' => $montantDispo,
'total_coupon' => $couponTotal,
'total_amount' => $montantTotal,
'coupons' => $coupons
]);
}
}

View file

@ -0,0 +1,68 @@
<?php
namespace App\Http\Controllers\Api\v1;
use App\Models\Calendrier;
use App\Models\Campagne;
use App\Enums\CampaignTypes;
use App\Http\Controllers\Controller;
use App\Http\Requests\Murs\MursShowRequest;
use App\Http\Resources\CouponsResource;
use App\Http\Resources\StatusResource;
use App\Traits\CouponTrait;
class MurController extends Controller
{
use CouponTrait;
public function show(MursShowRequest $request)
{
$datas = $request->validated();
$campagne = Campagne::find($datas['refcamp']);
if ($campagne->camp_published === 0) {
return new StatusResource(['status' => 'KO', 'code' => 404, 'message' => 'Campaign not found.']);
}
if (!$campagne->camp_type->equals(CampaignTypes::mur())) {
return new StatusResource(['status' => 'KO', 'code' => 403, 'message' => 'Campaign type error.']);
}
$coupons = $campagne->coupons()->whereRaw("coupon_published = 1 AND (coupon_mindatediffusion IS NULL OR coupon_mindatediffusion <= NOW()) AND (coupon_maxdatediffusion IS NULL OR coupon_maxdatediffusion >= NOW()) AND (coupon_maxdatevalidity IS NULL OR coupon_maxdatevalidity >= NOW())")->get();
$montantDispo = 0;
$montantTotal = 0;
// TODO : Improve
foreach ($coupons as $key => $coupon) {
// ---- Contrôle des calendriers de diffusion
$calendars = Calendrier::where(['calendrier_couponId' => $coupon->coupon_id])->get();
if (!$calendars->isEmpty()) {
$pub = false;
foreach ($calendars as $calendar) {
if ($calendar->isPublished()) {
$pub = true;
}
}
if (!$pub) {
$coupons->forget($key);
continue;
}
}
$montantTotal += $coupon->coupon_value;
if (!$coupon->isUsed) {
$montantDispo += $coupon->coupon_value;
}
}//end foreach
return new StatusResource([
'status' => "OK",
'name' => $campagne->camp_name,
'limited_printing' => $campagne->camp_limitedPrinting,
'total' => count($coupons),
'available_amount' => $montantDispo,
'total_amount' => $montantTotal,
'coupons' => CouponsResource::collection($coupons)
]);
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/';
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
/**
* The user has been authenticated.
*
* @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
*/
protected function authenticated()
{
return redirect('/');
}
}

View file

@ -1,54 +0,0 @@
<?php
namespace App\Http\Controllers\Bo\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:backend')->except('logout');
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard(): StatefulGuard
{
return Auth::guard('backend');
}
/**
* Show the application's login form.
*
* @return \Illuminate\Contracts\View\View
*/
public function showLoginForm(): View
{
return view('bo.auth.login');
}
/**
* Where to redirect users after login.
*
* @return string
*/
protected function redirectTo(): string
{
return response()->redirectToIntended()->getTargetUrl();
}
}

View file

@ -1,33 +0,0 @@
<?php
namespace App\Http\Controllers\Bo\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Support\Facades\Auth;
class ResetPasswordController extends Controller
{
use ResetsPasswords;
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard(): StatefulGuard
{
return Auth::guard('backend');
}
/**
* Where to redirect users after login.
*
* @return string
*/
protected function redirectTo(): string
{
return \route('bo.login');
}
}

View file

@ -1,145 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Brands\StoreBrandRequest;
use App\Http\Requests\Bo\Brands\UpdateBrandRequest;
use App\Models\Brand;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class BrandController extends Controller
{
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
/** @var \Illuminate\Database\Eloquent\Builder $brand */
$brand = Brand::query();
if ($request->search) {
$this->searchQuery(
$brand,
$request->search,
null,
'name',
);
}
$this->sortQuery($brand);
$searchFields = trans('Name');
$brandModels = $brand->paginate(10);
return view('bo.pages.brands.index', compact('brandModels', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('bo.pages.brands.create');
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Brands\StoreBrandRequest $request
* @return \Illuminate\Http\Response
*/
public function store(StoreBrandRequest $request)
{
return DB::transaction(function () use ($request) {
$brand = new Brand();
$brand->fill($request->validated());
if ($brand->saveOrFail()) {
return redirect()
->route('bo.brands.edit', $brand)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.brands'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.brands'))]
));
});
}
/**
* Display a listing of the resource.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function edit(Brand $brand)
{
return view('bo.pages.brands.edit', ['brandModel' => $brand]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Brands\UpdateBrandRequest $request
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\Response
*/
public function update(UpdateBrandRequest $request, Brand $brand)
{
return DB::transaction(function () use ($request, $brand) {
$brand->fill($request->validated());
if ($brand->saveOrFail()) {
return redirect()
->route('bo.brands.edit', $brand)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.brands'))]
));
} //end if
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.brands'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Brand $brand
* @return \Illuminate\Http\Response
*/
public function destroy(Brand $brand)
{
if ($brand->deleteOrFail()) {
return redirect()
->route('bo.brands.index')
->with('success', trans(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.brands'))]
));
}
return redirect()
->back()
->with('error', trans(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.brands'))]
));
}
}

View file

@ -1,19 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\View\View;
class DashboardController extends Controller
{
/**
* Dashboard Page
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): View
{
return view('bo.pages.dashboard');
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\Log;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class MaintenanceController extends Controller
{
public function index(Request $request)
{
$datas = Log::select(
DB::raw("DATE_FORMAT(created_at, '%m/%Y') as month"),
DB::raw("COUNT(*) as count")
)
->where('log_statut', 'NOK')
->where('created_at', '>=', \Illuminate\Support\Facades\Date::now()->subMonths(5)->startOfMonth())
->groupBy('month')
->orderBy('month', 'asc')
->get();
$logs = $datas->toArray();
return view('bo.maintenance.index', compact('logs'));
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Users\DestroyUserRequest;
use App\Http\Requests\Bo\Users\StoreUserRequest;
use App\Http\Requests\Bo\Users\UpdateUserRequest;
use Illuminate\Http\Request;
use App\Models\Site;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class UserController extends Controller
{
public function index(Request $request)
{
$users = User::all();
return view('bo.users.index')->with(['users' => $users, 'logs' => []]);
}
public function create(Request $request)
{
$sites = Site::all();
return view('bo.users.create', compact('sites'));
}
public function store(StoreUserRequest $request)
{
$user = new User();
$user->fill($request->validated());
$user->password = Hash::make($request->password);
$user->save();
$sites = Site::whereIn('site_id', $request->site)->get()->pluck('id')->toArray();
$user->sites()->sync($sites);
return to_route('bo.users.edit', $user);
}
public function edit(User $user)
{
$sites = Site::all();
$usersites = $user->sites()->get()->pluck('site_id')->toArray();
return view('bo.users.edit', compact('user', 'sites', 'usersites'));
}
public function update(UpdateUserRequest $request, User $user)
{
$user->fill($request->validated());
$user->save();
$sites = Site::whereIn('site_id', $request->site)->get()->pluck('id')->toArray();
$user->sites()->sync($sites);
$marques = Auth::user()->sites;
$submarques = $marques->map(fn($marque) => $marque->only(['id', 'site_nom', 'site_id', 'site_logo']));
session()->put('marques', $submarques);
return to_route('bo.users.edit', $user);
}
public function destroy(DestroyUserRequest $request, User $user)
{
if ($user->delete()) {
return to_route('bo.users.index');
} else {
session()->flash('delete_nok', 'Erreur lors de la suppression');
return view('bo.user.index');
}
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\BrandChange\InvokeBrandChange;
class BrandChangeController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\InvokeBrandChange $request
* @return \Illuminate\Http\Response
*/
public function __invoke(InvokeBrandChange $request)
{
// TODO : Revoir le passage du site
$site = \App\Models\Site::find($request->site_id);
session()->put('site', $site);
return back();
}
}

View file

@ -0,0 +1,415 @@
<?php
namespace App\Http\Controllers;
use App\Models\Campagne;
use App\Models\Site;
use App\Models\Coupon;
use App\Models\Contact;
use App\Enums\CampaignTypes;
use App\Http\Requests\Campaign\AddCouponsCampaign;
use App\Http\Requests\Campaign\DeleteCampaign;
use App\Http\Requests\Campaign\RemoveCouponCampaign;
use App\Http\Requests\Campaign\RemoveNotifCampaign;
use App\Http\Requests\Campaign\ShowDemoCampaign;
use App\Http\Requests\Campaign\StoreCampaign;
use App\Http\Requests\Campaign\StoreNotifCampaign;
use App\Http\Requests\Campaign\UpdateCampaign;
use App\Models\Mur;
use App\Models\PanierContent;
use App\Models\Notification;
use App\Models\Panier;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use App\Traits\CouponTrait;
class CampagneController extends Controller
{
use CouponTrait;
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// TODO : Revoir le passage du site id ?
$siteId = session()->get('site')->site_id;
$campagnes = Campagne::where('camp_siteId', $siteId)->get();
return view('campagnes.index')->with('campagnes', $campagnes);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('campagnes.create');
}
/**
* Store a newly created resource in storage.
*
* @param StoreCampaign $request
* @return \Illuminate\Http\Response
*/
public function store(StoreCampaign $request)
{
// TODO : Revoir le passage du site
$site = session()->get('site');
$campagne = new Campagne();
$campagne->fill(array_merge($request->validated(), ['camp_siteId' => $site->site_id]));
$campagne->save();
if ($site->campagnes()->save($campagne)) {
if ($campagne->camp_type->equals(CampaignTypes::mur())) {
File::copyDirectory(resource_path('/views/template/mur'), public_path('/landings/' . $campagne->camp_id));
} elseif ($campagne->camp_type->equals(CampaignTypes::panier())) {
File::copyDirectory(resource_path('/views/template/panier'), public_path('/landings/' . $campagne->camp_id));
} elseif ($campagne->camp_type->equals(CampaignTypes::murss())) {
File::copyDirectory(resource_path('/views/template/murnoselection'), public_path('/landings/' . $campagne->camp_id));
} elseif ($campagne->camp_type->equals(CampaignTypes::paniers())) {
File::copyDirectory(resource_path('/views/template/panierselection'), public_path('/landings/' . $campagne->camp_id));
}
}
return redirect(route('campagne.edit', ['campagne' => $campagne]));
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Campagne $campagne
* @return \Illuminate\Http\Response
*/
public function edit(Campagne $campagne)
{
// TODO : Revoir le passage du site id
$siteId = session()->get('site')->id;
$couponsNotLinked = Coupon::whereDoesntHave('campagnes', function (\Illuminate\Contracts\Database\Query\Builder $q) use ($campagne): void {
$q->where('campagne_id', $campagne->camp_id);
})->where('coupon_siteId', $siteId)->where('coupon_published', 1)->get();
return view('campagnes.edit', ['campagne' => $campagne, 'coupons' => $couponsNotLinked]);
}
/**
* Update the specified resource in storage.
*
* @param UpdateCampaign $request
* @param \App\Models\Campagne $campagne
* @return \Illuminate\Http\Response
*/
public function update(UpdateCampaign $request, Campagne $campagne)
{
$campagne->fill($request->validated());
if (!isset($request->camp_limitedPrinting)) {
$campagne->camp_limitedPrinting = 0;
}
if ($campagne->save()) {
session()->flash('update_ok', __('La campagne a bien été modifiée'));
} else {
session()->flash('update_nok', __("Erreur lors de l'enregistrement"));
}
return to_route('campagne.edit', ['campagne' => $campagne]);
}
/**
* Remove the specified resource from storage.
*
* @param DeleteCampaign $request
* @param \App\Models\Campagne $campagne
* @return \Illuminate\Http\Response
*/
public function destroy(DeleteCampaign $request, Campagne $campagne)
{
$campagne->camp_published = 0;
$campagne->save();
if ($campagne->delete()) {
return redirect(route('campagne.index'));
} else {
session()->flash('delete_nok', 'Erreur lors de la suppression');
return view('campagnes.edit')->with('campagne', $campagne);
}
}
// ---- Ajoute des coupons à une campagne
public function addCoupons(AddCouponsCampaign $request, Campagne $campaign)
{
$coupons = Coupon::find($request->ids);
$campaign->coupons()->attach($coupons);
return json_encode($coupons);
}
// ---- Efface des coupons d'une campagne
public function removeCoupon(RemoveCouponCampaign $request, Campagne $campaign, Coupon $coupon)
{
$campaign->coupons()->detach($coupon);
return json_encode($coupon);
}
/**
* @param \Illuminate\Http\Request $request
*
* @return array
*/
public function saveNotification(StoreNotifCampaign $request, Campagne $campaign)
{
$notification = new Notification();
$notification->fill(array_merge($request->validated(), ['notif_campId' => $campaign->camp_id]));
$notification->save();
return back();
}
/**
* @param RemoveNotifCampaign $request
* @param \App\Models\Notification $notification
*
* @return array
*/
public function deleteNotification(RemoveNotifCampaign $request, Notification $notification)
{
if ($notification->delete()) {
return back();
} else {
session()->flash('delete_nok', 'Erreur lors de la suppression');
return back();
}
}
// ---- Montre les campagnes avec un compte de démo
public function showDemo(ShowDemoCampaign $request, Campagne $campaign)
{
$siteId = $campaign->camp_siteId;
$demoContact = Contact::where(['contact_siteId' => $siteId, 'contact_ref' => 'DEMO'])->first();
if (!isset($demoContact)) {
$req = new \Illuminate\Http\Request();
$req->setMethod('POST');
$req->request->add([
'refsite' => $siteId,
'refadherent' => 'DEMO',
'prenom' => 'Compte',
'nom' => 'Démonstration',
'email' => 'demo@demo.fr',
'code_postal' => '72000',
'commune' => 'Le Mans',
'pays' => 250
]);
$contact = new \App\Http\Controllers\ContactController();
$res = $contact->updateContact($req);
$demoContact = Contact::where(['contact_siteId' => $siteId, 'contact_ref' => 'DEMO'])->first();
}
if ($campaign->camp_type->equals(CampaignTypes::mur()) || $campaign->camp_type->equals(CampaignTypes::murss())) {
// ---- DEMONSTRATION POUR LES MURS
$myRequest = new \Illuminate\Http\Request();
$myRequest->setMethod('POST');
$myRequest->request->add(['refcamp' => $campaign->camp_id, 'refadherent' => 'DEMO', 'admin' => 1]);
// ---- EFFACER LES CONTROLES SI EXISTANT
$mur = new \App\Http\Controllers\MurController();
$res = $mur->deleteControlContact($myRequest);
// ---- RETOURNE l'URL
$url = "/?refsite=" . $siteId . "&refcamp=" . $campaign->camp_id . "&hash=" . $demoContact->contact_hash;
return json_encode($url);
} else {
// ---- DEMONSTRATION POUR LES PANIERS
$panier = Panier::where(['panier_campId' => $campaign->camp_id, 'panier_contactId' => $demoContact->contact_id, 'panier_pending' => 1])->first();
if ($panier) {
$url = "/?basketid=" . $panier->panier_ref;
} else {
// --- Pas de panier Création d'un nouveau
// --- Récuperation des coupons de la campagne
$coupons = $campaign->coupons()->get();
foreach ($coupons as $key => $coupon) {
if (!$this->isAvailableToPrint($coupon, $campaign)) {
$coupons->forget($key);
}
}
$couponsTotal = count($coupons);
$couponsAdded = 0;
$basketContent = "";
foreach ($coupons as $coupon) {
$basketContent .= "(1)" . $coupon->coupon_code;
$couponsAdded++;
if ($couponsAdded != $couponsTotal) {
$basketContent .= ",";
}
}
// --- création de l'objet request
$req = new \Illuminate\Http\Request();
$req->setMethod('POST');
$req->request->add([
'refsite' => $siteId,
'refcamp' => $campaign->camp_id,
'refadherent' => $demoContact->contact_ref,
'nom' => $demoContact->contact_nom,
'prenom' => $demoContact->contact_prenom,
'email' => $demoContact->contact_email,
'code_postal' => $demoContact->contact_cp,
'commune' => $demoContact->contact_ville,
'pays' => $demoContact->contact_country,
'panier' => $basketContent,
'admin' => 1
]);
$panier = new \App\Http\Controllers\PanierController();
$res = $panier->updateBasket($req);
$url = "/?basketid=" . $res->original['Panier']->Panier;
}
return json_encode($url);
}
}
// ---- Dépublie une campagne
public function togglePublish(Request $request, Campagne $campaign, int $state)
{
$campaign->camp_published = $state;
$campaign->save();
return json_encode($campaign);
}
public function getDetail(Request $request)
{
$error = false;
// ---- Contrôle des paramètres
if (isset($request->refcamp) && $request->refcamp != "") {
$refcamp = $request->refcamp;
$campagne = Campagne::where(['camp_id' => $refcamp])->first();
if (!$campagne) {
return response()->json([
'Statut' => 'KO',
'Code' => 103,
'Message' => 'La campagne n\'existe pas'
]);
}
} else {
$error = true;
}
if (isset($request->refsite) && $request->refsite != "") {
$refsite = $request->refsite;
$site = Site::where(['site_id' => $refsite])->first();
if (!$site) {
return response()->json([
'Statut' => 'KO',
'Code' => 102,
'Message' => 'Le site n\'existe pas'
]);
};
} else {
$error = true;
}
if ($campagne->camp_siteId != $site->site_id) {
return response()->json([
'Statut' => 'KO',
'Code' => 108,
'Message' => 'Pas de campagne pour ce site'
]);
}
if ($error) {
return response()->json([
'Statut' => 'KO',
'Code' => 101,
'Message' => 'Des paramètres de la requête sont mal renseignés ou non présents'
]);
}
$enligne = ($campagne->camp_published == 1) ? "oui" : "non";
switch ($campagne->camp_type) {
case CampaignTypes::mur():
$type = "mur";
break;
case CampaignTypes::panier():
$type = "panier";
break;
case CampaignTypes::murss():
$type = "mur sans sélection";
break;
case CampaignTypes::paniers():
$type = "panier avec sélection";
break;
}
$data = [
'Site' => $site->site_nom,
'Ref campagne' => $campagne->camp_id,
'Nom campagne' => $campagne->camp_name,
"En ligne" => $enligne,
"Type" => $type,
];
$coupons = $campagne->coupons()->get();
if ($coupons->count() > 0) {
foreach ($coupons as $coupon) {
// ---- Calcul du nombre de BR consommé
$diffuseMur = Mur::where(['mur_campId' => $campagne->camp_id, 'mur_couponId' => $coupon->coupon_id])->count();
$diffusePanier01 = PanierContent::where(['panier_content_couponId' => $coupon->coupon_id])->sum('panier_content_quantity');
$diffusePanier02 = PanierContent::where(['panier_content_couponId' => $coupon->coupon_id])->sum('panier_content_printed');
$diffusePanier = $diffusePanier01 + $diffusePanier02;
if (!$diffusePanier) {
$diffusePanier = 0;
}
$diffuse = $diffuseMur + $diffusePanier;
// ---- Calcul de la quantité restante
$qRestante = $this->getFullQuantity($coupon) - $this->getUsedQuantity($coupon);
// ---- En ligne oui/non
$enligne = ($coupon->coupon_published == 1) ? "oui" : "non";
// ---- Calcul de la date de fin de diffusion
$dateFinDiffusion = "n/c";
if ($coupon->coupon_maxdatediffusion != null) {
$dateFinDiffusion = date("d/m/Y", strtotime($coupon->coupon_maxdatediffusion));
}
// ---- Calcul de la date de fin de validité
$dateFinValidite = "n/c";
if ($coupon->coupon_maxdatevalidity != null) {
$dateFinValidite = date("d/m/Y", strtotime($coupon->coupon_maxdatevalidity));
}
$codeTraitement = [
"Code traitement" => $coupon->coupon_code,
"Nom" => $coupon->coupon_name,
"Nb à diffuser" => $this->getFullQuantity($coupon),
"Nb diffusé" => $diffuse,
"Quantité restante" => $qRestante,
"Valeur faciale" => $coupon->coupon_value . "€",
"En ligne" => $enligne,
"Date de fin de diffusion" => $dateFinDiffusion,
"Date de fin de validité" => $dateFinValidite,
];
$data['Coupons'][] = $codeTraitement;
}//end foreach
}//end if
return response()->json([
'Statut' => 'OK',
'Détails Campagne' => $data
]);
}
}

View file

@ -2,122 +2,14 @@
namespace App\Http\Controllers;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Session;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests;
use DispatchesJobs;
use ValidatesRequests;
/**
* Build Search query on specified fields
* splitting search into words or using whole sentence
*
* @param \Illuminate\Database\Eloquent\Builder $query The eloquent query builder.
* @param string $search The query string.
* @param callable $searchQuery The query string.
* @param string ...$fields Either a simple array or a string
* in case of a string the two fields
* would be concatenate to make the search.
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function searchQuery(
Builder $query,
string $search,
callable $searchQuery = null,
string ...$fields
): Builder {
if (count($fields)) {
// Search using words.
$words = explode(' ', $search);
$query->where(function ($query) use ($searchQuery, $words, $search, $fields) {
foreach ($words as $word) {
if (!strlen($word)) {
continue;
}
$this->searchOnFields($query, $word, $fields);
} //end foreach
// Search whole using whole sentence.
$this->searchOnFields($query, $search, $fields);
if ($searchQuery) {
$searchQuery($query);
}
});
} //end if
return $query;
}
/**
* Build query search on all fields
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $search
* @param array $fields
* @return \Illuminate\Database\Eloquent\Builder
*/
private function searchOnFields(Builder $query, string $search, array $fields): Builder
{
$table = $query->getModel()->getTable();
foreach ($fields as $f) {
$f = str_replace('?', '\?', $f);
if (is_array($f)) {
$query->orWhereRaw(
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($f)->map(function ($q) use ($table) {
return "`$table`.`$q`";
})->implode(', \' \', ')),
['%' . filter_var($search, FILTER_SANITIZE_STRING) . '%']
);
} else {
$query->orWhereRaw(
"UPPER(`$table`.`$f`) LIKE UPPER(?)",
['%' . filter_var($search, FILTER_SANITIZE_STRING) . '%']
);
}
}
return $query;
}
/**
* Sort columns with a query
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $ignore
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function sortQuery(Builder $query, array $ignore = []): Builder
{
$rName = request()->route()->getName();
$table = $query->getModel()->getTable();
if (request()->sort_col) {
Session::put("$rName.sort_col", request()->sort_col);
Session::put("$rName.sorted", true);
}
if (request()->sort_way) {
Session::put("$rName.sort_way", request()->sort_way);
Session::put("$rName.sorted", true);
}
if (request()->rst) {
Session::remove("$rName.sorted");
Session::remove("$rName.sort_col");
Session::remove("$rName.sort_way");
}
if (request()->sort_col and request()->sort_way and Schema::hasColumn($table, request()->sort_col)) {
if (
!isset($ignore) or
(isset($ignore) and !in_array(request()->sort_col, $ignore))
) {
$query = $query->orderBy(\sprintf("$table.%s", request()->sort_col), request()->sort_way);
}
} elseif (Schema::hasColumn($table, 'order')) {
$query = $query->orderBy('order', 'ASC');
Session::put("$rName.sort_col", 'order');
Session::put("$rName.sort_way", 'asc');
}
return $query;
}
}

View file

@ -0,0 +1,243 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Models\Coupon;
use App\Models\Site;
use App\Models\Campagne;
use App\Models\Mouvement;
use App\Models\Calendrier;
use App\Http\Requests\Coupons\StoreCoupons;
use App\Http\Requests\Coupons\UpdateCoupons;
use App\Traits\GenerateBR;
use App\Traits\CouponTrait;
class CouponController extends Controller
{
use GenerateBR;
use CouponTrait;
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
// TODO : Revoir le passage du site
$site = session()->get('site');
$coupons = Coupon::where('coupon_siteId', $site->id)->get();
foreach ($coupons as $coupon) {
// ---- Calcul de la quantité mise à disposition grace aux fonctions dans CouponTrait.php
$coupon->coupon_quantity = $this->getFullQuantity($coupon);
// ---- Calcul de la quantité restante toutes campagnes comprises grace aux fonctions dans CouponTrait.php
$coupon->coupon_left = 0;
// $coupon->coupon_quantity - $this->getUsedQuantity($coupon);
}
return view('coupon.index', ['coupons' => $coupons]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
// TODO : Revoir le passage du site
$site = session()->get('site');
$campagnes = Campagne::where('camp_siteId', session()->get('site')->site_id)->get()
->pluck('camp_name', 'camp_id');
$site = Site::findOrFail($site->id);
return view('coupon.create')->with('campagnes', $campagnes)->with('site', $site);
}
/**
* Store a newly created resource in storage.
*
* @param StoreCoupons $request
* @return \Illuminate\Http\Response
*/
public function store(StoreCoupons $request)
{
$site_id = $request->site_id;
$datas = $this->saveImg($request);
$coupon = new Coupon();
$coupon->fill($datas);
// TODO : A revoir au moment ou on enlevera les images mobiles
if (isset($datas['coupon_thumbnail1'])) {
$coupon->coupon_thumbnail1 = $datas['coupon_thumbnail1'];
}
if (isset($datas['coupon_thumbnail2'])) {
$coupon->coupon_thumbnail2 = $datas['coupon_thumbnail2'];
}
if (isset($datas['coupon_thumbnail3'])) {
$coupon->coupon_thumbnail3 = $datas['coupon_thumbnail3'];
}
if (isset($datas['coupon_thumbnail4'])) {
$coupon->coupon_thumbnail4 = $datas['coupon_thumbnail4'];
}
if (isset($datas['coupon_image'])) {
$coupon->coupon_image = $datas['coupon_image'];
}
//TODO : Voir si on peut mettre le set a 0 dans la request
if (!isset($datas['coupon_published'])) {
$coupon->coupon_published = 0;
}
if (!isset($datas['coupon_legal_mentions_splitted'])) {
$coupon->coupon_legal_mentions_splitted = 0;
}
$br_path = $this->generateBase($request, $coupon);
$coupon->coupon_image = $br_path;
$coupon->coupon_siteId = $site_id;
$coupon->save();
$site = Site::findOrFail($site_id);
$site->coupons()->save($coupon);
if (isset($datas['initial_quantity'])) {
$mouvement = new Mouvement();
$mouvement->mouvement_nombre = $datas['initial_quantity'];
$coupon->mouvements()->save($mouvement);
}
if (isset($datas['startdate'])) {
foreach ($datas['startdate'] as $key => $value) {
$calendar = new Calendrier();
$calendar->calendrier_startdate = $value;
$calendar->calendrier_enddate = $datas['enddate'][$key];
$coupon->calendriers()->save($calendar);
}
}
return to_route('coupon.edit', ['coupon' => $coupon]);
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Coupon $coupon
* @return \Illuminate\Http\Response
*/
public function edit(Coupon $coupon)
{
return view('coupon.edit', ['coupon' => $coupon]);
}
/**
* Update the specified resource in storage.
*
* @param UpdateCoupons $request
* @param \App\Models\Coupon $coupon
* @return \Illuminate\Http\Response
*/
public function update(UpdateCoupons $request, Coupon $coupon)
{
//TODO : Voir si on peut mettre le set a 0 dans la request
if (!isset($request->coupon_enablelimitquantity)) {
$coupon->coupon_enablelimitquantity = 0;
}
if (!isset($request->coupon_enablelimitperiod)) {
$coupon->coupon_enablelimitperiod = 0;
}
if (!isset($request->coupon_norme)) {
$coupon->coupon_norme = 0;
}
if (!isset($request->coupon_published)) {
$coupon->coupon_published = 0;
}
if (!isset($request->coupon_legal_mentions_splitted)) {
$coupon->coupon_legal_mentions_splitted = 0;
}
$datas = $this->saveImg($request);
// On sauvegarde les informations
if ($coupon->update($datas)) {
// Si l'update est OK on met à jour l'image du BR
$br_path = $this->generateBase($request, $coupon);
$coupon->coupon_image = $br_path;
$coupon->save();
// Si on ajoute des BR
// TODO : Gestion de l'erreur si on ajoute une ligne vide
if (isset($datas['mouvementNbre'])) {
foreach ($datas['mouvementNbre'] as $key => $value) {
$mouvement = new Mouvement();
$mouvement->mouvement_nombre = $value;
$mouvement->mouvement_created_at = $datas['mouvementDate'][$key];
$coupon->mouvements()->save($mouvement);
}
}
// Si on ajoute une plage de diffusion
// TODO : Gestion de l'erreur si on ajoute une ligne vide
if (isset($datas['startdate'])) {
$coupon->calendriers()->delete();
foreach ($datas['startdate'] as $key => $value) {
$calendar = new Calendrier();
$calendar->calendrier_startdate = $value;
$calendar->calendrier_enddate = $datas['enddate'][$key];
$coupon->calendriers()->save($calendar);
}
}
session()->flash('update_ok', 'Mise à jour du coupon réussie !');
return to_route('coupon.edit', ['coupon' => $coupon]);
} else {
return view('holder');
} //end if
return to_route('coupon.edit', ['coupon' => $coupon]);
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Coupon $coupon
* @return \Illuminate\Http\Response
*/
public function destroy(Coupon $coupon)
{
$coupon->coupon_published = 0;
$coupon->save();
if ($coupon->delete()) {
return to_route('coupon.index');
} else {
session()->flash('delete_nok', 'Erreur lors de la suppression');
return back();
}
}
/**
* @param \Illuminate\Http\Request $request
*
* @return array
*/
private function saveImg(Request $request)
{
$datas = collect($request->all());
foreach ($datas as $key => $item) {
if ($key == 'coupon_image' || $key == 'coupon_gs1code' || $key == 'coupon_decoration_image' || $key == 'coupon_logo_image' || (substr($key, 7, 9) == 'thumbnail' && strlen($key) < 18)) {
if (isset($item)) {
/** @var \Illuminate\Http\UploadedFile $item */
$path = $item->store('modelfiles/coupons', 'public');
$path = Str::start($path, 'storage/');
$datas->put($key, $path);
} else {
$datas->put($key, $request->input($key . '_hidden'));
}
}
}
return $datas->toArray();
}
}

View file

@ -0,0 +1,88 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Models\Calendrier;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\Basket\PrintRequest;
use App\Models\Basket;
use App\Traits\GenerateBR;
use PDF;
use Illuminate\Http\Request;
use LDC\LDCCRM\CrmApiV4;
class BasketController extends Controller
{
use GenerateBR;
// FIXME: Docblock
public function show(Request $request, Basket $basket)
{
$totalQuantity = $basket->contents->sum(fn($content) => $content->quantity - $content->printed);
if (!$totalQuantity) {
return view('fo.basket.empty', compact('basket'));
}
return view('fo.basket.show', compact('basket', 'totalQuantity'));
}
// FIXME: Docblock
public function print(PrintRequest $request, Basket $basket)
{
$campagne = $basket->campagne;
$crm = new CrmApiV4(config('services.crm.endpoint'), $campagne->site->crm_token, $campagne->site->crm_password);
/**
* @var \LDC\LDCCRM\Models\Customer
*/
$crmInfos = $crm->getCustomer($basket->customer->hashcode);
throw_if(is_null($crmInfos), \Exception::class, 'Customer not found.');
$coupons = [];
$currentDateTime = date('Y-m-d H:i:s');
foreach ($basket->contents as $content) {
$coupon = $content->coupon()->whereRaw(
"coupon_published = 1 AND
(coupon_mindatediffusion IS NULL OR coupon_mindatediffusion <= NOW()) AND
(coupon_maxdatediffusion IS NULL OR coupon_maxdatediffusion >= NOW()) AND
(coupon_maxdatevalidity IS NULL OR coupon_maxdatevalidity >= NOW())"
)->first();
if ($coupon !== null) {
$calendars = Calendrier::where('calendrier_couponId', $coupon->coupon_id)->get();
$published = true;
if (!$calendars->isEmpty()) {
$published = false;
foreach ($calendars as $calendar) {
if ($currentDateTime > $calendar->calendrier_startdate && $currentDateTime < $calendar->calendrier_enddate) {
$published = true;
break; // Exit loop early as condition is met
}
}
}
if ($published) {
$qtyToPrint = $content->quantity - $content->printed;
for ($i = 0; $i < $qtyToPrint; $i++) {
$coupons[] = $this->printCoupon($coupon, $basket->customer, $crmInfos, $campagne);
}
$content->printed = $content->quantity;
$content->save();
}
}
}
if (empty($coupons)) {
return to_route('fo.basket.show', $basket);
}
// $coupons contains all printed coupons
$pdf = PDF::loadView('pdf.coupons', ['coupons' => $coupons]);
return $pdf->download(sprintf("coupons_%s_%s_%s.pdf", $crmInfos->firstname, $crmInfos->lastname, date('d-m-Y_H-i-s')));
}
}

View file

@ -1,19 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\View\View;
class HomeController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): View
{
return view('fo.pages.home');
}
}

View file

@ -0,0 +1,160 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Panier;
use App\Models\Campagne;
use App\Models\Coupon;
use App\Models\Contact;
use App\Enums\CampaignTypes;
use App\Traits\CouponTrait;
use App\Traits\ThanksTrait;
class PanierController extends Controller
{
use ThanksTrait;
use CouponTrait;
public function showTemplate(Request $request)
{
// $panier = Panier::find($request->query('basketid'));
$panier = Panier::where(['panier_ref' => $request->basketid])->first();
abort_unless($panier, 404);
session()->put('panier', $panier);
$panierCouponsCount = $this->getCountCouponsPanierPublished($panier);
$contact = Contact::where(['contact_id' => $panier->panier_contactId])->first();
abort_unless($contact, 404);
session()->put('contact', $contact);
$campagne = Campagne::where(['camp_id' => $panier->panier_campId, 'camp_published' => 1])->first();
abort_unless($campagne, 404);
session()->put('campagne', $campagne);
if ($campagne->camp_type->equals(CampaignTypes::panier())) {
$coupons = $this->getCouponsPublished($campagne);
} else {
$panierContents = $this->getPanierContentPublished($panier);
$coupons = [];
foreach ($panierContents as $panierContent) {
$cp = Coupon::where(['coupon_id' => $panierContent->panier_content_couponId])->first();
$qty = $panierContent->panier_content_quantity;
for ($i = 0; $i < $qty; $i++) {
$coupons[] = $cp;
}
}
}
session()->put('coupons', $coupons);
return view('landings::' . $panier->panier_campId . '.index')
->with(['ref' => $panier->panier_campId, 'coupons' => $coupons, 'contact' => $contact, 'nb' => $panierCouponsCount]);
}
public function printPanierSelect(Request $request)
{
if (isset($request->coupons)) {
session()->put('coupons', $request->coupons);
}
$coupons = session('coupons', []);
abort_unless($request->session()->has('campagne'), 404);
$campagne = $request->session()->get('campagne');
$ref = $campagne->camp_id;
return view('landings::' . $ref . '.imprimer')
->with(['ref' => $ref, 'coupons' => $coupons, 'contact' => $request->session()->get('contact')]);
}
public function showBasket(Request $request)
{
// ---- Contrôle des paramètres
if (isset($request->basketid) && $request->basketid != "") {
$basketid = $request->basketid;
} else {
return response()->json([
'Statut' => 'KO',
'Code' => 106,
'Message' => 'Le panier n\'existe pas'
]);
}
$panier = Panier::where('panier_ref', $basketid)->first();
if (!$panier) {
return response()->json([
'Statut' => 'KO',
'Code' => 106,
'Message' => 'Le panier n\'existe pas'
]);
}
if ($panier->panier_pending == 1) {
$encours = "oui";
} else {
$encours = "non";
}
$contact = $panier->contact()->where(['contact_id' => $panier->panier_contactId])->first();
if (!$contact) {
return response()->json([
'Statut' => 'KO',
'Code' => 104,
'Message' => 'Le contact n\'existe pas'
]);
}
$campagne = $panier->campagne()->where(['camp_id' => $panier->panier_campId])->first();
if (!$campagne) {
return response()->json([
'Statut' => 'KO',
'Code' => 103,
'Message' => 'La campagne n\'existe pas'
]);
}
$site = $campagne->site()->first();
if ($site === null) {
return response()->json([
'Statut' => 'KO',
'Code' => 102,
'Message' => 'Le site n\'existe pas'
]);
}
$allPanierContent = $panier->panierContents()->get();
if ($allPanierContent->count() == 0) {
return response()->json([
'Statut' => 'KO',
'Code' => 108,
'Message' => 'Le panier n\'a pas de coupons liés'
]);
}
$response = new \stdClass();
$response->Site = $site->site_nom . " (" . $site->site_id . ")";
$response->Campagne = $campagne->camp_name . " (" . $campagne->camp_id . ")";
$response->Panier = $panier->panier_ref;
$response->DateCreation = date("d/m/Y", strtotime($panier->panier_createdate));
$response->EnCours = $encours;
$response->Nom = $contact->contact_nom;
$response->Prenom = $contact->contact_prenom;
$response->Email = $contact->contact_email;
$response->CodePostal = $contact->contact_cp;
$response->Commune = $contact->contact_ville;
$panCont = [];
foreach ($allPanierContent as $panierContent) {
$coupon = Coupon::where(['coupon_id' => $panierContent->panier_content_couponId])->first();
if ($coupon) {
array_push($panCont, $coupon->coupon_code . " - " . $coupon->coupon_name . " (x" . $panierContent->panier_content_quantity . ")");
}
}
$response->panierContent = $panCont;
return response()->json([
'Statut' => 'OK',
'Informations Panier' => $response
]);
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers;
use Illuminate\Http\Request;
class RedirectController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$panier = new Controllers\PanierController();
if (isset($request->basketid)) {
return $panier->showTemplate($request);
} else {
return to_route('login');
}
}
}

View file

@ -0,0 +1,125 @@
<?php
namespace App\Http\Controllers;
use App\Models\Site;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class SiteController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$sites = Site::all();
return view('site.index')->with('sites', $sites);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('site.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'site_id' => 'required|unique:site',
'site_nom' => 'required',
'site_contact' => 'required',
'site_logo' => 'required|image|mimes:png',
'site_rcs' => 'required',
'site_libelle' => 'required'
]);
$site = new Site();
$datas = $this->saveImg($request);
$site->site_id = $datas['site_id'];
$site->site_nom = $datas['site_nom'];
$site->site_contact = $datas['site_contact'];
$site->site_logo = $datas['site_logo'];
$site->site_rcs = $datas['site_rcs'];
$site->site_libelle = $datas['site_libelle'];
$site->save();
// --- ADD all new sites to all SuperAdmin
$admins = User::where(['roles' => 'superadmin'])->get();
foreach ($admins as $admin) {
$admin->sites()->save($site);
}
// --- MAJ Selecteur marques
$marques = Auth::user()->sites;
$submarques = $marques->map(fn($marque) => $marque->only(['id', 'site_nom', 'site_id', 'site_logo']));
session()->put('marques', $submarques);
return view('site.edit', ['site' => $site]);
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Site $site
* @return \Illuminate\Http\Response
*/
public function edit(Site $site)
{
return view('site.edit')->with('site', $site);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Site $site
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Site $site)
{
if ($site->update($this->saveImg($request))) {
session()->flash('update_ok', 'Le site a bien été modifié');
} else {
session()->flash('update_nok', 'Erreur lors de l\'enregistrement');
}
return to_route('site.edit', ['site' => $site]);
}
/**
* @param \Illuminate\Http\Request $request
*
* @return array
*/
private function saveImg(Request $request)
{
$datas = collect($request->all());
// Enregistrer le fichiersi il a changé
if ($request->site_logo) {
$path = $request->site_logo->store('images/logos');
$path = str_replace('public/', '', $path);
$datas->put('site_logo', $path);
} else {
$datas->put('site_logo', $request->input('site_logo_hidden'));
}
return $datas->toArray();
}
}

View file

@ -11,38 +11,35 @@ class Kernel extends HttpKernel
*
* These middleware are run during every request to your application.
*
* @var array<int, class-string|string>
* @var array
*/
protected $middleware = [
\App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
* @var array
*/
protected $middlewareGroups = [
'web' => [
'htmlsanitize',
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\SecureHeaders::class
\Illuminate\Routing\Middleware\SubstituteBindings::class
],
'api' => [
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
'throttle:60,1',
'bindings',
],
];
@ -51,19 +48,34 @@ class Kernel extends HttpKernel
*
* These middleware may be assigned to groups or used individually.
*
* @var array<string, class-string|string>
* @var array
*/
protected $middlewareAliases = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \App\Http\Middleware\ValidateSignature::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'htmlsanitize' => \App\Http\Middleware\HtmlSanitizer::class,
'saveroute' => \App\Http\Middleware\SaveCurrentRoute::class,
];
/**
* The priority-sorted list of middleware.
*
* This forces the listed middleware to always be in the given order.
*
* @var array
*/
protected $middlewarePriority = [
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\Authenticate::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];
}

View file

@ -3,8 +3,6 @@
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
class Authenticate extends Middleware
{
@ -12,29 +10,10 @@ class Authenticate extends Middleware
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
* @return string
*/
protected function redirectTo(Request $request): ?string
protected function redirectTo($request)
{
$logins = [
'backend' => route('bo.login')
];
if (!$request->expectsJson()) {
// * Notify must login
Session::flash('warning', trans('Veuillez vous connecter pour continuer'));
foreach ($request->route()->gatherMiddleware() as $middleware) {
if (\is_string($middleware) and strpos($middleware, 'auth:') !== false) {
$route = $logins[str_replace('auth:', '', $middleware)] ?? null;
if ($route) {
return $route;
}
}
}
return route('login');
}
abort(401);
return null;
return route('login');
}
}

View file

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
class CheckForMaintenanceMode extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array
*/
protected $except = [
];
}

View file

@ -9,7 +9,9 @@ class EncryptCookies extends Middleware
/**
* The names of the cookies that should not be encrypted.
*
* @var array<int, string>
* @var array
*/
protected $except = [];
protected $except = [
];
}

View file

@ -1,61 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class HtmlSanitizer
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|array ...$params
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle(Request $request, \Closure $next, string|array ...$params): Response
{
$inputs = $request->all();
/** @var callable|null */
$cleanInput = null;
$cleanInput = function (
null|string|array &$input,
string $name,
?string $rootName = null
) use (
$params,
&$cleanInput
): void {
// * Nested element array
if (is_array($input)) {
array_walk_recursive($input, $cleanInput, $name);
}
if (!is_string($input)) {
return;
}
if (in_array($name, $params) or in_array($rootName ?? $name, $params)) {
// ? Is a json input ?
if ($isJson = \json_decode($input, true) and is_array($isJson)) {
// ! Decode each json field recursive.
\array_walk_recursive($isJson, function (string|array &$item) {
if (\is_string($item)) {
$item = clean($item);
$item = ToolboxHelper::stripCkEditorSchemesOnMediaInputs($item);
}
});
} else {
$input = clean($input);
$input = ToolboxHelper::stripCkEditorSchemesOnMediaInputs($input);
}
} else {
$input = strip_tags($input);
}
};
\array_walk($inputs, $cleanInput);
$request->merge($inputs);
return $next($request);
}
}

View file

@ -1,15 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
class PreventRequestsDuringMaintenance extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array<int, string>
*/
protected $except = [];
}

View file

@ -2,41 +2,23 @@
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Closure;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
* @param string|null ...$guards
* @return \Symfony\Component\HttpFoundation\Response
* @throws \RuntimeException If guard is unhandled.
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle(Request $request, \Closure $next, ...$guards): Response
public function handle($request, Closure $next, $guard = null)
{
// phpcs:enable phpcs:disable
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
switch ($guard) {
case 'frontend':
return \redirect()->route('home');
case 'backend':
if (!$request->routeIs('bo.*')) {
continue;
}
return \redirect()->route('bo.dashboard');
default:
throw new \RuntimeException("Unhandled guard `{$guard}` .");
}
}
if (Auth::guard($guard)->check()) {
return to_route('campagne.index');
}
return $next($request);

View file

@ -0,0 +1,38 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class SaveCurrentRoute
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$site = session()->get('site');
$siteId = session()->get('marques');
if (!$site) {
$site = Auth::user()->sites->first();
session()->put('site', $site);
}
$currentLogo = $site->only(['site_logo']);
session()->put('current_logo', $currentLogo);
if (!$siteId) {
$marques = Auth::user()->sites;
$submarques = $marques->map(fn($marque) => $marque->only(['id', 'site_nom', 'site_id', 'site_logo']));
session()->put('marques', $submarques);
}
return $next($request);
}
}

View file

@ -1,103 +0,0 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Vite;
use Symfony\Component\HttpFoundation\Response;
class SecureHeaders
{
/**
* Enumerate headers which you do not want in your application's responses.
* Great starting point would be to go check out @Scott_Helme's:
* https://securityheaders.com/
*
* @var array
*/
private $unwantedHeaderList = [
'X-Powered-By',
'Server',
];
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
* @return \Symfony\Component\HttpFoundation\Response
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
*/
public function handle(Request $request, Closure $next): Response
{
// phpcs:enable
View::share('nonce', $nonce = Vite::useCspNonce());
// * For VueJS dev tool to execute
$jsDev = config('app.debug') ? "'unsafe-eval' 'unsafe-inline'" : "'nonce-{$nonce}' 'strict-dynamic'";
$scheme = config('app.env') === 'local' ? 'http' : 'https';
$reportUri = Route::has('cspReportUri') ?
\sprintf(' report-uri %s ;', \parse_url(route('cspReportUri'), \PHP_URL_PATH)) : '';
$this->removeUnwantedHeaders($this->unwantedHeaderList);
$response = $next($request);
$response->headers->set('Referrer-Policy', 'no-referrer-when-downgrade');
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-XSS-Protection', '1; mode=block');
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains;');
$cspPolicies = [
"default-src 'none';",
"manifest-src 'self';",
// * CKEDITOR Specific https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/csp.html
"connect-src 'self' blob:;",
"img-src * data: blob:;",
'frame-src ' . implode(' ', [
'https://www.google.com/recaptcha/',
'https://recaptcha.google.com/recaptcha/',
'https://www.google.com/maps/'
]) . ';',
"font-src 'self' data: https://fonts.gstatic.com;",
// ! Using CKEditor will must have unsafe-inline style
// phpcs:ignore Generic.Files.LineLength.TooLong
"style-src 'self' 'unsafe-inline' " . \implode(' ', [
'https://cdnjs.cloudflare.com',
// * File Manager
'https://fonts.googleapis.com',
'https://cdn.jsdelivr.net',
'https://use.fontawesome.com',
'https://fonts.googleapis.com'
]) . ';',
// ! If you dont use ckeditor use this
// "style-src 'self' 'nonce-$nonce';",
// phpcs:ignore Generic.Files.LineLength.TooLong
"script-src 'self' {$jsDev} " . \implode(' ', [
'https: blob:',
'https://www.googletagmanager.com',
'https://cdnjs.cloudflare.com',
"$scheme://www.google-analytics.com",
]) . ';'
];
$response->headers->set(
'Content-Security-Policy',
implode(' ', $cspPolicies) . $reportUri
);
$response->headers->set('Feature-Policy', 'fullscreen \'self\';');
return $response;
}
/**
* Remove unwanted headers
*
* @param array $headerList
* @return void
*/
private function removeUnwantedHeaders(array $headerList)
{
foreach ($headerList as $header) {
header_remove($header);
}
}
}

View file

@ -9,10 +9,10 @@ class TrimStrings extends Middleware
/**
* The names of the attributes that should not be trimmed.
*
* @var array<int, string>
* @var array
*/
protected $except = [
'current_password',
'password',
'password_confirmation',
];

View file

@ -15,6 +15,7 @@ class TrustHosts extends Middleware
{
return [
$this->allSubdomainsOfApplicationUrl(),
config('app.k8s_internal_host'),
];
}
}
}

View file

@ -2,17 +2,17 @@
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array<int, string>|string|null
* @var array
*/
protected $proxies;
protected $proxies = ['*'];
/**
* The headers that should be used to detect proxies.

View file

@ -1,15 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Routing\Middleware\ValidateSignature as Middleware;
class ValidateSignature extends Middleware
{
/**
* The names of the query string parameters that should be ignored.
*
* @var array<int, string>
*/
protected $except = [];
}

View file

@ -4,14 +4,25 @@ namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
class VerifyCsrfToken extends \Illuminate\Foundation\Http\Middleware\PreventRequestForgery
{
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var boolean
*/
protected $addHttpCookie = true;
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
* @var array
*/
protected $except = [
'/csp-report'
'updatecontact',
'updatebasket',
'showbasket',
];
}

View file

@ -1,52 +0,0 @@
<?php
namespace App\Http\Requests\Bo\Brands;
use App\Traits\Requests\HasPicture;
use Illuminate\Foundation\Http\FormRequest;
class StoreBrandRequest extends FormRequest
{
use HasPicture;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth('backend')->check();
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation()
{
$this->mergePicture('logo');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$rules = [
'name' => 'required|string|min:3|max:255',
'contact_mail' => 'required|email:rfc,spoof,dns,strict',
'rcs' => 'required|string|min:3|max:255',
'crm_token' => 'required|string|min:3|max:500',
'crm_password' => 'required|string|min:3|max:500',
];
return \array_merge(
$rules,
$this->pictureRules('logo', 135, 70, 135, 70, false)
);
}
}

View file

@ -1,7 +0,0 @@
<?php
namespace App\Http\Requests\Bo\Brands;
class UpdateBrandRequest extends StoreBrandRequest
{
}

View file

@ -1,229 +0,0 @@
<?php
namespace App\Http\Requests\Bo;
use App\Enums\InputType;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;
abstract class UpdateMiniCrudRequest extends FormRequest
{
/**
* The model parameter name
*
* @var string
*/
protected $modelName = null;
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth('backend')->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
* @phpcs:disable Generic.Metrics.NestingLevel.TooHigh
*/
public function rules()
{
// phpcs:enable
$rules = [];
foreach ($this->{$this->modelName}->data as $iptName => $input) {
$input = \json_decode(\json_encode($input), true);
switch ($input['inputType']) {
case InputType::number->value:
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate('required|numeric', $input)
]);
break;
case InputType::videoYoutube->value:
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate('regex:%([^"&?\/\s]{11})%i', $input)
]);
break;
case InputType::videoVimeo->value:
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate('regex:%([0-9]{8,10})%i', $input)
]);
break;
case InputType::video->value:
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate([
'regex:%([0-9]{8,10}|[^"&?\/\s]{11})%i'
], $input)
]);
break;
case InputType::string->value:
$rules = array_merge($rules, [
"data.$iptName.value" => $this->compileValidate('required|string|min:3', $input)
]);
break;
case InputType::text->value:
$mergeRules = $this->compileValidate('required|string|min:15', $input);
$mergeRules = collect($mergeRules)
->map(function ($rule) {
if (\strpos($rule, 'max:') !== false) {
$max = \intval(str_replace('max:', '', $rule));
return function ($attribute, $value, $fail) use ($max) {
if (\strlen(\strip_tags($value)) > $max) {
$fail("$attribute ne doit pas excéder $max caractères");
}
};
}
return $rule;
});
$rules = array_merge($rules, [
"data.$iptName.value" => $mergeRules
]);
break;
case InputType::image->value:
$required = $this->isUpdate() ? 'sometimes' : 'required';
$ipt = $this->data[$iptName];
$max = isset($ipt['dimensionsMax']);
$dim = \is_string($input['dimensions']) ? collect(explode(
',',
(isset($ipt['dimensionsMax']) and is_string($ipt['dimensionsMax'])) ?
$ipt['dimensionsMax'] : $input['dimensions']
))->mapWithKeys(function ($v) {
$v = explode(' ', $v);
return [$v[0] => $v[1]];
}) : $input['dimensions'];
// * Adapt dimensions
$sizes = (object)[
'minHeight' => $dim['height'],
'maxHeight' => $dim['height'],
'minWith' => $dim['width'],
'maxWith' => $dim['width'],
];
$rules = array_merge($rules, [
"data.$iptName.value" => [
function (string $attribute, $value, callable $fail) use ($sizes) {
return ToolboxHelper::validatePicture($attribute, $value, $fail, $sizes);
}
],
$this->compileValidate(
implode('|', [
$required,
'image',
'mimes:png,jpg,jpeg',
sprintf(
'dimensions:%s=%d,%s=%d',
$max ? 'max_height' : 'height',
$dim['height'],
$max ? 'max_width' : 'width',
$dim['width']
)
]),
$input
),
"data.$iptName.alt" => $this->compileValidate("$required|string|min:5", $input),
"data.$iptName.title" => $this->compileValidate("$required|string|min:5", $input)
]);
break;
case InputType::url->value:
$rules = array_merge($rules, [
"data.$iptName.value" => [
'required', 'url',
// @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
function ($attribute, $value, $fail) {
try {
ToolboxHelper::assertNoInternalUrls($attribute, $value);
ToolboxHelper::assertNoInternalBoUrls($attribute, $value);
} catch (ValidationException $e) {
$fail(collect($e->errors())->first()[0]);
}
}
]
]);
break;
case InputType::boolean->value:
$all = $this->all();
$nested = ToolboxHelper::dotStringToNestedArray(
"data.$iptName.value",
$this->input("data.$iptName.value") ? true : false
);
$all = ToolboxHelper::arrayMergeRecursiveDistinct($all, $nested);
$this->merge($all);
$rules = array_merge($rules, [
"data.$iptName.value" => 'boolean'
]);
break;
} //end switch
} //end foreach
return $rules;
}
/**
* Undocumented function
*
* @param string|array $inputTypeValidate
* @param array $input
* @return array
*/
public function compileValidate(string|array $inputTypeValidate, array $input): array
{
if (\is_string($inputTypeValidate)) {
$inputTypeValidate = explode('|', $inputTypeValidate);
}
/** @var array|string */
$inputValidate = \collect($input)->get('validate', $input);
$inputValidate = \is_string($inputValidate) ? explode('|', $inputValidate) : $inputValidate;
foreach ($inputValidate as $validate) {
if (!\in_array($validate, $inputTypeValidate)) {
$inputTypeValidate[] = $validate;
}
}
$test = \collect($inputTypeValidate)->all();
$test = \collect($inputTypeValidate)->sort(function ($valueA, $valueB) {
$valueA = $this->ruleHasToComeFirst($valueA) ? 0 : 2;
$valueB = $this->ruleHasToComeFirst($valueB) ? 1 : 2;
return $valueA - $valueB;
})->unique()->all();
return \collect($inputTypeValidate)->unique()->sort(function ($valueA, $valueB) {
$valueA = $this->ruleHasToComeFirst($valueA) ? 0 : 2;
$valueB = $this->ruleHasToComeFirst($valueB) ? 1 : 2;
return $valueA - $valueB;
})->all();
}
/**
* Does the rulle need to come first ?
*
* @param string $rule
* @return boolean
*/
private function ruleHasToComeFirst(string $rule): bool
{
$rule = \collect(\explode(':', $rule, 1))->filter()->first(null, '');
return \collect([
'nullable', 'present', 'required', 'required_if',
'required_unless', 'required_with', 'required_with_all',
'required_without', 'required_without_all', 'required_with_all',
'missing', 'missing_if', 'missing_unless',
'missing_with', 'missing_with_all',
])->first(fn (string $firstRule) => \strpos($rule, $firstRule) === 0) ? true : false;
}
/**
* Is this request an update request ?
*
* @return boolean
*/
private function isUpdate(): bool
{
return $this->isMethod('PUT');
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Bo\Users;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class DestroyUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\Bo\Users;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class StoreUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => 'required|unique:users|email',
'name' => 'required',
'password' => 'min:8|required',
'site' => 'required',
'roles' => 'required'
];
}
}

View file

@ -0,0 +1,38 @@
<?php
namespace App\Http\Requests\Bo\Users;
use Illuminate\Validation\Rule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class UpdateUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => [
'required',
Rule::unique('users')->ignore($this->user->id)
],
'name' => 'required',
'site' => 'required',
'roles' => 'required'
];
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\BrandChange;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class InvokeBrandChange extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'site_id' => 'exists:site,id|required'
];
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Campaign;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class AddCouponsCampaign extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'ids' => 'required'
];
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Campaign;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class DeleteCampaign extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Campaign;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class RemoveCouponCampaign extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Campaign;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class RemoveNotifCampaign extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Campaign;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class ShowDemoCampaign extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
//
];
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\Campaign;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class StoreCampaign extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'camp_name' => 'min:5|required',
'camp_type' => 'integer|required',
'camp_published' => 'integer|required',
'camp_limitedPrinting' => 'sometimes|integer|required'
];
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace App\Http\Requests\Campaign;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
class StoreNotifCampaign extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'notif_name' => 'min:5|required',
'notif_email' => [
'required',
Rule::unique('notification')->where(fn($query) => $query->where('notif_campId', $this->campaign->camp_id)),
]
];
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\Campaign;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class UpdateCampaign extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'camp_name' => 'min:5|required',
'camp_type' => 'integer|required',
'camp_published' => 'integer|required',
'camp_limitedPrinting' => 'sometimes|integer|required'
];
}
}

View file

@ -0,0 +1,48 @@
<?php
namespace App\Http\Requests\Coupons;
use App\Http\Resources\StatusResource;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class PrintRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
// TODO : Validate coupons formats
return [
'refcamp' => 'string|exists:campagne,camp_id|required',
'hashcode' => 'string|exists:customers,hashcode|required',
'coupons' => 'required',
'type' => 'nullable|in:stream,dl'
];
}
protected function failedValidation(Validator $validator)
{
if ($this->wantsJson()) {
throw new HttpResponseException(response()->json(new StatusResource([
'status' => 'KO',
'code' => 422,
'message' => $validator->errors()->messages()
]), 422));
}
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace App\Http\Requests\Coupons;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
class StoreCoupons extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'coupon_code' => [
'required',
Rule::unique('coupon', 'coupon_code')
],
'coupon_name' => 'string|required',
'coupon_value' => 'numeric|required',
'coupon_validity_text' => 'required',
'coupon_legal_mentions' => 'required',
'coupon_decoration_image' => 'required|image|mimes:jpeg,png',
'coupon_logo_image' => 'required|image|mimes:jpeg,png',
'coupon_rcs' => 'required',
'coupon_site_contact' => 'required',
'coupon_seuil_alert' => 'integer|required',
'coupon_enablelimitperiod' => 'sometimes|integer|required',
'coupon_enablelimitquantity' => 'sometimes|integer|required',
'coupon_mindatediffusion' => 'nullable',
'coupon_maxdatediffusion' => 'nullable',
'coupon_validity' => 'integer|required',
'coupon_maxdatevalidity' => 'nullable',
'coupon_legal_mentions_splitted' => 'sometimes|integer|required',
];
}
/**
* Configure the validator instance.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return void
*/
public function withValidator($validator)
{
$validator->sometimes('coupon_gs1code', 'required|image|mimes:jpeg', fn($input) => isset($input->coupon_norme));
$validator->sometimes('coupon_limitquantity', 'integer|required', fn($input) => !is_null($input->coupon_enablelimitquantity));
$validator->sometimes('coupon_limitperiod', 'integer|required', fn($input) => !is_null($input->coupon_enablelimitperiod));
}
}

View file

@ -0,0 +1,78 @@
<?php
namespace App\Http\Requests\Coupons;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
class UpdateCoupons extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'coupon_code' => [
'required',
Rule::unique('coupon', 'coupon_code')->ignore($this->coupon->coupon_id, 'coupon_id')
],
'coupon_name' => 'string|required',
'coupon_value' => 'numeric|required',
'coupon_seuil_alert' => 'integer|required',
'coupon_enablelimitperiod' => 'sometimes|integer|required',
'coupon_enablelimitquantity' => 'sometimes|integer|required',
'coupon_mindatediffusion' => 'nullable',
'coupon_maxdatediffusion' => 'nullable',
'coupon_validity' => 'integer|required',
'coupon_maxdatevalidity' => 'nullable',
'coupon_treatment_center' => 'integer|required',
'coupon_validity_text' => 'required',
'coupon_legal_mentions' => 'required',
'coupon_rcs' => 'required',
'coupon_site_contact' => 'email|required',
'coupon_norme' => 'sometimes|integer|required',
'coupon_published' => 'sometimes|integer|required',
'coupon_legal_mentions_splitted' => 'sometimes|integer|required',
'coupon_decoration_image' => 'image|mimes:jpeg,png',
'coupon_logo_image' => 'image|mimes:jpeg,png',
];
}
/**
* Configure the validator instance.
*
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return void
*/
public function withValidator($validator)
{
$validator->sometimes('coupon_gs1code', 'required|image|mimes:jpeg', function ($input) {
if (isset($input->coupon_gs1code_image_hidden)) {
return false;
}
return isset($input->coupon_norme);
});
$validator->sometimes('coupon_limitquantity', 'integer|required', fn($input) => !is_null($input->coupon_enablelimitquantity));
$validator->sometimes('coupon_limitperiod', 'integer|required', fn($input) => !is_null($input->coupon_enablelimitperiod));
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace App\Http\Requests\Customers;
use App\Http\Resources\StatusResource;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class BasketRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'refcamp' => 'string|exists:campagne,camp_id|required',
'hashcode' => 'string|exists:customers,hashcode|required'
];
}
protected function failedValidation(Validator $validator)
{
if ($this->wantsJson()) {
throw new HttpResponseException(response()->json(new StatusResource([
'status' => 'KO',
'code' => 422,
'message' => $validator->errors()->messages()
]), 422));
}
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace App\Http\Requests\Customers;
use App\Http\Resources\StatusResource;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class MurRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'refcamp' => 'string|exists:campagne,camp_id|required',
'hashcode' => 'string|exists:customers,hashcode|required'
];
}
protected function failedValidation(Validator $validator)
{
if ($this->wantsJson()) {
throw new HttpResponseException(response()->json(new StatusResource([
'status' => 'KO',
'code' => 422,
'message' => $validator->errors()->messages()
]), 422));
}
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests\Customers;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class SearchCustomers extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check()
&& in_array(Auth::user()->roles, [UserRoles::superadmin()->value, UserRoles::admin()->value]);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => 'sometimes|email|required'
];
}
}

View file

@ -0,0 +1,46 @@
<?php
namespace App\Http\Requests\Customers;
use App\Http\Resources\StatusResource;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class StoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'hashcode' => 'string|required',
'email' => 'email|required',
'country' => 'string|required'
];
}
protected function failedValidation(Validator $validator)
{
if ($this->wantsJson()) {
throw new HttpResponseException(response()->json(new StatusResource([
'status' => 'KO',
'code' => 422,
'message' => $validator->errors()->messages()
]), 422));
}
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace App\Http\Requests\Export;
use App\Enums\UserRoles;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class PDFExport extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check() && (Auth::user()->roles === UserRoles::superadmin()->value || Auth::user()->roles === UserRoles::admin()->value);
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'ids' => 'required',
'startdate' => 'date|required',
'enddate' => 'date|required'
];
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace App\Http\Requests\Fo\Basket;
use App\Enums\CampaignTypes;
use Illuminate\Foundation\Http\FormRequest;
class PrintRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
// FIXME: Docblock
protected function prepareForValidation()
{
$campagne = $this->basket->campagne;
throw_unless($campagne->camp_type->equals(CampaignTypes::panier()), \Exception::class, 'Campaign is not basket.');
throw_if($campagne->camp_published === 0, \Exception::class, 'Campaign is not published.');
throw_if($campagne->site->crm_token === null, \Exception::class, 'CRM Token is missing.');
throw_if($campagne->site->crm_password === null, \Exception::class, 'CRM Password is missing.');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [];
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace App\Http\Requests\Murs;
use App\Http\Resources\StatusResource;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
class MursShowRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'refcamp' => 'exists:campagne,camp_id|required'
];
}
protected function failedValidation(Validator $validator)
{
if ($this->wantsJson()) {
throw new HttpResponseException(response()->json(new StatusResource([
'status' => 'KO',
'code' => 422,
'message' => $validator->errors()->messages()
]), 422));
}
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class CouponsResource extends JsonResource
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$coupon = [
'code' => $this->coupon_code,
'name' => $this->coupon_name,
'value' => $this->coupon_value,
'used' => $this->isUsed ?? false,
'desktop_image_available' => $this->returnUrl($this->coupon_thumbnail1),
'desktop_image_unavailable' => $this->returnUrl($this->coupon_thumbnail2),
'mobile_image_available' => $this->returnUrl($this->coupon_thumbnail3),
'mobile_image_unavailable' => $this->returnUrl($this->coupon_thumbnail4),
'validity_text' => $this->coupon_validity_text
];
if (isset($this->isUsed)){
return array_merge($coupon, [
'used' => $this->isUsed,
]);
}
return $coupon;
}
private function returnUrl($assets)
{
return !empty($assets) ? config('app.url') . "/$assets" : null;
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class CustomersResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return StatusResource
*/
public function toArray($request)
{
return new StatusResource([
'status' => 'OK',
'customer' => parent::toArray($request)
]);
}
}

View file

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

View file

@ -0,0 +1,67 @@
<?php
namespace App\Jobs;
use App\Models\ArchiveStat;
use App\Models\Statistique;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ArchiveStatsJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
// Construct method.
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try {
DB::transaction(function (): void {
Statistique::query()
->where('date', '<', now())
->each(function ($stat): void {
$archiveStat = new ArchiveStat();
$archiveStat->quantity = $stat->stat_couponPrinted;
$archiveStat->date = $stat->date;
$archiveStat->archive_coupon_id = $stat->stat_couponId;
$archiveStat->archive_campaign_id = $stat->stat_campId;
$archiveStat->saveOrFail();
});
Statistique::query()
->where('date', '<', now())
->delete();
});
} catch (\Exception $e) {
Log::error(
sprintf(
"ArchiveStatsJob failed - Code : %s - %s",
$e->getCode(),
$e->getMessage(),
)
);
\report($e);
} //end try
}
}

View file

@ -0,0 +1,81 @@
<?php
namespace App\Jobs;
use App\Models\Contact;
use App\Models\Log as LogModel;
use App\Models\Customers;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class CleanOldDatasJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
// Construct method.
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try {
DB::transaction(function (): void {
// Delete old contacts.
$deletedContact = Contact::query()
->where('contact_updatedate', '<', now()->subYears(3))
->delete();
Log::info(\sprintf(
'CleanOldDatasJob : %s contacts deleted',
$deletedContact
));
// Delete old customers.
$deletedCustomers = Customers::query()
->where('updated_at', '<', now()->subYears(3))
->delete();
Log::info(\sprintf(
'CleanOldDatasJob : %s customers deleted',
$deletedCustomers
));
// Delete old logs.
$deletedLogs = LogModel::query()
->where('created_at', '<', now()->subYears(3))
->delete();
Log::info(\sprintf(
'CleanOldDatasJob : %s logs deleted',
$deletedLogs
));
});
} catch (\Exception $e) {
Log::error(
sprintf(
"CleanOldDatasJob failed - Code : %s - %s",
$e->getCode(),
$e->getMessage(),
)
);
\report($e);
} //end try
}
}

View file

@ -0,0 +1,103 @@
<?php
namespace App\Jobs;
use App\Models\Contact;
use App\Models\Customers;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class DeleteCrmCustomerJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
/**
* Create a new job instance.
*
* @param array $customer
*/
public function __construct(private $customer)
{
$this->onConnection('rabbitmq');
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$hashchode = $this->customer['hashcode'];
$email = $this->customer['email'];
try {
DB::transaction(function () use ($hashchode, $email): void {
// For baskets and old walls.
$contact = Contact::query()->where('contact_ref', $hashchode)->first();
if ($contact) {
$contact->deleteOrFail();
$this->writeCsvLog('Contact deleted');
}
// For walls.
$customer = Customers::query()->where('hashcode', $hashchode)->first();
if ($customer) {
$customer->deleteOrFail();
$this->writeCsvLog('Customer deleted');
}
});
} catch (\Exception $e) {
Log::info(
sprintf(
"DeleteCrmCustomerJob failed - Code : %s - %s",
$e->getCode(),
$e->getMessage(),
)
);
\report($e);
} //end try
}
/**
* Write logs in /logs/crm.csv.
*
* @param string $message
*
* @return void
*/
private function writeCsvLog(string $message)
{
$csvPath = \storage_path('/logs/crm.csv');
if (!\file_exists($csvPath)) {
$logFile = fopen($csvPath, 'w');
\fputcsv($logFile, ['date', 'hashcode', 'email', 'action'], ';', escape: '\\');
\fclose($logFile);
}
$logFile = fopen($csvPath, 'a');
\fputcsv(
$logFile,
[
\now()->toAtomString(),
$this->customer['hashcode'],
$this->customer['email'],
$message
],
';',
escape: '\\'
);
\fclose($logFile);
}
}

View file

@ -1,64 +0,0 @@
<?php
namespace App\Lib;
use Illuminate\Container\Container;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
class CollectionHelper
{
/**
* Paginate a collection
*
* @param \Illuminate\Support\Collection $results
* @param integer $pageSize
* @return \Illuminate\Pagination\LengthAwarePaginator
*/
public static function paginate(Collection $results, int $pageSize): LengthAwarePaginator
{
$page = Paginator::resolveCurrentPage('page');
return self::paginateManually($results, $pageSize, $page);
}
/**
* Paginate a collection
*
* @param \Illuminate\Support\Collection $results
* @param integer $pageSize
* @param integer $page
* @return \Illuminate\Pagination\LengthAwarePaginator
*/
public static function paginateManually(Collection $results, int $pageSize, int $page = 1): LengthAwarePaginator
{
$total = $results->count();
return self::paginator($results->forPage($page, $pageSize), $total, $pageSize, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => 'page',
]);
}
/**
* Create a new length-aware paginator instance.
*
* @param \Illuminate\Support\Collection $items
* @param integer $total
* @param integer $perPage
* @param integer $currentPage
* @param array $options
* @return \Illuminate\Pagination\LengthAwarePaginator
*/
protected static function paginator(Collection $items, int $total, int $perPage, int $currentPage, array $options)
{
return Container::getInstance()->makeWith(LengthAwarePaginator::class, [
'items' => $items,
'total' => $total,
'perPage' => $perPage,
'currentPage' => $currentPage,
'options' => $options
]);
}
}

View file

@ -145,7 +145,7 @@ class ExceptionsHelper
$traceStr .= self::handleArgs($stack);
}
$traceStr .= ")\n";
} elseif (isset($stack['function'])) {
} else {
$traceStr .= "{$stack['function']}(";
if (isset($stack['args'])) {
$traceStr .= self::handleArgs($stack);
@ -170,19 +170,12 @@ class ExceptionsHelper
$argsCount = count($stack['args']);
for ($i = 0; $i < $argsCount; $i++) {
$type = \gettype($stack['args'][$i]);
switch ($type) {
case 'object':
$traceArgs .= sprintf('Object(%s)', \get_class($stack['args'][$i]));
break;
case 'array':
$traceArgs .= sprintf('Array(%d)', \count($stack['args'][$i]));
break;
case 'string':
$traceArgs .= sprintf('String(%d)', \strlen($stack['args'][$i]));
break;
default:
$traceArgs .= \gettype($stack['args'][$i]);
}
match ($type) {
'object' => $traceArgs .= sprintf('Object(%s)', $stack['args'][$i]::class),
'array' => $traceArgs .= sprintf('Array(%d)', \count($stack['args'][$i])),
'string' => $traceArgs .= sprintf('String(%d)', \strlen($stack['args'][$i])),
default => $traceArgs .= \gettype($stack['args'][$i]),
};
$traceArgs .= ($i !== ($argsCount - 1) ? ',' : '');
}
return $traceArgs;

View file

@ -1,454 +0,0 @@
<?php
namespace App\Lib\Helpers;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
/**
* This class is used to handle files in LDC Laravel stack
*
* * The storage strategy will be using date.
* The file name may contain sufix timestamp highresolution time (hrtime or microtime) if is duplicate.
* (function() { return time() . ' ' . Str::slug(microtime(true)) . ' ' . hrtime(true); })();
*
* posts/ - The model table name
* 10/ - Year
* 04/ - Month
* 19/ - Day
* 5f/ - First two letters of md5 file
* black-cat-under-red-car.png - Slugified file name
* black-cat-under-red-car-286071690833400.png - Slugified file name that is duplicated
*
* The final path will be storage/modelfiles/posts/10/04/19/5f/black-cat-under-red-car-286071690833400.png
*
* ! No limits of file per folder will be handled.
*
* @author Munsch Jérémy <jeremy.munsch@ldc.fr>
*/
class FileStorageHelper
{
/**
* Destroy the file associate with the attribute.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $attribute
* @return void
*/
public static function removeFile(Model $model, string $attribute): void
{
$path = \ltrim(\urldecode($model->{$attribute}), '/');
if (\strpos($path, 'storage') !== 0) {
return;
}
$path = ToolboxHelper::mbReplace('storage/', '', $path);
if (Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
}
/**
* Destroy the file associate with the attribute old value (before updated to DB).
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $attribute
* @param boolean $onlyIfUpdated
* @return void
*/
public static function removeOldFile(Model $model, string $attribute, bool $onlyIfUpdated = true): void
{
// * Ignore If removal has to be done only if the field has changed and it actually hasnt.
if ($onlyIfUpdated and $model->{$attribute} === ToolboxHelper::getOriginal($model, $attribute)) {
return;
}
$originalPath = \ltrim(\urldecode(ToolboxHelper::getOriginal($model, $attribute)), '/');
if (\strpos($originalPath, 'storage') !== 0) {
return;
}
$originalPath = ToolboxHelper::mbReplace('storage/', '', $originalPath);
if (Storage::disk('public')->exists($originalPath)) {
Storage::disk('public')->delete($originalPath);
}
}
/**
* Store a file using optimized storage strategy
*
* You can use filename param to overload file name.
*
* @param \Illuminate\Database\Eloquent\Model $model The model that will hold the picture.
* @param \Illuminate\Http\UploadedFile|\SplFileInfo|string $file The file, will just return itself is string.
* @param boolean $slugify Force filename slugification.
* @param string|null $filename This string may be used to store the file.
* @param boolean $private To store the file in a private space.
* @return string
* @throws \RuntimeException If file copy fails.
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public static function storeFile(
Model $model,
$file,
bool $slugify = false,
string $filename = null,
bool $private = false
): string {
// phpcs:enable
$tableName = $model->getTable();
if (\is_object($file) and $file instanceof \Illuminate\Http\UploadedFile) {
/** @var \Illuminate\Http\UploadedFile $file */
$filename = $filename ?: $file->getClientOriginalName();
$filename = $slugify ? self::slugifyFileName($filename) : $filename;
$newPath = self::prepareMoveFile($tableName, $filename, $private);
$newPath = str_replace(storage_path('app'), '', $newPath);
if (!$private) {
// * Store public file.
$file->storePubliclyAs(
pathinfo($newPath, \PATHINFO_DIRNAME),
pathinfo($newPath, \PATHINFO_BASENAME)
);
return 'storage' . str_replace('/public', '', $newPath);
}
$file->storeAs(
pathinfo($newPath, \PATHINFO_DIRNAME),
pathinfo($newPath, \PATHINFO_BASENAME)
);
return str_replace('/private/', '', $newPath);
}//end if
if (\is_object($file) and $file instanceof \SplFileInfo) {
/** @var \SplFileInfo $file */
$filename = $filename ?: $file->getBaseName();
$filename = $slugify ? self::slugifyFileName($filename) : $filename;
$newPath = self::prepareMoveFile($tableName, $filename, $private);
if (!File::copy($file->getRealPath(), $newPath)) {
throw new \RuntimeException(sprintf(
'Failed to copy file %s to %s',
$file->getRealPath(),
$newPath
));
}
return $private ?
\ltrim(str_replace(\storage_path('app/private'), '/storage/app/private', $newPath), '/') :
\ltrim(str_replace(\storage_path('app/public'), '/storage', $newPath), '/');
}
return strval($file);
}
/**
* Store all files from string attribute html
* If oldHtmlString is passed, a diff is done with new and old files
* to keep only files that are present in the new html string.
*
* @param \Illuminate\Database\Eloquent\Model $model The model that will hold the picture.
* @param string $htmlString The html string to parse and modify files.
* @param string|null $oldHtmlString The old html string with alreadyParsed
* files using storeModelFilesFromHtml.
* @return string Html with files pathes replaced using storage strategy.
*/
public static function storeModelFilesFromHtml(
Model $model,
string $htmlString,
string $oldHtmlString = null
): string {
\collect(self::onlyUploadedFilesWithFileManager(self::findFilesInHtml($htmlString)))
->each(function (string $path) use ($model, &$htmlString) {
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$disk = Storage::disk('uploads');
$fileInfo = new \SplFileInfo($disk->path(
ToolboxHelper::mbReplace('/uploads/', '', \urldecode($path))
));
$htmlString = ToolboxHelper::mbReplace(
$path,
'/' . self::storeFile($model, $fileInfo, true),
$htmlString
);
});
if ($oldHtmlString) {
self::removeOldModelFilesFromHtml($htmlString, $oldHtmlString);
}
return $htmlString;
}
/**
* Remove all old files from string attribute html that are stored in public that
* are nove present anymore on new html string
*
* @param string $newHtmlString The html string with alreadyParsed files using storeModelFilesFromHtml.
* @param string $oldHtmlString The old html string with alreadyParsed files using storeModelFilesFromHtml.
* @return void
*/
public static function removeOldModelFilesFromHtml(string $newHtmlString, string $oldHtmlString): void
{
self::removeOldFiles(self::findFilesInHtml($oldHtmlString), self::findFilesInHtml($newHtmlString));
}
/**
* Remove all old files that are stored in public that
* are not present anymore on new array files
*
* @param string[] $oldFiles The old array files.
* @param string[] $newFiles The new array files.
* @return void
*/
public static function removeOldFiles(array $oldFiles, array $newFiles): void
{
$oldFiles = \collect(self::onlyUploadedFilesWithFileStorageHelper($oldFiles));
$filesToKeep = \collect(self::onlyUploadedFilesWithFileStorageHelper($newFiles));
$filesToRemove = $oldFiles->diff($filesToKeep);
$filesToRemove->each(function (string $publicStorageFilePath) {
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
if (Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
});
}
/**
* Remove all files from string attribute html that are stored in public
*
* @param string $htmlString The html string with alreadyParsed files using storeModelFilesFromHtml.
* @return void
*/
public static function removeModelFilesOfHtml(string $htmlString): void
{
$filesToRemove = \collect(self::onlyUploadedFilesWithFileStorageHelper(self::findFilesInHtml($htmlString)));
$filesToRemove->each(function (string $publicStorageFilePath) {
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
if (Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
});
}
/**
* Find all occurence of files in html
*
* @param string $html
* @return array
*/
public static function findFilesInHtml(string $html): array
{
preg_match_all('/href="(?P<href>.*)"|src="(?P<src>.*)"|url="(?P<url>.*)"/Um', $html, $m, PREG_SET_ORDER, 0);
return collect($m)->pluck('href')->filter()
->concat(collect($m)->pluck('url')->filter())
->concat(collect($m)->pluck('src')->filter())
->all();
}
/**
* Filter array to get only uploaded files that exists
* on disk 'public' (using helper storage strategy)
*
* @param array $urls
* @return array
*/
public static function onlyUploadedFilesWithFileStorageHelper(array $urls): array
{
return \collect($urls)->unique()
// * Filter to get only /uploads and using app url or empty
->filter(function (string $url) {
$path = \parse_url($url, \PHP_URL_PATH);
return \strpos(\ltrim($path, '/'), 'storage/modelfiles') === 0;
})->filter(function (string $url) {
$path = \parse_url($url, \PHP_URL_PATH);
return Storage::disk('public')
->exists(ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($path), '/')));
})->all();
}
/**
* Filter array to get only uploaded files that exists
* on disk 'uploads'
*
* @param array $urls
* @return array
*/
private static function onlyUploadedFilesWithFileManager(array $urls): array
{
return \collect($urls)->unique()
// * Filter to get only /uploads and using app url or empty
->filter(function (string $url) {
$host = \parse_url($url, \PHP_URL_HOST);
$path = \parse_url($url, \PHP_URL_PATH);
return ($host === \parse_url(config('app.url'), PHP_URL_HOST) or \is_null($host)) and
\strpos(\ltrim($path, '/'), 'uploads') === 0;
})->filter(function (string $url) {
$path = \parse_url($url, \PHP_URL_PATH);
return Storage::disk('uploads')
->exists(ToolboxHelper::mbReplace('uploads/', '', \ltrim(\urldecode($path), '/')));
})->all();
}
/**
* Prepare storage path and return
* the file full path
*
* @param string $tableName Model table name.
* @param string $filename The basename for the file.
* @param boolean $private May the file be stored in a private dir.
* @return string
*/
private static function prepareMoveFile(string $tableName, string $filename, bool $private = false): string
{
// * Security filter
$filename = \htmlspecialchars($filename);
// * Security filter + beautifier
$filename = self::sanitizeFileName($filename);
// * Slugify filename
$ext = \pathinfo($filename, \PATHINFO_EXTENSION);
$filename = Str::slug(\pathinfo($filename, \PATHINFO_FILENAME)) .
(\strlen($ext) ? ".{$ext}" : '');
$folderPath = self::getStoragePath(
$private ? 'app/private/modelfiles' : 'app/public/modelfiles',
$tableName,
$filename,
$private
);
$filename = self::getFileUniqueName($folderPath, $filename);
return "{$folderPath}/{$filename}";
}
/**
* Create sub folders to store files using pattern
* storage/modelfiles/posts/10/04/19/5f
* year/month/day/md5 first 2 letters
*
* @param string $storage_dir
* @param string $table
* @param string $filename
* @return string
*/
private static function getStoragePath(string $storage_dir, string $table, string $filename): string
{
$filenameHash = \md5($filename);
$pathFolder = \storage_path(sprintf(
'%s/%s/%s/%s/%s/%s',
$storage_dir,
$table,
gmdate('y'),
gmdate('m'),
gmdate('d'),
substr($filenameHash, 0, 2)
));
if (!File::exists($pathFolder)) {
File::makeDirectory($pathFolder, 0755, true);
}
return $pathFolder;
}
/**
* Get unique filename if the path is already occupied
*
* @param string $folderPath
* @param string $filename
* @return string
* @throws \RuntimeException If a unique filename cannot be obtained.
*/
private static function getFileUniqueName(string $folderPath, string $filename): string
{
$attempts = 0;
$maxAttempts = 20;
while (File::exists("{$folderPath}/{$filename}")) {
if ($attempts++ >= $maxAttempts) {
throw new \RuntimeException("Failed to have a unique filename for {$folderPath}/{$filename}");
}
$filename = pathinfo($filename, \PATHINFO_FILENAME) .
\uniqid('-') . '.' .
pathinfo($filename, \PATHINFO_EXTENSION);
}
return $filename;
}
/**
* Slugify the filename
*
* @param string $filename
* @return string
*/
public static function slugifyFileName(string $filename): string
{
return Str::slug(pathinfo($filename, \PATHINFO_FILENAME)) . '.' . pathinfo($filename, \PATHINFO_EXTENSION);
}
/**
* Sanitize File name for uploaded files
*
* @param string $filename The original uploaded client file name.
* @param boolean $beautify Beautify the filename.
* @return string The sanitized file name.
*/
public static function sanitizeFileName(string $filename, bool $beautify = true): string
{
// * Sanitize filename
// phpcs:disable Generic.Files.LineLength.TooLong
$filename = preg_replace(
'~
[<>:"/\\\|?*]| # file system reserved https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
[\x00-\x1F]| # control characters http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
[\x7F\xA0\xAD]| # non-printing characters DEL, NO-BREAK SPACE, SOFT HYPHEN
[#\[\]@!$&\'()+,;=]| # URI reserved https://tools.ietf.org/html/rfc3986#section-2.2
[{}^\~`] # URL unsafe characters https://www.ietf.org/rfc/rfc1738.txt
~x',
'-',
$filename
);
// phpcs:enable
// * Avoids '.' '..' or '.hiddenFiles' .
$filename = Str::of($filename)->ltrim('.-');
// * Optional beautification
if ($beautify) {
$filename = static::beautifyFilename($filename);
}
// * Maximize filename length to 255 bytes http://serverfault.com/a/9548/44086
/** @var string */
$extension = pathinfo($filename, \PATHINFO_EXTENSION);
/** @var string */
$filename = pathinfo($filename, \PATHINFO_FILENAME);
$encoding = mb_detect_encoding($filename);
$encoding = $encoding ? $encoding : null;
return \mb_strcut(
$filename,
0,
255 - (!empty($extension) ? strlen($extension) + 1 : 0),
$encoding
) . (!empty($extension) ? ".$extension" : '');
}
/**
* Beautify a filename
*
* @param string $filename
* @return string
*/
private static function beautifyFilename(string $filename): string
{
// Reduce consecutive characters.
$filename = preg_replace([
// * "file name.zip" becomes 'file-name.zip'
'/ +/',
// * "file___name.zip" becomes 'file-name.zip'
'/_+/',
// * "file---name.zip" becomes 'file-name.zip'
'/-+/'
], '-', $filename);
$filename = preg_replace([
// * "file--.--.-.--name.zip" becomes "file.name.zip"
'/-*\.-*/',
// * "file...name..zip" becomes "file.name.zip"
'/\.{2,}/'
], '.', $filename);
// Lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625 .
$filename = mb_strtolower($filename, mb_detect_encoding($filename));
// * ".file-name.-" becomes "file-name"
$filename = trim($filename, '.-');
return $filename;
}
}

View file

@ -14,6 +14,7 @@ use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Enum;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Finder\SplFileInfo;
@ -21,197 +22,20 @@ use Symfony\Component\Finder\SplFileInfo;
class ToolboxHelper
{
/**
* @param array<int|string, mixed> $array1
* @param array<int|string, mixed> $array2
*
* @return array<int|string, mixed>
*/
public static function arrayMergeRecursiveDistinct(array &$array1, array &$array2): array
{
$merged = $array1;
foreach ($array2 as $key => &$value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = self::arrayMergeRecursiveDistinct($merged[$key], $value);
} else {
$merged[$key] = $value;
}
}
return $merged;
}
/**
* Validate recaptcha
*
* @param \Illuminate\Http\Request $request
* @param boolean $isV3
* @return void
*/
public static function validateRecaptcha(Request $request, bool $isV3 = true)
{
Validator::validate($request->all(), [
'g-recaptcha-response' => [
'required', 'string',
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed, Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
function ($attribute, $value, $fail) use ($isV3) {
try {
$response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [
'secret' => config('services.google.recaptcha.private'),
'response' => \strval($value),
'remoteip' => app('clientIp')
]);
if ($e = $response->toException()) {
throw $e;
}
if ($isV3) {
if (
!$response->json('success') or
!$response->json('challenge_ts') or
Carbon::parse($response->json('challenge_ts'))->lessThan(\now('utc')->subMinutes(5)) or
$response->json('hostname') !== \parse_url(config('app.url'), \PHP_URL_HOST) or
!$response->json('score')
) {
throw new \RuntimeException();
}
if (\floatval($response->json('score')) < 0.8) {
$fail("Vous n'avez pas obtenu un score assez élevé lors de la validation du recaptcha");
}
return;
}
if (
!$response->json('success') or
!$response->json('challenge_ts') or
Carbon::parse($response->json('challenge_ts'))->lessThan(\now('utc')->subMinutes(5)) or
$response->json('hostname') !== \parse_url(config('app.url'), \PHP_URL_HOST)
) {
throw new \RuntimeException();
}
} catch (\Exception $e) {
$fail('Erreur lors de la validation du formulaire veuillez réssayer');
} //end try
}
]
], [], ['g-recaptcha-response' => 'reCaptcha']);
}
/**
* Strip scheme (https) on oembed urls
* Only embed allowed are for MP4 self hosted videos right now
*
* https is force by ckeditor MediaElements which natively supports
* only cloud hosted medias (youtube, spotify etc..)
*
* @param string $input
* @return string
*/
public static function stripCkEditorSchemesOnMediaInputs(string $input): string
{
$input = \preg_replace('/(?<=<oembed url=")(https:\/\/)(?=.*?">)/m', '', $input);
return $input;
}
/**
* Assert That no Back Office url is present on txt
*
* @param string $field
* @param string $text
* @return string
* @throws \Illuminate\Validation\ValidationException If url is a bo url.
*/
public static function assertNoInternalBoUrls(string $field, string $text): string
{
$routes = Route::getRoutes();
// * Url replace and email replace.
$text = preg_replace_callback(
// phpcs:ignore Generic.Files.LineLength.TooLong
'/(?P<url>(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/',
function ($matches) use ($routes, $field) {
$match = collect($matches)->first() ?? '';
$url = $match;
try {
$request = Request::create($url);
// If a route is match then it do not throws exception.
if (
\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) &&
trim($routes->match($request)->getPrefix() ?? '', '/') === 'bo'
) {
// Removes the matched url.
throw ValidationException::withMessages([
$field => trans(
'crud.libs.toolbox.assertNoInternalBoUrls',
['attribute' => $field]
)
]);
}
return $match;
} catch (NotFoundHttpException $e) {
return $match;
}
},
$text
);
return $text;
}
/**
* Assert That only external url is present on txt
*
* @param string $field
* @param string $text
* @return string
* @throws \Illuminate\Validation\ValidationException If url is a bo url.
*/
public static function assertNoInternalUrls(string $field, string $text): string
{
self::assertNoInternalBoUrls($field, $text);
$routes = Route::getRoutes();
// * Url replace and email replace.
$text = preg_replace_callback(
// phpcs:ignore Generic.Files.LineLength.TooLong
'/(?P<url>(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/',
function ($matches) use ($routes, $field) {
$match = collect($matches)->first() ?? '';
$url = $match;
try {
$request = Request::create($url);
// If a route is match then it do not throws exception.
if (
\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) &&
$routes->match($request)
) {
// Removes the matched url.
throw ValidationException::withMessages([
$field => trans(
'crud.libs.toolbox.assertNoInternalUrls',
['attribute' => $field, 'appname' => config('app.name')]
)
]);
}
return $match;
} catch (NotFoundHttpException $e) {
return $match;
}
},
$text
);
return $text;
}
/**
* Mutltibyte string replace
* Mutltibyte string replace.
*
* @param array|string $search
* @param array|string $replace
* @param array|string $subject
* @param integer $count
* @return array|string
* @return array|string|false
*/
public static function mbReplace(
array|string $search,
array|string $replace,
array|string $subject,
$search,
$replace,
$subject,
int &$count = 0
): array|string {
) {
if (!is_array($search) && is_array($replace)) {
return false;
}
@ -242,7 +66,7 @@ class ToolboxHelper
}
/**
* Asserts that the field is unique
* Asserts that the field is unique.
*
* @param string $table
* @param string $field
@ -255,10 +79,10 @@ class ToolboxHelper
public static function assertFieldIsUnique(
string $table,
string $field,
string|int|float|bool|null|array $value,
$value,
?int $id = null,
?callable $query = null
) {
): void {
if (!$query) {
Validator::make([$field => $value], [
self::mbReplace('.', '\.', $field) => Rule::unique($table, $field)->ignore($id),
@ -277,243 +101,4 @@ class ToolboxHelper
)
])->validate();
}
/**
* Get original polyfill with autotranslate behavior
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $attribute
* @return mixed
*/
public static function getOriginal(Model $model, string $attribute): mixed
{
if (\in_array('Spatie\Translatable\HasTranslations', \class_uses_recursive($model))) {
return $model->getTranslation(
$attribute,
$model->getLocale(),
$model->useFallbackLocale()
);
}
return $model->getOriginal($attribute);
}
/**
* Dynamic model query
*
* @param string $defaultLocale
* @param \Illuminate\Contracts\Database\Eloquent\Builder $q
* @param string $column
* @param string $value
* @return \Illuminate\Contracts\Database\Eloquent\Builder
*/
public static function queryColumnWithLocales(
string $defaultLocale,
Builder $q,
string $column,
string $value
): Builder {
$currentLocale = app()->currentLocale();
$locales = collect(config('app.locales'))
->mapWithKeys(fn (string $locale) => [$locale => $locale]);
if (!$locales->has($defaultLocale)) {
// * Remove default locale.
$locales->pull($defaultLocale);
}
if (!$locales->has($currentLocale)) {
// * Remove current locale.
$locales->pull($currentLocale);
}
return $q->where(function (Builder $q) use ($defaultLocale, $currentLocale, $locales, $column, $value) {
// * Query default locale
$q->whereRaw("JSON_EXTRACT({$column}, '$.{$defaultLocale}') = '{$value}'");
if ($defaultLocale !== $currentLocale) {
// * Query current locale
$q->whereRaw("JSON_EXTRACT({$column}, '$.{$currentLocale}') = '{$value}'");
}
// * Query any other locale
$locales->each(fn ($locale) => $q->orWhereRaw(
"JSON_EXTRACT({$column}, '$.{$locale}') = '{$value}'"
));
});
}
/**
* Generates an array from a dot separated string
*
* @param string $path
* @param mixed $value
* @param string $separator
* @return array
*/
public static function dotStringToNestedArray(string $path, mixed $value, string $separator = '.'): array
{
$arr = $value;
$keys = array_reverse(explode($separator, $path));
foreach ($keys as $key) {
$arr = [$key => $arr];
}
return $arr;
}
/**
* Convert deeply an object to array
*
* @param array|object $input
* @return array
* @throws \RuntimeException If $input var is a scalar value.
*/
public static function objectToArray($input): array
{
// Only process if it's an object or array being passed to the function.
if (is_object($input) or is_array($input)) {
$ret = (array)$input;
foreach ($ret as &$item) {
// Recursively process EACH element only if not scalar.
$item = (is_object($item) or is_array($item)) ?
self::objectToArray($item) : $item;
}
return $ret;
} else {
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
}
}
/**
* Convert deeply an array to object
*
* @param array|object $input
* @return object
* @throws \RuntimeException If $input var is a scalar value.
*/
public static function arrayToObject($input): object
{
// Only process if it's an object or array being passed to the function.
if (is_object($input) or is_array($input)) {
$ret = (object)$input;
foreach ($ret as &$item) {
// Recursively process EACH element only if not scalar.
$item = (is_object($item) or is_array($item)) ?
self::arrayToObject($item) : $item;
}
return $ret;
} else {
throw new \RuntimeException('Cannot handle $input of type ' . \gettype($input));
}
}
/**
* Validate picture
*
* @param string $attribute
* @param string|null $value
* @param callback $fail
* @param object $sizes
* @return void
*/
public static function validatePicture(string $attribute, string|null $value, callable $fail, object $sizes)
{
if (!($useStorage = Storage::exists($value)) and !File::exists($value)) {
$fail(trans(':attribute n\'existe pas dans le système de fichier', [
'attribute' => $attribute
]));
return;
}
/** @var string */
$fileFullPath = self::getUploadedFileFullPath($value, $useStorage);
if (
!\in_array(self::getUploadedFileMimeType($value, $useStorage), [
'image/jpeg', 'image/jpg', 'image/png', 'image/gif'
])
) {
$fail(trans(':attribute doit être une image de type \'image/jpeg,image/jpg,image/png,image/gif\'', [
'attribute' => $attribute
]));
}
if (!($dimensions = \getimagesize($fileFullPath)) or !isset($dimensions[0]) or !isset($dimensions[1])) {
$fail(trans(':attribute impossible de valider les dimensions', [
'attribute' => $attribute
]));
} else {
$width = intval($dimensions[0]);
$height = intval($dimensions[1]);
$xMessage = trans(
":attribute la largeur doit être comprise entre {$sizes->minWith}px et {$sizes->maxWith}px"
);
if ($sizes->minWith === $sizes->maxWith) {
$xMessage = trans(":attribute la largeur doit être de {$sizes->minWith}px");
}
$yMessage = trans(
":attribute la hauteur doit être comprise entre {$sizes->minWith}px et {$sizes->maxWith}px"
);
if ($sizes->minHeight === $sizes->maxHeight) {
$yMessage = trans(":attribute la hauteur doit être de {$sizes->minWith}px");
}
if (($width < $sizes->minWith) or ($width > $sizes->maxWith)) {
$fail($xMessage);
}
if (($height < $sizes->minHeight) or ($height > $sizes->maxHeight)) {
$fail($yMessage);
}
} //end if
}
/**
* Get the file full path
*
* @param string $value
* @param boolean $useStorage
* @return string
*/
private static function getUploadedFileFullPath(string $value, bool $useStorage): string
{
/** @var \Illuminate\Filesystem\FilesystemAdapter */
$disk = Storage::disk();
return !$useStorage ? (realpath($value) ?: $value) : $disk->path($value);
}
/**
* Get the file mimetype
*
* @param string $value
* @param boolean $useStorage
* @return string|false
*/
private static function getUploadedFileMimeType(string $value, bool $useStorage)
{
return !$useStorage ? File::mimeType($value) : Storage::mimeType($value);
}
/**
* Fetch class list from a specific namespace
*
* @param string $namespace
* @return array<string> An array of classe namespaces
*/
public static function getClassesUsingNamespace(string $namespace): array
{
return collect(File::files(\app_path(Str::of($namespace)->replaceFirst('\App', ''))))
->filter(fn (SplFileInfo $splFileInfo) => $splFileInfo->getExtension() === 'php')
->map(fn (SplFileInfo $splFileInfo) => Str::of($splFileInfo->getBasename())
->replace('.' . $splFileInfo->getExtension(), '')->prepend("{$namespace}\\"))->all();
}
/**
* Get all classes from a specific namespace that implement a specific interface
*
* @param string $namespace
* @param string $interface
* @return array<string> An array of classe namespaces
*/
public static function getClassesUsingInterface(string $namespace, string $interface): array
{
return Arr::where(
static::getClassesUsingNamespace($namespace),
fn (string $class_namespace) => \collect(class_implements($class_namespace, true))->filter()
->contains(fn (string $class_interface) => $class_interface === $interface)
);
}
}

37
app/Mail/AlertBr.php Normal file
View file

@ -0,0 +1,37 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class AlertBr extends Mailable
{
use Queueable;
use SerializesModels;
public $subject;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(public $couponSeuil, public $couponDiffusion, $sitename)
{
$this->subject = 'Notification mes BR : ' . $sitename;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->subject($this->subject)->view('mail.alert')->with(['couponSeuil' => $this->couponSeuil, 'couponDiffusion' => $this->couponDiffusion]);
}
}

37
app/Mail/AlertBrAdmin.php Normal file
View file

@ -0,0 +1,37 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class AlertBrAdmin extends Mailable
{
use Queueable;
use SerializesModels;
public $subject;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(public $couponSeuil, public $couponDiffusion)
{
$this->subject = 'Notification mes BR : Récapitulatif global';
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->subject($this->subject)->view('mail.alertadmin')->with(['couponSeuil' => $this->couponSeuil, 'couponDiffusion' => $this->couponDiffusion]);
}
}

View file

@ -0,0 +1,83 @@
<?php
namespace App\Models;
use App\Models\Site;
use App\Traits\HasUniqueField;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* @property string $name Name of the archived campaign.
* @property string $campaign_id Id of the archived campaign.
* @property-read \Carbon\Carbon $created_at Created date.
* @property-read \Carbon\Carbon $updated_at Updated date.
*
* @property-read \App\Models\ArchiveStat $archiveStat ArchiveStat Has many relationship.
* @property-read \App\Models\ArchiveSite $archiveSite ArchiveSite Belongs to relationship.
*/
class ArchiveCampaign extends Model
{
use HasFactory;
use HasUniqueField;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'campaign_id',
'archive_site_id'
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model): void {
$model->assertFieldIsUnique('campaign_id', $model->campaign_id);
$site = Site::query()->where('site_id', $model->archive_site_id)->firstOrFail();
$archiveSite = ArchiveSite::query()->firstOrCreate(
[
'site_id' => $model->archive_site_id
],
[
'name' => $site->site_nom
]
);
$model->archiveSite()->associate($archiveSite);
});
static::updating(function (): void {
throw new \RuntimeException('Updating an archived campaign is not authorized');
});
static::deleting(function (): void {
throw new \RuntimeException('Deleting an archived campaign is not authorized');
});
}
// * RELATIONS
/**
* ArchiveSite model relation
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function archiveSite()
{
return $this->belongsTo(ArchiveSite::class);
}
/**
* ArchiveSite model relation
* @return Illuminate\Database\Eloquent\Relations\HasMany
*/
public function archiveStat()
{
return $this->hasMany(ArchiveStat::class);
}
}

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