Compare commits

..

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

692 changed files with 13363 additions and 48269 deletions

View file

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

View file

@ -3,9 +3,9 @@ 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]
@ -13,9 +13,3 @@ trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4
[*.vue]
indent_size = 2

View file

@ -5,60 +5,36 @@ APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=dev-mysql
DB_HOST=dev-mariadb
DB_PORT=3306
DB_DATABASE=laravel
DB_DATABASE=
DB_USERNAME=root
DB_PASSWORD=
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
QUEUE_CONNECTION=database
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=dev-mailpit
MAIL_HOST=dev-mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
MAIL_ADMIN=digital@ldc.fr
# Sentry
SENTRY_LARAVEL_DSN=
# MATOMO
MATOMO_SITE_ID=
MAIL_ADMIN=equipe.web@ldc.fr
# CRM
CRM_ENDPOINT=
CRM_TOKEN=
CRM_PASSWORD=
# MESBR
MESBR_ENDPOINT=
# ADMIN SECURE
# - API ENDPOINT (Optional)
LDC_WEB_API_ENDPOINT=""
# - API KEY
LDC_WEB_API_KEY=""
# - LIST SEPARATED WITH ',' (Optional)
LDC_WEB_CIDR_MANUAL_ALLOWED_LIST=""
# Export pagination config, defaut 65530.
CODE_PAGINATE=
# Dictionnary of chars to use fo generating unique codes.

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

58
.gitignore vendored
View file

@ -1,46 +1,32 @@
.env
.env.backup
.env.production
.phpunit.result.cache
.stylelintcache
/.fleet
/.idea
/.phpunit.cache
/.vscode
public/front/*
/node_modules
/bootstrap
/public/build
/public/cache
/public/hot
/public/sitemap.xml
/public/storage
/public/fichiers
/public/images/produits
/public/images/ranges
/public/css/*
/public/js/*
resources/views/errors/*
resources/views/front/basic/*
mix-manifest.json
/storage/*.key
/vendor
auth.json
docker-compose.override.yml
/resources/views/front/basic
.env
.env.dev
.env.prod
.env.backup
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
.npmrc
/resources/theme
# https://lab.s-web.fr/ldc-web/projets/gen-game-web/-/issues/17
public/fichiers
package-lock.json
composer.lock
resources/front
resources/js/basic.js
.vscode
storage
resources/theme
.npm/
.composer/
.zshrc
# Ignore public favicon
/public/android-chrome-192x192.png
/public/android-chrome-512x512.png
/public/apple-touch-icon.png
/public/browserconfig.xml
/public/browserconfig.xml
/public/favicon-16x16.png
/public/favicon-32x32.png
/public/favicon.ico
/public/mstile-150x150.png
/public/safari-pinned-tab.svg
/public/site.webmanifest
README.txt
webpack.mix.js

View file

@ -1,11 +1,46 @@
include:
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'lint/lint.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'security/security.yml'
image: $CI_REGISTRY/service-web-lab/ldc-web-images-docker/ldcweb-qa:php7.3-1.0
stages:
- lint
- security
- Security
- CodingStandards
composer-security:
stage: Security
script:
- local-php-security-checker --format=json --path=./composer.lock > composer-security-checker-report.json
artifacts:
when: on_failure
expose_as: 'composer-security-checker'
paths:
- composer-security-checker-report.json
allow_failure: true
npm-security:
stage: Security
script:
- audit-ci -p npm -o json > npm-security-checker-report.json
artifacts:
when: on_failure
expose_as: 'npm-security-checker'
paths:
- npm-security-checker-report.json
allow_failure: true
phpcs:
stage: CodingStandards
before_script:
- composer config gitlab-token.gitlab.com $CI_DEPLOY_USER $CI_DEPLOY_PASSWORD
- composer install
cache:
paths:
- vendor/
script:
- vendor/bin/phpcs --report=junit --report-file=phpcs-report.xml
artifacts:
when: on_failure
expose_as: 'phpcs'
paths:
- phpcs-report.xml
reports:
junit: phpcs-report.xml
allow_failure: false

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "resources/theme"]
path = resources/theme
url = ../gen-game-web-themes/theme-merger.git

View file

@ -1,2 +0,0 @@
#!/bin/sh
npx commitlint --config node_modules/@uwil/husky-config/commitlint.config.js --edit $1

13
.styleci.yml Normal file
View file

@ -0,0 +1,13 @@
php:
preset: laravel
disabled:
- unused_use
finder:
not-name:
- index.php
- server.php
js:
finder:
not-name:
- webpack.mix.js
css: true

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": {
"declaration-property-value-no-unknown": null,
"selector-max-id": null,
"color-no-invalid-hex": true,
"order/properties-alphabetical-order": null,
"max-nesting-depth": 5,
"selector-max-compound-selectors": 5,
"scss/double-slash-comment-empty-line-before": [
"always",
{
"ignore": [
"between-comments",
"stylelint-commands",
"inside-block"
]
}
]
}
}

22
.vscode/settings.json vendored
View file

@ -1,22 +0,0 @@
{
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#962a40",
"activityBar.background": "#962a40",
"activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799",
"activityBarBadge.background": "#40952a",
"activityBarBadge.foreground": "#e7e7e7",
"commandCenter.border": "#e7e7e799",
"sash.hoverBorder": "#962a40",
"statusBar.background": "#6e1f2f",
"statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#962a40",
"statusBarItem.remoteBackground": "#6e1f2f",
"statusBarItem.remoteForeground": "#e7e7e7",
"titleBar.activeBackground": "#6e1f2f",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#6e1f2f99",
"titleBar.inactiveForeground": "#e7e7e799"
},
"peacock.remoteColor": "#6e1f2f"
}

View file

@ -1,59 +1,23 @@
# GEN GAME WEB
## Installation
``` Bash
```
cp .env.example .env
php artisan key:generate /!\ bien sauvegarder la key
php artisan migrate:fresh --step
# Seulement pour developper un theme par exemple
php artisan db:seed --class DevelopmentSeeder
php artisan uwil:user:create
php artisan migrate --seed
```
## Création du compte Admin
``` Bash
php artisan uwil:user:create
```
php artisan create:admin
```
## Ajouter Parametrage du jeu
**Les lots sont à ajouter avant de générer les instants gagants**. En effet les instants gagants sont liés à des lots.
## Générer des coupons et les mails
``` Bash
artisan queue:work
## CRON
```
php artisan users:deletenc à mettre 1 fois par jour
```
En cas de manipulation pourrie, penser a vider le cache pour supprimer le lock
sur le job de generation des codes.
## THEME
### Instalation
Pour installer le theme bien **mettre à jour les submodules avec git**,
`git submodule update --init --recursive`
puis utiliser la commande `php artisan uwil:theme:switch NOM_DU_THEME` et `php artisan optimize:clear && php artisan optimize`
Pour mettre a jour la liste des themes :
### Mise à jour
**Note** : cette partie n'est pas encore certaine.
- Mettre à jour `git submodule update --remote --merge resources/theme`
Ou
``` Bash
cd resources/themes;
git pull origin main;
cd ../..;
git add resources/themes
## TODO
```
- SH - Soucis de connexion / déconnexion quand le jeu est terminé et que l'adresse du jeu redirige vers une autre adresse : si on se déconnecte et qu'on revient sur le bo, on est toujours connecté
-> MJ - Pour que le cookie soit delete il ne faut pas renvoyer un 302 juste apres le disconnect
```
Puis commit.

View file

@ -1,188 +0,0 @@
<?php
namespace App\Auth;
use App\Models\Customer;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider as UserProviderContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
use LDC\LDCCRM\Models\Customer as CrmCustomer;
/**
* Crm user provider to integrate nicely with Laravel
*/
class CrmUserProvider extends EloquentUserProvider implements UserProviderContract
{
/**
* The model to use, specified in auth config guard.
*
* @var string
*/
private $usedModel = Customer::class;
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
// * Let laravel find a model
$model = parent::retrieveByCredentials($credentials) ??
self::retrieveTrashed($credentials);
try {
/** @var \LDC\LDCCRM\CrmApiV4 */
$crm = app('crmAPI');
// Si pas de compte local.
if (!$model) {
$crmCustomer = $crm->getCustomer($credentials['email']);
if (!$crmCustomer) {
// * Customer is not found on CRM.
return null;
}
$model = $this->createLocalCustomer($crmCustomer);
}
return $model;
} catch (ApiErrorException $e) {
// * Customer is not found.
if ($e->getApiError()->equals(ApiError::modelNotFound)) {
return null;
}
report($e);
Log::error('Unhandled response ' . $e->getApiError()->label());
} catch (CrmException | \Exception $e) {
report($e);
// Une erreur critique est survenue avec la CRM.
return null;
} //end try
Log::error(__CLASS__ . '::retrieveByCredentials reached end of possibilities.');
return null;
}
/**
* Validate a user against the given credentials.
*
* @param UserContract $model
* @param array $credentials
* @return boolean|null
* @throws \RuntimeException If model provided is not a Customer or connection to server fails.
* @throws \LDC\LDCCRM\Exceptions\CrmException On CRM call error.
* @throws \Exception On CRM call error.
*/
public function validateCredentials(UserContract $model, array $credentials): bool|null
{
/** @var \App\Models\Customer $model */
if (\get_class($model) !== $this->usedModel) {
throw new \RuntimeException('Cannot authenticate any thing else than ' . $this->usedModel);
}
try {
/** @var \LDC\LDCCRM\CrmApiV4 */
$crm = app('crmAPI');
// * If has trait soft delete and customer trashed, then restore customer.
if (
\in_array(\Illuminate\Database\Eloquent\SoftDeletes::class, \class_uses_recursive($model)) and
$model->trashed()
) {
$model->restore();
}
// * Ne devrait pas survenir, $crm->login throws ApiError::authFailed()
return $crm->login($credentials['email'], $credentials['password']);
} catch (ApiErrorException $e) {
if (
$e->getApiError()->equals(ApiError::modelNotFound) ||
($e->getApiError()->equals(ApiError::authFailed) && !$model->existsInCrm())
) {
$model->delete();
return false;
}
if ($e->getApiError()->equals(ApiError::authFailed)) {
return false;
}
// ! Assert Authenticable model must be valided (MustValidate trait).
if ($e->getApiError()->equals(ApiError::customerNotActivated)) {
$model->email_verified_at = null;
$model->save();
$model->sendEmailVerificationNotification();
Session::flash('warning', \trans('front.messages.account_not_activated'));
return true;
}
} catch (CrmException | \Exception $e) {
report($e);
if (config('app.debug')) {
throw $e;
}
return false;
} //end try
Log::error(__CLASS__ . '::validateCredentials reached end of possibilities.');
return null;
}
/**
* Create a local customer
*
* @param \LDC\LDCCRM\Models\Customer $crmCustomer
* @return \Illuminate\Database\Eloquent\Model
* @throws \Throwable If saving to DB failed.
*/
private function createLocalCustomer(\LDC\LDCCRM\Models\Customer $crmCustomer): Model
{
/** @var \App\Models\Customer $model */
$model = $this->usedModel::withTrashed()->firstOrNew([
'email' => $crmCustomer->email
]);
$model->hashcode = $crmCustomer->hashcode;
$model->email_verified_at = $crmCustomer->status ? now() : null;
if ($model->trashed()) {
$model->restore();
}
$model->saveOrFail();
return $model;
}
/**
* Retrieve a trashed customer by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
* @throws \ErrorException If cannot connect to LDAP.
*/
private function retrieveTrashed(array $credentials): ?Authenticatable
{
// * Make changes
if (empty($credentials)) {
return null;
}
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a customer, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
$query = $this->createModel()->newQuery();
foreach ($credentials as $key => $value) {
if (!Str::contains($key, 'password')) {
$query->where($key, $value);
}
}
/** @var \App\Models\Customer|null $query */
return $query->withTrashed()->first();
}
}

View file

@ -1,46 +0,0 @@
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class AsArrayOfDiscount implements CastsAttributes
{
/**
* Cast the given value.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return array<\App\Lib\Discount>
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
*/
public function get($model, string $key, $value, array $attributes): array
{
// phpcs:enable
return \collect(\json_decode($value, true))->map(function ($input) use ($model, $key, $attributes) {
$inputCast = new AsDiscount();
return $inputCast->get($model, $key, \json_encode($input), $attributes);
})->all();
}
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param \App\Lib\Discount $value
* @param array $attributes
* @return string Json encoded array<\App\Lib\Discount>
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
*/
public function set($model, string $key, $value, array $attributes)
{
// phpcs:enable
return \json_encode(\collect($value)->map(function ($input) use ($model, $key, $attributes) {
$inputCast = new AsDiscount();
return \json_decode($inputCast->set($model, $key, $input, $attributes));
})->all());
}
}

View file

@ -1,65 +0,0 @@
<?php
namespace App\Casts;
use App\Lib\Discount;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class AsDiscount implements CastsAttributes
{
/**
* Cast the given value.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return \App\Lib\Discount
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
*/
public function get($model, string $key, $value, array $attributes): Discount
{
// phpcs:enable
$inputData = \json_decode($value, true);
return Discount::make(...\array_values($inputData));
}
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array $attributes
* @return string Json encoded \App\Lib\Inputs\Definition\Input
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
*/
public function set($model, string $key, $value, array $attributes)
{
// phpcs:enable
$this->assertIsInput($value);
/** @var \App\Lib\Discount $value */
return $value->toJson();
}
/**
* Assert is instance of \App\Lib\Discount
*
* @param mixed $value
* @return void
* @throws \RuntimeException If the value is not an input.
*/
private function assertIsInput(mixed $value): void
{
if (!\is_object($value) or !($value instanceof Discount)) {
$value = \json_encode($value);
throw new \RuntimeException(
__CLASS__ . ' needs value to be array of \'' . Discount::class . "' given is {$value}"
);
}
}
}

View file

@ -1,61 +0,0 @@
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
/**
* @template TGet
* @template TSet
*/
class Ip implements CastsAttributes
{
/**
* Transform the attribute from the underlying model values.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value
* @param array<string,mixed> $attributes
* @return \IPLib\Address\AddressInterface|null
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
*/
public function get(Model $model, string $key, mixed $value, array $attributes)
{
// phpcs:enable
return \IPLib\Factory::parseAddressString($value);
}
/**
* Transform the attribute to its underlying model values.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param \IPLib\Address\AddressInterface|string|null $value
* @param array<string,mixed> $attributes
* @return mixed
* @throws \RuntimeException If value is not or instance of \IPLib\Address\AddressInterface.
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
*/
public function set(Model $model, string $key, mixed $value, array $attributes)
{
// phpcs:enable
if (is_null($value)) {
return null;
}
if (is_string($value)) {
$value = \IPLib\Factory::parseAddressString($value);
}
if (!is_object($value) or !($value instanceof \IPLib\Address\AddressInterface)) {
throw new \RuntimeException(
"{$key} has to be instance of " .
\IPLib\Address\AddressInterface::class
);
}
$value->getAddressType();
return $value;
}
}

View file

@ -0,0 +1,57 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Hash;
class CreateAdmin extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'create:admin';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return integer
*/
public function handle()
{
$firstname = $this->ask('What is the firstname?', 'Equipe');
$lastname = $this->ask('What is the lastname?', 'Web');
$email = $this->ask('What is the email?', 'equipe.web@ldc.fr');
$pwd = $this->secret('What is the password?');
$role = $this->ask('Role ?', '1');
$user = new User();
$user->firstname = $firstname;
$user->lastname = $lastname;
$user->birth_date = now();
$user->email = $email;
$user->password = Hash::make($pwd);
$user->address = "-";
$user->town = "Le Mans";
$user->postal_code = "72000";
$user->country = "France";
$user->email_verify_token = "-";
$user->email_verified = 1;
$user->role = $role;
$user->save();
$this->info('User created.');
return 0;
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
class DeleteNotConfirmedUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'users:deletenc';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Remove users who have not confirmed their accounts within 24 hours of registration';
/**
* Execute the console command.
*
* @return integer
*/
public function handle()
{
$users = User::where([['email_verified', 0], ['created_at', '<', Carbon::now()->subDay()]])->get();
foreach ($users as $user) {
$user->delete();
}
return 0;
}
}

View file

@ -0,0 +1,192 @@
<?php
namespace App\Console\Commands;
use App\Mail\ExportCodesUniques as MailExportCodesUniques;
use App\Models\Code;
use App\Models\Settings;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class ExportCodesUniques extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'export:codeunique';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return integer
*/
public function handle()
{
// Nombre total de code à exporter.
$nbCodeTot = $this->ask("Combien de code doivent être exporté ?");
while (empty(intval($nbCodeTot)) || !is_int(intval($nbCodeTot))) {
$this->info("Valeur incorrect, veuillez entrer un nombre entier.");
$nbCodeTot = $this->ask("Veuillez entrer une nouvelle valeur");
}
$nbCodeTot = intval($nbCodeTot);
// Nombre de code par fichier.
$nbCodeFic = $this->ask("Combien de code par fichier ?");
while (empty(intval($nbCodeFic)) || !is_int(intval($nbCodeFic))) {
$this->info("Valeur incorrect, veuillez entrer un nombre entier.");
$nbCodeFic = $this->ask("Veuillez entrer une nouvelle valeur");
}
$nbCodeFic = intval($nbCodeFic);
// Nombre de code par ligne.
$nbCodeLigne = $this->ask("Combien de code par ligne dans un fichier ?");
while (empty(intval($nbCodeLigne)) || !is_int(intval($nbCodeLigne))) {
$this->info("Valeur incorrect, veuillez entrer un nombre entier.");
$nbCodeLigne = $this->ask("Veuillez entrer une nouvelle valeur");
}
$nbCodeLigne = intval($nbCodeLigne);
$totalExportedCodes = 0;
$currentFilename = 1;
$currentExportedCodes = 0;
$currentLineCodes = ($nbCodeLigne === 1 ? 1 : 0);
$this->info("Traitement en cours, veuillez patienter...");
$this->process(
$nbCodeFic,
$nbCodeTot,
$nbCodeLigne,
$totalExportedCodes,
$currentFilename,
$currentExportedCodes,
$currentLineCodes
);
$this->info("Fin du traitement, creation de l'archive...");
// Compression des fichiers.
$zip = new \ZipArchive();
if (
$zip->open(
storage_path('export_codes_uniques/') . "CodesUniques_" . date('dmY') . ".zip",
\ZipArchive::CREATE
) === true
) {
if ($handle = opendir(storage_path('export_codes_uniques/tmp'))) {
while (false !== ($file_to_zip = readdir($handle))) {
if (pathinfo($file_to_zip, PATHINFO_EXTENSION) != 'csv') {
continue;
}
$zip->addFile(storage_path('export_codes_uniques/tmp/') . $file_to_zip, "$file_to_zip");
}
closedir($handle);
}
$zip->close();
}
// On vide le dossier temporaire des fichiers csv.
if ($handle = opendir(storage_path('export_codes_uniques/tmp'))) {
while (false !== ($file_to_zip = readdir($handle))) {
if (pathinfo($file_to_zip, PATHINFO_EXTENSION) != 'csv') {
continue;
}
unlink(storage_path('export_codes_uniques/tmp/') . $file_to_zip);
}
closedir($handle);
}
$this->info("L'archive CodesUniques_" . date('dmY') . ".zip a ete creer.");
// Envoi de mail à MAIL_ADMIN avec le nom du ZIP "CodesUniques_". date('dmY') .".zip" .
Mail::to(config('mail.MAIL_ADMIN'))
->send(new MailExportCodesUniques(app(Settings::class)->name, $nbCodeFic, $nbCodeTot, $nbCodeLigne));
return 0;
}
private function process($nbCodeFic, $nbCodeTot, $nbCodeLigne, $totalExportedCodes, $currentFilename, $currentExportedCodes, $currentLineCodes, $lastExportedCodeId = null)
{
$paginate = config('codes.paginate');
if ($nbCodeTot < $paginate) {
$nbCodeToRetrieve = $nbCodeTot;
} else {
if ($totalExportedCodes + $paginate > $nbCodeTot) {
$nbCodeToRetrieve = $nbCodeTot - $totalExportedCodes;
} else {
$nbCodeToRetrieve = $paginate;
}
}
if ($lastExportedCodeId === null) {
$codes = Code::where('code_exported', 0)->take($nbCodeToRetrieve)->get();
} else {
$codes = Code::where([
['code_exported', '=', 0],
['id', '>', $lastExportedCodeId]
])->take($nbCodeToRetrieve)->get();
}
$countCodes = count($codes);
$exportedCodesId = [];
foreach ($codes as $k => $code) {
if ($currentExportedCodes < $nbCodeTot) {
if ($currentLineCodes === ($nbCodeLigne === 1 ? 1 : $nbCodeLigne - 1)) {
file_put_contents(
storage_path('export_codes_uniques/tmp/') . $currentFilename . ".csv",
$code->code_unique . PHP_EOL,
FILE_APPEND
);
$totalExportedCodes++;
$currentExportedCodes++;
$currentLineCodes = ($nbCodeLigne === 1 ? 1 : 0);
} else {
file_put_contents(
storage_path('export_codes_uniques/tmp/') . $currentFilename . ".csv",
$code->code_unique . ";",
FILE_APPEND
);
$totalExportedCodes++;
$currentExportedCodes++;
$currentLineCodes++;
}
array_push($exportedCodesId, $code->id);
$lastExportedCodeId = $code->id;
if ($currentExportedCodes === $nbCodeFic) {
$currentFilename++;
$currentExportedCodes = 0;
}
if ((($k + 1) === $countCodes) && $totalExportedCodes < $nbCodeTot) {
Code::whereIn('id', $exportedCodesId)->update(['code_exported' => 1]);
return $this->process(
$nbCodeFic,
$nbCodeTot,
$nbCodeLigne,
$totalExportedCodes,
$currentFilename,
$currentExportedCodes,
$currentLineCodes,
$lastExportedCodeId
);
}
if (($k + 1) === $countCodes) {
Code::whereIn('id', $exportedCodesId)->update(['code_exported' => 1]);
}
} //end if
}//end foreach
}
}

View file

@ -1,35 +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 void
*/
public function handle()
{
Mail::raw(sprintf('UWIL mail-test from %s %s', \config('app.name'), \config('app.url')), function ($msg) {
$msg->to('equipe.web@ldc.fr')->subject('Test Email');
});
}
}

View file

@ -1,77 +0,0 @@
<?php
namespace App\Console\Commands\Theme;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use function Laravel\Prompts\search;
class SwitchCommand extends Command implements PromptsForMissingInput
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:theme:switch {theme : The theme folder name on theme-merge project}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Switch GGW theme and install it';
/**
* Prompt for missing input arguments using the returned questions.
*
* @return array
*/
protected function promptForMissingArgumentsUsing()
{
return [
'theme' => fn () => search(
label: 'Search for a theme:',
placeholder: 'default-theme',
options: fn (string $value): array => \collect(File::directories(\resource_path('theme')))
->map(fn (string $dir_path) => \pathinfo($dir_path, \PATHINFO_BASENAME))
->filter(fn (string $dir_path) => $value ? Str::of($dir_path)->contains($value) : true)
->filter(fn (string $dir_path) => $dir_path !== 'mounted')
->all()
)
];
}
/**
* Execute the console command.
*
* @return void
*/
public function handle(): void
{
$mount_path = \resource_path('theme/mounted');
/** @var string */
$theme = $this->argument('theme');
if (File::exists($mount_path)) {
\throw_if(
empty(ToolboxHelper::runConsoleCommand("readlink {$mount_path}", false)),
"{$mount_path} is not a link, cannot remove it"
);
\throw_if(
!File::delete($mount_path),
"{$mount_path} Failed to remove file"
);
}
File::link(\resource_path("theme/{$theme}"), $mount_path);
Artisan::call('optimize:clear');
}
}

View file

@ -1,231 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Enums\Users\RoleEnum;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class UserCreate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'uwil:user:create';
/**
* The console command description.
*
* @var string|null
*/
protected $description = 'Create a backend admin user';
/**
* The first name of the new user.
*
* @var string|null
*/
protected $first_name;
/**
* The last name of the new user.
*
* @var string|null
*/
protected $last_name;
/**
* The email of the new user.
*
* @var string|null
*/
protected $email;
/**
* The password of the new user.
*
* @var string|null
*/
protected $password;
/**
* The role of the new user.
*
* @var string|null
*/
protected $role;
/**
* Execute the console command.
*
* @return integer
*/
public function handle(): int
{
$this->first_name = null;
$this->addFirstName();
$this->last_name = null;
$this->addLastName();
$this->email = null;
$this->addEmail();
$this->password = null;
$this->addPassword();
$this->role = null;
$this->addRole();
$user = new User([
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'email' => $this->email,
'password' => $this->password,
'role' => $this->role,
'published' => true,
'published_at' => Carbon::now(),
]);
$user->saveOrFail();
$this->info('User created 👌');
return 0;
}
/**
* Add a first name to the user.
*
* @return void
*/
private function addFirstName(): void
{
while (is_null($this->first_name)) {
try {
$tmp = $this->ask('Type the wanted user first name', 'Admin');
$validator = Validator::make(['first_name' => $tmp], [
'first_name' => 'required|min:3|max:255'
]);
$validator->validate();
$this->first_name = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid first name %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
/**
* Add a last name to the user.
*
* @return void
*/
private function addLastName(): void
{
while (is_null($this->last_name)) {
try {
$tmp = $this->ask('Type the wanted user last name', 'Saïtama');
$validator = Validator::make(['last_name' => $tmp], [
'last_name' => 'required|min:3|max:255'
]);
$validator->validate();
$this->last_name = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please provide a valid last_name %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
}
/**
* Add a role to the user.
*
* @return void
*/
private function addRole(): void
{
while (is_null($this->role)) {
try {
$tmp = $this->choice(
'Select his role',
[RoleEnum::conceptor->label(), RoleEnum::admin->label(), RoleEnum::marketing->label()],
RoleEnum::marketing->label(),
$maxAttempts = null,
$allowMultipleSelections = false
);
if ($tmp === RoleEnum::conceptor->label()) {
$tmp = RoleEnum::conceptor;
}
if ($tmp === RoleEnum::admin->label()) {
$tmp = RoleEnum::admin;
}
if ($tmp === RoleEnum::marketing->label()) {
$tmp = RoleEnum::marketing;
}
$validator = Validator::make(['role' => $tmp], [
'role' => 'required'
]);
$validator->validate();
$this->role = $tmp;
} catch (ValidationException $e) {
$this->error(sprintf(
'Please choose from the selection %s',
\implode(',', collect($e->errors())->flatten()->all())
));
continue;
} //end try
}; //end while
}
}

View file

@ -2,7 +2,6 @@
namespace App\Console;
use App\Jobs\DeleteOlds\DeleteOldCustomers;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -23,9 +22,6 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule)
{
// ! ATTENTION: Le job DeleteOldCustomers a été désactivé, car il n'est pas applicable pour l'instant.
// ! Il faudra décorreler les customers des gains et participations via les FK.
// $schedule->job(DeleteOldCustomers::class)->dailyAt('22:50');
}
/**

View file

@ -1,48 +0,0 @@
<?php
namespace App\Enums\ActivityLogs;
use App\Traits\Enums\BaseEnum;
enum ActivityLogsEventEnum: int
{
use BaseEnum;
case created = 1;
case updated = 2;
case duplicated = 3;
case deleted = 4;
/**
* Optionnal labels definition
*
* @phpstan-ignore-next-line
*/
private const LABELS = [
self::created->name => 'Création',
self::updated->name => 'Mise à jour',
self::duplicated->name => 'Duplication',
self::deleted->name => 'Suppression',
];
/**
* Custom added classes definition
*/
private const BOOTSTRAPCLASS = [
self::created->name => 'success',
self::updated->name => 'warning',
self::duplicated->name => 'secondary',
self::deleted->name => 'danger',
];
/**
* Get Class
*
* @return string
*/
public function bootstrapClass(): string
{
return self::BOOTSTRAPCLASS[$this->name];
}
}

View file

@ -1,25 +0,0 @@
<?php
namespace App\Enums;
use App\Traits\Enums\BaseEnum;
enum CodeType: int
{
use BaseEnum;
case unique = 1;
case ean = 2;
case both = 3;
/**
* Optionnal labels definition.
*
* @phpstan-ignore-next-line
*/
private const LABELS = [
self::unique->name => 'Codes uniques',
self::ean->name => 'Codes EAN',
self::both->name => 'Codes uniques et codes EAN'
];
}

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;
}

View file

@ -1,16 +0,0 @@
<?php
namespace App\Enums\Pagination;
use App\Traits\Enums\BaseEnum;
enum ItemsPerPaginationEnum: int
{
use BaseEnum;
case five = 5;
case twelve = 12;
case twentyfive = 25;
case fifty = 50;
case onehundred = 100;
}

View file

@ -1,25 +0,0 @@
<?php
namespace App\Enums;
use App\Traits\Enums\BaseEnum;
enum StaticPageType: int
{
use BaseEnum;
case legals = 1;
case rules = 2;
case confidentiality = 3;
/**
* Optionnal labels definition.
*
* @phpstan-ignore-next-line
*/
private const LABELS = [
self::legals->name => 'Mentions légales',
self::rules->name => 'Règlement',
self::confidentiality->name => 'Charte de confidentialité'
];
}

View file

@ -1,23 +0,0 @@
<?php
namespace App\Enums\Theme;
use App\Traits\Enums\BaseEnum;
enum BootstrapThemeEnum: int
{
use BaseEnum;
case light = 1;
case dark = 2;
/**
* Optionnal labels definition
*
* @phpstan-ignore-next-line
*/
private const LABELS = [
self::light->name => 'Light',
self::dark->name => 'Dark',
];
}

View file

@ -1,25 +0,0 @@
<?php
namespace App\Enums\Users;
use App\Traits\Enums\BaseEnum;
enum RoleEnum: int
{
use BaseEnum;
case conceptor = 1;
case admin = 2;
case marketing = 3;
/**
* Optionnal labels definition
*
* @phpstan-ignore-next-line
*/
private const LABELS = [
self::conceptor->name => 'Concepteur',
self::admin->name => 'Administrator',
self::marketing->name => 'Marketing',
];
}

View file

@ -2,47 +2,26 @@
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of exception types with their corresponding custom log levels.
*
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
*/
protected $levels = [];
/**
* A list of the exception types that are not reported.
*
* @var array<int, class-string<\Throwable>>
* @var array
*/
protected $dontReport = [];
/**
* A list of the inputs that are never flashed to the session on validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
protected $dontReport = [
RedirectTo::class
];
/**
* Register the exception handling callbacks for the application.
* A list of the inputs that are never flashed for validation exceptions.
*
* @return void
* @var array
*/
public function register()
{
$this->reportable(function (Throwable $e) {
if (app()->bound('sentry')) {
app('sentry')->captureException($e);
}
});
}
protected $dontFlash = [
'password',
'password_confirmation',
];
}

View file

@ -1,71 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\ActivityLog;
use App\Traits\Controllers\ChangesModelOrder;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
class ActivityLogController extends Controller
{
use ChangesModelOrder;
use UpdateModelPublished;
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
$this->authorize('isConceptor');
/** @var \Illuminate\Database\Eloquent\Builder $query */
$query = ActivityLog::query()->with('user');
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$query,
$search,
null,
'model_class',
);
}
$searchFields = \implode(', ', [
trans('validation.custom.target'),
]);
/** Sort columns with a query */
$this->sortQuery($query);
/** Custom pagination */
$activitylogModels = $this->paginate($query);
return view('back::pages.activity_logs.index', compact('activitylogModels', 'search', 'searchFields'));
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\ActivityLog $activity_log
* @return \Illuminate\Contracts\View\View
*/
public function show(ActivityLog $activity_log): \Illuminate\Contracts\View\View
{
$this->authorize('isConceptor');
$targetModelClass = $activity_log->model_class;
$targetModel = $activity_log->model_class::where(
(new $targetModelClass())->getRouteKeyName(),
$activity_log->model_id
)->first();
return view('back::pages.activity_logs.show', [
'activitylogModel' => $activity_log,
'targetModel' => $targetModel,
]);
}
}

View file

@ -1,72 +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\Http\Request;
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('back::auth.login');
}
/**
* Where to redirect users after login.
*
* @return string
*/
protected function redirectTo(): string
{
return response()->redirectToIntended()->getTargetUrl();
}
/**
* Attempt to log the user into the application.
*
* @param \Illuminate\Http\Request $request
* @return boolean
*/
protected function attemptLogin(Request $request)
{
$credentials = $this->credentials($request);
// * Attempt login only using published users.
$credentials['published'] = true;
return $this->guard()->attempt(
$credentials,
$request->boolean('remember')
);
}
}

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

@ -3,160 +3,38 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\BannedIps\StoreBannedIpRequest;
use App\Http\Requests\Bo\BannedIps\UpdateBannedIpRequest;
use App\Models\BannedIp;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class BannedIpController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
public function index()
{
$this->authorizeResource(BannedIp::class);
$ips = BannedIp::all();
return view('bo.banned-ip.index', compact('ips'));
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
public function saveDatas(Request $request)
{
/** @var \Illuminate\Database\Eloquent\Builder $bannedipModels */
$bannedipModels = BannedIp::query();
$ips = $request->ips;
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$bannedipModels,
$search,
null,
'ip',
);
for ($i = 0; $i < count($ips); $i++) {
if (!empty($ips[$i]["ip"])) {
$ip = BannedIp::updateOrCreate(['ip' => $ips[$i]["ip"]]);
} else {
unset($ips[$i]);
$i--;
}
$searchFields = trans('validation.custom.ip');
/** Sort columns with a query */
$this->sortQuery($bannedipModels);
/** Custom pagination */
$bannedipModels = $this->paginate($bannedipModels);
return view('back::pages.banned-ips.index', compact('bannedipModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\BannedIp $banned_ip
* @return \Illuminate\Contracts\View\View
*/
public function create(BannedIp $banned_ip): \Illuminate\Contracts\View\View
return $ips;
}
public function destroy(Request $request)
{
return view('back::pages.banned-ips.create', [
'bannedipModel' => $banned_ip,
]);
}
$ip = BannedIp::where("ip", $request->ip);
$ip->delete();
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\BannedIps\StoreBannedIpRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreBannedIpRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$banned_ip = new BannedIp();
$banned_ip->fill($request->validated());
if ($banned_ip->saveOrFail()) {
return redirect()
->route('bo.banned_ips.edit', $banned_ip)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(trans('models.classes.banned_ips'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(trans('models.classes.banned_ips'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\BannedIp $banned_ip
* @return \Illuminate\Contracts\View\View
*/
public function edit(BannedIp $banned_ip): \Illuminate\Contracts\View\View
{
return view('back::pages.banned-ips.edit', [
'bannedipModel' => $banned_ip,
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\BannedIps\UpdateBannedIpRequest $request
* @param \App\Models\BannedIp $banned_ip
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateBannedIpRequest $request, BannedIp $banned_ip): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $banned_ip) {
$banned_ip->fill($request->validated());
if ($banned_ip->saveOrFail()) {
return redirect()
->route('bo.banned_ips.edit', $banned_ip)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(trans('models.classes.banned_ips'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(trans('models.classes.banned_ips'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\BannedIp $banned_ip
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(BannedIp $banned_ip): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($banned_ip) {
if ($banned_ip->deleteOrFail()) {
return redirect()
->route('bo.banned_ips.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => Str::singular(trans('models.classes.banned_ips'))]
));
}
return redirect()
->back()
->with('error', __(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(trans('models.classes.banned_ips'))]
));
});
return "Suppression terminée !";
}
}

View file

@ -1,135 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Codes\CodeSearchRequest;
use App\Http\Requests\Bo\Codes\ExportCodesRequest;
use App\Http\Requests\Bo\Codes\GenerateCodesRequest;
use App\Jobs\ProcessExportCodesUniques;
use App\Jobs\ProcessUniqueCode;
use App\Models\Code;
use App\Models\Participation;
use App\Models\Settings;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Queue;
use Kwaadpepper\Serial\Exceptions\SerialCasterException;
class CodeController extends Controller
{
/**
* Show code form to generate and export
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): \Illuminate\Contracts\View\View
{
$this->authorize('generate', Code::class);
/** @var \App\Models\Settings */
$settings = app(Settings::class);
$nbCodeBase = Code::query()->max('id');
$nbCodeUsed = Code::query()->whereHas(
'participations',
operator: '>',
count: $settings->nb_unique_code_use
)->count();
$nbCodeExported = Code::query()->where('code_exported', true)->count();
$nbCodeRemainingToExport = Code::query()->where('code_exported', false)->count();
return view('back::pages.codes.index', compact(
'settings',
'nbCodeBase',
'nbCodeUsed',
'nbCodeExported',
'nbCodeRemainingToExport'
));
}
/**
* Run generate codes action
*
* @param \App\Http\Requests\Bo\Codes\GenerateCodesRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function generate(GenerateCodesRequest $request): \Illuminate\Http\RedirectResponse
{
$this->authorize('generate', Code::class);
Queue::push(
new ProcessUniqueCode(
intval($request->quantity),
config('codes.codeLength')
)
);
return back()->with(
'success',
trans(
// phpcs:ignore Generic.Files.LineLength.TooLong
'La tache de génération à été ajoutée, un mail de notification sera envoyé à l\'adresse :email lorsque le traitement sera terminé.',
[
'email' => config('mail.admin')
]
)
);
}
/**
* Run export codes
*
* @param \App\Http\Requests\Bo\Codes\ExportCodesRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function export(ExportCodesRequest $request): \Illuminate\Http\RedirectResponse
{
$this->authorize('export', Code::class);
Queue::push(
new ProcessExportCodesUniques(
intval($request->nb_code_fic),
intval($request->nb_code_tot),
intval($request->nb_code_ligne)
)
);
return back()->with(
'success',
// phpcs:ignore Generic.Files.LineLength.TooLong
__('L\'export des codes à commencé, un mail de notification sera envoyé à l\'adresse :emaillorsque le traitement sera terminé.', [
'email' => config('mail.admin')
])
);
}
/**
* Search for a specific code.
*
* @param \App\Http\Requests\Bo\Codes\CodeSearchRequest $request
* @return \Illuminate\Contracts\View\View
*/
public function search(CodeSearchRequest $request): \Illuminate\Contracts\View\View
{
$this->authorize('search', Code::class);
$code = null;
try {
$code = Code::query()->where('id', Code::serialToInt($request->code))->first();
} catch (\Throwable $e) {
if (\get_class($e) === SerialCasterException::class) {
$code = false;
}
} finally {
if ($code === false) {
\session()->flash('warning', trans('Code non valide.'));
}
if ($code === null) {
\session()->flash('warning', trans('Code introuvable.'));
}
}
$used_counter = null;
if ($code) {
$used_counter = Participation::query()
->whereHas('code', fn(Builder $q) => $q->where('id', $code->id))
->count();
}
return view('back::pages.codes.search', compact('code', 'used_counter'));
}
}

View file

@ -0,0 +1,104 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\CodeSearchRequest;
use App\Http\Requests\ExportCodesRequest;
use App\Http\Requests\GenerateCodesRequest;
use App\Jobs\ProcessExportCodesUniques;
use App\Jobs\ProcessUniqueCode;
use App\Models\Code;
use App\Models\Settings;
use Kwaadpepper\Serial\Exceptions\SerialCasterException;
class CodesController extends Controller
{
/**
* Show code form to generate and export
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
public function index()
{
$settings = app(Settings::class);
$nbCodeBase = Code::count();
$nbCodeUsed = Code::where('code_used', 1)->count();
$nbCodeExported = Code::where('code_exported', 1)->count();
$nbCodeRemainingToExport = Code::where('code_exported', 0)->count();
return view('bo.codes.index', compact(
'settings',
'nbCodeBase',
'nbCodeUsed',
'nbCodeExported',
'nbCodeRemainingToExport'
));
}
/**
* Run generate codes action
*
* @param GenerateCodesRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function generate(GenerateCodesRequest $request)
{
ProcessUniqueCode::dispatch(
$request->quantity,
$request->code_length
);
return back()->with(
'success',
"La génération à commencée, un mail de notification sera envoyé à l'adresse " .
config('mail.MAIL_ADMIN') . " lorsque le traitement sera terminé."
);
}
/**
* Run export codes
*
* @param ExportCodesRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function export(ExportCodesRequest $request)
{
ProcessExportCodesUniques::dispatch(
intval($request->nb_code_fic),
intval($request->nb_code_tot),
intval($request->nb_code_ligne)
);
return back()->with(
'success',
"L'export des codes à commencé, un mail de notification sera envoyé à l'adresse " .
config('mail.MAIL_ADMIN') . " lorsque le traitement sera terminé."
);
}
/**
* Search for a specific code.
*
* @param CodeSearchRequest $request
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
public function search(CodeSearchRequest $request)
{
$code = null;
try {
$code = Code::whereId(Code::serialToInt($request->code))->first();
} catch (\Throwable $e) {
if (\get_class($e) === SerialCasterException::class) {
$code = false;
}
} finally {
if ($code === false) {
\session()->flash('warning', trans('Code non valide.'));
}
if ($code === null) {
\session()->flash('warning', trans('Code introuvable.'));
}
}
return view('bo.codes.search', compact('code'));
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\CodeEan;
use Illuminate\Http\Request;
class CodesEANController extends Controller
{
public function index()
{
$ean = CodeEan::all();
return view('bo.codes-ean.index', compact('ean'));
}
public function saveDatas(Request $request)
{
$codes = $request->codes;
for ($i = 0; $i < count($codes); $i++) {
$codeToInsert = !empty($codes[$i]["code"]) && !empty($codes[$i]["product"]);
if (isset($codes[$i]["id"]) && $codes[$i]["id"] !== null && $codeToInsert) {
$c = CodeEan::findOrFail($codes[$i]["id"]);
$c->code = $codes[$i]["code"];
$c->product = $codes[$i]["product"];
$c->save();
} else {
if ($codeToInsert) {
$c = CodeEan::updateOrCreate(['code' => $codes[$i]["code"], 'product' => $codes[$i]["product"]]);
$codes[$i]["id"] = $c->id;
} else {
unset($codes[$i]);
$i--;
}
}
}
return $codes;
}
public function destroy(Request $request)
{
$code = CodeEan::findOrFail($request->id);
$code->delete();
return "Suppression terminée !";
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\Content;
use Illuminate\Http\Request;
class ContentController extends Controller
{
public function manage($id, Request $request)
{
$content = Content::findOrFail($id);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$value = $request->value;
$content->value = $value;
$content->save();
return redirect()->route('bo.content', $content->id)->with('success', 'Enregistré !');
}
return view('bo.content.manage', compact('content'));
}
}

View file

@ -6,76 +6,65 @@ use App\Http\Controllers\Controller;
use App\Models\Participation;
use App\Models\Settings;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
class DashboardController extends Controller
{
/**
* Dashboard Page
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): \Illuminate\Contracts\View\View
public function index()
{
// * Pour les stats.
/** @var \App\Models\Settings */
// Pour les stats.
$settings = app(Settings::class);
$avgParticipUser = 0;
$participationPeriod = [];
$participations = Participation::selectRaw("COUNT(*) AS count, DATE(created_at) AS date")
->groupByRaw("DATE(created_at)")->get();
$participationsUniquePerDay = Participation::selectRaw("DISTINCT user_id AS user, COUNT(*) AS count, DATE(created_at) AS date")
->groupByRaw("DATE(created_at), user")->get();
$statsUnique = [];
$query = DB::table((new Participation())->getTable());
$dateFrmtr = function (object $row) {
$row->date = Carbon::parse($row->date)->isoFormat('DD/MM/YYYY');
return $row;
};
foreach ($participationsUniquePerDay as $participationPerDay) {
$dateUnique = Carbon::parse($participationPerDay->date)->format('d/m/Y');
$statsUnique[$dateUnique] = isset($statsUnique[$dateUnique]) ? $statsUnique[$dateUnique] + 1 : 1;
}
$participationsUnique = Participation::selectRaw("DISTINCT user_id AS user, COUNT(*) AS count")
->groupBy("user")->orderBy("user")->get();
/** @var \Illuminate\Support\Collection<string,object> */
$participationsPerDay = (clone $query)
->selectRaw('COUNT(*) AS count, DATE(created_at) AS date')
->groupByRaw('DATE(created_at)')->get()->map($dateFrmtr)->keyBy('date');
/** @var \Illuminate\Support\Collection<object> */
$participationsUniquePerDay = (clone $query)
->selectRaw('DISTINCT customer_id AS user, COUNT(*) AS count, DATE(created_at) AS date')
->groupByRaw('DATE(created_at), user')->get()->map($dateFrmtr);
/** @var \Illuminate\Support\Collection<object> */
$participationsUniquePerCustomer = (clone $query)
->selectRaw("DISTINCT customer_id AS user, COUNT(*) AS count")
->groupBy('user')->orderBy('user')->get();
$participationsTotal = Participation::query()->count();
/** @var \Illuminate\Support\Collection<object> 3 codes EAN les plus utilisés */
$codesEan = (clone $query)
->selectRaw('COUNT(product_id) AS nb_usage, product_id, ean_code')
->join('products', 'product_id', '=', 'products.id')
->groupBy('product_id', 'ean_code')
->orderByDesc('nb_usage')->limit(3)->get();
$participationsUniquePerDay->each(function (object $row) use (&$statsUnique) {
Arr::set($statsUnique, $row->date, (Arr::get($statsUnique, $row->date) ?? 0) + 1);
});
// * Calcul participation moyenne par utilisateur.
if ($participationsUniquePerCustomer->count() > 0) {
$avgParticipUser = round($participationsTotal / $participationsUniquePerCustomer->count(), 1);
// Données calculées à afficher.
$totalParticipation = Participation::count();
if (count($participationsUnique) > 0) {
$avgParticipUser = round($totalParticipation / count($participationsUnique), 1);
} else {
$avgParticipUser = 0;
}
// * Création des tableaux avec toutes les dates depuis le début du jeu
// * et le nombre de participations associées pour le graph JS.
$start_date = $settings->start_date;
$end_date = now()->lt($settings->end_date) ? now() : $settings->end_date;
$dates = $participationsPerDay->keys();
$count = $participationsPerDay->pluck('count');
$countUnique = $dates->map(fn (string $formated_date) => Arr::get($statsUnique, $formated_date, 0));
// Tableau des dates comprises dans la table participation.
foreach ($participations as $participation) {
$datesParticipations[Carbon::parse($participation->date)->format('d/m/Y')] = $participation->count;
}
return view('back::pages.dashboard.index', compact(
// Création des tableaux avec toutes les dates depuis le début du jeu et le nombre de participations associées.
$date = Carbon::parse($settings->start_date);
$dateFin = now() < $settings->end_date ? Carbon::now() : Carbon::parse($settings->end_date);
// Récupération des 3 codes EAN les plus utilisés.
$codesEan = Participation::select(
DB::raw('COUNT(code_ean_id) AS nb_usage, code_ean_id')
)->groupBy('code_ean_id')->orderByDesc('nb_usage')->limit(3)->get();
// Génération des tableaux de date depuis le début du jeu.
$dates = [];
$count = [];
$countUnique = [];
while ($dateFin > $date) {
$dates[] = $date->format('d/m/Y');
$count[] = isset($datesParticipations[$date->format('d/m/Y')]) ?
$datesParticipations[$date->format('d/m/Y')] : 0;
$countUnique[] = isset($statsUnique[$date->format('d/m/Y')]) ? $statsUnique[$date->format('d/m/Y')] : 0;
$date->addDay();
}
return view('bo.dashboard.index', compact(
'dates',
'count',
'countUnique',
'participationsTotal',
'totalParticipation',
'avgParticipUser',
'codesEan',
'settings'

View file

@ -1,180 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\FaqQuestions\StoreFaqQuestionRequest;
use App\Http\Requests\Bo\FaqQuestions\UpdateFaqQuestionRequest;
use App\Models\FaqQuestion;
use App\Models\FaqTheme;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class FaqQuestionController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(FaqQuestion::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $faqQuestionModels */
$faqQuestionModels = FaqQuestion::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$faqQuestionModels,
$search,
null,
'question',
'answer'
);
}
$searchFields = \sprintf(
'%s, %s ...',
Str::ucfirst(__('validation.custom.question')),
__('validation.custom.answer'),
);
/** Sort columns with a query */
$this->sortQuery($faqQuestionModels);
/** Custom pagination */
$faqQuestionModels = $this->paginate($faqQuestionModels);
return view('back::pages.faq-questions.index', compact('faqQuestionModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\FaqQuestion $faqQuestion
* @return \Illuminate\Contracts\View\View
*/
public function create(FaqQuestion $faqQuestion): \Illuminate\Contracts\View\View
{
$faqThemeModels = FaqTheme::all();
return view('back::pages.faq-questions.create', [
'faqQuestionModel' => $faqQuestion,
'faqThemeModels' => $faqThemeModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\FaqQuestions\StoreFaqQuestionRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreFaqQuestionRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$faqQuestion = new FaqQuestion();
$faqQuestion->fill($request->validated());
if ($faqQuestion->saveOrFail()) {
return redirect()
->route('bo.faq-questions.edit', $faqQuestion)
->with(
'success',
trans(
'crud.messages.has_been_created',
['model' => trans_choice('models.classes.faq-questions', 1)]
)
);
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\FaqQuestion $faqQuestion
* @return \Illuminate\Contracts\View\View
*/
public function edit(FaqQuestion $faqQuestion): \Illuminate\Contracts\View\View
{
$faqThemeModels = FaqTheme::all();
return view('back::pages.faq-questions.edit', [
'faqQuestionModel' => $faqQuestion,
'faqThemeModels' => $faqThemeModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\FaqQuestions\UpdateFaqQuestionRequest $request
* @param \App\Models\FaqQuestion $faqQuestion
* @return \Illuminate\Http\RedirectResponse
*/
public function update(
UpdateFaqQuestionRequest $request,
FaqQuestion $faqQuestion
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($request, $faqQuestion) {
$faqQuestion->fill($request->validated());
if ($faqQuestion->saveOrFail()) {
return redirect()
->route(
'bo.faq-questions.edit',
$faqQuestion
)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\FaqQuestion $faqQuestion
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(FaqQuestion $faqQuestion): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($faqQuestion) {
if ($faqQuestion->deleteOrFail()) {
return redirect()
->route('bo.faq-questions.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
}
return redirect()
->back()
->with('error', __(
':crud.messages.cannot_be_deleted',
['model' => trans_choice('models.classes.faq-questions', 1)]
));
});
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\FaqQuestion;
use App\Models\FaqTheme;
use Illuminate\Http\Request;
class FaqQuestionsController extends Controller
{
public function index()
{
$questions = FaqQuestion::all();
for ($i = 0; $i < count($questions); $i++) {
$questions[$i]['toggle'] = false;
}
$themes = FaqTheme::all();
return view('bo.faq-questions.index', compact('questions', 'themes'));
}
public function destroy(Request $request)
{
if ($request->id !== null) {
$question = FaqQuestion::findOrFail($request->id);
$question->delete();
}
}
public function saveDatas(Request $request)
{
$questions = $request->questions;
for ($i = 0; $i < count($questions); $i++) {
if (isset($questions[$i]["id"])) {
$q = FaqQuestion::findOrFail($questions[$i]["id"]);
$q->question = $questions[$i]["question"];
$q->answer = $questions[$i]["answer"];
$q->positive_vote = $questions[$i]["positive_vote"];
$q->negative_vote = $questions[$i]["negative_vote"];
$q->theme_id = $questions[$i]["theme_id"];
$q->save();
} else {
$t = FaqQuestion::updateOrCreate(
[
'question' => $questions[$i]["question"],
'answer' => $questions[$i]["answer"],
'positive_vote' => $questions[$i]["positive_vote"],
'negative_vote' => $questions[$i]["negative_vote"],
'theme_id' => $questions[$i]["theme_id"]
]
);
$questions[$i]["id"] = $t->id;
}
}//end for
return $questions;
}
}

View file

@ -1,170 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\FaqThemes\StoreFaqThemeRequest;
use App\Http\Requests\Bo\FaqThemes\UpdateFaqThemeRequest;
use App\Models\FaqTheme;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class FaqThemeController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(FaqTheme::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $faqThemeModels */
$faqThemeModels = FaqTheme::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$faqThemeModels,
$search,
null,
'name',
);
}
$searchFields = Str::ucfirst(__('validation.attributes.name'));
/** Sort columns with a query */
$this->sortQuery($faqThemeModels);
/** Custom pagination */
$faqThemeModels = $this->paginate($faqThemeModels);
return view('back::pages.faq-themes.index', compact('faqThemeModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\FaqTheme $faqTheme
* @return \Illuminate\Contracts\View\View
*/
public function create(FaqTheme $faqTheme): \Illuminate\Contracts\View\View
{
return view('back::pages.faq-themes.create', [
'faqThemeModel' => $faqTheme,
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\FaqThemes\StoreFaqThemeRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreFaqThemeRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$faqTheme = new FaqTheme();
$faqTheme->fill($request->validated());
if ($faqTheme->saveOrFail()) {
return redirect()
->route('bo.faq-themes.edit', $faqTheme)
->with(
'success',
trans(
'crud.messages.has_been_created',
['model' => trans_choice('models.classes.faq-themes', 1)]
)
);
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\FaqTheme $faqTheme
* @return \Illuminate\Contracts\View\View
*/
public function edit(FaqTheme $faqTheme): \Illuminate\Contracts\View\View
{
return view('back::pages.faq-themes.edit', [
'faqThemeModel' => $faqTheme,
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\FaqThemes\UpdateFaqThemeRequest $request
* @param \App\Models\FaqTheme $faqTheme
* @return \Illuminate\Http\RedirectResponse
*/
public function update(
UpdateFaqThemeRequest $request,
FaqTheme $faqTheme
): \Illuminate\Http\RedirectResponse {
return DB::transaction(function () use ($request, $faqTheme) {
$faqTheme->fill($request->validated());
if ($faqTheme->saveOrFail()) {
return redirect()
->route(
'bo.faq-themes.edit',
$faqTheme
)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\FaqTheme $faqTheme
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(FaqTheme $faqTheme): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($faqTheme) {
if ($faqTheme->deleteOrFail()) {
return redirect()
->route('bo.faq-themes.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
}
return redirect()
->back()
->with('error', __(
'crud.messages.cannot_be_deleted',
['model' => trans_choice('models.classes.faq-themes', 1)]
));
});
}
}

View file

@ -0,0 +1,51 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\FaqQuestion;
use App\Models\FaqTheme;
use Illuminate\Http\Request;
class FaqThemesController extends Controller
{
public function index()
{
$themes = FaqTheme::all();
return view('bo.faq-themes.index', compact('themes'));
}
public function destroy(Request $request)
{
$deleteOk = 0;
if (FaqQuestion::where('theme_id', $request->id)->count() > 0) {
$deleteOk = 1;
} elseif ($request->id !== null) {
$theme = FaqTheme::findOrFail($request->id);
$theme->delete();
} else {
$deleteOk = 2;
}
return $deleteOk;
}
public function saveDatas(Request $request)
{
$themes = $request->themes;
for ($i = 0; $i < count($themes); $i++) {
if (isset($themes[$i]["id"])) {
$t = FaqTheme::findOrFail($themes[$i]["id"]);
$t->name = $themes[$i]["name"];
$t->save();
} else {
$t = FaqTheme::updateOrCreate(['name' => $themes[$i]["name"]]);
$themes[$i]["id"] = $t->id;
}
}
return $themes;
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\GainView;
use Illuminate\Http\Request;
class GainViewController extends Controller
{
public function index()
{
$gv = GainView::all();
return view('bo.gain-views.index', compact('gv'));
}
public function destroy(Request $request)
{
$retour = "Suppression terminée !";
if ($request->id !== null) {
$gv = GainView::findOrFail($request->id);
$gv->delete();
}
return $retour;
}
public function saveDatas(Request $request)
{
$gv = $request->gainViews;
for ($i = 0; $i < count($gv); $i++) {
if (isset($gv[$i]["id"])) {
$g = GainView::findOrFail($gv[$i]["id"]);
$g->name = $gv[$i]["name"];
$g->file_name = $gv[$i]["file_name"];
$g->save();
} else {
$g = GainView::updateOrCreate(['name' => $gv[$i]["name"], 'file_name' => $gv[$i]["file_name"]]);
$gv[$i]["id"] = $g->id;
}
}
return $gv;
}
}

View file

@ -6,177 +6,104 @@ use App\Http\Controllers\Controller;
use App\Models\InstantWin;
use App\Models\Prize;
use App\Models\Settings;
use Carbon\CarbonInterval;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class InstantWinController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
public function index()
{
$this->authorizeResource(InstantWin::class);
$nbInstantWin = InstantWin::count();
$canGenerate = 0;
if (intval($nbInstantWin) > 0) {
$canGenerate = 0;
} else {
$nbLots = Prize::count();
if (intval($nbLots) > 0) {
$canGenerate = 1;
} else {
$canGenerate = 0;
}
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Contracts\View\View
*/
public function index(): \Illuminate\Contracts\View\View
{
$instantWinModelList = InstantWin::query()->orderBy('available_at')->get();
$instantWin = InstantWin::orderBy('appear_date')->get();
return view('back::pages.instant-win.index', [
'instantWinModelList' => $instantWinModelList
return view('bo.instant-win.index', [
'can_generate' => $canGenerate,
'instant_win' => $instantWin
]);
}
/**
* Returns generated instant win.
*
* @return \Illuminate\Http\JsonResponse
*/
public function generate(): JsonResponse
public function instantWinGenerate()
{
$this->authorize('generate', InstantWin::class);
$start_date = Settings::latest()->value("start_date");
$end_date = Settings::latest()->value("end_date");
$lots = Prize::all();
return DB::transaction(function () {
/**
* À partir de quelle heure on peut gagner
* ! Seul l'heure sera prize en compte
*/
$day_start = now()->setTime(6, 0);
/**
* Jusqu'à quelle heure on peut gagner
* ! Seul l'heure sera prize en compte
*/
$day_end = now()->setTime(22, 29);
/** @var \App\Models\Settings */
$settings = app(Settings::class);
$prizeModelList = Prize::all();
/** @var \Illuminate\Support\Collection<array-key,\App\Http\Controllers\Bo\WinDayCalendar> */
$datesGlobal = collect();
/**
* @var \Illuminate\Support\Collection<array-key,\App\Http\Controllers\Bo\WinTimeElement>
* Liste de tous les lots à gagner
*/
$lotsGlobal = collect();
$begin = new \DateTime($start_date);
$end = new \DateTime($end_date);
$interval = new \DateInterval('P1D');
$daterange = new \DatePeriod($begin, $interval, $end);
$dateGlobal = [];
$lotsGlobal = [];
// * Seed srand !
\mt_srand(time());
// * Init prize list
$prizeModelList->each(function (Prize $prize) use ($lotsGlobal, $day_start, $day_end) {
for ($i = 0; $i < $prize->quantity; $i++) {
$el = new WinTimeElement();
$el->prize = $prize;
$el->time = now()->setTime(
mt_rand($day_start->hour, $day_end->hour),
mt_rand($day_start->minute, $day_end->minute)
);
$lotsGlobal->push($el);
foreach ($lots as $k => $lot) {
for ($i = 0; $i < $lot->quantity; $i++) {
$lotsGlobal[] = [
'id' => $lot->id,
'name' => $lot->label_one,
'hour' => str_pad(mt_rand(6, 22), 2, "0", STR_PAD_LEFT)
. ":" . str_pad(mt_rand(0, 59), 2, "0", STR_PAD_LEFT) . ":00"
];
}
});
$lotsGlobal->shuffle(time());
// * Init days calendar
foreach ($settings->start_date->toPeriod($settings->end_date, CarbonInterval::make('1day')) as $date) {
$el = new WinDayCalendar();
$el->lots = collect();
$el->time = $date->setTime(0, 0);
$datesGlobal->push($el);
}
shuffle($lotsGlobal);
foreach ($daterange as $date) {
array_push($dateGlobal, ['date' => $date->format("Y-m-d"), 'lots' => []]);
}
// * Save Instant wins
$this->generateArray($lotsGlobal, $datesGlobal, 0)->each(function (WinDayCalendar $winDayCalendar) {
$winDayCalendar->lots->each(function (WinTimeElement $winTimeElement) {
$instantWin = new InstantWin();
$instantWin->available_at = $winTimeElement->time;
$instantWin->prize()->associate($winTimeElement->prize);
$instantWin->saveOrFail();
});
});
$res = $this->generate($lotsGlobal, $dateGlobal, 0);
// * Output instant wins to ajax response
return response()->json(InstantWin::all());
});
foreach ($res as $date) {
foreach ($date['lots'] as $lot) {
$iw = new InstantWin();
$iw->prize_id = $lot['id'];
$iw->appear_date = date('Y-m-d H:i:s', strtotime($date['date'] . " " . $lot['hour']));
$iw->save();
}
}
/**
* Generate instant win.
*
* Même algo que celui implémenté par Romain.
*
* @param \Illuminate\Support\Collection<array-key,\App\Http\Controllers\Bo\WinTimeElement> $lotsGlobal
* Liste de tous les lots à gagner
* @param \Illuminate\Support\Collection<array-key,\App\Http\Controllers\Bo\WinDayCalendar> $dateGlobal
* @param integer $prizesDone
* @return \Illuminate\Support\Collection<array-key,\App\Http\Controllers\Bo\WinDayCalendar>
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
*/
private function generateArray(Collection $lotsGlobal, Collection $dateGlobal, int $prizesDone): Collection
$instantWins = InstantWin::all();
return json_encode($instantWins);
}
private function generate($lotsGlobal, $dateGlobal, $lotsDone)
{
// phpcs:enable
/** @var array-key Un jour sélectionné aléatoire. */
$rKey = $dateGlobal->keys()->random(1)->firstOrFail();
// ? À-t-on déjà assigné un lot par jour (au moins) ?
// ? Le jour aléatoire sélectionné à déja un lot ?
if ($prizesDone < $dateGlobal->count() and $dateGlobal->get($rKey)->lots->count() > 0) {
return $this->generateArray($lotsGlobal, $dateGlobal, $prizesDone);
$rKey = array_rand($dateGlobal, 1);
if ($lotsDone < count($dateGlobal)) {
if (count($dateGlobal[$rKey]['lots']) > 0) {
return $this->generate($lotsGlobal, $dateGlobal, $lotsDone);
}
// * Insert next prize on a randowm day
$dateGlobal->get($rKey)->lots->push($lotsGlobal->get($prizesDone++));
// ? On a distribué assez de lots ?
if ($prizesDone < $lotsGlobal->count()) {
return $this->generateArray($lotsGlobal, $dateGlobal, $prizesDone);
}
// * Tri par heure et assignation du jour correct.
$dateGlobal->each(function (WinDayCalendar $date) {
$date->lots = $date->lots->sort(fn (WinTimeElement $a, WinTimeElement $b) =>
$a->time->timestamp - $b->time->timestamp)
->map(function (WinTimeElement $time) use ($date) {
$time->time->setDate(
$date->time->year,
$date->time->month,
$date->time->day
);
return $time;
});
});
array_push($dateGlobal[$rKey]['lots'], $lotsGlobal[$lotsDone++]);
if ($lotsDone < count($lotsGlobal)) {
return $this->generate($lotsGlobal, $dateGlobal, $lotsDone);
}
foreach ($dateGlobal as $k => $date) {
usort($dateGlobal[$k]['lots'], [$this, 'sortFunction']);
}
return $dateGlobal;
}
}
/**
* @property \App\Models\Prize $prize Le lot à gagner.
* @property \Carbon\Carbon $time Une heure aléatoire.
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
*/
class WinTimeElement extends \stdClass
{
// phpcs:enable
}
/**
* @property \Carbon\Carbon|\Carbon\CarbonInterface $time
* Un jour dans le temps.
* @property \Illuminate\Support\Collection<array-key,\App\Http\Controllers\Bo\WinTimeElement> $lots
* Liste des lots tombant ce jour.
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
*/
class WinDayCalendar extends \stdClass
{
// phpcs:enable
private function sortFunction($a, $b)
{
return strtotime($a["hour"]) - strtotime($b["hour"]);
}
}

View file

@ -1,88 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\Participation;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
class ParticipationController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Participation::class);
}
/**
* View all winners
*
* @return \Illuminate\Contracts\View\View
*/
public function viewWinnerList(): View
{
$this->authorize('viewWinnerList', Participation::class);
/** @var \Illuminate\Database\Eloquent\Builder $participationModels */
$participationModels = Participation::query()->with(['customer', 'code', 'instantWin', 'product'])->whereHas('instantWin');
/** Sort columns with a query */
$this->sortQuery($participationModels);
/** Custom pagination */
$participationModels = $this->paginate($participationModels);
return view('back::pages.winners-list.index', compact(
'participationModels'
));
}
/**
* Display participation form
*
* @param \App\Models\Participation $participation
* @return \Illuminate\Contracts\View\View
*/
public function setComment(Participation $participation): View
{
$this->authorize('setComment', $participation);
return view('back::pages.winners-list.set-comment', [
'participationModel' => $participation
]);
}
/**
* Set Comment
*
* @param \App\Models\Participation $participation
* @return \Illuminate\Http\RedirectResponse
*/
public function setCommentSubmit(Participation $participation): RedirectResponse
{
$this->authorize('setComment', $participation);
$participation->comment = request()->string('comment');
$participation->saveOrFail();
return back()->with('success', \trans(
'Le commentaire à bien été mis à jour'
));
}
/**
* Change prize sent
*
* @param \App\Models\Participation $participation
* @return \Illuminate\Http\RedirectResponse
*/
public function changePrizeSent(Participation $participation): RedirectResponse
{
$this->authorize('changePrizeSent', $participation);
$participation->prize_sent = true;
$participation->saveOrFail();
return back()->with('success', \trans(
'Le lot est bien marqué comme envoyé et une notification à été envoyé au gagant'
));
}
}

View file

@ -1,176 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Prizes\StorePrizeRequest;
use App\Http\Requests\Bo\Prizes\UpdatePrizeRequest;
use App\Models\Prize;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class PrizeController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Prize::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $prizeModels */
$prizeModels = Prize::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$prizeModels,
$search,
null,
'label',
);
}
$searchFields = \sprintf(
'%s ...',
Str::ucfirst(__('validation.custom.label'))
);
/** Sort columns with a query */
$this->sortQuery($prizeModels);
/** Custom pagination */
$prizeModels = $this->paginate($prizeModels);
return view('back::pages.prizes.index', compact('prizeModels', 'search', 'searchFields'));
}
/**
* Display the specified resource.
*
* @param \App\Models\Prize $prize
* @return \Illuminate\Contracts\View\View
*/
public function show(Prize $prize): \Illuminate\Contracts\View\View
{
return view('back::pages.prizes.show', ['prizeModel' => $prize]);
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Prize $prize
* @return \Illuminate\Contracts\View\View
*/
public function create(Prize $prize): \Illuminate\Contracts\View\View
{
return view('back::pages.prizes.create', [
'prizeModel' => $prize
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Prizes\StorePrizeRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StorePrizeRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$prize = new Prize();
$prize->fill($request->validated());
if ($prize->saveOrFail()) {
return redirect()
->route('bo.prizes.edit', $prize)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(__('models.classes.prize'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(__('models.classes.prize'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Prize $prize
* @return \Illuminate\Contracts\View\View
*/
public function edit(Prize $prize): \Illuminate\Contracts\View\View
{
return view('back::pages.prizes.edit', [
'prizeModel' => $prize
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Prizes\UpdatePrizeRequest $request
* @param \App\Models\Prize $prize
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdatePrizeRequest $request, Prize $prize): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $prize) {
$prize->fill($request->validated());
if ($prize->saveOrFail()) {
return redirect()
->route('bo.prizes.edit', $prize)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(__('models.classes.prize'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(__('models.classes.prize'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Prize $prize
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Prize $prize): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($prize) {
if ($prize->deleteOrFail()) {
return redirect()
->route('bo.prizes.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => Str::singular(__('models.classes.prize'))]
));
}
return redirect()
->back()
->with('error', __(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(__('models.classes.prize'))]
));
});
}
}

View file

@ -0,0 +1,106 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Models\GainView;
use App\Models\Prize;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class PrizesController extends Controller
{
public function index()
{
$prizes = Prize::all();
$gainViews = GainView::all();
return view('bo.prizes.index', compact('prizes', 'gainViews'));
}
public function saveDatas(Request $request)
{
$prizes = json_decode($request->prizes);
$pdfs = $request->file('pdf');
try {
$request->validate([
'pdf_winning_proof.*' => 'file|mimes:pdf|size:20480',
]);
for ($i = 0; $i < count($prizes); $i++) {
$prize = $prizes[$i];
if ($prize->id !== null) {
$p = Prize::findOrFail($prize->id);
$p->arcadia_id = $prize->arcadia_id;
$p->label_one = $prize->label_one;
$p->label_many = $prize->label_many;
$p->arg_title = $prize->arg_title;
$p->arg_subtitle = $prize->arg_subtitle;
$p->arg_content = $prize->arg_content;
$p->quantity = $prize->quantity;
$p->arcadia_operation_code = $prize->arcadia_operation_code;
$p->arcadia_support_code = $prize->arcadia_support_code;
$p->need_proof = $prize->need_proof;
$p->gain_view_id = $prize->gain_view_id;
if (isset($pdfs[$i])) {
$fileName = Str::slug($prize->label_one) . '-' .
date('d-m-Y') . '.' . $pdfs[$i]->extension();
$p->pdf_winning_proof = $fileName;
$pdfs[$i]->move(public_path('fichiers/pdf/'), $fileName);
$prizes[$i]->pdf_winning_proof = $fileName;
}
$p->save();
} else {
$p = new Prize();
$p->arcadia_id = $prize->arcadia_id;
$p->label_one = $prize->label_one;
$p->label_many = $prize->label_many;
$p->arg_title = $prize->arg_title;
$p->arg_subtitle = $prize->arg_subtitle;
$p->arg_content = $prize->arg_content;
$p->quantity = $prize->quantity;
$p->arcadia_operation_code = $prize->arcadia_operation_code;
$p->arcadia_support_code = $prize->arcadia_support_code;
$p->need_proof = $prize->need_proof;
$p->gain_view_id = $prize->gain_view_id;
if (isset($pdfs[$i])) {
$fileName = Str::slug($prize->label_one) . '-' .
date('d-m-Y') . '.' . $pdfs[$i]->extension();
$p->pdf_winning_proof = $fileName;
$pdfs[$i]->move(public_path('fichiers/pdf/'), $fileName);
$prizes[$i]->pdf_winning_proof = $fileName;
}
$p->save();
$prizes[$i]->id = $p->id;
} //end if
}//end for
} catch (Exception $e) {
}//end try
return $prizes;
}
public function destroy(Request $request)
{
$retour = "Suppression terminée !";
if ($request->id !== null) {
try {
$prize = Prize::findOrFail($request->id);
$prize->delete();
} catch (Exception $e) {
$retour = "Erreur lors de la suppression : " . $e->getMessage();
}
} else {
$retour = "Erreur lors de la suppression : Aucun ID envoyé.";
}
return $retour;
}
}

View file

@ -1,190 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Products\StoreProductRequest;
use App\Http\Requests\Bo\Products\UpdateProductRequest;
use App\Models\Product;
use App\Models\Range;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class ProductController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(Product::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $productModels */
$productModels = Product::query()->with('range');
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$productModels,
$search,
null,
'name',
'ean_code',
);
}
$searchFields = \sprintf(
'%s, %s ...',
Str::ucfirst(__('validation.attributes.name')),
__('validation.custom.ean_code'),
);
/** Sort columns with a query */
$this->sortQuery($productModels);
/** Custom pagination */
$productModels = $this->paginate($productModels);
return view('back::pages.products.index', compact('productModels', 'search', 'searchFields'));
}
/**
* Display the specified resource.
*
* @param \App\Models\Product $product
* @return \Illuminate\Contracts\View\View
*/
public function show(Product $product): \Illuminate\Contracts\View\View
{
return view('back::pages.products.show', ['productModel' => $product]);
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Product $product
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
public function create(Product $product): \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
{
$rangeModels = Range::all();
if (!count($rangeModels)) {
return \redirect()->route('bo.ranges.index')
->with(
'error',
'Vous devez ajouter une gamme avant de pouvoir ajouter un produit'
);
}
return view('back::pages.products.create', [
'productModel' => $product,
'rangeModels' => $rangeModels
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Products\StoreProductRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreProductRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$product = new Product();
$product->fill($request->validated());
if ($product->saveOrFail()) {
return redirect()
->route('bo.products.edit', $product)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(__('models.classes.product'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(__('models.classes.product'))]
));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Product $product
* @return \Illuminate\Contracts\View\View
*/
public function edit(Product $product): \Illuminate\Contracts\View\View
{
$rangeModels = Range::all();
return view('back::pages.products.edit', [
'productModel' => $product,
'rangeModels' => $rangeModels
]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Products\UpdateProductRequest $request
* @param \App\Models\Product $product
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateProductRequest $request, Product $product): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $product) {
$product->fill($request->validated());
if ($product->saveOrFail()) {
return redirect()
->route('bo.products.edit', $product)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(__('models.classes.product'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(__('models.classes.product'))]
));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Product $product
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Product $product): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($product) {
if ($product->deleteOrFail()) {
return redirect()
->route('bo.products.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => Str::singular(__('models.classes.product'))]
));
}
return redirect()
->back()
->with('error', __(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(__('models.classes.product'))]
));
});
}
}

View file

@ -0,0 +1,154 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreProductRequest;
use App\Http\Requests\UpdateProductRequest;
use App\Models\Product;
use App\Models\Range;
use Illuminate\Support\Str;
class ProductsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$products = Product::all();
return view('bo.products.index', compact('products'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
$ranges = Range::all();
if (!count($ranges)) {
return \redirect()->route('bo.ranges.index')
->with(
'error',
'Vous devez ajouter une gamme avant de pouvoir ajouter un produit'
);
}
return view('bo.products.create', compact('ranges'));
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\StoreProductRequest $request
* @return \Illuminate\Http\Response
*/
public function store(StoreProductRequest $request)
{
$name = $request->name;
$slug = Str::slug($name);
$no_art = $request->no_art;
$code_ean = $request->code_ean;
$picture = $request->picture;
$product = new Product();
$product->name = $name;
$product->no_art = $no_art;
$product->code_ean = $code_ean;
$product->range()->associate($request->range_id);
$product->save();
if ($picture !== null) {
$imageName = $product->id . '_' . $slug . '_' . Str::random(5) . '.' . $picture->extension();
$picture->move(public_path('images/produits'), $imageName);
$product->picture = $imageName;
$product->save();
}
return redirect()->route('bo.products.index');
}
/**
* Display the specified resource.
*
* @param integer $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
}
/**
* Show the form for editing the specified resource.
*
* @param integer $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$ranges = Range::all();
if (!count($ranges)) {
return \redirect()->route('bo.ranges.index')
->with(
'error',
'Vous devez ajouter une gamme avant de pouvoir ajouter un produit'
);
}
$product = Product::findOrFail($id);
return view('bo.products.edit', compact('product', 'ranges'));
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\UpdateProductRequest $request
* @param integer $id
* @return \Illuminate\Http\Response
*/
public function update(UpdateProductRequest $request, $id)
{
$name = $request->name;
$slug = Str::slug($name);
$no_art = $request->no_art;
$code_ean = $request->code_ean;
$picture = $request->picture;
$product = Product::findOrFail($id);
$product->range()->associate($request->range_id);
if ($picture !== null) {
if ($product->picture !== null && file_exists(public_path('images/produits/') . $product->picture)) {
unlink(public_path('images/produits/') . $product->picture);
}
$imageName = $product->id . '_' . $slug . '_' . Str::random(5) . '.' . $picture->extension();
$picture->move(public_path('images/produits'), $imageName);
}
$product->name = $name;
$product->no_art = $no_art;
$product->code_ean = $code_ean;
if ($picture !== null) {
$product->picture = $imageName;
}
$product->save();
return redirect()->route('bo.products.edit', $product->id)->with('success', 'Modifications enregistrés !');
}
/**
* Remove the specified resource from storage.
*
* @param integer $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
$product = Product::findOrFail($id);
$product->delete();
return redirect()->route('bo.products.index');
}
}

View file

@ -3,176 +3,135 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Ranges\StoreRangeRequest;
use App\Http\Requests\Bo\Ranges\UpdateRangeRequest;
use App\Http\Requests\StoreRangeRequest;
use App\Http\Requests\UpdateRangeRequest;
use App\Models\Range;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class RangeController extends Controller
{
/**
* Create the controller instance.
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function __construct()
public function index()
{
$this->authorizeResource(Range::class);
$ranges = Range::paginate();
return view('bo.ranges.index', compact('ranges'));
}
/**
* Display a listing of the resource.
* Show the form for creating a new resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
* @return \Illuminate\Http\Response
*/
public function index(Request $request): \Illuminate\Contracts\View\View
public function create()
{
/** @var \Illuminate\Database\Eloquent\Builder $rangeModels */
$rangeModels = Range::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$rangeModels,
$search,
null,
'name',
);
return view('bo.ranges.create');
}
$searchFields = Str::ucfirst(__('validation.attributes.name'));
/** Sort columns with a query */
$this->sortQuery($rangeModels);
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\StoreRangeRequest $request
* @return \Illuminate\Http\Response
*/
public function store(StoreRangeRequest $request)
{
$name = $request->name;
$slug = Str::slug($name);
$picture = $request->picture;
/** Custom pagination */
$rangeModels = $this->paginate($rangeModels);
$range = new Range();
$range->name = $name;
$range->save();
return view('back::pages.ranges.index', compact('rangeModels', 'search', 'searchFields'));
if ($picture !== null) {
$imageName = $range->id . '_' . $slug . '_' . Str::random(5) . '.' . $picture->extension();
$picture->move(public_path('images/ranges'), $imageName);
$range->picture = $imageName;
$range->save();
}
return \response()->redirectToRoute('bo.ranges.index')
->with('success', 'La gamme à bien été enregistré !');
}
/**
* Display the specified resource.
*
* @param \App\Models\Range $range
* @return \Illuminate\Contracts\View\View
* @return \Illuminate\Http\Response
*/
public function show(Range $range): \Illuminate\Contracts\View\View
public function show(Range $range)
{
return view('back::pages.ranges.show', ['rangeModel' => $range]);
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\Range $range
* @return \Illuminate\Contracts\View\View
*/
public function create(Range $range): \Illuminate\Contracts\View\View
{
return view('back::pages.ranges.create', [
'rangeModel' => $range,
]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Ranges\StoreRangeRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreRangeRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$range = new Range();
$range->fill($request->validated());
if ($range->saveOrFail()) {
return redirect()
->route('bo.ranges.edit', $range)
->with('success', trans(
'crud.messages.has_been_created',
['model' => Str::singular(__('models.classes.range'))]
));
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_created',
['model' => Str::singular(__('models.classes.range'))]
));
});
return view('bo.ranges.view', compact('range'));
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Range $range
* @return \Illuminate\Contracts\View\View
* @return \Illuminate\Http\Response
*/
public function edit(Range $range): \Illuminate\Contracts\View\View
public function edit(Range $range)
{
return view('back::pages.ranges.edit', [
'rangeModel' => $range
]);
return view('bo.ranges.edit', compact('range'));
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Ranges\UpdateRangeRequest $request
* @param \App\Http\Requests\UpdateRangeRequest $request
* @param \App\Models\Range $range
* @return \Illuminate\Http\RedirectResponse
* @return \Illuminate\Http\Response
*/
public function update(UpdateRangeRequest $request, Range $range): \Illuminate\Http\RedirectResponse
public function update(UpdateRangeRequest $request, Range $range)
{
return DB::transaction(function () use ($request, $range) {
$range->fill($request->validated());
if ($range->saveOrFail()) {
return redirect()
->route('bo.ranges.edit', $range)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(__('models.classes.range'))]
));
$name = $request->name;
$slug = Str::slug($name);
$picture = $request->picture;
if ($picture !== null) {
if ($range->picture !== null && file_exists(public_path('images/ranges/') . $range->picture)) {
unlink(public_path('images/ranges/') . $range->picture);
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(__('models.classes.range'))]
));
});
$imageName = $range->id . '_' . $slug . '_' . Str::random(5) . '.' . $picture->extension();
$picture->move(public_path('images/ranges'), $imageName);
}
$range->name = $name;
if ($picture !== null) {
$range->picture = $imageName;
}
$range->saveOrFail();
return \response()->redirectToRoute('bo.ranges.edit', $range)
->with('success', 'La gamme à bien été mise à jour !');
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Range $range
* @return \Illuminate\Http\RedirectResponse
* @return \Illuminate\Http\Response
*/
public function destroy(Range $range): \Illuminate\Http\RedirectResponse
public function destroy(Range $range)
{
if ($range->products()->count()) {
return back()->withError(
'Cette gamme est associé a des produits, la supression n\'est pas possible'
);
}
return DB::transaction(function () use ($range) {
if ($range->deleteOrFail()) {
return redirect()
->route('bo.ranges.index')
->with('success', __(
'crud.messages.has_been_deleted',
['model' => Str::singular(__('models.classes.range'))]
));
if (!$range->delete()) {
return back()->withError(
'Erreur lors de la suppression de la gamme'
);
}
return redirect()
->back()
->with('error', __(
':crud.messages.cannot_be_deleted',
['model' => Str::singular(__('models.classes.range'))]
));
});
return \response()->redirectToRoute('bo.ranges.index')
->with('warning', 'La gamme à bien été supprimée !');
}
}

View file

@ -1,269 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Mail\Won\DiscountWonMail;
use App\Mail\Won\PrizeIsSentMail;
use App\Mail\Won\PrizeWonMail;
use App\Mail\Won\WinningProofSubmitedMail;
use App\Models\Prize;
use App\Models\Settings;
use App\Lib\Discount;
use App\Models\Participation;
use Illuminate\Contracts\View\View;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Support\Arr;
class Re7Controller extends Controller
{
/**
* Re7Controller
*
* @return void
*/
public function __construct()
{
$this->middleware(function (Request $request, \Closure $next) {
$this->authorize('fo.showRe7');
return $next($request);
});
}
/**
* Show Home page
*
* @return \Illuminate\Contracts\View\View
*/
public function home(): View
{
return view('theme::pages.home');
}
/**
* Show Teaser page
*
* @return \Illuminate\Contracts\View\View
*/
public function teaser(): View
{
return view('theme::pages.teaser');
}
/**
* Show Teaser page
*
* @return \Illuminate\Contracts\View\View
*/
public function endGame(): View
{
return view('theme::pages.end-game');
}
/**
* Show code input page
*
* @return \Illuminate\Contracts\View\View
*/
public function participate(): View
{
return view('theme::pages.participation.participate');
}
/**
* Show code input page
*
* @return \Illuminate\Contracts\View\View
*/
public function participationExhausted(): View
{
return view('theme::pages.participation.participation-exhausted');
}
// * -- Participation
/**
* Show prize page
*
* @param \App\Models\Prize $prize
* @return \Illuminate\Contracts\View\View
*/
public function prize(Prize $prize): View
{
// * Fake participation model
$participationModel = new Participation();
$participationModel = 9999999;
return view('theme::pages.participation.won', [
'prizeModel' => $prize,
'participationModel' => $participationModel
]);
}
/**
* Show discount page
*
* @return \Illuminate\Contracts\View\View
*/
public function discount(): View
{
/** @var \App\Models\Settings */
$settings = app(Settings::class);
/** @var \App\Lib\Discount */
$discount = Arr::get(
$settings->web_coupons,
$this->getRandomWeightedElementIndex($settings->web_coupons)
);
if (!$settings->discounts_activated) {
return abort(404);
}
$mesBrDiscount = new Discount();
return view('theme::pages.participation.won', compact('discount', 'mesBrDiscount'));
}
/**
* Show loose page
*
* @return \Illuminate\Contracts\View\View
*/
public function loose(): View
{
return view('theme::pages.participation.loose');
}
// * -- END Participation
/**
* View won prize mail
*
* @param \App\Models\Prize $prize
* @return \Illuminate\Contracts\View\View
*/
public function mailPrize(Prize $prize): View
{
return view('back::pages.re7-preview-mail', [
'render_url' => route('re7.mail-print', [
'type' => 'prize',
'prize' => $prize
])
]);
}
/**
* View won discount mail
*
* @return \Illuminate\Contracts\View\View
*/
public function mailDiscount(): View
{
/** @var \App\Models\Settings */
$settings = app(Settings::class);
if (!$settings->discounts_activated) {
return abort(404);
}
return view('back::pages.re7-preview-mail', [
'render_url' => route('re7.mail-print', [
'type' => 'discount'
])
]);
}
/**
* View proof mail received mail
*
* @return \Illuminate\Contracts\View\View
*/
public function mailProofReceived(): View
{
return view('back::pages.re7-preview-mail', [
'render_url' => route('re7.mail-print', [
'type' => 'proof'
])
]);
}
/**
* View sent prize mail
*
* @return \Illuminate\Contracts\View\View
*/
public function mailPrizeSent(): View
{
return view('back::pages.re7-preview-mail', [
'render_url' => route('re7.mail-print', [
'type' => 'prize-sent'
])
]);
}
/**
* Print a specific mail
*
* @param string $type
* @param \App\Models\Prize|null $prize
* @return \Illuminate\Http\Response
*/
public function mailPrint(string $type, Prize|null $prize = null): Response
{
/** @var \App\Models\User */
$user = auth('backend')->user();
/** @var \App\Models\Settings */
$settings = app(Settings::class);
switch ($type) {
case 'discount':
/** @var \App\Lib\Discount */
$discount = Arr::get(
$settings->web_coupons,
$this->getRandomWeightedElementIndex($settings->web_coupons)
);
return response((new DiscountWonMail(
new Address(
$user->email,
$user->first_name
),
$settings->name,
$discount,
config('app.url'),
$settings->company,
))->render());
case 'prize':
return response((new PrizeWonMail(
new Address(
$user->email,
$user->first_name
),
$settings->name,
$prize,
config('app.url'),
$settings->company,
))->render());
case 'prize-sent':
return response((new PrizeIsSentMail(
new Address(
$user->email,
$user->first_name
),
$settings->name,
$settings->company,
))->render());
case 'proof':
return response((new WinningProofSubmitedMail(
new Address(
$user->email,
$user->first_name
),
$settings->name,
$settings->company,
))->render());
default:
return response('', 404);
} //end switch
}
}

View file

@ -3,101 +3,89 @@
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Settings\UpdateSettingsRequest;
use App\Lib\Discount;
use App\Lib\Helpers\FileStorageHelper;
use App\Models\Settings;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
class SettingsController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
public function manage(Request $request)
{
$this->authorizeResource(Settings::class);
/** @var \App\Models\Settings $settings */
$settings = app(Settings::class);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $request->name;
$startDate = $request->start_date;
$endDate = $request->end_date;
$nbParticipationPlayer = $request->nb_participation_player;
$nbParticipationIp = $request->nb_participation_ip;
$nbUniqueCodeUse = $request->nb_unique_code_use;
$useEanCodes = $request->use_ean_codes === null ? 0 : 1;
$activatedTeaser = $request->activated_teaser === null ? 0 : 1;
$teaserEndActivity = $request->teaser_end_activity;
$activatedClosePage = $request->activated_close_page === null ? 0 : 1;
$closePageActiveDate = $request->close_page_active_date;
$redirectClose = $request->redirect_close;
$reductionsActivated = $request->reductions_activated === null ? 0 : 1;
$reductionsSite = $request->reductions_site;
$reductionsCampaign = $request->reductions_campaign;
$webCoupons = $request->web_coupons;
$facebookActivated = $request->facebook_activated === null ? 0 : 1;
$facebookAppId = $request->facebook_app_id;
$facebookSecret = $request->facebook_secret;
$notificationEmails = $request->notification_emails;
$winningProof = $request->winning_proof === null ? 0 : 1;
$company = $request->company;
$analytics = $request->analytics;
// Check du lien de redirection après fermeture.
if (strpos($redirectClose, 'https://') === false && strpos($redirectClose, 'http://') === false) {
$redirectClose = 'https://' . $redirectClose;
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Settings $settings
* @return \Illuminate\Contracts\View\View
*/
public function edit(Settings $settings): \Illuminate\Contracts\View\View
{
return view('back::pages.settings.edit', [
'settingsModel' => $settings
]);
$settings->name = $name;
$settings->start_date = $startDate;
$settings->end_date = $endDate;
$settings->nb_participation_player = $nbParticipationPlayer;
$settings->nb_participation_ip = $nbParticipationIp;
$settings->nb_unique_code_use = $nbUniqueCodeUse;
$settings->use_ean_codes = $useEanCodes;
$settings->activated_teaser = $activatedTeaser;
if ($activatedTeaser === 1) {
$settings->teaser_end_activity = Carbon::parse($teaserEndActivity);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Settings\UpdateSettingsRequest $request
* @param \App\Models\Settings $settings
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateSettingsRequest $request, Settings $settings): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $settings) {
$data = $request->validated();
// * Assign parsed Web coupon objects
Arr::set($data, 'web_coupons', collect(Arr::get($data, 'web_coupons'))->filter()
->map(fn (array $coupon) => $this->parseWebCoupon($coupon))
->filter()->all());
$settings->fill($data);
if ($settings->saveOrFail()) {
return redirect()
->route('bo.settings.edit', $settings)
->with('success', trans(
'crud.messages.has_been_updated',
['model' => Str::singular(__('models.classes.settings'))]
));
$settings->activated_close_page = $activatedClosePage;
if ($activatedClosePage === 1) {
$settings->close_page_active_date = Carbon::parse($closePageActiveDate);
}
return redirect()
->back()
->with('error', trans(
'crud.messages.cannot_be_updated',
['model' => Str::singular(__('models.classes.settings'))]
));
});
$settings->redirect_close = $redirectClose;
$settings->reductions_activated = $reductionsActivated;
if ($reductionsActivated === 1) {
$settings->reductions_site = $reductionsSite;
$settings->reductions_campaign = $reductionsCampaign;
$settings->web_coupons = $webCoupons;
}
$settings->facebook_activated = $facebookActivated;
$settings->facebook_app_id = $facebookAppId;
$settings->facebook_secret = $facebookSecret;
$settings->notification_emails = $notificationEmails;
$settings->winning_proof = $winningProof;
$settings->company = $company;
$settings->analytics = $analytics;
$settings->save();
/**
* Try to parse webCoupon
*
* @param array<string,string> $coupon
* @return \App\Lib\Discount|null
*/
private function parseWebCoupon(array $coupon): Discount | null
{
/** @var \Illuminate\Http\UploadedFile|string */
$picture = Arr::get($coupon, 'picture');
if (is_object($picture) and ($picture instanceof \Illuminate\Http\UploadedFile)) {
$picture = FileStorageHelper::storeFile(
new Settings(),
$picture,
true,
'web-coupon.' . $picture->extension()
);
}
try {
return Discount::make(
$picture,
Arr::get($coupon, 'valid_on'),
Arr::get($coupon, 'face_value'),
Arr::get($coupon, 'percentage'),
Arr::get($coupon, 'web_coupon_identifiant'),
);
} catch (\RuntimeException | \TypeError) {
return null;
}
$settingsGlobal = app(Settings::class)
->select('name', 'company', 'analytics', 'start_date', 'end_date')->first();
Cache::put('settingsGlobal', $settingsGlobal);
$success = "Modifications enregistrés !";
return view('bo.settings.manage', compact('settings', 'success'));
}//end if
return view('bo.settings.manage', compact('settings'));
}
}

View file

@ -1,91 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\StaticPages\UpdateStaticPageRequest;
use App\Models\StaticPage;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class StaticPageController extends Controller
{
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(StaticPage::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $query */
$query = StaticPage::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$query,
$search,
null,
'title',
);
}
$searchFields = \implode(', ', [
trans('validation.attributes.title'),
]);
/** Sort columns with a query */
$this->sortQuery($query);
/** Custom pagination */
$staticPageModelList = $this->paginate($query);
return view('back::pages.static_pages.index', compact('staticPageModelList', 'search', 'searchFields'));
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\StaticPage $static_page
* @return \Illuminate\Contracts\View\View
*/
public function edit(StaticPage $static_page): \Illuminate\Contracts\View\View
{
return view('back::pages.static_pages.edit', ['staticPageModel' => $static_page]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\StaticPages\UpdateStaticPageRequest $request
* @param \App\Models\StaticPage $static_page
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateStaticPageRequest $request, StaticPage $static_page): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $static_page) {
$static_page->fill($request->validated());
if ($static_page->saveOrFail()) {
return redirect()->route('bo.static_pages.edit', $static_page)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(\trans_choice('models.classes.static_page', 1))
]));
}
return redirect()->route('bo.static_pages.edit', $static_page)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(\trans_choice('models.classes.static_page', 1))
]));
});
}
}

View file

@ -1,169 +0,0 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Bo\Users\StoreUserRequest;
use App\Http\Requests\Bo\Users\UpdateUserRequest;
use App\Models\User;
use App\Traits\Controllers\UpdateModelPublished;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class UserController extends Controller
{
use UpdateModelPublished;
/**
* Create the controller instance.
*/
public function __construct()
{
$this->authorizeResource(User::class);
}
/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function index(Request $request): \Illuminate\Contracts\View\View
{
/** @var \Illuminate\Database\Eloquent\Builder $userModels */
$userModels = User::query();
/** @var string $search Search field */
$search = $request->search;
if ($search) {
$this->searchQuery(
$userModels,
$search,
null,
'first_name',
'last_name',
'email',
'role',
);
}
$searchFields = \implode(', ', [
trans('validation.attributes.first_name'),
trans('validation.attributes.last_name'),
trans('validation.attributes.email'),
trans('validation.attributes.role'),
]);
/** Sort columns with a query */
$this->sortQuery($userModels);
/** Custom pagination */
$userModels = $this->paginate($userModels);
return view('back::pages.users.index', compact('userModels', 'search', 'searchFields'));
}
/**
* Show the form for creating a new resource.
*
* @param \App\Models\User $user
* @return \Illuminate\Contracts\View\View
*/
public function create(User $user): \Illuminate\Contracts\View\View
{
return view('back::pages.users.create', ['userModel' => $user]);
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\Bo\Users\StoreUserRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreUserRequest $request): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request) {
$user = new User();
$user->fill($request->validated());
if ($user->saveOrFail()) {
return redirect()->route('bo.users.edit', $user)
->with('success', __('crud.messages.has_been_created', [
'model' => Str::ucfirst(__('models.classes.user'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_created', [
'model' => Str::ucfirst(__('models.classes.user'))
]));
});
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\User $user
* @return \Illuminate\Contracts\View\View
*/
public function edit(User $user): \Illuminate\Contracts\View\View
{
return view('back::pages.users.edit', ['userModel' => $user]);
}
/**
* Update the specified resource in storage.
*
* @param \App\Http\Requests\Bo\Users\UpdateUserRequest $request
* @param \App\Models\User $user
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateUserRequest $request, User $user): \Illuminate\Http\RedirectResponse
{
return DB::transaction(function () use ($request, $user) {
$user->fill($request->validated());
if ($user->saveOrFail()) {
return redirect()->route('bo.users.edit', $user)
->with('success', __('crud.messages.has_been_updated', [
'model' => Str::ucfirst(__('models.classes.user'))
]));
}
return redirect()->route('bo.users.edit', $user)
->with('error', __('crud.messages.cannot_be_updated', [
'model' => Str::ucfirst(__('models.classes.user'))
]));
});
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\User $user
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(User $user): \Illuminate\Http\RedirectResponse
{
if ($user->deleteOrFail()) {
return redirect()->route('bo.users.index')
->with('success', __('crud.messages.has_been_deleted', [
'model' => Str::ucfirst(__('models.classes.user'))
]));
}
return redirect()->back()
->with('error', __('crud.messages.cannot_be_deleted', [
'model' => Str::ucfirst(__('models.classes.user'))
]));
}
/**
* Duplicate the specified resource.
*
* @param \App\Models\User $user
* @return \Illuminate\Contracts\View\View
*/
public function duplicate(User $user): \Illuminate\Contracts\View\View
{
return $this->create($user->replicate());
}
}

View file

@ -0,0 +1,117 @@
<?php
namespace App\Http\Controllers\Bo;
use App\Http\Controllers\Controller;
use App\Mail\CourrierArcadiaError;
use App\Models\Participation;
use App\Models\Settings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
class WinnersListController extends Controller
{
private $apiCrm;
public function __construct()
{
$this->apiCrm = new \LDCCRM\ApiV1(config('crm.endpoint'), config('crm.token'));
}
public function index()
{
$winnersList = Participation::has('instantWin')->get();
$settings = Settings::select('use_ean_codes', 'winning_proof')->first();
return view('bo.winners-list.index', compact('winnersList', 'settings'));
}
public function courrierArcadia($id)
{
$participation = Participation::findOrFail($id);
$crmUser = $this->apiCrm->getCustomer($participation->user->crm_id);
if ($crmUser->status === 'NOK') {
return back()->withErrors("Erreur lors de la récupération de l'utilisateur dans la CRM : Code : " .
$crmUser->code . " Message : " . $crmUser->message);
}
$crmId = $participation->user->crm_id;
$crmUser = $crmUser->user;
$corps = '<arcadia>' . "\n";
$corps .= '<Commande> ' . "\n";
$corps .= "\t" . '<Num_Commande></Num_Commande>' . "\n";
$corps .= "\t" . '<Date_Commande>' . date('d/m/Y') . '</Date_Commande>' . "\n";
$corps .= "\t" . '<Operation></Operation> ' . "\n";
$corps .= "\t" . '<Civilite></Civilite>' . "\n";
$corps .= "\t" . '<Nom><![CDATA[' . trim($crmUser->firstname) . ']]></Nom>' . "\n";
$corps .= "\t" . '<Prenom><![CDATA[' . trim($crmUser->lastname) . ']]></Prenom>' . "\n";
$corps .= "\t" . '<Adresse><![CDATA[' . trim($crmUser->address) . ']]></Adresse>' . "\n";
$corps .= "\t" . '<Adresse_Complementaire><![CDATA[' . trim($crmUser->address2) . ']]></Adresse_Complementaire>' . "\n";
$corps .= "\t" . '<CP><![CDATA[' . trim($crmUser->postcode) . ']]></CP>' . "\n";
$corps .= "\t" . '<Ville><![CDATA[' . trim($crmUser->city) . ']]></Ville>' . "\n";
$corps .= '<Ligne_de_Commande>' . "\n";
$corps .= "\t" . '<Code_Support></Code_Support> ' . "\n";
$corps .= "\t" . '<Libelle_Type_Support></Libelle_Type_Support> ' . "\n";
$corps .= "\t" . '<Quantite>1</Quantite>' . "\n";
$corps .= "\t" . '<Poids_Unitaire_Colis></Poids_Unitaire_Colis>' . "\n";
$corps .= '</Ligne_de_Commande>' . "\n";
$corps .= '</Commande> ' . "\n";
$corps .= '</arcadia>';
return view('bo.winners-list.arcadia', compact('participation', 'corps', 'crmId'));
}
public function createCourrierArcadia(Request $request, $id)
{
$participation = Participation::findOrFail($id);
$instantWin = $participation->instantWin;
if ($instantWin->prize->arcadia_operation_code !== 0 && $instantWin->prize->arcadia_support_code !== 0) {
$fields = [
'root' => [
[
'fieldName' => 'order_date',
'fieldValue' => date('d/m/Y')
],
[
'fieldName' => 'operation',
'fieldValue' => $instantWin->prize->arcadia_operation_code
]
],
'orderLine' => [
[
'fieldName' => 'code_unique',
'fieldValue' => $participation->code->code_unique
],
[
'fieldName' => 'support_code',
'fieldValue' => $instantWin->prize->arcadia_support_code
],
[
'fieldName' => 'label_type_support',
'fieldValue' => 'Gain du lot : ' . $instantWin->prize->label_one
]
]
];
/** @var \App\Models\Settings $settings */
$settings = app(Settings::class);
if ($settings->use_ean_codes === 1) {
$fields['orderLine'][] = [
'fieldName' => 'code_on_pack',
'fieldValue' => $participation->codeEan->code
];
}
$arcadiaMail = $this->apiCrm->ArcadiaOutgoingMail($participation->user->crm_id, $fields, 'game');
if ($arcadiaMail->status === 'NOK') {
Mail::to(config('mail.MAIL_ADMIN'))->send(new CourrierArcadiaError($participation->user));
return back()->withErrors("Erreur lors de l'envoi du courrier Arcadia. Code : " .
$arcadiaMail->code . " Message : " . $arcadiaMail->message);
}
}//end if
return back()->with('success', 'Courrier envoyé !');
}
}

View file

@ -2,267 +2,14 @@
namespace App\Http\Controllers;
use App\Enums\Pagination\ItemsPerPaginationEnum;
use App\Enums\Theme\BootstrapThemeEnum;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Str;
class Controller extends BaseController
{
use AuthorizesRequests;
use DispatchesJobs;
use ValidatesRequests;
/**
* Utility function for getting random values with weighting.
* Pass in an associative array, such as array('A'=>5, 'B'=>45, 'C'=>50)
* An array like this means that "A" has a 5% chance of being selected, "B" 45%, and "C" 50%.
* The return value is the array key, A, B, or C in this case. Note that the values assigned
* do not have to be percentages. The values are simply relative to each other. If one value
* weight was 2, and the other weight of 1, the value with the weight of 2 has about a 66%
* chance of being selected. Also note that weights should be integers.
*
* @param array<\App\Lib\Discount> $weightedValues
* @return integer The winning key
* @url https://stackoverflow.com/a/11872928/4355295
*/
protected function getRandomWeightedElementIndex(array $weightedValues): int
{
mt_srand(time());
$rand = mt_rand(1, max((int) collect($weightedValues)->sum('percentage'), 1));
foreach ($weightedValues as $key => $value) {
$rand -= $value->percentage;
if ($rand <= 0) {
return $key;
}
}
return $rand;
}
/**
* Gives the redirection path for FO Auth controllers
*
* @return string
*/
protected function authLoggedRedirectPath(): string
{
return response()->redirectToRoute('fo.homepage')->getTargetUrl();
}
/**
* 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
): \Illuminate\Database\Eloquent\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
): \Illuminate\Database\Eloquent\Builder {
$table = $query->getModel()->getTable();
foreach ($fields as $field) {
$field = str_replace('?', '\?', $field);
if (is_array($field)) {
$query->orWhereRaw(
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($field)->map(function ($q) use ($table) {
return "`$table`.`$q`";
})->implode(', \' \', ')),
['%' . htmlspecialchars($search) . '%']
);
return $query;
}
// Get models woth enum's label.
if (is_array($this->getSearchValue($query, $search, $field))) {
foreach ($this->getSearchValue($query, $search, $field) as $array) {
$query->orWhereRaw(
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
['%' . htmlspecialchars($array->value) . '%']
);
}
return $query;
}
// Get models with relation's name/label.
if (Str::endsWith($field, '_id')) {
$query->orWhereHas(Str::remove('_id', $field), function ($queryRelation) use ($field, $search) {
if (Schema::hasColumn(Str::remove('_id', $field) . 's', 'name')) {
$queryRelation->where('name', 'like', '%' . $search . '%');
} elseif (Schema::hasColumn(Str::remove('_id', $field) . 's', 'label')) {
$queryRelation->where('label', 'like', '%' . $search . '%');
}
});
return $query;
}
$query->orWhereRaw(
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
['%' . htmlspecialchars($this->getSearchValue($query, $search, $field)) . '%']
);
} //end foreach
return $query;
}
/**
* Get the search value (on string or Enum).
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $search
* @param string $field
* @return string|array
*/
protected function getSearchValue(Builder $query, string $search, string $field): string|array
{
$cast = $query->getModel()->getCasts()[$field] ?? null;
if (
count($query->getModel()->getCasts()) and // Check if the model has casts.
$cast and // Check if there is cast about specific field.
enum_exists($cast) // Check if the cast is an enum.
) {
// @phpstan-ignore-next-line
$cases = collect($cast::toArray());
$enum = $cases->filter(function ($item) use ($search) {
return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label));
});
return $enum->toArray();
} else {
return $search;
}
}
/**
* 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 = []): \Illuminate\Database\Eloquent\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 (!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');
} elseif (Schema::hasColumn($table, 'updated_at')) {
$query = $query->orderBy('updated_at', 'DESC');
Session::put("$rName.sort_col", 'updated_at');
Session::put("$rName.sort_way", 'desc');
} elseif (Schema::hasColumn($table, 'created_at')) {
$query = $query->orderBy('created_at', 'DESC');
Session::put("$rName.sort_col", 'created_at');
Session::put("$rName.sort_way", 'desc');
}
return $query;
}
/**
* Customize pagination with cache or config (default).
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \App\Enums\Pagination\ItemsPerPaginationEnum|null $pagination
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
protected function paginate(
Builder $query,
ItemsPerPaginationEnum $pagination = null
): \Illuminate\Contracts\Pagination\LengthAwarePaginator {
$currentRoutePath = Str::slug(request()->route()->getName());
$cacheKey = "pagination.{$currentRoutePath}";
$pagination = $pagination ?? ItemsPerPaginationEnum::twelve;
$pagination = ToolboxHelper::getValidatedEnum(
Cache::get($cacheKey, $pagination->value()),
'pagination',
'\App\Enums\Pagination\ItemsPerPaginationEnum',
);
if (Cache::get($cacheKey) !== $pagination) {
Cache::put($cacheKey, $pagination);
}
$query = $query->paginate($pagination);
return $query;
}
/**
* Set the bootstrap theme or light (default).
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
protected function setTheme(Request $request): \Illuminate\Http\RedirectResponse
{
$theme = ToolboxHelper::getValidatedEnum(
$request->theme ?: Cache::get('theme', BootstrapThemeEnum::light->value()),
'theme',
'\App\Http\Controllers\BootstrapThemeEnum',
);
if (Cache::get("theme") !== $theme) {
Cache::put("theme", $theme);
}
return redirect()->back()->with('success', __('crud.messages.theme_updated'));
}
}

View file

@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers;
use App\Models\Settings;
class EndPageController extends Controller
{
/**
* index
* @return \Illuminate\View\View|Illuminate\Http\RedirectResponse
*/
public function index()
{
$settings = app(Settings::class)
->select('start_date', 'end_date', 'activated_close_page', 'close_page_active_date', 'redirect_close')
->first();
if (
$settings->end_date < now() &&
$settings->activated_close_page === 1 &&
$settings->close_page_active_date > now()
) {
return view('front.basic.end', compact('settings'));
}
return redirect()->route('home');
}
}

View file

@ -0,0 +1,291 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ParticipateRequest;
use App\Mail\CourrierArcadiaError;
use App\Mail\NotifAdmin;
use App\Mail\NotifWinAdmin;
use App\Mail\PrizeWon;
use App\Mail\ReductionWon;
use App\Models\BannedIp;
use App\Models\InstantWin;
use App\Models\Participation;
use App\Models\Reduction;
use LDCWeb\MesBR;
use App\Models\Settings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
class EnterCodeController extends Controller
{
/**
*
* @var \LDCCRM\ApiV1
*/
private $apiCrm;
/**
* EnterCodeController
*/
public function __construct()
{
$this->apiCrm = new \LDCCRM\ApiV1(config('crm.endpoint'), config('crm.token'));
}
/**
* Show enter code form
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function index()
{
$nbParticipations = Participation::where('user_id', Auth::user()->id)->count();
$settings = app(Settings::class)->select('use_ean_codes', 'nb_participation_player')->first();
if ($nbParticipations >= $settings->nb_participation_player) {
return view('front.basic.participation-exhausted', compact('settings'));
}
return view('front.basic.enter-code', compact('settings'));
}
/**
* Participate Method
*
* @param ParticipateRequest $request
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function participate(ParticipateRequest $request)
{
// Récupération des données à utilisées.
/** @var \App\Models\Settings $settings */
$settings = app(Settings::class);
// * Cas IP bannie.
$ipBanned = BannedIp::where('ip', app('clientIp'))->first() === null ? 0 : 1;
if ($ipBanned) {
return view('front.basic.participation-exhausted', compact('settings'));
}
// * Cas nombre de participation maximale atteint.
$nbParticipations = Participation::where('user_id', auth()->user()->id)->count();
if ($nbParticipations >= $settings->nb_participation_player) {
return view('front.basic.participation-exhausted', compact('settings'));
}
// * Tous les cas "bloquants" sont passé, l'utilisateur participe à partir d'ici.
$participation = new Participation();
$participation->user_id = auth()->user()->id;
$participation->code_unique_id = $request->code->id;
$participation->code_ean_id = $request->code_ean ? $request->code_ean->id : null;
$participation->ip = app('clientIp');
$participation->save();
// * Gestion des instants gagnants.
$userAlreadyWon = Participation::has('instantWin')
->whereHas('user', function ($q) {
$q->whereId(auth()->user()->id);
})->first();
// * Si l'utilisateur actuel à déjà gagné un gros lot, pas d'instant gagnant.
if ($userAlreadyWon) {
return $this->serveCouponWin($settings, $participation);
}
$instantWin = InstantWin::where([['appear_date', '<', now()], ['won', 0]])
->orderBy('appear_date', 'ASC')->first();
if ($instantWin) {
// Ici si fail car unique dupliqué catch.
try {
// Gain d'un gros lot.
return $this->instantWin($settings, $request, $participation, $instantWin);
} catch (\ErrorException $e) {
// Unbind instant gagnant.
$participation->instantWin()->delete();
// phpcs:ignore
// TODO: si erreur il faut envoyer un mail à equipe.web@ldc.fr.
} //end try
}
return $this->serveCouponWin($settings, $participation);
}
/**
* Handle instant wins
*
* @param Settings $settings
* @param Request $request
* @param Participation $participation
* @param InstantWin|null $instantWin
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
private function instantWin(Settings $settings, Request $request, Participation &$participation, $instantWin)
{
$instantWin->won = true;
// Should save now to prevent next player win on the same winning moment.
$instantWin->save();
$participation->instantWin()->save($instantWin);
// Envoi du courrier Arcadia.
if (
$instantWin->prize->arcadia_operation_code !== 0 &&
$instantWin->prize->arcadia_support_code !== 0
) {
$crmId = auth()->user()->crm_id;
$fields = [
'root' => [
[
'fieldName' => 'order_date',
'fieldValue' => date('d/m/Y')
],
[
'fieldName' => 'operation',
'fieldValue' => $instantWin->prize->arcadia_operation_code
]
],
'orderLine' => [
[
'fieldName' => 'code_unique',
'fieldValue' => $request->serial
],
[
'fieldName' => 'support_code',
'fieldValue' => $instantWin->prize->arcadia_support_code
],
[
'fieldName' => 'label_type_support',
'fieldValue' => 'Gain du lot : ' . $instantWin->prize->label_one
]
]
];
if ($settings->use_ean_codes === 1) {
$codeEan = $request->code_ean;
$fields['orderLine'][] = [
'fieldName' => 'code_on_pack',
'fieldValue' => "$codeEan->code"
];
}
$arcadiaMail = $this->apiCrm->ArcadiaOutgoingMail($crmId, $fields, 'game');
if ($arcadiaMail->status === 'KO') {
Mail::to(config('mail.MAIL_ADMIN'))->send(new CourrierArcadiaError(auth()->user()));
}
} //end if
Mail::to(auth()->user()->email)->send(new PrizeWon(auth()->user(), $instantWin->prize, $settings));
$mails = json_decode($settings->notification_emails);
foreach ($mails as $mail) {
Mail::to($mail->email)->send(new NotifWinAdmin($settings, $participation));
}
$participation->save();
return view("front.basic." . $instantWin->prize->gain_view->file_name, compact('settings'))
->with('prize', $instantWin->prize);
}
/**
* Détermine si un BR doit être servi
* renvoi la vue de gain BR ou la vue "Perdu"
*
* @param Settings $settings
* @param Participation $participation
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
private function serveCouponWin(Settings $settings, Participation $participation)
{
// Si le jeu est 100% gagnant.
if ($settings->reductions_activated === 1) {
$coupon = $this->getRandomCoupon($settings);
$crmCoupon = $this->updateCoupon($settings, $coupon->web_coupon_identifiant, $participation);
if (!$crmCoupon) {
$participation->delete();
return back()->withErrors("Une erreur est survenue, merci de réessayez ultérieurement.");
}
Mail::to(Auth::user()->email)->send(new ReductionWon(Auth::user(), $coupon, $settings, $crmCoupon));
return view('front.basic.reduction', compact('crmCoupon', 'coupon'));
} else {
return view('front.basic.loose');
}
}
/**
* Get a random coupon
*
* @param Settings $settings
* @return mixed
*/
private function getRandomCoupon(Settings $settings)
{
$webCoupons = json_decode($settings->web_coupons);
if (count($webCoupons) > 1) {
$lots = [];
foreach ($webCoupons as $webCoupon) {
$lots[] = $webCoupon;
}
foreach ($lots as $lot) {
for ($i = 0; $i < $lot->percentage; $i++) {
$tmp[] = $lot;
}
}
shuffle($tmp);
return $tmp[0];
} else {
return $webCoupons[0];
}
}
/**
* Update a coupon
*
* @param Settings $settings
* @param mixed $coupon
* @param Participation $participation
* @return \App\Models\Reduction|null
*/
private function updateCoupon(Settings $settings, $coupon, Participation $participation)
{
$reduction = null;
$mesBR = new MesBR(config('mesbr.endpoint'), $settings->reductions_site, $settings->reductions_campaign);
$crmUser = $this->apiCrm->getCustomer(Auth::user()->crm_id);
if ($crmUser->status === 'OK') {
$mesBR->updateContact($crmUser->user);
$result = $mesBR->updatePanier($crmUser->user, $coupon);
if ($result["status"] === "OK") {
$reduction = new Reduction();
$reduction->link = $result["link"];
$reduction->verification = $result["verif"];
$reduction->basket_id = $result["basketId"];
$reduction->save();
$participation->reduction_id = $reduction->id;
$participation->save();
} else {
Mail::to(config('mail.MAIL_ADMIN'))
->send(new NotifAdmin(\sprintf(
'MESBR : Une erreur est survenue. Code : %s Message : %s',
$result["code"],
$result["message"]
)));
}
} //end if
return $reduction;
}
/**
* Undocumented function
*
* @return \Illuminate\Http\Response
*/
public function formWinningProof()
{
$participation = Participation::where([
['user_id', Auth::user()->id],
['sticker', null],
['ticket', null],
['barcode', null]
])->has('instantWin')->first();
if ($participation) {
return view('front.basic.winning-proof', compact('participation'));
}
return redirect()->route('home');
}
}

View file

@ -0,0 +1,23 @@
<?php
namespace App\Http\Controllers;
use App\Models\FaqQuestion;
use App\Models\FaqTheme;
class FAQController extends Controller
{
/**
* index
* @return \Illuminate\View\View
*/
public function index()
{
$questions = FaqQuestion::all();
$themes = FaqTheme::all();
if (count($questions) === 0 && count($themes) === 0) {
return redirect()->route('home');
}
return view('front.basic.faq', compact('questions', 'themes'));
}
}

View file

@ -1,46 +0,0 @@
<?php
namespace App\Http\Controllers\Fo\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ConfirmsPasswords;
use Illuminate\Support\Facades\Auth;
class ConfirmPasswordController extends Controller
{
use ConfirmsPasswords;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:frontend');
}
/**
* Display the password confirmation view.
*
* @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
*/
public function showConfirmForm(): \Illuminate\View\View|\Illuminate\Http\RedirectResponse
{
if (Auth::guard('frontend')->check()) {
return \response()->redirectToRoute('home');
}
return view('theme::auth.passwords.confirm');
}
/**
* Get the post register / login redirect path.
*
* @return string
*/
public function redirectPath(): string
{
return $this->authLoggedRedirectPath();
}
}

View file

@ -1,85 +0,0 @@
<?php
namespace App\Http\Controllers\Fo\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
class ForgotPasswordController extends Controller
{
use SendsPasswordResetEmails;
/**
* Message to user
*
* @var string
* @phpcs:disable Generic.Files.LineLength.TooLong
*/
private $message = 'front.messages.password_reset_email_sent';
//phpcs:enable
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:frontend');
}
/**
* Display the form to request a password reset link.
*
* @return \Illuminate\View\View
*/
public function showLinkRequestForm(): View
{
return view('theme::auth.passwords.email');
}
/**
* Get the broker to be used during password reset.
*
* @return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker(): PasswordBroker
{
return Password::broker('customers');
}
/**
* Get the response for a successful password reset link.
* ! Dans les deux cas on ne divulgue pas si un user existe.
*
* @return \Illuminate\Http\RedirectResponse
*/
protected function sendResetLinkResponse()
{
return back()->with('info', trans($this->message));
}
/**
* Get the response for a failed password reset link.
* ! Dans les deux cas on ne divulgue pas si un user existe.
*
* @param \Illuminate\Http\Request $request
* @param string $response
* @return \Illuminate\Http\RedirectResponse
*/
protected function sendResetLinkFailedResponse(Request $request, string $response)
{
// ! Ne pas notifier que l'utilisateur n'existe pas.
if ($response === 'passwords.user') {
return back()->with('info', trans($this->message));
}
// * Renvoyer les autres message d'erreur style throttle.
return back()
->withInput($request->only('email'))
->withErrors(['email' => trans($response)]);
}
}

View file

@ -1,107 +0,0 @@
<?php
namespace App\Http\Controllers\Fo\Auth;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\Settings;
use App\Providers\RouteServiceProvider;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
class LoginController extends Controller
{
use AuthenticatesUsers;
use ThrottlesLogins;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:frontend')->except('logout');
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard(): StatefulGuard
{
return Auth::guard('frontend');
}
/**
* Show the application's login form.
*
* @return \Illuminate\View\View
*/
public function showLoginForm(): View
{
return view('theme::auth.login');
}
/**
* Check if the authenticated user can access the game
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Customer $user
* @return void
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing, Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
*/
protected function authenticated(Request $request, Customer $user): void
{
/** @var \LDC\LDCCRM\Models\Customer $crmCustomer */
$crmCustomer = $user->api_data;
/** @var \App\Models\Settings */
$settings = app(Settings::class);
$countries = $settings->authorized_countries;
if (count($countries) && !in_array($crmCustomer->country->value, $countries)) {
$this->logout($request);
Session::flash('info', trans('front.messages.game_not_available_in_country'));
} else {
$user->last_connection = \now();
$user->saveOrFail();
Session::flash('info', trans('front.messages.login_success'));
}
}
/**
* The user has logged out of the application.
*
* @param \Illuminate\Http\Request $request
* @return void
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
protected function loggedOut(Request $request): void
{
Session::flash('info', trans('front.messages.logout_success'));
}
/**
* Get the post register / login redirect path.
*
* @return string
*/
public function redirectPath(): string
{
return response()->redirectToIntended()->getTargetUrl();
}
}

View file

@ -1,157 +0,0 @@
<?php
namespace App\Http\Controllers\Fo\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\Customers\CreateAccountRequest;
use App\Models\Customer;
use Illuminate\Contracts\Validation\Validator as ValidationValidator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException as IlluminateValidationException;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\ValidationException as CrmValidationException;
use LDC\LDCCRM\Models\Customer as CrmCustomer;
class RegisterController extends Controller
{
use RegistersUsers;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:frontend');
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard('frontend');
}
/**
* Show the application registration form.
*
* @return \Illuminate\View\View
*/
public function showRegistrationForm()
{
return view('theme::auth.register');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
* @throws IlluminateValidationException If data is incorrect.
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
protected function validator(array $data): ValidationValidator
{
// phpcs:enable
$request = CreateAccountRequest::capture();
$request->prepareForValidation();
return Validator::make(
$request->validationData(),
$request->rules(),
$request->messages(),
$request->attributes()
);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\Customer
* @throws IlluminateValidationException If there are validation errors.
* @throws \RuntimeException On unhandled api Error.
*/
protected function create(array $data): Customer
{
$data['ok_cgv'] = \request()->boolean('ok_cgv');
$data['opt_in'] = \request()->boolean('opt_in');
$data['phone'] = Arr::get($data, 'phone');
// * This field is not standard in crm
$data['postcode'] = Arr::get($data, 'postal_code');
Arr::forget($data, 'postal_code');
try {
return DB::transaction(function () use ($data) {
$crmCustomer = new CrmCustomer(Arr::only(
$data,
[
'firstname', 'lastname', 'birth_date', 'address',
'address2', 'postcode', 'country', 'city', 'phone',
'email', 'password', 'opt_in',
]
));
$crmCustomer->save();
// * Enregistrement du Hashcode
/** @var \App\Models\Customer $customer */
$customer = Customer::withTrashed()->firstOrNew([
'email' => $data['email']
]);
$customer->fill(Arr::only($data, $customer->getFillable()));
$customer->hashcode = $crmCustomer->hashcode;
if ($customer->trashed()) {
$customer->restore();
}
$customer->email_verified_at = $crmCustomer->status ? now() : null;
// ! Last connection sera null, pour identifier la deuxième connexion,
// ! Pour accéder au partie du Klub.
if ($customer->saveOrFail()) {
// phpcs:ignore Generic.Files.LineLength.TooLong
Session::flash('success', trans('front.messages.account_created_email_confirmation_sent'));
}
return $customer;
});
} catch (ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::customerExists)) {
throw IlluminateValidationException::withMessages([
'error' => trans('front.messages.email_already_in_use')
]);
}
if ($e->getApiError()->equals(ApiError::validationFailed)) {
throw IlluminateValidationException::withMessages([
'error' => $e->getMessage()
]);
}
report($e);
Log::error(__CLASS__ . '::create reached end of possibilities.');
throw new \RuntimeException(__CLASS__ . '::create reached end of possibilities.');
} catch (CrmValidationException $e) {
throw IlluminateValidationException::withMessages([
'error' => $e->getMessage()
]);
} //end try
}
/**
* Get the post register / login redirect path.
*
* @return string
*/
public function redirectPath()
{
return $this->authLoggedRedirectPath();
}
}

View file

@ -1,122 +0,0 @@
<?php
namespace App\Http\Controllers\Fo\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
use LDC\LDCCRM\Exceptions\ValidationException as ExceptionsValidationException;
class ResetPasswordController extends Controller
{
use ResetsPasswords;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest:frontend');
$this->middleware('signed')->only('showResetForm');
$this->middleware('throttle:6,1')->only('showResetForm');
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard(): StatefulGuard
{
return Auth::guard('frontend');
}
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Contracts\View\View
*/
public function showResetForm(Request $request): \Illuminate\Contracts\View\View
{
$token = $request->route()->parameter('token');
return view('theme::auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}
/**
* Reset the given user's password.
*
* @param \App\Models\Customer $customer
* @param string $password
* @return void
* @throws \Illuminate\Validation\ValidationException If something goes wrong.
*/
protected function resetPassword(\App\Models\Customer $customer, string $password): void
{
/** @var \LDC\LDCCRM\CrmApiV4 */
$crm = app('crmAPI');
try {
if (!($crmCustomer = $crm->getCustomer($customer->hashcode))) {
throw ValidationException::withMessages([
'error' => trans('Changement impossible, compte inexistant.')
]);
}
$crmCustomer->password = $password;
$crmCustomer->save();
} catch (\TypeError | CrmException | ApiErrorException $e) {
report($e);
throw ValidationException::withMessages([
'error' => trans('front.messages.unexpected_error_try_later')
]);
} catch (ExceptionsValidationException $e) {
throw ValidationException::withMessages([
'password' => $e->getMessage()
]);
}
$customer->setRememberToken(Str::random(60));
$customer->save();
event(new PasswordReset($customer));
$this->guard()->login($customer);
}
/**
* Get the post register / login redirect path.
*
* @return string
*/
public function redirectPath(): string
{
return $this->authLoggedRedirectPath();
}
/**
* Get the broker to be used during password reset.
*
* @return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker(): PasswordBroker
{
return Password::broker('customers');
}
}

View file

@ -1,148 +0,0 @@
<?php
namespace App\Http\Controllers\Fo\Auth;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\Events\Verified;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\VerifiesEmails;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
use LDC\LDCCRM\Exceptions\ValidationException;
class VerificationController extends Controller
{
use VerifiesEmails;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:frontend')->except('verify');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
/**
* Show the email verification notice.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Contracts\View\View
*/
public function show(Request $request): RedirectResponse|View
{
return $request->user('frontend')->hasVerifiedEmail()
? redirect($this->redirectPath())
: view('theme::auth.verify');
}
/**
* Mark the authenticated user's email address as verified.
*
* ! Overloaded trait
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException If request is invalid.
*/
public function verify(Request $request): JsonResponse|RedirectResponse
{
/** @var \App\Models\Customer */
$user = Customer::findOrFail($request->route('id'));
if (!hash_equals((string) $request->route('id'), (string) $user->getKey())) {
throw new AuthorizationException();
}
if (!hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification()))) {
throw new AuthorizationException();
}
if ($user->hasVerifiedEmail()) {
return $request->wantsJson()
? new JsonResponse([], 204)
: redirect($this->redirectPath());
}
DB::transaction(function () use ($user) {
if ($user->markEmailAsVerified()) {
$this->setCrmCustomerAsVerified($user);
event(new Verified($user));
}
});
if ($response = $this->verified($request)) {
return $response;
}
return $request->wantsJson()
? new JsonResponse([], 204)
: redirect($this->redirectPath())->with('verified', true);
}
/**
* The user has been verified.
*
* @param \Illuminate\Http\Request $request
* @return mixed
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
protected function verified(Request $request)
{
// phpcs:enable
return redirect($this->redirectPath())->with('success', trans(
'front.messages.account_activated_can_play'
));
}
/**
* Get the post register / login redirect path.
*
* @return string
*/
public function redirectPath(): string
{
return response()->redirectToRoute('fo.participate')->getTargetUrl();
}
/**
* Set Crm Customer active
*
* @param \App\Models\Customer $customer
* @return void
* @throws \Illuminate\Http\Exceptions\HttpResponseException In case of failure.
*/
private function setCrmCustomerAsVerified(Customer $customer): void
{
try {
$customer->clearApiDataCache();
$crmCustomer = $customer->api_data;
$crmCustomer->activate();
$customer->clearApiDataCache();
} catch (ValidationException) {
redirect($this->redirectPath())->with('error', trans(
'front.messages.unexpected_error_try_later'
))->throwResponse();
} catch (CrmException | ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::customerAlreadyActive)) {
// * Ignore this and continue, as it may be activated via another CRM service.
return;
} else {
report($e);
redirect($this->redirectPath())->with('error', trans(
'front.messages.unexpected_error_try_later'
))->throwResponse();
}
}
}
}

View file

@ -1,175 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\Customers\VerifyInformationsRequest;
use App\Http\Requests\Fo\Customers\SingleOptinRequest;
use App\Repositories\Fo\CrmRepository;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\ValidationException as IlluminateValidationException;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\CrmException;
use LDC\LDCCRM\Exceptions\ValidationException as CrmValidationException;
use LDC\LDCCRM\Models\SingleOptin;
class CustomerController extends Controller
{
/** @var \App\Repositories\Fo\CrmRepository $crmRepository */
private $crmRepository;
/**
* ParticipateController
*
* @return void
*/
public function __construct()
{
$this->crmRepository = new CrmRepository();
}
/**
* Verify profil info form
*
* @return \Illuminate\Contracts\View\View
*/
public function profilVerify(): View
{
// ! Pas de Gate/Policies Ici volontairement, vu avec Vincent
/** @var \App\Models\Customer */
$customer = auth('frontend')->user();
$crmCustomer = $customer->api_data;
return view('theme::auth.profil-verify', compact('crmCustomer'));
}
/**
* Profile verify
*
* @param \App\Http\Requests\Fo\Customers\VerifyInformationsRequest $request
* @return \Illuminate\Http\RedirectResponse
* @throws IlluminateValidationException In case of any error validation or within the crm.
*/
public function profilVerifySubmit(VerifyInformationsRequest $request): RedirectResponse
{
// ! Pas de Gate/Policies Ici volontairement, vu avec Vincent
try {
return DB::transaction(function () use ($request) {
// * --- FILL AND SAVE CUSTOMER
/** @var \App\Models\Customer */
$customer = auth('frontend')->user();
// * Màj, on ne mets pas à jour le mdp ou l'adresse email, juste les champs pour mesBr
$customer->updateApiData(\array_merge(Arr::only(
$request->validated(),
[
'firstname',
'lastname',
'birth_date',
'address',
'country',
'city',
'phone',
'opt_in',
]
), ['postcode' => $request->input('postal_code')]));
Session::flash('success', trans('front.messages.profile_updated_success'));
return response()->redirectToRoute('fo.participate');
});
} catch (CrmValidationException $e) {
// * Local Validation failure
throw IlluminateValidationException::withMessages([
'error' => $e->getMessage()
]);
} catch (ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::validationFailed)) {
throw IlluminateValidationException::withMessages([
'error' => $e->getMessage()
]);
}
report($e);
Log::error(__CLASS__ . '::update reached end of possibilities.');
} catch (CrmException $e) {
report($e);
Log::error(__CLASS__ . '::error occured on calling crm.');
throw IlluminateValidationException::withMessages([
'error' => trans('Une erreur est survenue, veuillez réssayer plus tard')
]);
} //end try
return back()->withInput()->withErrors(trans('front.messages.unexpected_error_try_later'));
}
/**
* View all customer winnig participations
*
* @return \Illuminate\Contracts\View\View
*/
public function viewWinningParticipations(): View
{
$this->authorize('viewWonList', \App\Models\Participation::class);
/** @var \App\Models\Customer */
$customer = auth('frontend')->user();
// * Recupération des informations CRM
/** @var \LDC\LDCCRM\Models\Customer*/
$crmUser = $this->crmRepository->fetchCrmCustomer($customer);
/** @var \LDC\MESBR\MesBr */
$mesBr = app('mesBrAPI');
$brBasket = $mesBr->getBasket($crmUser);
if (!empty($brBasket['coupons'])) {
$canPrint = (collect($brBasket['coupons'])->sum('quantity') - collect($brBasket['coupons'])->sum('printed'));
}
$winningList = $customer->participations()
->with(['instantWin'])->where(function (Builder $q) {
$q->whereHas('instantWin');
})->get();
return view('theme::pages.participation.winning-participations', [
'winningList' => $winningList,
'canPrint' => $canPrint ?? null
]);
}
/**
* Call the CRM to add a single optin
*
* @param \App\Http\Requests\Fo\Customers\SingleOptinRequest $request
* @return string|array|null|\Illuminate\Contracts\Translation\Translator
* @throws \LDC\LDCCRM\Exceptions\ValidationException ValidationException.
* @throws \Illuminate\Contracts\Container\BindingResolutionException BindingResolutionException.
*/
public function addOptIn(SingleOptinRequest $request)
{
try {
SingleOptin::setStatus($request->email, true);
return \response(trans("front.messages.newsletter_subscription_success"), 200);
} catch (ApiErrorException $e) {
// Il y a deja un customerInfo avec optin a true pour ce customer.
if ($e->getApiError()->equals(ApiError::singleOptinCustomerExists)) {
return trans('front.messages.newsletter_email_already_subscribed');
}
if (app()->bound('sentry')) {
app('sentry')->captureException($e);
}
return \response(trans('front.messages.unexpected_error_try_later'), 404);
} catch (CrmException $e) {
if (app()->bound('sentry')) {
app('sentry')->captureException($e);
}
return \response(trans('front.messages.unexpected_error_try_later'), 404);
}
}
}

View file

@ -1,90 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use Illuminate\Support\Arr;
class DiscountController extends Controller
{
/**
* Fetch PDF BR.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function fetchBrPdf(): \Illuminate\Http\RedirectResponse
{
/** @var \App\Models\Customer $customer */
$customer = auth('frontend')->user();
$pdf = $this->fetchBrPdfFromMesBr($customer);
if ($pdf === null) {
\back()->withErrors([
'coupon' => trans('front.messages.pdf_download_error')
])->throwResponse();
}
return redirect()->to(
sprintf(
"%s/basket/%s/print",
config('mesbr.endpoint'),
$pdf
)
);
}
/**
* Fetch coupons PDF.
*
* @param \App\Models\Customer $customer
* @return string|null
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
private function fetchBrPdfFromMesBr(Customer $customer): ?string
{
// phpcs:enable
// * Phase - 1 Recupération des informations CRM
/** @var \App\Models\Customer $customer */
$customer = auth('frontend')->user();
/** @var \LDC\LDCCRM\Models\Customer $crmCustomer */
$crmCustomer = $customer->api_data;
try {
/** @var \LDC\MESBR\MesBr */
$mesBr = app('mesBrAPI');
$result = $mesBr->getBasket($crmCustomer);
$result = \is_object($result) ? (array) $result : $result;
if (Arr::get($result, 'status') !== "OK") {
report(new \RuntimeException(
\sprintf(
'MESBR : Une erreur est survenue. Code : %s Message : %s',
Arr::get($result, 'code') ?? 'Undefined',
Arr::get($result, 'message') ?? 'Undefined',
)
));
return null;
}
// * La réponse est conforme ?
$needed_fields = ['uuid'];
if (!Arr::has($result, $needed_fields)) {
report(new \RuntimeException(sprintf(
'MESBR : Il manques des champs dans la réponse, attendu => %s, donné => %s',
json_encode($needed_fields),
json_encode($result),
)));
return null;
}
// * Tout est OK
return Arr::get($result, 'uuid') ?: null;
} catch (\RuntimeException $e) {
report($e);
// * Retenter ?
return null;
} //end try
}
}

View file

@ -1,95 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Models\FaqQuestion;
use App\Models\FaqTheme;
use App\Models\Range;
use App\Models\Settings;
use Illuminate\Support\Facades\Gate;
class HomeController extends Controller
{
/**
* Display home page
*
* @return \Illuminate\Contracts\View\View
*/
public function home(): \Illuminate\Contracts\View\View
{
if (!Gate::check('fo.gameEnabled')) {
\session()->flash('warning', trans('front.messages.game_missing_required_elements'));
}
return view('theme::pages.home');
}
/**
* Display products with game stickers
*
* @return \Illuminate\Contracts\View\View
* @phpcs:ignore Squiz.Commenting.FunctionComment.EmptyThrows
* @throws \Illuminate\Http\Exceptions\HttpResponseException
*/
public function showProducts(): \Illuminate\Contracts\View\View
{
// ? Show product list authorized ?
if (!Gate::allows('fo.showProducts')) {
\response()->redirectToRoute('fo.homepage')->throwResponse();
}
$rangeModelList = Range::query()->with('products')->orderBy('id')->get();
return view('theme::pages.products', compact('rangeModelList'));
}
/**
* Display Faq page
*
* @return \Illuminate\Contracts\View\View
*/
public function showFaq(): \Illuminate\Contracts\View\View
{
// ? Show QA authorized ?
if (!Gate::allows('fo.showFaq')) {
\response()->redirectToRoute('fo.homepage')->throwResponse();
}
$questionModelList = FaqQuestion::getCached();
$themeModelList = FaqTheme::getCached();
return view('theme::pages.faq', compact(
'questionModelList',
'themeModelList'
));
}
/**
* Show the teaser page if it is activated
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
public function teaser(): \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
{
/** @var \App\Models\Settings */
$settings = app(Settings::class);
if (!$settings->should_display_teaser_page) {
return redirect()->route('fo.homepage');
}
return view('theme::pages.teaser');
}
/**
* Show the end game page if it is activated
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
public function endGame(): \Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
{
/** @var \App\Models\Settings */
$settings = app(Settings::class);
if (!$settings->should_display_end_page) {
return redirect()->route('fo.homepage');
}
return view('theme::pages.end-game');
}
}

View file

@ -1,308 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\Customers\CreateAccountRequest;
use App\Http\Requests\Fo\ParticipateRequest;
use App\Lib\Discount as LibDiscount;
use App\Mail\Won\PrizeWonAdminMail;
use App\Models\Customer;
use App\Models\InstantWin;
use App\Models\Participation;
use App\Models\Settings;
use App\Notifications\Customer\HasWonDiscount;
use App\Notifications\Customer\HasWonInstantWin;
use App\Repositories\Fo\CrmRepository;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class ParticipateController extends Controller
{
/** @var \App\Repositories\Fo\CrmRepository $crmRepository */
private $crmRepository;
/**
* ParticipateController
*
* @return void
*/
public function __construct()
{
$this->crmRepository = new CrmRepository();
$this->middleware(function (Request $request, callable $next) {
$this->authorize('fo.gameEnabled');
$this->assertUserHasEnoughInfoToUseMesBr();
return $next($request);
});
}
/**
* Display participation form
*
* @return \Illuminate\Contracts\View\View
*/
public function participate(): \Illuminate\Contracts\View\View
{
if (!Gate::check('participate', Participation::class)) {
return view('theme::pages.participation.participation-exhausted');
}
return view('theme::pages.participation.participate');
}
/**
* Participate Method
*
* @param \App\Http\Requests\Fo\ParticipateRequest $request
* @return \Illuminate\Contracts\View\View
*/
public function participateSubmit(ParticipateRequest $request): \Illuminate\Contracts\View\View
{
return DB::transaction(function () use ($request) {
// ! On verrouille le ou les instants gagnant
/** @var \App\Models\InstantWin|null */
$instantWin = InstantWin::query()->lockForUpdate()
->where('available_at', '<', now())
->whereDoesntHave('participation')
->get()->sortBy('available_at')->first();
/** @var \App\Models\Settings */
$settings = app(Settings::class);
/** @var \App\Models\Customer */
$customer = auth('frontend')->user();
/** @var \App\Models\Code|null */
$code = $request->post('unique_code');
/** @var \App\Models\Product|null */
$product = $request->post('product');
// * Make new participation
$participation = Participation::makeNew(
app('clientIp'),
$customer,
$code,
$product
);
// * Si l'utilisateur actuel à déjà gagné un gros lot, pas d'instant gagnant.
// ? As-t-on un instant gagnant ?
if (Participation::customerAlreadyHasAnInstantWin($customer) or !$instantWin) {
// * --- DISCOUNT WIN ---
// ? Les BR sont activés ?
if (!$settings->discounts_activated) {
// * On enregistre la participation du joueur.
$participation->save();
// * Pas de coupons disponibles, le joueur à perdu
return view('theme::pages.participation.loose');
}
// * Le joueur à gagné un coupon.
/** @var \App\Lib\Discount Coupon aléatoire en fonction du ratio de chaque coupon */
$discount = Arr::get(
$settings->web_coupons,
$this->getRandomWeightedElementIndex($settings->web_coupons)
);
$this->setDiscountAsWon($customer, $discount);
// * Le joueur à remporté un coupon
$participation->discount_code = (string) $discount->web_coupon_identifiant;
// * On enregistre la participation du joueur.
$participation->save();
$crmCustomer = $this->crmRepository->fetchCrmCustomer($customer);
$customer->notify(new HasWonDiscount(
$discount,
$crmCustomer->firstname
));
return view('theme::pages.participation.won', compact('discount'));
} //end if
// * --- INSTANT WIN ---
// * On enregistre la participation du joueur.
$participation->save();
// * Le joueur à remporté un instant gagnant
$instantWin->participation()->associate($participation);
$instantWin->save();
$crmCustomer = $this->crmRepository->fetchCrmCustomer($customer);
// * Notify customer for his win
$customer->notify(new HasWonInstantWin(
$instantWin->prize,
$crmCustomer->firstname
));
// * Dispatch notification to mail list
Mail::to($settings->notification_emails)->send(new PrizeWonAdminMail(
$settings->name,
$participation->created_at,
$instantWin->prize->label,
$crmCustomer,
optional($code)->code_unique,
optional($product)->ean_code
));
return view('theme::pages.participation.won', [
'prizeModel' => $instantWin->prize,
'participationModel' => $participation,
'crmCustomer' => $crmCustomer
]);
});
}
// * --- PRIVATE METHODS ---
/**
* Try Call CRM + MesBr to setup discount
*
* @param \App\Models\Customer $customer
* @param LibDiscount $discount
* @return void
* @throws \Illuminate\Http\Exceptions\HttpResponseException If Any error occurs.
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
*/
private function setDiscountAsWon(Customer $customer, LibDiscount $discount): void
{
// phpcs:enable
// * Phase - 1 Recupération des informations CRM
/** @var \LDC\LDCCRM\Models\Customer*/
$crmUser = $this->crmRepository->fetchCrmCustomer($customer);
// * Phase - 2 Mise à jour du coupon dans MesBr
try {
/** @var \App\Models\Settings */
$settings = app(Settings::class);
/** @var \LDC\MESBR\MesBr */
$mesBr = app('mesBrAPI');
// * MaJ Customer
/** @var string */
$crm_customer_hashcode = retry(3, function () use ($mesBr, $crmUser) {
/**
* Parce que MesBr n'est pas fiable il faut retenter pour avoir
* l'id client, des fois cet id sera dans hashcode...
*
* Id est necessaire pour update panier..
*/
$result = $mesBr->updateCustomer($crmUser->hashcode, $crmUser->email, $crmUser->country->label());
if (optional($result)->status !== "OK") {
throw new \RuntimeException(
\sprintf(
'MESBR : Une erreur est survenue. Code : %s Message : %s',
$result->code ?? 'Undefined',
$result->message ?? 'Undefined'
)
);
}
/** @var object|null */
$crm_customer = optional($result)->customer;
if (empty(optional($crm_customer)->hashcode)) {
throw new \RuntimeException(
'MESBR : Une erreur est survenue. Update Customer n\'as pas retourné le customer hashcode'
);
}
return $crm_customer->hashcode;
}, 100);
// * Maj Panier
$result = $mesBr->updateBasket(
$crmUser,
strval($discount->web_coupon_identifiant)
);
if (Arr::get($result, 'status') === "OK") {
// * La réponse est conforme ?
$needed_fields = ['ref'];
if (!Arr::has($result, $needed_fields)) {
throw new \RuntimeException(sprintf(
'MESBR : Il manques des champs dans la réponse, attendu => %s, donné => %s',
json_encode($needed_fields),
json_encode($result),
));
}
// * Tout est OK
return;
}
throw new \RuntimeException(
\sprintf(
'MESBR : Une erreur est survenue. Code : %s Message : %s',
$result["code"] ?? 'Undefined',
$result["message"] ?? 'Undefined'
)
);
} catch (\RuntimeException $e) {
report($e);
// * Retenter ?
back()->with('error', trans('front.messages.unexpected_error_try_later'))->throwResponse();
} //end try
throw new \Error('Should not reach this point');
}
/**
* Assert that user has enough info filled on his profile to win a Discount
* Or redirect him to the fill form
* ! Also validates its birth date (because beeing an adult is required to participate)
*
* @return void
* @throws \Illuminate\Http\Exceptions\HttpResponseException If customer data doest not validate
* or and error occurs.
*/
private function assertUserHasEnoughInfoToUseMesBr(): void
{
// * Valider que le client dispose des donnés requises pour MesBr
try {
/** @var \App\Models\Customer */
$authUser = auth('frontend')->user();
$crmCustomer = $this->crmRepository->fetchCrmCustomer($authUser);
// * On valide les données selon les critères du site
$rules = collect((new CreateAccountRequest())->rules());
Validator::make(
[
'birth_date' => $crmCustomer->birth_date,
'address' => $crmCustomer->address,
'postal_code' => $crmCustomer->postcode,
'country' => $crmCustomer->country->value,
'city' => $crmCustomer->city
],
[
'birth_date' => $rules->get('birth_date'),
'address' => $rules->get('address'),
'postal_code' => $rules->get('postal_code'),
'country' => $rules->get('country'),
'city' => $rules->get('city')
]
)->validate();
Session::remove('needCrmInfoUpdate');
} catch (ValidationException) {
response()->redirectToRoute('fo.profil.verify')
->with('warning', trans(
'front.messages.profile_incomplete_cannot_play'
))->throwResponse();
} catch (\Exception $e) {
report($e);
// * Retenter ?
response()->redirectToRoute('fo.homepage')
->with('error', trans('front.messages.unexpected_error_try_later'))
->throwResponse();
} //end try
}
// * --- END PRIVATE METHODS ---
}

View file

@ -1,57 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use App\Http\Controllers\Controller;
use App\Models\StaticPage;
use Illuminate\Contracts\View\View;
class StaticPageController extends Controller
{
/**
* Show the rules view
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function reglement()
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::rules)->firstOrFail();
return $this->viewStaticPage($staticPageModel);
}
/**
* Show the privacy view
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function charte()
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::confidentiality)->firstOrFail();
return $this->viewStaticPage($staticPageModel);
}
/**
* Show the legals view
*
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
*/
public function legals()
{
$staticPageModel = StaticPage::query()->where('type', StaticPageType::legals)->firstOrFail();
return $this->viewStaticPage($staticPageModel);
}
/**
* Display a static page
*
* @param \App\Models\StaticPage $staticPageModel
* @return \Illuminate\Contracts\View\View
*/
private function viewStaticPage(StaticPage $staticPageModel): View
{
return view('theme::pages.static_page', [
'staticPageModel' => $staticPageModel
]);
}
}

View file

@ -1,160 +0,0 @@
<?php
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\SubmitWinningProofRequest;
use App\Mail\Won\WinningProofAdminMail;
use App\Models\Participation;
use App\Models\Settings;
use App\Notifications\Customer\HasSubmitedWinProof;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\ValidationException as IlluminateValidationException;
use LDC\LDCCRM\Enums\ApiError;
use LDC\LDCCRM\Exceptions\ApiErrorException;
use LDC\LDCCRM\Exceptions\ValidationException as CrmValidationException;
class WinningProofController extends Controller
{
/**
* WinningProofController
*
* @return void
*/
public function __construct()
{
$this->middleware(function (Request $request, callable $next) {
$this->authorize('fo.gameEnabled');
$this->authorize('submitProof', $request->route('participation'));
return $next($request);
});
}
/**
* Display winning proof form
*
* @param \App\Models\Participation $participation
* @return \Illuminate\Contracts\View\View
*/
public function displayForm(Participation $participation): View
{
$participation->load('instantWin.prize');
/** @var \App\Models\Customer */
$customer = auth('frontend')->user();
$crmCustomer = $customer->api_data;
return view('theme::pages.participation.won-form-only', [
'participationModel' => $participation,
'prizeModel' => $participation->instantWin->prize,
'crmCustomer' => $crmCustomer
]);
}
/**
* Submit winning proofs,
* - 1 Met à jour le profil du customer (sans lui en faire part),
* - 2 Save les pictures de preuve de gains
* - 3 Envoi un mail au abonnés (settings notification_emails) avec les infos client
*
* @param \App\Http\Requests\Fo\SubmitWinningProofRequest $request
* @param \App\Models\Participation $participation
* @return \Illuminate\Http\RedirectResponse
* @throws IlluminateValidationException In case of failure.
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
*/
public function displayFormSubmit(
SubmitWinningProofRequest $request,
Participation $participation
): RedirectResponse {
// phpcs:enable
try {
return DB::transaction(function () use ($request, $participation) {
$participation->load([
'instantWin.prize',
'code',
'product'
]);
/** @var \App\Models\Settings */
$settings = app(Settings::class);
// * --- PHASE 1 Update Crm Customer ---
/** @var \App\Models\Customer */
$customer = auth('frontend')->user();
$crmCustomer = $customer->api_data;
/** @var array */
$data = $request->validated();
// * This field is not standard in crm
$data['postcode'] = Arr::get($data, 'postal_code');
Arr::forget($data, 'postal_code');
$customer->updateApiData(Arr::only(
$data,
[
'firstname',
'lastname',
'birth_date',
'address',
'address2',
'postcode',
'country',
'city',
'phone',
'email',
]
));
// * --- PHASE 2 Update participation ---
$participation->fill(Arr::only($request->validated(), [
'barcode',
'ticket',
'sticker'
]));
$participation->save();
$customer->notify(new HasSubmitedWinProof($request->input('firstname')));
// * Dispatch notification to mail list
Mail::to($settings->notification_emails)->send(new WinningProofAdminMail(
$settings->name,
$participation->created_at,
$participation->instantWin->prize->label,
$crmCustomer,
optional($participation->code)->code_unique,
optional($participation->product)->ean_code,
$participation->sticker,
$participation->ticket,
$participation->barcode,
));
return response()->redirectToRoute('fo.homepage')
->with('success', trans(
'front.messages.winning_proof_submitted_will_be_contacted'
));
});
} catch (ApiErrorException $e) {
if ($e->getApiError()->equals(ApiError::validationFailed)) {
throw IlluminateValidationException::withMessages([
'error' => $e->getMessage()
]);
}
report($e);
Log::error(__CLASS__ . '::create reached end of possibilities.');
throw new \RuntimeException(__CLASS__ . '::create reached end of possibilities.');
} catch (CrmValidationException $e) {
throw IlluminateValidationException::withMessages([
'error' => $e->getMessage()
]);
} //end try
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers;
class GainsController extends Controller
{
/**
* index
* @return \Illuminate\View\View
*/
public function index()
{
if (view()->exists('front.basic.gains')) {
return view('front.basic.gains');
}
return redirect()->route('home');
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers;
class HomeController extends Controller
{
/**
* home
* @return \Illuminate\View\View
*/
public function home()
{
return view('front.basic.home');
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers;
class HowToPlayController extends Controller
{
/**
* index
* @return \Illuminate\View\View|Illuminate\Http\RedirectResponse
*/
public function index()
{
if (view()->exists('front.basic.how-to-play')) {
return view('front.basic.how-to-play');
}
return redirect()->route('home');
}
}

View file

@ -0,0 +1,287 @@
<?php
namespace App\Http\Controllers;
use App\Mail\PasswordReset;
use App\Mail\VerifyEmail;
use App\Models\Settings;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
class LoginController extends Controller
{
private $apiCrm;
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->apiCrm = new \LDCCRM\ApiV1(config('crm.endpoint'), config('crm.token'));
}
/**
* index
* @return \Illuminate\View\View
*/
public function index()
{
return view('front.basic.login');
}
public function authenticate(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$email = filter_var($request->email, FILTER_SANITIZE_EMAIL);
$password = $request->password;
$remember = $request->remember !== null ? true : false;
$userLocal = User::where('email', $email)->first();
if ($userLocal) {
if ($userLocal->email_verified === 1) {
if ($userLocal->role > 2) {
$connect = $this->apiCrm->loginCustomer($email, $password);
if ($connect->status === 'KO') {
if ($connect->code === 500) {
return back()->withInput($request->except("password"))
->withErrors("La connexion est impossible pour le moment, veuillez réessayer plus tard.");
} else {
return back()->withInput($request->except("password"))
->withErrors("Email ou mot de passe incorrect.");
}
}
}
} else {
$userLocal->email_verify_token = Str::uuid();
$userLocal->save();
Mail::to($email)->send(new VerifyEmail($userLocal));
return back()->withInput($request->except("password"))
->withErrors("Votre compte existe mais votre email n'est pas confirmé, merci de vérifier vos emails.");
}//end if
} else {
$connect = $this->apiCrm->loginCustomer($email, $password);
if ($connect->status === 'OK') {
$userLocal = User::create([
'crm_id' => $connect->user->crm_id,
'firstname' => $connect->user->firstname,
'lastname' => $connect->user->lastname,
'birth_date' => $connect->user->birth_date,
'email' => $email,
// TODO : MOTDEPASSE ???.
'password' => Hash::make("MOTDEPASSE"),
'address' => $connect->user->address,
'address2' => $connect->user->address2,
'town' => $connect->user->city,
'postal_code' => $connect->user->postcode,
'country' => $connect->user->country,
'email_verified' => 1
]);
} else {
// Compte existant mais non activé.
if ($connect->code === 116) {
$userLocal = User::create([
'crm_id' => $connect->user->crm_id,
'firstname' => $connect->user->firstname,
'lastname' => $connect->user->lastname,
'birth_date' => $connect->user->birth_date,
'email' => $email,
// TODO : MOTDEPASSE ???.
'password' => Hash::make("MOTDEPASSE"),
'address' => $connect->user->address,
'address2' => $connect->user->address2,
'town' => $connect->user->city,
'postal_code' => $connect->user->postcode,
'country' => $connect->user->country
]);
$userLocal->email_verify_token = Str::uuid();
$userLocal->save();
Mail::to($email)->send(new VerifyEmail($userLocal));
return back()->withInput($request->except("password"))
->withErrors("Votre compte existe mais votre email n'est pas confirmé, merci de vérifier vos emails.");
} elseif ($connect->code === 500) {
return back()->withInput($request->except("password"))
->withErrors("La connexion est impossible pour le moment, veuillez réessayer plus tard.");
} else {
return back()->withInput($request->except("password"))
->withErrors("Email ou mot de passe incorrect.");
} //end if
} //end if
}//end if
// phpcs:ignore
// TODO : Modifier avec separation guard.
$tmpPwd = "MOTDEPASSE";
if ($userLocal->role <= 2) {
$tmpPwd = $password;
}
if (Auth::attempt(["email" => $email, "password" => $tmpPwd], $remember)) {
if ($userLocal->role <= 2) {
return redirect()->route('bo.dashboard');
}
return redirect()->route('saisir-code');
} else {
return back()->withInput($request->except('password'))->withErrors('Les identifiants entrés sont incorrects.');
}
}
/**
* logout
* @return Illuminate\Http\RedirectResponse
*/
public function logout()
{
Auth::logout();
return redirect()->route('home');
}
/**
* confirm email
* @param string $verifyToken
* @return \Illuminate\View\View|Illuminate\Http\RedirectResponse
*/
public function confirmEmail(string $verifyToken)
{
$result = false;
$user = User::where('email_verify_token', $verifyToken)->first();
if (!$user) {
return view('front.basic.confirm-email', compact('result'));
}
$activation = $this->apiCrm->activateCustomer($user->crm_id);
if ($activation->status === 'OK') {
$user->email_verified = 1;
$user->email_verify_token = null;
$user->save();
$result = true;
} else {
// User already active.
if ($activation->code === 110) {
$user->email_verified = 1;
$user->email_verify_token = null;
$user->save();
$result = true;
}
}
return view('front.basic.confirm-email', compact('result'));
}
public function forgotPassword(Request $request)
{
if ($request->tokenValid && $request->token) {
$tokenValid = $request->tokenValid;
$token = $request->token;
return view('front.basic.forgot-password', compact('tokenValid', 'token'));
}
return view('front.basic.forgot-password');
}
public function forgotPasswordReset(Request $request, $token)
{
if (!$request->hasValidSignature(false)) {
return redirect()->route('login')
->withErrors("Le lien de changement de votre mot de passe n'est plus valide, veuillez réessayer.");
}
$tokenValid = false;
$user = User::where('password_token', $token)->first();
if (!$user) {
return redirect()->route('forgot-password', compact('tokenValid'))
->withErrors('Le lien de changement du mot de passe est incorrect.');
}
$tokenValid = true;
return redirect()->route('forgot-password', compact('tokenValid', 'token'));
}
public function mailPassword(Request $request)
{
$email = filter_var($request->email, FILTER_SANITIZE_STRING);
$user = User::where('email', $email)->first();
if (!$user) {
$userCrm = $this->apiCrm->getCustomerByEmail($email);
if ($userCrm->status === 'OK') {
$user = User::create([
'crm_id' => $userCrm->user->crm_id,
'firstname' => $userCrm->user->firstname,
'lastname' => $userCrm->user->lastname,
'birth_date' => $userCrm->user->birth_date,
'email' => $email,
// TODO : MOTDEPASSE ???
'password' => Hash::make("MOTDEPASSE"),
'address' => $userCrm->user->address,
'address2' => $userCrm->user->address2,
'town' => $userCrm->user->city,
'postal_code' => $userCrm->user->postcode,
'country' => $userCrm->user->country,
'email_verified' => 1
]);
if ($userCrm->user->status === 0) {
$user->email_verified = 0;
$user->email_verify_token = Str::uuid();
$user->save();
Mail::to($email)->send(new VerifyEmail($user));
return back()->withInput($request->except("password"))
->withErrors("Votre compte existe mais votre email n'est pas confirmé, merci de vérifier vos emails.");
}
} else {
if ($userCrm->code === 101) {
return back()->withInput($request->only('email'))
->withErrors("Le mail que vous avez entré n'est pas enregistré dans nos services.");
} else {
return back()->withErrors("Une erreur est survenue, veuillez réessayer plus tard.");
}
} //end if
}//end if
$user->password_token = Str::uuid();
$user->save();
/** @var \App\Models\Settings $settings */
$settings = app(Settings::class);
Mail::to($email)->send(new PasswordReset($user, $settings));
return redirect()->route('login')
->with('success', 'Un mail de réinitialisation de votre mot de passe vous a été envoyé(e).');
}
public function changePassword(Request $request)
{
$request->validate([
'password' => 'required|min:8|confirmed',
]);
$user = User::where('password_token', filter_var($request->token, FILTER_SANITIZE_STRING))->first();
if (!$user) {
return back()->withErrors('Le lien de changement de votre mot de passe est incorrect, veuillez réessayer.');
}
// TODO : Ajouter controle du contenu du mot de passe.
$newPassword = $request->password;
$update = $this->apiCrm->changePwdCustomer($user->crm_id, $newPassword);
if ($update->status === 'OK') {
$user->password_token = null;
$user->save();
return redirect()->route('login')
->with('success', 'Vous pouvez désormais vous connecter avec votre nouveau mot de passe.');
} else {
if ($update->code === 123) {
return back()
->withErrors("Il semblerait que vous ayez déjà utilisé ce mot de passe pour votre compte. Veuillez réessayer en changeant de mot de passe.");
} else {
return back()->withErrors("Une erreur est survenue, veuillez réessayer plus tard.");
}
}
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers;
use App\Models\Range;
class ProduitsController extends Controller
{
/**
* index
* @return \Illuminate\View\View|Illuminate\Http\RedirectResponse
*/
public function index()
{
$ranges = Range::with('products')->orderBy('id')->get();
if (view()->exists('front.basic.produits-porteurs')) {
return view('front.basic.produits-porteurs', compact('ranges'));
}
return redirect()->route('home');
}
}

View file

@ -0,0 +1,144 @@
<?php
namespace App\Http\Controllers;
use App\Mail\VerifyEmail;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Mail;
class RegisterController extends Controller
{
use RegistersUsers;
// TODO : Utilité ??
protected $redirectTo = RouteServiceProvider::HOME;
private $apiCrm;
public function __construct()
{
$this->middleware('guest');
$this->apiCrm = new \LDCCRM\ApiV1(config('crm.endpoint'), config('crm.token'));
}
public function index()
{
return view('front.basic.register-crm');
}
public function register(Request $request)
{
$request->validate([
'lastname' => 'required|string|max:255',
'firstname' => 'required|string|max:255',
'birth_date' => 'required|string|max:10',
'email' => 'required|string|email|max:255|unique:users|confirmed',
'password' => 'required|string|min:8|confirmed',
'address' => 'required|string|max:255',
'address2' => 'max:255',
'town' => 'required|string|max:255',
'postal_code' => 'required|string|max:255',
'country' => 'required|string|max:255',
'reglement' => 'accepted',
]);
$lastname = filter_var($request->lastname, FILTER_SANITIZE_STRING);
$firstname = filter_var($request->firstname, FILTER_SANITIZE_STRING);
$birthdate = $request->birth_date;
$email = filter_var($request->email, FILTER_SANITIZE_EMAIL);
$password = $request->password;
$address = filter_var($request->address, FILTER_SANITIZE_STRING);
$address2 = $request->address2 !== null ? filter_var($request->address2, FILTER_SANITIZE_STRING) : null;
$town = filter_var($request->town, FILTER_SANITIZE_STRING);
$postcode = filter_var($request->postal_code, FILTER_SANITIZE_STRING);
$country = filter_var($request->country, FILTER_SANITIZE_STRING);
$optin = $request->news !== null ? 1 : 0;
$tokenMail = Str::uuid();
$MJ = Carbon::now()->subYears(18);
if ($this->isSQLDate($birthdate)) {
$d = Carbon::createFromFormat('Y-m-d', $birthdate);
if (!$d->lessThanOrEqualTo($MJ)) {
return back()
->withInput($request->except('password'))
->withErrors("Vous devez être majeur pour vous inscrire au jeu.");
}
} elseif ($this->isFormDate($birthdate)) {
$d = Carbon::createFromFormat('d/m/Y', $birthdate);
if (!$d->lessThanOrEqualTo($MJ)) {
return back()
->withInput($request->except('password'))
->withErrors("Vous devez être majeur pour vous inscrire au jeu.");
}
$birthdate = $d->toDateString();
} else {
return back()
->withInput($request->except('password'))
->withErrors("Erreur sur le champs : date de naissance.");
}//end if
$crmUser = $this->apiCrm->createCustomer($email, $password, $firstname, $lastname, $optin, $birthdate, null, $address, $address2, $town, $postcode, ucfirst($country));
if ($crmUser->status === 'OK') {
$user = User::create([
'crm_id' => $crmUser->user->crm_id,
'firstname' => $firstname,
'lastname' => $lastname,
'birth_date' => $birthdate,
'email' => $email,
'password' => Hash::make("MOTDEPASSE"),
// TODO : ???
'address' => $address,
'address2' => $address2,
'town' => $town,
'postal_code' => $postcode,
'country' => ucfirst($country),
'email_verify_token' => $tokenMail,
]);
Mail::to($email)->send(new VerifyEmail($user));
return redirect()->route('login')
->with('success', "Pour finaliser votre inscription, merci de cliquer sur le lien qui vient de vous être envoyé par email<br>" .
"Informations complémentaires :<br>" .
"- Vérifiez vos spams : l'email de confirmation s'y trouve peut-être<br>" .
"- Attention : le mail peut parfois mettre quelques minutes à vous parvenir<br>" .
"- L'activation de votre compte doit se faire dans les 24 heures qui suivent la demande de création.");
} else {
if ($crmUser->code === 103) {
return back()
->withInput($request->except('password'))
->withErrors("Un compte utilisateur est déjà associé à votre email.");
} else {
return back()
->withInput($request->except('password'))
->withErrors("Une erreur est survenue, merci de recommencer.");
}
}//end if
}
private function isSQLDate($date)
{
if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $date)) {
return true;
}
return false;
}
private function isFormDate($date)
{
if (preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/[0-9]{4}$/", $date)) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers;
use App\Models\Settings;
class TeaserController extends Controller
{
public function index()
{
$settings = app(Settings::class)
->select('start_date', 'end_date', 'activated_teaser', 'teaser_end_activity')->first();
if ($settings->activated_teaser === 1 && $settings->teaser_end_activity > now()) {
return view('front.basic.teaser', compact('settings'));
}
return redirect()->route('home');
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace App\Http\Controllers;
use App\Models\Content;
class ViewContentController extends Controller
{
public function reglement()
{
$content = Content::find(3);
return view('front.basic.reglement', compact('content'));
}
public function charte()
{
$content = Content::find(2);
return view('front.basic.charte', compact('content'));
}
public function legals()
{
$content = Content::find(1);
return view('front.basic.legals', compact('content'));
}
}

View file

@ -0,0 +1,132 @@
<?php
namespace App\Http\Controllers;
use App\Mail\NotifAdmin;
use App\Mail\WinningProof;
use App\Models\Participation;
use App\Models\Settings;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
class WinningProofController extends Controller
{
private $apiCrm;
public function __construct()
{
$this->apiCrm = new \LDCCRM\ApiV1(config('crm.endpoint'), config('crm.token'));
}
public function sendWinningProof(Request $request)
{
// On récupère la participation gagnante en attente des infos
$participation = Participation::where([
['user_id', Auth::user()->id],
['sticker', null],
['ticket', null],
['barcode', null]
])->has('instantWin')->first();
if (!$participation) {
return redirect()->route('home');
}
$request->validate([
'lastname' => 'required|string|max:255',
'firstname' => 'required|string|max:255',
'address' => 'required|string|max:255',
'address2' => 'max:255',
'town' => 'required|string|max:255',
'postal_code' => 'required|max:255',
'country' => 'required|string|max:255',
'phone' => 'required|string|max:50',
'sticker' => 'required|mimes:jpeg,png,jpg,pdf|max:2048',
'ticket' => 'required|mimes:jpeg,png,jpg,pdf|max:2048',
'barcode' => 'required|mimes:jpeg,png,jpg,pdf|max:2048',
]);
$lastname = filter_var($request->lastname, FILTER_SANITIZE_STRING);
$firstname = filter_var($request->firstname, FILTER_SANITIZE_STRING);
$address = filter_var($request->address, FILTER_SANITIZE_STRING);
$address2 = $request->address2 !== null ? filter_var($request->address2, FILTER_SANITIZE_STRING) : null;
$town = filter_var($request->town, FILTER_SANITIZE_STRING);
$postalCode = filter_var($request->postal_code, FILTER_SANITIZE_STRING);
$country = filter_var($request->country, FILTER_SANITIZE_STRING);
$phone = filter_var($request->phone, FILTER_SANITIZE_STRING);
$sticker = $request->sticker;
$ticket = $request->ticket;
$barcode = $request->barcode;
// Mise à jour de l'utilisateur en local.
$user = User::find(Auth::user()->id);
$user->lastname = $lastname;
$user->firstname = $firstname;
$user->address = $address;
$user->address2 = $address2;
$user->town = $town;
$user->postal_code = $postalCode;
$user->country = $country;
$user->phone = $phone;
$user->save();
// Mise à jour utilisateur dans la CRM.
$update = $this->apiCrm->updateCustomer(
$user->crm_id,
$firstname,
$lastname,
null,
null,
$phone,
$address,
$address2,
$town,
$postalCode,
ucfirst($country)
);
if ($update->status !== 'OK') {
Log::warning('Erreur lors de la mise a jour du user (crm_id : ' . $user->crm_id .
') - code : ' . $update->code . ' - message : ' . $update->message);
Mail::to(config('mail.MAIL_ADMIN'))->send(new NotifAdmin(
'CRM : Erreur lors de la mise a jour du user (crm_id : ' .
$user->crm_id . ') - code : ' . $update->code . ' - message : ' . $update->message
));
}
$participationId = $participation->id;
$stickerFileName = $participationId . '-sticker.' . $sticker->extension();
$sticker->move(public_path('fichiers/preuve-de-gain/' . $participationId . '/'), $stickerFileName);
$stickerPath = public_path() . '/fichiers/preuve-de-gain/' . $participationId . '/' . $stickerFileName;
$ticketFileName = $participationId . '-ticket.' . $ticket->extension();
$ticket->move(public_path('fichiers/preuve-de-gain/' . $participationId . '/'), $ticketFileName);
$ticketPath = public_path() . '/fichiers/preuve-de-gain/' . $participationId . '/' . $ticketFileName;
$barcodeFileName = $participationId . '-code-barre.' . $barcode->extension();
$barcode->move(public_path('fichiers/preuve-de-gain/' . $participationId . '/'), $barcodeFileName);
$barcodePath = public_path() . '/fichiers/preuve-de-gain/' . $participationId . '/' . $barcodeFileName;
$participation->sticker = $stickerFileName;
$participation->ticket = $ticketFileName;
$participation->barcode = $barcodeFileName;
$participation->save();
/** @var \App\Models\Settings $settings */
$settings = app(Settings::class);
$mails = json_decode($settings->notification_emails);
foreach ($mails as $mail) {
Mail::to($mail->email)->send(new WinningProof(
$stickerPath,
$ticketPath,
$barcodePath,
$participation,
$user,
$settings
));
}
return view('front.basic.replay');
}
}

View file

@ -0,0 +1,101 @@
<?php
namespace App\Http\Controllers;
use App\Models\Settings;
use App\Models\Reduction;
class re7Controller extends Controller
{
/**
* index
* @return \Illuminate\View\View
*/
public function index()
{
return view('re7');
}
/**
* teaser
* @return \Illuminate\View\View
*/
public function teaser()
{
$settings = app(Settings::class)
->select('start_date', 'end_date', 'activated_teaser', 'teaser_end_activity')->first();
return view('front.basic.teaser', compact('settings'));
}
/**
* prizeMail
* @return \Illuminate\View\View
*/
public function prizeMail()
{
return view('front.basic.prize-mail');
}
/**
* reductionMail
* @return \Illuminate\View\View
*/
public function reductionMail()
{
return view('front.basic.reduction-mail');
}
/**
* br
* @return \Illuminate\View\View
*/
public function br()
{
$settings = app(Settings::class);
$coupon = $this->getRandomCoupon($settings);
$crmCoupon = new Reduction();
return view('front.basic.reduction', compact('coupon', 'crmCoupon'));
}
/**
* gain 1
* @return \Illuminate\View\View
*/
public function gain1()
{
return view('front.basic.gain1');
}
/**
* gain 2
* @return \Illuminate\View\View
*/
public function gain2()
{
return view('front.basic.gain2');
}
/**
* getRandomCoupon
* @param App\Models\Settings $settings
* @return string
*/
private function getRandomCoupon(Settings $settings)
{
$webCoupons = json_decode($settings->web_coupons);
if (count($webCoupons) > 1) {
$lots = [];
foreach ($webCoupons as $webCoupon) {
$lots[] = $webCoupon;
}
foreach ($lots as $lot) {
for ($i = 0; $i < $lot->percentage; $i++) {
$tmp[] = $lot;
}
}
shuffle($tmp);
return $tmp[0];
} else {
return $webCoupons[0];
}
}
}

View file

@ -11,13 +11,12 @@ class Kernel extends HttpKernel
*
* These middleware are run during every request to your application.
*
* @var array<int, 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,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
@ -26,23 +25,20 @@ class Kernel extends HttpKernel
/**
* The application's route middleware groups.
*
* @var array<string, array<int, string>>
* @var array
*/
protected $middlewareGroups = [
'web' => [
'htmlsanitize',
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\SecureHeaders::class,
\App\Http\Middleware\CheckThemeVersion::class
],
'api' => [
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
@ -52,20 +48,22 @@ class Kernel extends HttpKernel
*
* These middleware may be assigned to groups or used individually.
*
* @var array<string, string>
* @var array
*/
protected $routeMiddleware = [
'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,
'game-date' => \App\Http\Middleware\GameCheckDate::class,
'is-admin' => \App\Http\Middleware\isAdmin::class,
'is-super-admin' => \App\Http\Middleware\isSuperAdmin::class,
're7' => \App\Http\Middleware\re7Middleware::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'check-game-status' => \App\Http\Middleware\CheckGameStatus::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,
];
}

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
{
@ -14,26 +12,10 @@ class Authenticate extends Middleware
* @param \Illuminate\Http\Request $request
* @return string|null
*/
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;
if (! $request->expectsJson()) {
return route('login');
}
}
}
return route('fo.login');
}
return null;
}
}

View file

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

@ -1,38 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Models\Settings;
use Illuminate\Http\Request;
class CheckGameStatus
{
/**
* Handle an incoming request.
*
* * Check with game settings which page should be shown and redirect if needed.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
* @throws \RuntimeException If tha game has an unhandled state.
*/
public function handle(Request $request, \Closure $next)
{
/** @var \App\Models\Settings $settings */
$settings = app(Settings::class);
return match (true) {
// * End page
$settings->should_display_end_page => redirect()->route('fo.end'),
// * Teaser
$settings->should_display_teaser_page => redirect()->route('fo.teaser'),
// * Game is ended
$settings->game_has_ended => redirect($settings->redirect_close),
// * Game has started
$settings->game_has_begun => $next($request),
// * The game will begun, but has no teaser activated.
default => redirect($settings->redirect_close)
};
}
}

View file

@ -1,48 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
class CheckThemeVersion
{
/**
* 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
if (!app()->runningInConsole()) {
$appInfos = Cache::remember('composer', 84600, function () {
return json_decode(File::get(\app_path('../composer.json')));
});
// * Assert theme version does not diverge more than minor
$appVer = Str::of($appInfos->version)->explode('.');
$themeVer = Str::of(config('theme.version'))->explode('.');
if (
// * Major check
Arr::get($appVer, 0) !== Arr::get($themeVer, 0) or
// * Patch check
Arr::get($appVer, 1) !== Arr::get($themeVer, 1)
) {
Session::flash('warning', trans(
'Ce thème n\'a semble t-il pas été vérifié pour cette version du moteur'
));
}
}
return $next($request);
}
}

View file

@ -9,7 +9,8 @@ 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

@ -0,0 +1,40 @@
<?php
namespace App\Http\Middleware;
use App\Models\Settings;
use Closure;
class GameCheckDate
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
/** @var \App\Models\Settings $settings */
$settings = app(Settings::class);
// Check si le teaser est actif
if ($settings->start_date > now()) {
if ($settings->activated_teaser === 1 && $settings->teaser_end_activity > now()) {
return redirect()->route('teaser');
}
return redirect($settings->redirect_close);
}
// Check si le jeu est terminé
if ($settings->end_date < now()) {
if ($settings->activated_close_page === 1 && $settings->close_page_active_date > now()) {
return redirect()->route('end');
}
return redirect($settings->redirect_close);
}
return $next($request);
}
}

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,8 +2,9 @@
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
@ -11,31 +12,14 @@ 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 \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)->check()) {
switch ($guard) {
case 'frontend':
return \redirect()->route('fo.homepage');
case 'backend':
if (!$request->routeIs('bo.*')) {
continue 2;
}
return \redirect()->route('bo.dashboard');
default:
throw new \RuntimeException("Unhandled guard `{$guard}` .");
}
}
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
return $next($request);

View file

@ -1,97 +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
{
private $unwantedHeaderList = [
'X-Powered-By',
'Server',
];
public function handle(Request $request, Closure $next): Response
{
// * For Vite DEV
$host = \parse_url((string) \config('app.url'), \PHP_URL_HOST);
$viteDevOrigin = config('app.debug') && \is_string($host) && $host !== '' ? "https://{$host}:4443" : null;
$viteDevSocket = config('app.debug') && \is_string($host) && $host !== '' ? "wss://{$host}:4443" : null;
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;');
// Utilisation de array_filter pour ne pas inclure les valeurs null en production
$cspPolicies = [
"default-src 'none';",
"manifest-src 'self';",
"connect-src 'self' blob: " . implode(' ', array_filter([
$viteDevSocket,
$viteDevOrigin,
'https://yl.s-web.fr'
])) . ';',
"img-src 'self' data: blob: " . implode(' ', array_filter([
$viteDevOrigin,
])) . ';',
"object-src 'self';",
"frame-src 'self' " . implode(' ', [
'https://www.google.com/recaptcha/',
'https://recaptcha.google.com/recaptcha/',
'https://www.google.com/maps/'
]) . ';',
"font-src 'self' data: " . implode(' ', array_filter([
$viteDevOrigin,
'https://fonts.gstatic.com' // <-- Point-virgule retiré ici
])) . ';',
"style-src 'self' 'unsafe-inline' " . implode(' ', array_filter([
'https://cdnjs.cloudflare.com',
'https://fonts.googleapis.com',
'https://cdn.jsdelivr.net',
'https://use.fontawesome.com',
$viteDevOrigin,
])) . ';',
"script-src 'self' {$jsDev} " . implode(' ', array_filter([
'https:',
'blob:',
'https://www.googletagmanager.com',
'https://cdnjs.cloudflare.com',
"$scheme://www.google-analytics.com",
$viteDevOrigin,
])) . ';'
];
$response->headers->set(
'Content-Security-Policy',
implode(' ', $cspPolicies) . $reportUri
);
$response->headers->set('Feature-Policy', 'fullscreen \'self\';');
return $response;
}
private function removeUnwantedHeaders(array $headerList): void
{
foreach ($headerList as $header) {
header_remove($header);
}
}
}

View file

@ -9,10 +9,9 @@ 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

@ -9,7 +9,7 @@ class TrustHosts extends Middleware
/**
* Get the host patterns that should be trusted.
*
* @return array<int, string|null>
* @return array
*/
public function hosts()
{

View file

@ -2,7 +2,7 @@
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
@ -10,19 +10,14 @@ class TrustProxies extends Middleware
/**
* The trusted proxies for this application.
*
* @var array<int, string>|string|null
* @var array|string|null
*/
protected $proxies = '*';
protected $proxies;
/**
* The headers that should be used to detect proxies.
*
* @var integer
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}

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

@ -9,9 +9,8 @@ class VerifyCsrfToken extends Middleware
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
* @var array
*/
protected $except = [
'/csp-report'
];
}

View file

@ -0,0 +1,25 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class isAdmin
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$role = Auth::user()->role;
if ($role === 1 || $role === 2) {
return $next($request);
}
abort(404, "Cette page n'existe pas.");
}
}

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