Compare commits

..

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

124 changed files with 3943 additions and 7986 deletions

View file

@ -3,7 +3,6 @@ APP_ENV=local
APP_KEY= APP_KEY=
APP_DEBUG=true APP_DEBUG=true
APP_URL=http://localhost APP_URL=http://localhost
APP_DOMAIN=
LOG_CHANNEL=stack LOG_CHANNEL=stack
@ -38,6 +37,7 @@ CAFEL_PASSWORD=
MAIL_INVALID_CAFEL_DATA=equipe.web@ldc.fr MAIL_INVALID_CAFEL_DATA=equipe.web@ldc.fr
MAIL_INVALID_CAFEL_DATA_IMAGE=equipe.web@ldc.fr MAIL_INVALID_CAFEL_DATA_IMAGE=equipe.web@ldc.fr
MAIL_INVALID_XML=equipe.web@ldc.fr MAIL_INVALID_XML=equipe.web@ldc.fr
MAIL_LIST_SERVICEWEB=equipe.web@ldc.fr
## LDC WEB STATUS CHECKER ## LDC WEB STATUS CHECKER
LDC_STATUS_CHECKER_API_KEY="MY_KEY" LDC_STATUS_CHECKER_API_KEY="MY_KEY"
@ -45,9 +45,6 @@ LDC_STATUS_CHECKER_UUID="UUID_PROJECT"
## LDC WEB ADMIN SECURE ## LDC WEB ADMIN SECURE
LDC_WEB_API_KEY="MY_KEY" LDC_WEB_API_KEY="MY_KEY"
## GOOGLE ## GOOGLE
ANALYTICS_GOOGLE_ID= ANALYTICS_GOOGLE_ID=
# TERRE D'ACTION MODAL (YYYY-MM-DD)
TERRE_ACTION_START_DATE=
TERRE_ACTION_END_DATE=

1
.gitignore vendored
View file

@ -18,4 +18,3 @@ Homestead.json
Homestead.yaml Homestead.yaml
npm-debug.log npm-debug.log
yarn-error.log yarn-error.log
auth.json

View file

@ -1,12 +1,46 @@
include: image: $CI_REGISTRY/service-web-lab/ldc-web-images-docker/ldcweb-qa:php7.3-1.0
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'lint/lint7.3.yml'
- project: 'ldc-web/shared-ci'
ref: 'main'
file: 'security/security7.3.yml'
stages: 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

View file

@ -1,11 +0,0 @@
## Comportement constaté
## Comportement attendu
## Solution envisagée
## Étapes pour la reproduction du bug
*

View file

@ -1,7 +0,0 @@
## Présentation du besoin
## Implémentation
## Maquettes, documentations...

View file

@ -0,0 +1,79 @@
<?php
namespace App\Console\Commands;
/*
* Command Name: LDC Web Status Checker
* Description: Envoi des infos Serveur/Laravel vers LDC Web
* Version: 1.0
* Author: Vincent BRIDIER
* Author URI: vincent.bridier@ldc.fr
*/
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
class LDCWebStatusChecker extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ldcweb:statuschecker';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Envoi des infos Serveur/Laravel vers LDC Web';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$data = [];
$data['uuid'] = config('app.project_uuid');
// Sitemap.xml ?
if (file_exists(public_path() . '/sitemap.xml')) {
$data['sitemap'] = 'true';
} else {
$data['sitemap'] = 'false';
}
// Robots.txt ?
if (file_exists(public_path() . '/robots.txt')) {
$data['robots'] = 'true';
} else {
$data['robots'] = 'false';
}
// Check logs .
$data['logs'] = 0;
$patherror = storage_path('/logs');
$files = glob($patherror . '/laravel-*.log');
if (count($files) > 0) {
foreach ($files as $file) {
$data['logs'] = $data['logs'] + filesize($file);
}
}
$data['code']['version'] = app()->version();
try {
Http::post(
'https://ldc-web.s-web.test/api/status-checker',
['token' => 'CE8S52Qq7stf5k8frF4T', 'datas' => json_encode($data)]
);
} catch (\Exception $e) {
report($e);
}
return 0;
}
}

View file

@ -30,15 +30,14 @@ class Kernel extends ConsoleKernel
protected function schedule(Schedule $schedule) protected function schedule(Schedule $schedule)
{ {
// * Jobs cafel sur queue cafel // * Jobs cafel sur queue cafel
$schedule->job(CafelFoodJob::class, 'cafel')->onOneServer()->dailyAt('22h30'); $schedule->job(CafelFoodJob::class, 'cafel')->onOneServer()->everyThreeHours();
$schedule->job(CafelBeaVolJob::class, 'cafel')->onOneServer()->dailyAt('22h45'); $schedule->job(CafelBeaVolJob::class, 'cafel')->onOneServer()->everyThreeHours();
$schedule->job(CafelMepEggJob::class, 'cafel')->onOneServer()->dailyAt('23h00'); $schedule->job(CafelMepEggJob::class, 'cafel')->onOneServer()->everyThreeHours();
$schedule->job(CafelEggBreederJob::class, 'cafel')->onOneServer()->dailyAt('23h15'); $schedule->job(CafelEggBreederJob::class, 'cafel')->onOneServer()->everyThreeHours();
$schedule->job(CafelPoultryBreederJob::class, 'cafel')->onOneServer()->dailyAt('23h30'); $schedule->job(CafelPoultryBreederJob::class, 'cafel')->onOneServer()->everyThreeHours();
$schedule->job(XmlFluxEggJob::class, 'tracea')->onOneServer()->dailyAt('02:00'); $schedule->job(XmlFluxEggJob::class, 'tracea')->onOneServer()->dailyAt('02:00');
$schedule->job(XmlFluxPoultryJob::class, 'tracea')->onOneServer()->dailyAt('22:00'); $schedule->job(XmlFluxPoultryJob::class, 'tracea')->onOneServer()->dailyAt('22:00');
$schedule->command('xml:clean_olds')->onOneServer()->dailyAt('06:00');
} }
/** /**

View file

@ -4,8 +4,8 @@ namespace App\Exceptions;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Throwable;
use Sentry\Laravel\Integration; use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
{ {
@ -27,19 +27,18 @@ class Handler extends ExceptionHandler
]; ];
/** /**
* Register the exception handling callbacks for the application. * Report or log an exception.
* *
* @param \Throwable $exception
* @return void * @return void
*/ */
public function register() public function report(Throwable $exception)
{ {
$this->reportable(function (\Throwable $e) { if ($exception instanceof CafelApiImageFetchException) {
if ($e instanceof CafelApiImageFetchException) { $this->reportCafelApiImageErrorException($exception);
$this->reportCafelApiImageErrorException($e);
return; return;
} }
Integration::captureUnhandledException($e); parent::report($exception);
});
} }
/** /**

View file

@ -27,7 +27,7 @@ class EggController extends Controller
$month = $date[1]; $month = $date[1];
$moba = TraceaEgg::where('ede_code', '=', $code) $moba = TraceaEgg::where('ede_code', '=', $code)
->where('dcr', Carbon::createFromDate(null, $month, $day)->format('Y-m-d')) ->whereDate('dcr', Carbon::createFromDate(null, $month, $day)->toDate())
->orderBy('box_code', 'DESC')->first(); ->orderBy('box_code', 'DESC')->first();
if (!$moba) { if (!$moba) {
@ -49,7 +49,7 @@ class EggController extends Controller
$mobas = TraceaEgg::where('box_code', $id)->orderBy('box_code', 'DESC')->first(); $mobas = TraceaEgg::where('box_code', $id)->orderBy('box_code', 'DESC')->first();
if (!$mobas) { if (!$mobas) {
return redirect()->route('egg.search'); return redirect('/search');
} }
$edes = $mobas->code_edes; $edes = $mobas->code_edes;
@ -84,11 +84,8 @@ class EggController extends Controller
$inuavs = $eleveurs->pluck('inuavs')->flatten(1); $inuavs = $eleveurs->pluck('inuavs')->flatten(1);
$mep = CafelEggMiseEnPlace::query(); $mep = CafelEggMiseEnPlace::whereIn('inuav_code', $inuavs)
collect($inuavs)->map(function ($inuav) use ($mep) { ->where('transfert_date', '<', $datePonte)
$mep->where('inuav_codes', 'LIKE', "%{$inuav}%");
});
$mep = $mep->where('transfert_date', '<', $datePonte)
->orderBy('transfert_date', 'DESC')->first(); ->orderBy('transfert_date', 'DESC')->first();
if ($mep) { if ($mep) {

View file

@ -70,8 +70,8 @@ class TraceaPoultryController extends Controller
\redirect()->route('poultry.search')->throwResponse(); \redirect()->route('poultry.search')->throwResponse();
} }
// ! Test that breeder, food and mep are available // ! Test that food and mep are available
if (!$traceaPoultry->mep or !$traceaPoultry->food or !$traceaPoultry->breeder) { if (!$traceaPoultry->mep or !$traceaPoultry->food) {
return \view('front.poultry.unavailable'); return \view('front.poultry.unavailable');
} }

View file

@ -14,7 +14,6 @@ class TrustHosts extends Middleware
public function hosts() public function hosts()
{ {
return [ return [
\config('app.egg_domain'),
$this->allSubdomainsOfApplicationUrl(), $this->allSubdomainsOfApplicationUrl(),
]; ];
} }

View file

@ -23,7 +23,7 @@ class RemoveOldXmlEntries
} }
try { try {
$q = TraceaEgg::query(); $q = TraceaEgg::query();
$q->where('dcr', '<=', now()->subMonths(config('tracea.keepEggMonths', 12))); $q->where('dcr', '<=', now()->subMonths(config('tracea.keepEggMonths', 12)))->destroy();
$q->delete(); $q->delete();
} catch (\Exception $e) { } catch (\Exception $e) {
report($e); report($e);

View file

@ -11,7 +11,6 @@ use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
abstract class XmlJobs extends XArcadiaFlux abstract class XmlJobs extends XArcadiaFlux
{ {
@ -175,25 +174,7 @@ abstract class XmlJobs extends XArcadiaFlux
), ),
LogType::critical() LogType::critical()
); );
$this->sendInvalidXmlEmail( $this->sendInvalidXmlEmail($filename, $e);
$filename,
$e->getPrevious()->getMessage(),
$e->getPrevious()
);
$this->moveToInvalid($filename);
continue;
} catch (ValidationException $e) {
$message = $e->getMessage();
$this->log(
sprintf(
'File %s could not be parsed => %s on line %d',
$filename,
$message,
$e->getLine()
),
LogType::critical()
);
$this->sendInvalidXmlEmail($filename, $e->getMessage(), $e);
$this->moveToInvalid($filename); $this->moveToInvalid($filename);
continue; continue;
} catch (AbortXmlImportException $e) { } catch (AbortXmlImportException $e) {
@ -206,8 +187,6 @@ abstract class XmlJobs extends XArcadiaFlux
), ),
LogType::error() LogType::error()
); );
$this->sendInvalidXmlEmail($filename, $e->getMessage(), $e);
$this->moveToInvalid($filename);
report($e); report($e);
continue; continue;
// * ignore the file // * ignore the file
@ -386,12 +365,12 @@ abstract class XmlJobs extends XArcadiaFlux
* Send invalid XML email * Send invalid XML email
* *
* @param string $filename * @param string $filename
* @param string $message
* @param \Throwable $e * @param \Throwable $e
* @return void * @return void
*/ */
protected function sendInvalidXmlEmail(string $filename, string $message, \Throwable $e) protected function sendInvalidXmlEmail(string $filename, \Throwable $e)
{ {
$message = $e->getPrevious()->getMessage();
Mail::send('mails.invalidxml', [ Mail::send('mails.invalidxml', [
'strError' => sprintf( 'strError' => sprintf(
'File %s could not be parsed => %s on line %d', 'File %s could not be parsed => %s on line %d',
@ -400,7 +379,7 @@ abstract class XmlJobs extends XArcadiaFlux
$e->getLine() $e->getLine()
), ),
'filename' => $filename, 'filename' => $filename,
'exception' => $e 'exception' => $e->getPrevious()
], function ($m) { ], function ($m) {
$m->to( $m->to(
config('mail.contactsList.invalidXml'), config('mail.contactsList.invalidXml'),

View file

@ -5,9 +5,7 @@ namespace App\Jobs;
use App\Exceptions\CafelApiException; use App\Exceptions\CafelApiException;
use App\Exceptions\CafelApiImageFetchException; use App\Exceptions\CafelApiImageFetchException;
use App\Lib\CafelApi\Models\CafelEggBreeder as ApiCafelEggBreeder; use App\Lib\CafelApi\Models\CafelEggBreeder as ApiCafelEggBreeder;
use App\Lib\ToolboxHelper;
use App\Models\CafelEggBreeder; use App\Models\CafelEggBreeder;
use Illuminate\Validation\ValidationException;
class CafelEggBreederJob extends CafelJobs class CafelEggBreederJob extends CafelJobs
{ {
@ -18,16 +16,6 @@ class CafelEggBreederJob extends CafelJobs
*/ */
public function handle() public function handle()
{ {
// ! We have to remove all breeders to reimport them all in order to make sure
// ! to delete breeders that dont exists anymore (Api fetch constrain)
// ! vu avec Sylvain 27/10/2022
// * Destroy breeder one by one to trigger destroy event
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\CafelEggBreeder> */
$eggBreeders = CafelEggBreeder::all();
$eggBreeders->each(function (CafelEggBreeder $breeder) {
$breeder->deleteOrFail();
});
$this->syncWithCafelApi( $this->syncWithCafelApi(
ApiCafelEggBreeder::class, ApiCafelEggBreeder::class,
'cafel.ldc.eleveursoeufs', 'cafel.ldc.eleveursoeufs',
@ -53,23 +41,8 @@ class CafelEggBreederJob extends CafelJobs
) : null; ) : null;
} catch (CafelApiImageFetchException | CafelApiException $e) { } catch (CafelApiImageFetchException | CafelApiException $e) {
report($e); report($e);
$validationException = ValidationException::withMessages([ $row['path_picture_1'] = null;
'path_picture_1' => $e->getMessage() }
]);
ToolboxHelper::useReflectionToUpdateProperty(
$validationException->validator,
'data',
['path_picture_1' => $row['path_picture_1']]
);
ToolboxHelper::useReflectionToUpdateProperty(
$validationException->validator,
'failedRules',
['path_picture_1' => $e->getMessage()]
);
throw $validationException;
}//end try
try { try {
$row['path_picture_2'] = !empty($row['path_picture_2']) ? $row['path_picture_2'] = !empty($row['path_picture_2']) ?
ApiCafelEggBreeder::fetchPicture( ApiCafelEggBreeder::fetchPicture(
@ -78,23 +51,8 @@ class CafelEggBreederJob extends CafelJobs
) : null; ) : null;
} catch (CafelApiImageFetchException | CafelApiException $e) { } catch (CafelApiImageFetchException | CafelApiException $e) {
report($e); report($e);
$validationException = ValidationException::withMessages([ $row['path_picture_2'] = null;
'path_picture_2' => $e->getMessage() }
]);
ToolboxHelper::useReflectionToUpdateProperty(
$validationException->validator,
'data',
['path_picture_2' => $row['path_picture_2']]
);
ToolboxHelper::useReflectionToUpdateProperty(
$validationException->validator,
'failedRules',
['path_picture_2' => $e->getMessage()]
);
throw $validationException;
}//end try
foreach (['exploitation', 'aboutyou', 'vocation', 'likeinjob', 'loue_means'] as $fieldName) { foreach (['exploitation', 'aboutyou', 'vocation', 'likeinjob', 'loue_means'] as $fieldName) {
$row[$fieldName] = !empty($row[$fieldName]) ? $row[$fieldName] : null; $row[$fieldName] = !empty($row[$fieldName]) ? $row[$fieldName] : null;

View file

@ -3,8 +3,6 @@
namespace App\Jobs; namespace App\Jobs;
use App\Lib\CafelApi\Models\CafelClientModel; use App\Lib\CafelApi\Models\CafelClientModel;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
@ -72,26 +70,12 @@ abstract class CafelJobs implements ShouldQueue
try { try {
$saveCallback($row); $saveCallback($row);
} catch (ValidationException $e) { } catch (ValidationException $e) {
/** @var \Illuminate\Validation\Validator $validator */
$validator = $e->validator;
/** @var array<string,integer|string> */
$failed = $validator->invalid();
$this->invalidRows[] = collect($row)->put('validation_message', collect($e->errors()) $this->invalidRows[] = collect($row)->put('validation_message', collect($e->errors())
->mapWithKeys(function (array $messages, string $attribute) use ($failed) { ->mapWithKeys(function (array $messages, string $attribute) {
$verifiedValue = ''; return [$attribute => collect($messages)->implode(', ')];
if (array_key_exists($attribute, $failed)) {
$verifiedValue = ' Valeur vérifiée : ' . \json_encode($failed[$attribute]);
}
return [
$attribute => collect($messages)->implode(', ') . $verifiedValue
];
})->implode(' '))->all(); })->implode(' '))->all();
} catch (ConnectException | RequestException $e) { }
// ! Guzzle SSL Error connection failure }
\report($e);
$this->invalidRows[] = collect($row)->put('validation_message', $e->getMessage())->all();
}//end try
}//end foreach
} while (!empty($result)); } while (!empty($result));
} }

View file

@ -23,11 +23,6 @@ class CafelMepEggJob extends CafelJobs
'dateFin' => now()->format('Y-m-d') 'dateFin' => now()->format('Y-m-d')
], ],
function (array $row) { function (array $row) {
// * Explode inuav
if (\array_key_exists('inuav_codes', $row)) {
$row['inuav_codes'] = explode(',', $row['inuav_codes']);
}
// * Validate row data // * Validate row data
CafelMepEgg::validateDataRow($row); CafelMepEgg::validateDataRow($row);

View file

@ -17,17 +17,12 @@ class CafelMepPoultryJob extends CafelJobs
$dateDebut = now()->subDays(config('cafel.mises_en_places_retain', 370)); $dateDebut = now()->subDays(config('cafel.mises_en_places_retain', 370));
$this->syncWithCafelApi( $this->syncWithCafelApi(
CafelMepPoultry::class, CafelMepPoultry::class,
'cafel.ldc.mepvolailles', 'cafel.ldc.mepoeufs',
[ [
'dateDebut' => $dateDebut->format('Y-m-d'), 'dateDebut' => $dateDebut->format('Y-m-d'),
'dateFin' => now()->format('Y-m-d') 'dateFin' => now()->format('Y-m-d')
], ],
function (array $row) { function (array $row) {
// * Explode inuav
if (\array_key_exists('inuav_codes', $row)) {
$row['inuav_codes'] = explode(',', $row['inuav_codes']);
}
// * Validate row data // * Validate row data
CafelMepPoultry::validateDataRow($row); CafelMepPoultry::validateDataRow($row);

View file

@ -5,9 +5,7 @@ namespace App\Jobs;
use App\Exceptions\CafelApiException; use App\Exceptions\CafelApiException;
use App\Exceptions\CafelApiImageFetchException; use App\Exceptions\CafelApiImageFetchException;
use App\Lib\CafelApi\Models\CafelPoultryBreeder as ApiCafelPoultryBreeder; use App\Lib\CafelApi\Models\CafelPoultryBreeder as ApiCafelPoultryBreeder;
use App\Lib\ToolboxHelper;
use App\Models\CafelPoultryBreeder; use App\Models\CafelPoultryBreeder;
use Illuminate\Validation\ValidationException;
class CafelPoultryBreederJob extends CafelJobs class CafelPoultryBreederJob extends CafelJobs
{ {
@ -18,16 +16,6 @@ class CafelPoultryBreederJob extends CafelJobs
*/ */
public function handle() public function handle()
{ {
// ! We have to remove all breeders to reimport them all in order to make sure
// ! to delete breeders that dont exists anymore (Api fetch constrain)
// ! vu avec Sylvain 27/10/2022
// * Destroy breeder one by one to trigger destroy event
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\CafelEggBreeder> */
$poultryBreeders = CafelPoultryBreeder::all();
$poultryBreeders->each(function (CafelPoultryBreeder $breeder) {
$breeder->deleteOrFail();
});
$this->syncWithCafelApi( $this->syncWithCafelApi(
ApiCafelPoultryBreeder::class, ApiCafelPoultryBreeder::class,
'cafel.ldc.eleveursvolailles', 'cafel.ldc.eleveursvolailles',
@ -53,23 +41,8 @@ class CafelPoultryBreederJob extends CafelJobs
) : null; ) : null;
} catch (CafelApiImageFetchException | CafelApiException $e) { } catch (CafelApiImageFetchException | CafelApiException $e) {
report($e); report($e);
$validationException = ValidationException::withMessages([ $row['path_picture_1'] = null;
'path_picture_1' => $e->getMessage() }
]);
ToolboxHelper::useReflectionToUpdateProperty(
$validationException->validator,
'data',
['path_picture_1' => $row['path_picture_1']]
);
ToolboxHelper::useReflectionToUpdateProperty(
$validationException->validator,
'failedRules',
['path_picture_1' => $e->getMessage()]
);
throw $validationException;
}//end try
try { try {
$row['path_picture_2'] = !empty($row['path_picture_2']) ? $row['path_picture_2'] = !empty($row['path_picture_2']) ?
ApiCafelPoultryBreeder::fetchPicture( ApiCafelPoultryBreeder::fetchPicture(
@ -78,23 +51,8 @@ class CafelPoultryBreederJob extends CafelJobs
) : null; ) : null;
} catch (CafelApiImageFetchException | CafelApiException $e) { } catch (CafelApiImageFetchException | CafelApiException $e) {
report($e); report($e);
$validationException = ValidationException::withMessages([ $row['path_picture_2'] = null;
'path_picture_2' => $e->getMessage() }
]);
ToolboxHelper::useReflectionToUpdateProperty(
$validationException->validator,
'data',
['path_picture_2' => $row['path_picture_2']]
);
ToolboxHelper::useReflectionToUpdateProperty(
$validationException->validator,
'failedRules',
['path_picture_2' => $e->getMessage()]
);
throw $validationException;
}//end try
foreach (['issue_1', 'issue_2'] as $fieldName) { foreach (['issue_1', 'issue_2'] as $fieldName) {
$row[$fieldName] = !empty($row[$fieldName]) ? $row[$fieldName] : null; $row[$fieldName] = !empty($row[$fieldName]) ? $row[$fieldName] : null;

View file

@ -25,11 +25,7 @@ abstract class CafelBeaVol extends CafelClientModel
// Eg Score A . // Eg Score A .
'bea_code' => 'required|string|min:2|max:10', 'bea_code' => 'required|string|min:2|max:10',
// Eg 19377/0 . // Eg 19377/0 .
'batch_code' => [ 'batch_code' => 'required|max:10|regex:/^[0-9A-Z]*\/\d$/',
'required',
'max:10',
'regex:/^[0-9A-Z]+\/(?:\d|[A-Z])$/',
],
'last_audit_date' => 'required|date_format:Y-m-d' 'last_audit_date' => 'required|date_format:Y-m-d'
]; ];

View file

@ -125,7 +125,7 @@ abstract class CafelClientModel implements \JsonSerializable
* @return array * @return array
* @throws \Illuminate\Validation\ValidationException If data does not validate. * @throws \Illuminate\Validation\ValidationException If data does not validate.
*/ */
protected static function validateData(array $data, array $rules): array protected function validateData(array $data, array $rules): array
{ {
return Validator::validate($data, $rules); return Validator::validate($data, $rules);
} }
@ -228,25 +228,15 @@ abstract class CafelClientModel implements \JsonSerializable
// * Filter Keys using intersection // * Filter Keys using intersection
\extract(\array_intersect_key($response->body, ['Ext' => '', 'Name' => '', 'Data' => ''])); \extract(\array_intersect_key($response->body, ['Ext' => '', 'Name' => '', 'Data' => '']));
// * Create temp file and get its absolute path
if (!($tempFile = tmpfile())) {
new \RuntimeException('Could not create temp file');
}
$filePath = ToolboxHelper::storeImage( return ToolboxHelper::storeImage(
$folder, $folder,
FileHelper::fromBase64( FileHelper::fromBase64(
$tempFile,
Str::lower($Name), Str::lower($Name),
Str::lower($Ext), Str::lower($Ext),
$Data $Data
), ),
false false
); );
// * Closing the file will cause to remove it from temp dir!
fclose($tempFile);
return $filePath;
} }
} }

View file

@ -17,7 +17,7 @@ abstract class CafelEggBreeder extends CafelClientModel
* @var array * @var array
*/ */
public const UNIQUE_COLUMN_KEYS = [ public const UNIQUE_COLUMN_KEYS = [
'cafel_code', 'ede_code' 'cafel_code'
]; ];
/** /**
@ -43,7 +43,7 @@ abstract class CafelEggBreeder extends CafelClientModel
* 2 chiffres qui représentent le numéro d’ordre de chaque atelier dans une même exploitation * 2 chiffres qui représentent le numéro d’ordre de chaque atelier dans une même exploitation
* eg : 1FRZFC01 * eg : 1FRZFC01
*/ */
'ede_code' => 'required|regex:/^[0-3][A-Z]{5}\d\d$/', 'ede_code' => 'required|regex:/[0-3][A-Z]{5}\d\d/',
// Valeurs possibles pour civility : 1 M, 2 MME, 3 EUX, 4 ELLES . // Valeurs possibles pour civility : 1 M, 2 MME, 3 EUX, 4 ELLES .
'civility' => ['required', [EnumIsValidRule::class, BreederCivilty::class]], 'civility' => ['required', [EnumIsValidRule::class, BreederCivilty::class]],
'lastname' => 'required|string|min:1|max:255', 'lastname' => 'required|string|min:1|max:255',

View file

@ -28,11 +28,7 @@ abstract class CafelFood extends CafelClientModel
// 1 Pondeuse ou 2 Poulet . // 1 Pondeuse ou 2 Poulet .
'food_type' => ['required', [EnumIsValidRule::class, FoodType::class]], 'food_type' => ['required', [EnumIsValidRule::class, FoodType::class]],
// Eg 19377/0 . // Eg 19377/0 .
'batch_code' => [ 'batch_code' => 'required|max:10|regex:/^[0-9A-Z]*\/\d$/',
'required',
'max:10',
'regex:/^[0-9A-Z]+\/(?:\d|[A-Z])$/',
],
'delivery_date' => 'required|date_format:Y-m-d' 'delivery_date' => 'required|date_format:Y-m-d'
]; ];

View file

@ -22,16 +22,10 @@ abstract class CafelMepEgg extends CafelClientModel
* @var array * @var array
*/ */
protected static $validationRules = [ protected static $validationRules = [
// Eg V072FXT (un seul ou plusieurs separe par une virgule).
'inuav_codes' => 'required|array',
// Eg V072FXT (un seul par ligne). // Eg V072FXT (un seul par ligne).
'inuav_codes.*' => 'required|string|regex:/^[A-Z]\d{3}[A-Z]{3}$/', 'inuav_code' => 'required|string|regex:/^[A-Z]\d{3}[A-Z]{3}$/',
// Eg 19377/0 . // Eg 19377/0 .
'batch_code' => [ 'batch_code' => 'required|max:10|regex:/^[0-9A-Z]*\/\d$/',
'required',
'max:10',
'regex:/^[0-9A-Z]+\/(?:\d|[A-Z])$/',
],
'transfert_date' => 'required|date_format:Y-m-d' 'transfert_date' => 'required|date_format:Y-m-d'
]; ];
@ -41,7 +35,7 @@ abstract class CafelMepEgg extends CafelClientModel
* @var array * @var array
*/ */
protected static $columnsTranslations = [ protected static $columnsTranslations = [
'Inuav_code' => 'inuav_codes', 'Inuav_code' => 'inuav_code',
'Batch_code' => 'batch_code', 'Batch_code' => 'batch_code',
'Transfert_date' => 'transfert_date' 'Transfert_date' => 'transfert_date'
]; ];

View file

@ -22,16 +22,10 @@ abstract class CafelMepPoultry extends CafelClientModel
* @var array * @var array
*/ */
protected static $validationRules = [ protected static $validationRules = [
// Eg V072FXT (un seul ou plusieurs separe par une virgule).
'inuav_codes' => 'required|array',
// Eg V072FXT (un seul par ligne). // Eg V072FXT (un seul par ligne).
'inuav_codes.*' => 'required|string|regex:/^[A-Z]\d{3}[A-Z]{3}$/', 'inuav_code' => 'required|string|regex:/^[A-Z]\d{3}[A-Z]{3}$/',
// Eg 19377/0 . // Eg 19377/0 .
'batch_code' => [ 'batch_code' => 'required|max:10|regex:/^[0-9A-Z]*\/\d$/',
'required',
'max:10',
'regex:/^[0-9A-Z]+\/(?:\d|[A-Z])$/',
],
'transfert_date' => 'required|date_format:Y-m-d' 'transfert_date' => 'required|date_format:Y-m-d'
]; ];
@ -41,7 +35,7 @@ abstract class CafelMepPoultry extends CafelClientModel
* @var array * @var array
*/ */
protected static $columnsTranslations = [ protected static $columnsTranslations = [
'Inuav_code' => 'inuav_codes', 'Inuav_code' => 'inuav_code',
'Batch_code' => 'batch_code', 'Batch_code' => 'batch_code',
'Transfert_date' => 'transfert_date' 'Transfert_date' => 'transfert_date'
]; ];

View file

@ -105,7 +105,7 @@ class ApiInterface
* *
* @param \App\Lib\CafelApi\Transport\Request $request * @param \App\Lib\CafelApi\Transport\Request $request
* @return \App\Lib\CafelApi\Transport\Response * @return \App\Lib\CafelApi\Transport\Response
* @throws \App\Exceptions\CafelApiException If reponse status is KO or not Json. * @throws \App\Exceptions\CafelApiException If reponse status is KO.
*/ */
public function call(Request $request): Response public function call(Request $request): Response
{ {
@ -122,9 +122,8 @@ class ApiInterface
/** /**
* Process request * Process request
* *
* @param \App\Lib\CafelApi\Transport\Request $request * @param Request $request
* @return \App\Lib\CafelApi\Transport\Response * @return Response
* @throws \App\Exceptions\CafelApiException If HTTP response body in not JSON.
*/ */
private function processRequest(Request $request): Response private function processRequest(Request $request): Response
{ {
@ -137,13 +136,13 @@ class ApiInterface
$status = in_array($response->getStatusCode(), [200, 201]) ? $status = in_array($response->getStatusCode(), [200, 201]) ?
ApiStatus::OK() : ApiStatus::KO(); ApiStatus::OK() : ApiStatus::KO();
return new Response($status, $response, $request); return new Response($status, $response);
} }
/** /**
* Add spécific headers to the request * Add spécific headers to the request
* *
* @param \App\Lib\CafelApi\Transport\Request $request * @param Request $request
* @return void * @return void
*/ */
private function setHeaders(Request &$request): void private function setHeaders(Request &$request): void

View file

@ -56,10 +56,9 @@ class Response
* *
* @param \App\Enums\ApiStatus $status * @param \App\Enums\ApiStatus $status
* @param \Psr\Http\Message\ResponseInterface $response * @param \Psr\Http\Message\ResponseInterface $response
* @param \App\Lib\CafelApi\Transport\Request $request
* @throws \App\Exceptions\CafelApiException If HTTP response body in not JSON. * @throws \App\Exceptions\CafelApiException If HTTP response body in not JSON.
*/ */
public function __construct(ApiStatus $status, ResponseInterface $response, Request $request) public function __construct(ApiStatus $status, ResponseInterface $response)
{ {
$this->response = $response; $this->response = $response;
$this->status = $status; $this->status = $status;
@ -75,18 +74,9 @@ class Response
// * Body should be json data. // * Body should be json data.
if (($decodedJson = $this->tryDecodeJson($this->body->getContents())) === false) { if (($decodedJson = $this->tryDecodeJson($this->body->getContents())) === false) {
if (in_array(config('app.env'), ['testing', 'local'])) { if (in_array(config('app.env'), ['testing', 'local'])) {
dump( dump((string)$this->body);
'should have been json',
$this->httpCode,
$this->status,
$this->headers,
$request->uri,
(string)$this->body
);
} }
throw new CafelApiException( throw new CafelApiException('The Api should have returned JSON data');
"The Api should have returned JSON data '{$request->uri}'"
);
} }
$this->body = $decodedJson; $this->body = $decodedJson;

View file

@ -1,190 +0,0 @@
<?php
namespace App\Lib;
class ExceptionsHelper
{
/**
* Handle sentry event
*
* @param \Sentry\Event $event
* @return null|\Sentry\Event
*/
public static function sentryEventHandler(\Sentry\Event $event): ?\Sentry\Event
{
// Remove unwanted reports.
$event->setModules([]);
$event->setOsContext(null);
/** @var \Sentry\ExceptionDataBag[] */
$exceptionBag = [];
foreach ($event->getExceptions() as $exceptionDataBag) {
$exceptionBag[] = self::getAnonymizedSentryException($exceptionDataBag);
}
$event->setExceptions($exceptionBag);
return $event;
}
/**
* Anonimize Sentry Exception bag
*
* @param \Sentry\ExceptionDataBag $exceptionDataBag
* @return \Sentry\ExceptionDataBag
*/
private static function getAnonymizedSentryException(
\Sentry\ExceptionDataBag $exceptionDataBag
): \Sentry\ExceptionDataBag {
$exceptionDataBag->setValue(self::getAnonymizedMessage($exceptionDataBag->getValue()));
if ($stackTrace = $exceptionDataBag->getStacktrace()) {
$exceptionDataBag->setStacktrace(self::getAnonymizedSentryStackTrace($stackTrace));
}
return $exceptionDataBag;
}
/**
* Anonymise sentry stacktrace
*
* @param \Sentry\Stacktrace $stackTrace
* @return \Sentry\Stacktrace
*/
private static function getAnonymizedSentryStackTrace(\Sentry\Stacktrace $stackTrace): \Sentry\Stacktrace
{
/** @var \Sentry\Frame[] */
$frames = \array_reverse($stackTrace->getFrames(), true);
$i = \count($frames) - 1;
// * Remove all but keep first (index.php).
while ($i-- > 0) {
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
}
foreach ($frames as $index => $frame) {
$frame->setPostContext([]);
$frame->setPreContext([]);
$frame->setContextLine('');
$frame->setVars(self::getAnonymizedSentryParams($frame->getVars()));
$stackTrace->addFrame($frame);
if ($index === 0) {
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
}
}
return $stackTrace;
}
/**
* Get anonymized sentry params
*
* @param mixed[] $params
* @return string[]
*/
private static function getAnonymizedSentryParams(array $params): array
{
foreach ($params as &$param) {
$type = \strtolower(\gettype($param));
if (\is_string($param)) {
$type = \explode(' ', \trim($param))[0] ?? null;
}
switch ($type) {
case 'Lambda':
case 'Object':
continue 2;
case 'array':
$param = sprintf('Array(%d)', \count($param));
continue 2;
default:
if (\is_numeric($param)) {
$param = \ucfirst($type);
continue 2;
}
if (\is_string($param)) {
$param = sprintf('String(%d)', \strlen($param));
continue 2;
}
} //end switch
} //end foreach
return $params;
}
/**
* Anonymize at least Sql queries
*
* @param string $message
* @return string
*/
public static function getAnonymizedMessage(string $message): string
{
$message = \preg_replace('/^(.*)( \(SQL:.*\))$/', '$1', $message) ?? $message;
if ($sqlPos = \strpos($message, 'to use near')) {
$message = \mb_strcut($message, 0, $sqlPos);
}
return $message;
}
/**
* Anonymize stack trace
*
* @param \Throwable $e
* @return string
*/
public static function getAnonymizedStackTrace(\Throwable $e): string
{
$projectPath = \realpath(\sprintf('%s/../', \app_path()));
$traceStack = $e->getTrace();
$traceStr = '';
$maxStackStage = 0;
foreach ($traceStack as $stackStage => $stack) {
$maxStackStage = $stackStage;
$traceStr .= \sprintf(
'#%s %s(%d): ',
$stackStage,
str_replace($projectPath, '', $stack['file'] ?? ''),
$stack['line'] ?? ''
);
if (isset($stack['class'])) {
$traceStr .= "{$stack['class']}->{$stack['function']}(";
if (isset($stack['args'])) {
$traceStr .= self::handleArgs($stack);
}
$traceStr .= ")\n";
} elseif (isset($stack['function'])) {
$traceStr .= "{$stack['function']}(";
if (isset($stack['args'])) {
$traceStr .= self::handleArgs($stack);
}
$traceStr .= ")\n";
}
} //end foreach
$maxStackStage++;
$traceStr .= "#$maxStackStage {main}";
return $traceStr;
}
/**
* Handle Args
*
* @param array $stack
* @return string
*/
public static function handleArgs(array $stack): string
{
$traceArgs = '';
$argsCount = count($stack['args']);
for ($i = 0; $i < $argsCount; $i++) {
$type = \gettype($stack['args'][$i]);
switch ($type) {
case 'object':
$traceArgs .= sprintf('Object(%s)', \get_class($stack['args'][$i]));
break;
case 'array':
$traceArgs .= sprintf('Array(%d)', \count($stack['args'][$i]));
break;
case 'string':
$traceArgs .= sprintf('String(%d)', \strlen($stack['args'][$i]));
break;
default:
$traceArgs .= \gettype($stack['args'][$i]);
}
$traceArgs .= ($i !== ($argsCount - 1) ? ',' : '');
}
return $traceArgs;
}
}

View file

@ -51,18 +51,21 @@ class FileHelper
} }
/** /**
* Generate from base64 blob * Generate from blob
* *
* @param resource $tempFile A temp file where to store data. * @param string $fileName
* @param string $fileName The target filename. * @param string $extension
* @param string $extension The file extension to use. * @param string $base64String
* @param string $base64String The base64 encode picture.
* @return SplFileInfo * @return SplFileInfo
* @throws \ErrorException If writing to temp file failed. * @throws \ErrorException If writing to temp file failed.
* @throws \App\Exceptions\CafelApiImageFetchException If invalid image was given or ext could not be confirmed. * @throws \App\Exceptions\CafelApiImageFetchException If invalid image was given or ext could not be confirmed.
*/ */
public static function fromBase64($tempFile, string $fileName, string $extension, string $base64String): SplFileInfo public static function fromBase64(string $fileName, string $extension, string $base64String): SplFileInfo
{ {
// * Create temp file and get its absolute path
if (!($tempFile = tmpfile())) {
new \ErrorException('Could not create temp file');
}
$tempFilePath = stream_get_meta_data($tempFile)['uri']; $tempFilePath = stream_get_meta_data($tempFile)['uri'];
if (!($blob = \base64_decode($base64String, true))) { if (!($blob = \base64_decode($base64String, true))) {
@ -90,6 +93,12 @@ class FileHelper
throw new \ErrorException('Could not write on temp file'); throw new \ErrorException('Could not write on temp file');
} }
// Close this file after response is sent.
// Closing the file will cause to remove it from temp director!
app()->terminating(function () use ($tempFile) {
fclose($tempFile);
});
return new SplFileInfo(\storage_path("tmp/$filePath.$extension")); return new SplFileInfo(\storage_path("tmp/$filePath.$extension"));
} }
} }

View file

@ -12,23 +12,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
abstract class ToolboxHelper abstract class ToolboxHelper
{ {
/**
* Update any prop using reflexion
*
* @param object $object
* @param string $property
* @param mixed $value
* @return void
* @throws \ReflectionException If the class or property does not exist.
*/
public static function useReflectionToUpdateProperty(object &$object, string $property, $value)
{
$refProperty = new \ReflectionProperty(\get_class($object), $property);
$refProperty->setAccessible(true);
$refProperty->setValue($object, $value);
$refProperty->setAccessible(false);
}
/** /**
* Store an image of different types * Store an image of different types
* *

View file

@ -5,8 +5,6 @@ namespace App\Models;
use App\Enums\BreederCivilty; use App\Enums\BreederCivilty;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
use Kwaadpepper\Enum\Traits\CastsEnums; use Kwaadpepper\Enum\Traits\CastsEnums;
@ -99,8 +97,7 @@ class CafelEggBreeder extends Model
{ {
// * EVENT CLOSURES. // * EVENT CLOSURES.
static::creating(function (self $model) { static::creating(function (self $model) {
self::areInuavCodesUniques($model); return self::areInuavCodesUniques($model);
self::isEdeCodeUnique($model);
}); });
static::updating(function (self $model) { static::updating(function (self $model) {
if ($model->getRawOriginal('path_picture_1') !== $model->path_picture_1) { if ($model->getRawOriginal('path_picture_1') !== $model->path_picture_1) {
@ -109,16 +106,7 @@ class CafelEggBreeder extends Model
if ($model->getRawOriginal('path_picture_2') !== $model->path_picture_2) { if ($model->getRawOriginal('path_picture_2') !== $model->path_picture_2) {
Storage::delete(\public_path($model->getRawOriginal('path_picture_2'))); Storage::delete(\public_path($model->getRawOriginal('path_picture_2')));
} }
self::areInuavCodesUniques($model); return self::areInuavCodesUniques($model);
self::isEdeCodeUnique($model);
});
static::deleting(function (self $model) {
if ($model->getRawOriginal('path_picture_1')) {
Storage::delete(\public_path($model->getRawOriginal('path_picture_1')));
}
if ($model->getRawOriginal('path_picture_2')) {
Storage::delete(\public_path($model->getRawOriginal('path_picture_2')));
}
}); });
} }
@ -149,44 +137,26 @@ class CafelEggBreeder extends Model
/** /**
* Check if inuav codes are unique * Check if inuav codes are unique
* *
* @param self $breeder * @param self $eleveur
* @return boolean * @return boolean
* @throws \Illuminate\Validation\ValidationException If inuav code is already used. * @throws \Illuminate\Validation\ValidationException If inuav code is already used.
*/ */
protected static function areInuavCodesUniques(self $breeder): bool protected static function areInuavCodesUniques(self $eleveur): bool
{ {
$q = self::query(); $q = self::query();
// * Update condition // * Update condition
$q->where(function ($q) use ($breeder) { $q->where(function ($q) use ($eleveur) {
foreach ($breeder->inuavs as $inuav) { foreach ($eleveur->inuavs as $inuav) {
$q->orWhere('inuavs', '=', $inuav); $q->orWhere('inuavs', 'LIKE', "%$inuav%");
} }
}); });
if ($breeder->cafel_code) { if ($eleveur->cafel_code) {
$q->where('cafel_code', '!=', $breeder->cafel_code); $q->where('cafel_code', '!=', $eleveur->cafel_code);
} }
if ($q->count()) { if ($q->count()) {
throw ValidationException::withMessages([ throw ValidationException::withMessages(['inuavs' => 'Les codes INUAVS doinvent être uniques'
'inuavs' => 'Les codes INUAVS doinvent être uniques : ' . collect($breeder->inuavs)->implode(',')
]); ]);
} }
return true; return true;
} }
/**
* Check if ede code is unique
*
* @param self $breeder
* @return boolean
* @throws \Illuminate\Validation\ValidationException If ede code is already used.
*/
protected static function isEdeCodeUnique(self $breeder): bool
{
Validator::make([
'ede_code' => $breeder->ede_code
], ['ede_code' => [
Rule::unique($breeder->getTable(), 'ede_code')->ignore($breeder->id)
]])->validate();
return true;
}
} }

View file

@ -33,8 +33,7 @@ class CafelEggMiseEnPlace extends Model
* @var array * @var array
*/ */
protected $casts = [ protected $casts = [
'transfert_date' => 'date', 'transfert_date' => 'date'
'inuav_codes' => 'array'
]; ];
/** /**
@ -44,7 +43,7 @@ class CafelEggMiseEnPlace extends Model
*/ */
protected $fillable = [ protected $fillable = [
'batch_code', 'batch_code',
'inuav_codes', 'inuav_code',
'transfert_date' 'transfert_date'
]; ];
} }

View file

@ -94,14 +94,6 @@ class CafelPoultryBreeder extends Model
} }
return self::areInuavCodesUniques($model); return self::areInuavCodesUniques($model);
}); });
static::deleting(function (self $model) {
if ($model->getRawOriginal('path_picture_1')) {
Storage::delete(\public_path($model->getRawOriginal('path_picture_1')));
}
if ($model->getRawOriginal('path_picture_2')) {
Storage::delete(\public_path($model->getRawOriginal('path_picture_2')));
}
});
} }
// * METHODS // * METHODS
@ -127,7 +119,7 @@ class CafelPoultryBreeder extends Model
} }
if ($q->count()) { if ($q->count()) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'inuavs' => 'Les codes INUAVS doinvent être uniques : ' . collect($breeder->inuavs)->implode(',') 'inuavs' => 'Les codes INUAVS doinvent être uniques'
]); ]);
} }
return true; return true;

View file

@ -34,8 +34,7 @@ class CafelPoultryMiseEnPlace extends Model
* @var array * @var array
*/ */
protected $casts = [ protected $casts = [
'transfert_date' => 'date', 'transfert_date' => 'date'
'inuav_codes' => 'array'
]; ];
/** /**
@ -45,7 +44,7 @@ class CafelPoultryMiseEnPlace extends Model
*/ */
protected $fillable = [ protected $fillable = [
'batch_code', 'batch_code',
'inuav_codes', 'inuav_code',
'transfert_date' 'transfert_date'
]; ];

View file

@ -1,11 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PoultryPackshot extends Model
{
use HasFactory;
}

View file

@ -8,7 +8,6 @@ use App\Traits\HasCompositePrimaryKey;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class TraceaPoultry extends Model class TraceaPoultry extends Model
{ {
@ -71,22 +70,6 @@ class TraceaPoultry extends Model
'prep_date' => 'date' 'prep_date' => 'date'
]; ];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted()
{
// * EVENT CLOSURES.
static::creating(function (self $model) {
self::hasAtLeastOneBarCode($model);
});
static::updating(function (self $model) {
self::hasAtLeastOneBarCode($model);
});
}
// * METHODS // * METHODS
/** /**
@ -98,10 +81,10 @@ class TraceaPoultry extends Model
{ {
$family = Str::upper($this->getAttributeFromArray('family')); $family = Str::upper($this->getAttributeFromArray('family'));
switch (true) { switch (true) {
case \strpos($family, 'LOUE') !== false: case \strpos($family, 'LABEL') !== false:
return PoultryLabelType::labelRouge(); return PoultryLabelType::labelRouge();
case \strpos($family, 'BIO') !== false: case \strpos($family, 'BIO') !== false:
return PoultryLabelType::bio(); return PoultryLabelType::labelRouge();
default: default:
return PoultryLabelType::unkown(); return PoultryLabelType::unkown();
} }
@ -192,32 +175,4 @@ class TraceaPoultry extends Model
// * On utilise code lot_opa vue que son explication de merde est inversée ... Uu // * On utilise code lot_opa vue que son explication de merde est inversée ... Uu
return CafelPoultryMiseEnPlace::whereCodeLotCafel(\intval($this->opa_lot)); return CafelPoultryMiseEnPlace::whereCodeLotCafel(\intval($this->opa_lot));
} }
/**
* Assert has at least one barcode
*
* @param self $tracea
* @return boolean
* @throws \Illuminate\Validation\ValidationException If inuav code is already used.
*/
protected static function hasAtLeastOneBarCode(self $tracea): bool
{
if (empty($tracea->barcode_price) and empty($tracea->barcode_weight)) {
throw ValidationException::withMessages([
'barcode_price' => "Il faut au moins un code barre pour faire la recherche '{$tracea->barcode_price}'",
'barcode_weight' => "Il faut au moins un code barre pour faire la recherche '{$tracea->barcode_weight}'"
]);
}
return true;
}
/**
* Get Packshot
*
* @return \App\Models\PoultryPackshot|null
*/
public function getPackshotAttribute(): ?PoultryPackshot
{
return PoultryPackshot::whereItemCode($this->item_code)->first();
}
} }

View file

@ -1,26 +0,0 @@
<?php
namespace App\Providers;
use Carbon\Carbon;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(): void
{
if (!app()->runningInConsole()) {
View::share('isDisplayedTAModal', (function () {
$now = now();
return $now->greaterThanOrEqualTo(new Carbon(config('modal.terreActionStartDate'))) &&
$now->lessThanOrEqualTo(new Carbon(config('modal.terreActionEndDate')));
})());
}
}
}

5
auth.json Normal file
View file

@ -0,0 +1,5 @@
{
"gitlab-token": {
"gitlab.com": "glpat-gbNVMUd6T2kaB5eii7TZ"
}
}

View file

@ -17,16 +17,16 @@
"fideloper/proxy": "^4.0", "fideloper/proxy": "^4.0",
"guzzlehttp/guzzle": "^7.4", "guzzlehttp/guzzle": "^7.4",
"kwaadpepper/enum": "^2.1", "kwaadpepper/enum": "^2.1",
"kwaadpepper/exception-handler": "^0.0.6",
"kwaadpepper/refresh-sitemap": "^1.0", "kwaadpepper/refresh-sitemap": "^1.0",
"laravel/ui": "^3.0",
"laravel/framework": "^8.0", "laravel/framework": "^8.0",
"laravel/tinker": "^2.0", "laravel/tinker": "^2.0",
"laravel/ui": "^3.0",
"laravelcollective/html": "^6.0", "laravelcollective/html": "^6.0",
"ldc/web-admin-secure-laravel": "^1.0", "ldc/web-admin-secure-laravel": "1.0.1",
"ldc/web-status-checker-laravel": "^1.0", "ldc/web-status-checker-laravel": "1.0.3",
"mews/purifier": "^3.3", "mews/purifier": "^3.3",
"nesbot/carbon": "^2.29", "nesbot/carbon": "^2.29",
"sentry/sentry-laravel": "^3.1",
"spatie/laravel-mix-preload": "^1.3" "spatie/laravel-mix-preload": "^1.3"
}, },
"require-dev": { "require-dev": {
@ -45,10 +45,7 @@
"sort-packages": true, "sort-packages": true,
"allow-plugins": { "allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true "dealerdirect/phpcodesniffer-composer-installer": true
}, }
"gitlab-domains": [
"lab.s-web.fr"
]
}, },
"extra": { "extra": {
"laravel": { "laravel": {
@ -82,9 +79,9 @@
] ]
}, },
"repositories": { "repositories": {
"lab.s-web.fr": { "gitlab.com/16669037": {
"type": "composer", "type": "composer",
"url": "https://lab.s-web.fr/api/v4/group/23/-/packages/composer/packages.json" "url": "https://gitlab.com/api/v4/group/16669037/-/packages/composer/packages.json"
} }
} }
} }

2187
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -53,8 +53,6 @@ return [
*/ */
'url' => env('APP_URL', 'http://localhost'), 'url' => env('APP_URL', 'http://localhost'),
'domain' => env('APP_DOMAIN', 'tracabilite.loue.fr'),
'egg_domain' => env('APP_EGG_DOMAIN', 'bo.gt'),
'asset_url' => env('ASSET_URL', null), 'asset_url' => env('ASSET_URL', null),
@ -177,7 +175,6 @@ return [
App\Providers\AuthServiceProvider::class, App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,
App\Providers\ViewServiceProvider::class,
], ],
@ -237,4 +234,7 @@ return [
'CafelPoultryBreeder' => \App\Models\CafelPoultryBreeder::class, 'CafelPoultryBreeder' => \App\Models\CafelPoultryBreeder::class,
], ],
'project_uuid' => env('PROJECT_UUID'),
]; ];

View file

@ -1,9 +1,8 @@
<?php <?php
return [ return [
// ! Food et MEp sont requis pour afficher un resultat traca volaille
// * How many days should we retain Aliment // * How many days should we retain Aliment
'food_retain' => 370, 'food_retain' => 30,
// * How many days should we retain MEP (egg) // * How many days should we retain MEP (egg)
'mises_en_places_retain' => 370, 'mises_en_places_retain' => 370,
'client_version' => '1.0', 'client_version' => '1.0',
@ -52,12 +51,6 @@ return [
'methods' => [ 'methods' => [
'GET' 'GET'
] ]
],
'cafel.ldc.mepvolailles' => [
'uri' => 'api/ldc/mepvolailles',
'methods' => [
'GET'
]
] ]
] ]
]; ];

View file

@ -0,0 +1,15 @@
<?php
return [
/**
* Send mail when app debug is turn off
* so you can be warned if an unhandled exception occurs
*/
'enableMaiLog' => !config('app.debug'),
/**
* Put a developper secured mailbox in here
* so you can receive email if things go mad
*/
'contactsList' => explode(',', env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr')),
];

View file

@ -62,12 +62,9 @@ return [
// * Contacts List // * Contacts List
'contactsList' => [ 'contactsList' => [
'invalidXml' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_INVALID_XML', 'equipe.web@ldc.fr')), 'invalidXml' => explode(',', env('MAIL_INVALID_XML', 'equipe.web@ldc.fr')),
'invalidCafel' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_INVALID_CAFEL_DATA', 'equipe.web@ldc.fr')), 'invalidCafel' => explode(',', env('MAIL_INVALID_CAFEL_DATA', 'equipe.web@ldc.fr')),
'invalidCafelImage' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env( 'invalidCafelImage' => explode(',', env('MAIL_INVALID_CAFEL_DATA_IMAGE', 'equipe.web@ldc.fr')),
'MAIL_INVALID_CAFEL_DATA_IMAGE',
'equipe.web@ldc.fr'
)),
], ],
/* /*

View file

@ -1,6 +0,0 @@
<?php
return [
'terreActionStartDate' => env('TERRE_ACTION_START_DATE'),
'terreActionEndDate' => env('TERRE_ACTION_END_DATE')
];

View file

@ -1,62 +0,0 @@
<?php
return [
'dsn' => env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')),
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')).
'release' => env('SENTRY_RELEASE'),
// When left empty or `null` the Laravel environment will be used.
'environment' => env('SENTRY_ENVIRONMENT'),
'breadcrumbs' => [
// Capture Laravel logs in breadcrumbs.
'logs' => true,
// Capture SQL queries in breadcrumbs.
'sql_queries' => true,
// Capture bindings on SQL queries logged in breadcrumbs.
'sql_bindings' => true,
// Capture queue job information in breadcrumbs.
'queue_info' => true,
// Capture command information in breadcrumbs.
'command_info' => true,
],
'tracing' => [
// Trace queue jobs as their own transactions.
'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', false),
// Capture queue jobs as spans when executed on the sync driver.
'queue_jobs' => true,
// Capture SQL queries as spans.
'sql_queries' => true,
// Try to find out where the SQL query originated from and add it to the query spans.
'sql_origin' => true,
// Capture views as spans.
'views' => true,
// Indicates if the tracing integrations supplied by Sentry should be loaded.
'default_integrations' => true,
// Indicates that requests without a matching route should be traced.
'missing_routes' => false,
],
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send-default-pii
'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces-sample-rate
'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float)env('SENTRY_TRACES_SAMPLE_RATE'),
'before_send' => [\App\Lib\ExceptionsHelper::class, 'sentryEventHandler'],
];

View file

@ -1,34 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIndexesOnTracaEgg extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('tracea_eggs', function (Blueprint $table) {
$table->index(['ede_code']);
$table->index(['dcr']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('tracea_eggs', function (Blueprint $table) {
$table->dropIndex(['ede_code']);
$table->dropIndex(['dcr']);
});
}
}

View file

@ -1,42 +0,0 @@
<?php
use App\Models\CafelEggBreeder;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
class AddUniqueOnEdeEggBreeders extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// * Destroy breeder one by one to trigger destroy event
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\CafelEggBreeder> */
$eggBreeders = CafelEggBreeder::all();
$eggBreeders->each(function (CafelEggBreeder $breeder) {
$breeder->deleteOrFail();
});
Schema::table('cafel_egg_breeders', function (Blueprint $table) {
$table->unique(['ede_code']);
});
Log::alert('Please reimport all egg breeders');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('cafel_egg_breeders', function (Blueprint $table) {
$table->dropUnique(['ede_code']);
});
}
}

View file

@ -1,81 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class MakeMisesEnPlaceHandleMultipleInuav extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('cafel_egg_mise_en_places', function (Blueprint $table) {
$table->renameColumn('inuav_code', 'inuav_codes');
});
Schema::table('cafel_poultry_mise_en_places', function (Blueprint $table) {
$table->renameColumn('inuav_code', 'inuav_codes');
});
Schema::table('cafel_egg_mise_en_places', function (Blueprint $table) {
$table->string('inuav_codes', 400)->change();
});
Schema::table('cafel_poultry_mise_en_places', function (Blueprint $table) {
$table->string('inuav_codes', 400)->change();
});
DB::table('cafel_egg_mise_en_places')->get()
->each(function (object $eggMep) {
DB::table('cafel_egg_mise_en_places')
->where('batch_code', $eggMep->batch_code)
->update(['inuav_codes' => collect(
explode(',', $eggMep->inuav_codes)
)->filter()->jsonSerialize()]);
});
DB::table('cafel_poultry_mise_en_places')->get()
->each(function (object $poultryMep) {
DB::table('cafel_poultry_mise_en_places')
->where('batch_code', $poultryMep->batch_code)
->update(['inuav_codes' => collect(
explode(',', $poultryMep->inuav_codes)
)->filter()->jsonSerialize()]);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
DB::table('cafel_egg_mise_en_places')->get()
->each(function (object $eggMep) {
DB::table('cafel_egg_mise_en_places')
->where('batch_code', $eggMep->batch_code)
->update(['inuav_codes' => collect(json_decode($eggMep->inuav_codes))->filter()
->first()]);
});
DB::table('cafel_poultry_mise_en_places')->get()
->each(function (object $poultryMep) {
DB::table('cafel_poultry_mise_en_places')
->where('batch_code', $poultryMep->batch_code)
->update(['inuav_codes' => collect(json_decode($poultryMep->inuav_codes))->filter()
->first()]);
});
Schema::table('cafel_egg_mise_en_places', function (Blueprint $table) {
$table->string('inuav_codes', 100)->change();
});
Schema::table('cafel_poultry_mise_en_places', function (Blueprint $table) {
$table->string('inuav_codes', 100)->change();
});
Schema::table('cafel_egg_mise_en_places', function (Blueprint $table) {
$table->renameColumn('inuav_codes', 'inuav_code');
});
Schema::table('cafel_poultry_mise_en_places', function (Blueprint $table) {
$table->renameColumn('inuav_codes', 'inuav_code');
});
}
}

View file

@ -1,33 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePoultryPackshotsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('poultry_packshots', function (Blueprint $table) {
$table->id();
$table->string('item_code', 14)->comment("Item Code = tracea_poultries.item_code");
$table->string('ean', 13)->comment("Ean 13");
$table->string('packshot_name')->comment("Packshot picture name");
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('poultry_packshots');
}
}

View file

@ -13,6 +13,5 @@ class DatabaseSeeder extends Seeder
*/ */
public function run() public function run()
{ {
$this->call(PoultryPackshotsTableSeeder::class);
} }
} }

File diff suppressed because it is too large Load diff

5142
package-lock.json generated

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

View file

@ -10,7 +10,7 @@ document.addEventListener('DOMContentLoaded', () => {
imageHeight: 200, imageHeight: 200,
imageAlt: 'Logo Loué terre d\'action', imageAlt: 'Logo Loué terre d\'action',
background: '#4b8764', background: '#4b8764',
confirmButtonText: '<a href="https://action-reboisement.loue.fr" target="_blank">Je valide mon achat</a>', confirmButtonText: '<a href="https://www.loue.fr/article/Des-arbres-et-des-haies-pour-les-volailles-fermières-de-Loué/a3.aspx" target="_blank">Je valide mon achat</a>',
confirmButtonColor: '#005621', confirmButtonColor: '#005621',
showCloseButton: true, showCloseButton: true,
}) })

View file

@ -1,19 +1,19 @@
// 1. Include new custom variables // Variables
@import 'variables'; @import 'variables';
// 2. Include functions first (so you can manipulate colors, SVGs, calc, etc) // 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "~bootstrap/scss/functions"; @import '~bootstrap/scss/functions';
// 2. Include any default variable overrides here
// 3. Include remainder of required Bootstrap stylesheets // 3. Include remainder of required Bootstrap stylesheets
@import "~bootstrap/scss/variables"; @import '~bootstrap/scss/variables';
@import '~bootstrap/scss/mixins';
// 4. Include remainder of required parts
@import "~bootstrap/scss/maps";
@import "~bootstrap/scss/mixins";
@import "~bootstrap/scss/root";
// 5. Optionally include any other parts as needed // 4. Include any optional Bootstrap components as you like
@import '~bootstrap/scss/root';
@import '~bootstrap/scss/reboot'; @import '~bootstrap/scss/reboot';
@import '~bootstrap/scss/type'; @import '~bootstrap/scss/type';
@import '~bootstrap/scss/images'; @import '~bootstrap/scss/images';
@ -27,9 +27,6 @@
@import '~bootstrap/scss/alert'; @import '~bootstrap/scss/alert';
@import '~bootstrap/scss/close'; @import '~bootstrap/scss/close';
// 6. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
@import "~bootstrap/scss/utilities/api";
// Fix for bootstrap // Fix for bootstrap
.text-break { .text-break {
overflow-wrap: break-word !important; overflow-wrap: break-word !important;

View file

@ -28,8 +28,17 @@
.container-fluid.poultryInfoFarmChicken { .container-fluid.poultryInfoFarmChicken {
& .breederIs { & .breederIs {
& img { display: block;
max-width: 100%; margin: 0 2vw;
background-color: $bgSalmon;
padding: 0.2rem 0.5rem 0.3rem 0.5rem;
font-weight: bold;
font-size: 1.3rem;
& > span:last-child {
display: inline-block;
font-size: 1.7rem;
background-color: $white;
padding: 0.2rem 1rem;
} }
} }
} }

View file

@ -38,7 +38,5 @@
& .signPicture { & .signPicture {
max-width: 11rem; max-width: 11rem;
padding: 15px;
background-color: white;
} }
} }

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