Compare commits

..

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

109 changed files with 1709 additions and 21749 deletions

View file

@ -1,8 +1,8 @@
APP_NAME=Incollector APP_NAME=Laravel
APP_ENV=local APP_ENV=local
APP_KEY= APP_KEY=
APP_DEBUG=true APP_DEBUG=true
APP_URL=https://incollector.s-web.test APP_URL=http://localhost
LOG_CHANNEL=stack LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null LOG_DEPRECATIONS_CHANNEL=null

View file

@ -1,47 +0,0 @@
APP_NAME=Incollector
APP_ENV=testing
APP_KEY=base64:oRXNjgvWgIcboJN2O0NgaBt3kMUUfgyQ1Wv0S9/7sAA=
APP_DEBUG=true
APP_URL="http://127.0.0.1:8888"
LOG_CHANNEL=stack
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=dev-mariadb
DB_PORT=3306
DB_DATABASE=testing-incollector
DB_USERNAME=
DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=database
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=incollector@ldc.fr
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

13
.gitignore vendored
View file

@ -1,22 +1,9 @@
/node_modules /node_modules
/public/hot /public/hot
/public/storage /public/storage
/public/css
/public/js
/public/images
/public/fonts
/public/medias
/public/uploads
/public/assets
/public/mix-manifest.json
.vscode
/storage/*.key /storage/*.key
/storage/inco/*
/storage/marque/*
/vendor /vendor
.env .env
.env.testing
.env.backup .env.backup
.phpunit.result.cache .phpunit.result.cache
docker-compose.override.yml docker-compose.override.yml

24
.vscode/settings.json vendored
View file

@ -1,23 +1,23 @@
{ {
"phpcs.executablePath": "vendor/bin/phpcs", "phpcs.executablePath": "vendor/bin/phpcs",
"workbench.colorCustomizations": { "workbench.colorCustomizations": {
"activityBar.activeBackground": "#834329", "activityBar.activeBackground": "#a714ac",
"activityBar.activeBorder": "#08180c", "activityBar.activeBorder": "#eb549a",
"activityBar.background": "#834329", "activityBar.background": "#a714ac",
"activityBar.foreground": "#e7e7e7", "activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799", "activityBar.inactiveForeground": "#e7e7e799",
"activityBarBadge.background": "#08180c", "activityBarBadge.background": "#eb549a",
"activityBarBadge.foreground": "#e7e7e7", "activityBarBadge.foreground": "#15202b",
"sash.hoverBorder": "#834329", "sash.hoverBorder": "#a714ac",
"statusBar.background": "#5c2f1d", "statusBar.background": "#0f437e",
"statusBar.foreground": "#e7e7e7", "statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#834329", "statusBarItem.hoverBackground": "#a714ac",
"statusBarItem.remoteBackground": "#5c2f1d", "statusBarItem.remoteBackground": "#0f437e",
"statusBarItem.remoteForeground": "#e7e7e7", "statusBarItem.remoteForeground": "#e7e7e7",
"titleBar.activeBackground": "#5c2f1d", "titleBar.activeBackground": "#0f437e",
"titleBar.activeForeground": "#e7e7e7", "titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#5c2f1d99", "titleBar.inactiveBackground": "#0f437e99",
"titleBar.inactiveForeground": "#e7e7e799" "titleBar.inactiveForeground": "#e7e7e799"
}, },
"peacock.remoteColor": "#5c2f1d" "peacock.remoteColor": "#0f437e"
} }

View file

@ -1,78 +0,0 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
/**
* Command Name: LDC Web Status Checker
* Description: Envoi des infos Serveur/Laravel vers LDC Web
* Version: 1.1
* Author: Vincent BRIDIER
* Author URI: vincent.bridier@ldc.fr
*
* @codeCoverageIgnore
*/
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('ldcweb.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 . '/*.log');
if (count($files) > 0) {
foreach ($files as $file) {
$data['logs'] = $data['logs'] + filesize($file);
}
}
$data['code']['version'] = app()->version();
// Send by cURL.
$url = 'https://ldc-web.ldc.fr/api/status-checker';
$ch = curl_init($url);
$payload = ['token' => 'CE8S52Qq7stf5k8frF4T', 'datas' => json_encode($data)];
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
return 0;
}
}

View file

@ -1,49 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use Illuminate\Console\Command;
/**
* @codeCoverageIgnore
*/
class UserCreate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'user:create';
/**
* 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?');
$lastname = $this->ask('What is the lastname?');
$email = $this->ask('What is the email?');
$pwd = $this->secret('What is the password?');
$user = new User();
$user->firstname = $firstname;
$user->lastname = $lastname;
$user->email = $email;
$user->password = $pwd;
$user->saveOrFail();
$this->info('User created.');
return 0;
}
}

View file

@ -1,37 +0,0 @@
<?php
namespace App\Console\Commands;
use App\Jobs\Arcadia\XmlBrandReaderJob;
use Illuminate\Console\Command;
class XmlBrandReader extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'xml:brand';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Run the XmlBrandReaderJob manually';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->info('Running the Job, this could take some time.');
$job = new XmlBrandReaderJob();
$job->console = $this;
$job->handle();
$this->info('Job completed');
}
}

View file

@ -2,11 +2,12 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Jobs\Arcadia\XmlIncoReaderJob; use App\Jobs\XmlIncoReader as JobsXmlIncoReader;
use Illuminate\Console\Command; use Illuminate\Console\Command;
class XmlIncoReader extends Command class XmlIncoReader extends Command
{ {
/** /**
* The name and signature of the console command. * The name and signature of the console command.
* *
@ -29,7 +30,7 @@ class XmlIncoReader extends Command
public function handle() public function handle()
{ {
$this->info('Running the Job, this could take some time.'); $this->info('Running the Job, this could take some time.');
$job = new XmlIncoReaderJob(); $job = new JobsXmlIncoReader();
$job->console = $this; $job->console = $this;
$job->handle(); $job->handle();
$this->info('Job completed'); $this->info('Job completed');

View file

@ -2,7 +2,6 @@
namespace App\Console; namespace App\Console;
use App\Console\Commands\LdcWebStatusChecker;
use Illuminate\Console\Scheduling\Schedule; use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel; use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -13,17 +12,20 @@ class Kernel extends ConsoleKernel
* *
* @var array * @var array
*/ */
protected $commands = []; protected $commands = [
//
];
/** /**
* Define the application's command schedule. * Define the application's command schedule.
* *
* @param \Illuminate\Console\Scheduling\Schedule $schedule * @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void * @return void
*/ */
protected function schedule(Schedule $schedule) protected function schedule(Schedule $schedule)
{ {
$schedule->command(LdcWebStatusChecker::class)->everyFifteenMinutes(); // $schedule->command('inspire')->hourly();
//$schedule->job(new XmlIncoReader)->weeklyOn(1, '8:00');
} }
/** /**
@ -33,6 +35,8 @@ class Kernel extends ConsoleKernel
*/ */
protected function commands() protected function commands()
{ {
$this->load(__DIR__ . '/Commands'); $this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
} }
} }

View file

@ -1,84 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* This describes an API error.
*
* @method static self modelNotFound()
* The request model was not found (typically the customer)
*
* @method static self validationFailed()
* This means some data could not be validated,
* you may have to look into message to get the details
*
* @method static self apiAuthFailed()
* The authentification to the api failed. You may have to
* check into config or .env file for your service credentials
*
* @method static self methodNotAllowed()
* This http method is not allowed
*
* @method static self wrongTimeStamp()
* The timestamp given is wrong. This would happen in case if
* a replay attack scenario. Timestamps are provided in headers
* and in the http body
*
* @method static self missingParameter()
* The request is missing some parameters
*
* @method static self throttleRequestsException()
* Too many requests have been attempted. The is a throttle security.
* Normally you should not trigger this.
* If this happens fill a ticket on https://supportweb.ldc.fr
* with some technical details
*
* @method static self authorizationException()
* You are maybe trying to access data that is out of your range.
* This should not happen normally, it is here to allow you to handle this case.
* If this happens fill a ticket on https://supportweb.ldc.fr
* with some technical details
*
*/
class ApiError extends BaseEnumRoutable
{
/**
* Valeurs des possibilités de cet énumération (value)
*
* @return array
*/
public static function values(): array
{
return [
'modelNotFound' => 101,
'validationFailed' => 102,
'apiAuthFailed' => 119,
'methodNotAllowed' => 150,
'wrongTimeStamp' => 151,
'missingParameter' => 400,
'authorizationException' => 403,
'throttleRequestsException' => 429
];
}
/**
* Libellés des possibilités de cet énumération (label)
*
* @return array
*/
public static function labels(): array
{
return [
'modelNotFound' => '%s introuvable.',
'validationFailed' => 'Impossible de valider les données',
'apiAuthFailed' => 'Echec de l\'authentification client à l\'Api LDC-CRM pour ce service',
'methodNotAllowed' => 'This method is not allowed for this request',
'wrongTimeStamp' => 'Your request is malformed, please check timestamp header and parameter',
'missingParameter' => 'The request is missing some parameters',
'authorizationException' => 'You are not autorized to access this',
'throttleRequestsException' => 'Throttle: too many request have been attempted, please retry later'
];
}
}

View file

@ -1,16 +0,0 @@
<?php
namespace App\Enums;
use Kwaadpepper\Enum\BaseEnumRoutable;
/**
* @method static self OK()
* @method static self KO()
*
* @package LDCCrmClient
* @subpackage enums
*/
class ApiStatus extends BaseEnumRoutable
{
}

View file

@ -2,8 +2,8 @@
namespace App\Exceptions; namespace App\Exceptions;
use ErrorException; use Exception;
class AbortXmlImportException extends ErrorException class AbortXmlImportException extends Exception
{ {
} }

View file

@ -1,101 +0,0 @@
<?php
namespace App\Exceptions\Api;
use App\Enums\ApiError;
use Exception;
use Illuminate\Support\Facades\Log;
use Throwable;
/**
* This would be thrown if any of the case
* referenced in \App\Enums\ApiError would
* occur within the crm
*
* On the client an ApiErrorException would
* also be throw with the ApiError corresponding to
* the situation
*/
class ApiErrorException extends Exception
{
/**
* Api Error
* This value makes the error more explicit.
* Handling these errors are normal as inputs or
* request may be undesired or refused by the crm.
*
* @var \App\Enums\ApiError
*/
protected $error;
/**
* This is an explicit error message,
* ou may print this to the front or not depending
* on $error value
*
* @var string
*/
protected $message;
/**
* This is the http code returned by the crm.
* This value could be used to handle errors.
* But please take in consideration $error first
*
* @var integer
*/
protected $httpCode;
/**
* Create a new exception base on ApiError enum.
*
* @param ApiError $error
* @param integer $httpCode
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(ApiError $error, int $httpCode = 400, string $message = '', Throwable $previous = null)
{
$this->error = $error;
$this->message = $message;
$this->httpCode = $httpCode;
parent::__construct(
strlen($this->message) ? $this->message : $error->label,
$error->value,
$previous
);
}
/**
* Get the Api Error
*
* @return ApiError
*/
public function getApiError(): ApiError
{
return $this->error;
}
/**
* Get the http code
*
* @return integer
*/
public function getStatusCode(): int
{
return $this->httpCode;
}
/**
* This is used by laravel only.
* It uses Log class to print the error.
*
* @return void
*/
public function report()
{
// @codeCoverageIgnoreStart
Log::debug(sprintf('CRM API: %s', $this->getMessage()));
// @codeCoverageIgnoreEnd
}
}

View file

@ -1,25 +0,0 @@
<?php
namespace App\Exceptions\Api;
use Exception;
use Illuminate\Support\Facades\Log;
/**
* This is a critical error.
* The request could not be handled. You may dump any value you can
* get before submitting a ticket to https://supportweb.ldc.fr
*/
class ApplicationException extends Exception
{
/**
* This is used by laravel only.
* It uses Log class to print the error.
*
* @return void
*/
public function report()
{
Log::critical(sprintf('API: %s', $this->getMessage()));
}
}

View file

@ -2,20 +2,7 @@
namespace App\Exceptions; namespace App\Exceptions;
use App\Enums\ApiError;
use App\Enums\ApiStatus;
use App\Exceptions\Api\ApiErrorException;
use App\Http\Resources\Api\V1\ApiResponseResource;
use App\Lib\Helper;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler; use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Throwable; use Throwable;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
@ -23,18 +10,19 @@ class Handler extends ExceptionHandler
/** /**
* A list of the exception types that are not reported. * A list of the exception types that are not reported.
* *
* @var array * @var string[]
*/ */
protected $dontReport = [ protected $dontReport = [
ApiErrorException::class //
]; ];
/** /**
* A list of the inputs that are never flashed for validation exceptions. * A list of the inputs that are never flashed for validation exceptions.
* *
* @var array * @var string[]
*/ */
protected $dontFlash = [ protected $dontFlash = [
'current_password',
'password', 'password',
'password_confirmation', 'password_confirmation',
]; ];
@ -46,125 +34,8 @@ class Handler extends ExceptionHandler
*/ */
public function register() public function register()
{ {
} $this->reportable(function (Throwable $e) {
//
/** });
* Render an exception into an HTTP response.
*
* @param mixed $request
* @param \Throwable $e
* @return \Symfony\Component\HttpFoundation\Response
*/
public function render($request, Throwable $e)
{
if (Helper::isRequestForApiV1($request) and $request->isJson()) {
return $this->handleApiV1Exception($request, $e);
} //end if
// @codeCoverageIgnoreStart
return parent::render($request, $e);
// @codeCoverageIgnoreEnd
}
/**
* Generate a json response for any apiV2 error case
*
* @param Request $request
* @param \Throwable $e
* @return JsonResponse
*/
private function handleApiV1Exception(Request $request, \Throwable $e): JsonResponse
{
switch (get_class($e)) {
case AuthenticationException::class:
/** @var AuthenticationException $e */
return $this->getReponse(
$request,
401,
ApiError::apiAuthFailed()->value,
sprintf('%s, %s', ApiError::apiAuthFailed()->label, $e->getMessage())
);
case MethodNotAllowedHttpException::class:
/** @var MethodNotAllowedHttpException $e */
return $this->getReponse(
$request,
$e->getStatusCode(),
ApiError::methodNotAllowed()->value,
sprintf('%s, %s', ApiError::methodNotAllowed()->label, $e->getMessage())
);
case ValidationException::class:
/** @var ValidationException $e */
return $this->getReponse(
$request,
$e->status,
ApiError::validationFailed()->value,
sprintf(ApiError::validationFailed()->label, $e->getMessage()),
['errors' => $e->errors()]
);
case ModelNotFoundException::class:
/** @var ModelNotFoundException $e */
return $this->getReponse(
$request,
404,
ApiError::modelNotFound()->value,
sprintf(
ApiError::modelNotFound()->label,
\array_slice(explode('\\', $e->getModel()), -1)[0]
)
);
case ApiErrorException::class:
/** @var ApiErrorException $e */
return $this->getReponse(
$request,
$e->getStatusCode(),
$e->getCode(),
$e->getMessage()
);
case ThrottleRequestsException::class:
/** @var ThrottleRequestsException $e */
return $this->getReponse(
$request,
429,
ApiError::throttleRequestsException()->value,
ApiError::throttleRequestsException()->label
);
case AuthorizationException::class:
/** @var AuthorizationException $e */
return $this->getReponse(
$request,
403,
ApiError::authorizationException()->value,
ApiError::authorizationException()->label
);
} //end switch
// @codeCoverageIgnoreStart
if (config('app.env') === 'testing') {
// phpcs:ignore Squiz.PHP.DiscouragedFunctions.Found
print_r((string)$e);
}
return $this->getReponse($request, 500, $e->getCode(), $e->getMessage());
// @codeCoverageIgnoreEnd
}
/**
* Generate an ApiV2 json response
*
* @param Request $request
* @param integer $httpCode
* @param integer $apiCode
* @param string $message
* @param array $data
* @return JsonResponse
*/
private static function getReponse(
Request $request,
int $httpCode,
int $apiCode,
string $message,
array $data = []
): JsonResponse {
return (new ApiResponseResource(
(object)array_merge($data, ['message' => $message, 'code' => $apiCode]),
ApiStatus::KO()
))->toResponse($request)->setStatusCode($httpCode);
} }
} }

View file

@ -2,8 +2,8 @@
namespace App\Exceptions; namespace App\Exceptions;
use ErrorException; use Exception;
class InvalidXmlException extends ErrorException class InvalidXmlException extends Exception
{ {
} }

View file

@ -1,19 +0,0 @@
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
class ApiController extends Controller
{
/**
* Just returns HTTP 200 response
*
* @return JsonResponse
*/
public function ping(): JsonResponse
{
return response()->json();
}
}

View file

@ -1,58 +0,0 @@
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\V1\XmlIncosIndexRequest;
use App\Http\Resources\Api\V1\XmlIncoResource;
use App\Models\XmlInco;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
class XmlIncoController extends Controller
{
/**
* Returns xmlIncos.
*
* @param XmlIncosIndexRequest $request
* - autorised is 'brand' with id
* @return JsonResource
*/
public function index(XmlIncosIndexRequest $request): ResourceCollection
{
/** @var \App\Models\ArcadiaBrand|null $arcadiaBrand */
$arcadiaBrand = $request->arcadiaBrand;
$xmlIncos = XmlInco::query();
if ($arcadiaBrand) {
// * Make sure we are accessing xmlIncos that belongs to our service.
$this->authorize('arcadiaBrandBelongsToService', $arcadiaBrand);
$xmlIncos->whereHas('arcadiaBrands', function ($q) use ($arcadiaBrand) {
$q->whereId($arcadiaBrand->id);
});
}
return XmlIncoResource::collection($xmlIncos->simplePaginate(
$request->per_page,
['*'],
'page',
$request->page
)->items());
}
/**
* Return a specific xmlInco.
*
* @param XmlInco $xmlInco
* @return JsonResource
*/
public function show(XmlInco $xmlInco): JsonResource
{
// * Make sure we are accessing a xmlInco that belongs to our service.
$this->authorize('arcadiaBrandBelongsToService', $xmlInco->arcadiaBrand);
return new XmlIncoResource($xmlInco);
}
}

View file

@ -9,7 +9,5 @@ use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController class Controller extends BaseController
{ {
use AuthorizesRequests; use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
use DispatchesJobs;
use ValidatesRequests;
} }

View file

@ -14,12 +14,12 @@ class Kernel extends HttpKernel
* @var array * @var array
*/ */
protected $middleware = [ protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class, \Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class, \App\Http\Middleware\TrimStrings::class,
\App\Http\Middleware\XssSanitizer::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
]; ];
@ -33,18 +33,16 @@ class Kernel extends HttpKernel
\App\Http\Middleware\EncryptCookies::class, \App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class, \Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class, \App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
], ],
'api' => [ 'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api', 'throttle:api',
\App\Http\Middleware\JsonOnly::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\ApiResponse::class,
\App\Http\Middleware\ApiCheckTimeStamps::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class
], ],
]; ];

View file

@ -1,38 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Enums\ApiError;
use App\Exceptions\Api\ApiErrorException;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
/**
* Check Http Header Timestamp with request timestamp
* to prevent replay attacks
* https://restfulapi.net/security-essentials/
*/
class ApiCheckTimeStamps
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
* @throws ApiErrorException With ApiError::wrongTimeStamp if timestamp has an incorrect format or is timed out.
*/
public function handle(Request $request, \Closure $next)
{
if (!\is_string($request->timestamp) or !Carbon::hasFormat($request->timestamp, 'Y-m-d H:i:s')) {
throw new ApiErrorException(ApiError::wrongTimeStamp());
}
if (
Carbon::parse($request->timestamp, 'utc')
->isBefore(Carbon::now('UTC')->subSeconds(config('api.timestampTimeout', 10)))
) {
throw new ApiErrorException(ApiError::wrongTimeStamp());
}
return $next($request);
}
}

View file

@ -1,57 +0,0 @@
<?php
namespace App\Http\Middleware;
use App\Enums\ApiStatus;
use App\Http\Resources\Api\V1\ApiResponseResource;
use App\Models\Service;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ApiResponse
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
* @throws \ErrorException If the received response is not a JsonResponse.
*/
public function handle(Request $request, \Closure $next)
{
/** @var \Illuminate\Http\JsonResponse $response */
$response = $next($request);
if (\get_class($response) !== JsonResponse::class) {
// @codeCoverageIgnoreStart
throw new \ErrorException('All api responses should be json.');
// @codeCoverageIgnoreEnd
}
// Set no cache header.
$response->header('Cache-Control', 'No-Store');
/** @var \App\Models\Service|null */
if (\optional($service = app(Service::class))->id) {
$service->incrementStat();
}
/** @var object $data */
$data = $response->getData();
// If reponse is already a V2ApiResponse then just return it. This happens if error handler comes to action.
if (
isset($data->status) and
isset($data->data) and
isset($data->version) and
in_array($data->status, [ApiStatus::OK()->value, ApiStatus::KO()->value])
) {
return $response;
}
/** @var \App\Enums\ApiStatus $status */
$status = intval($response->getStatusCode() / 100) == 2 ? ApiStatus::OK() : ApiStatus::KO();
return $response->setData(new ApiResponseResource((object)$response->getData(), $status));
}
}

View file

@ -9,7 +9,7 @@ class Authenticate extends Middleware
/** /**
* Get the path the user should be redirected to when they are not authenticated. * Get the path the user should be redirected to when they are not authenticated.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @return string|null * @return string|null
*/ */
protected function redirectTo($request) protected function redirectTo($request)

View file

@ -12,5 +12,6 @@ class EncryptCookies extends Middleware
* @var array * @var array
*/ */
protected $except = [ protected $except = [
]; //
];
} }

View file

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

View file

@ -12,5 +12,6 @@ class PreventRequestsDuringMaintenance extends Middleware
* @var array * @var array
*/ */
protected $except = [ protected $except = [
]; //
];
} }

View file

@ -12,9 +12,9 @@ class RedirectIfAuthenticated
/** /**
* Handle an incoming request. * Handle an incoming request.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Closure $next * @param \Closure $next
* @param string|null ...$guards * @param string|null ...$guards
* @return mixed * @return mixed
*/ */
public function handle(Request $request, Closure $next, ...$guards) public function handle(Request $request, Closure $next, ...$guards)

View file

@ -17,7 +17,7 @@ class TrustProxies extends Middleware
/** /**
* The headers that should be used to detect proxies. * The headers that should be used to detect proxies.
* *
* @var integer * @var int
*/ */
protected $headers = protected $headers =
Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_FOR |

View file

@ -12,5 +12,6 @@ class VerifyCsrfToken extends Middleware
* @var array * @var array
*/ */
protected $except = [ protected $except = [
]; //
];
} }

View file

@ -1,25 +0,0 @@
<?php
namespace App\Http\Middleware;
use Closure;
class XssSanitizer
{
/**
* Handle an incoming request.
*
* @param mixed $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$input = $request->all();
array_walk_recursive($input, function (&$input) {
$input = strip_tags($input);
});
$request->merge($input);
return $next($request);
}
}

View file

@ -1,31 +0,0 @@
<?php
namespace App\Http\Requests\Api\V1;
use Illuminate\Foundation\Http\FormRequest;
class PaginatorRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
return auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'page' => 'sometimes|numeric|min:1',
'per_page' => 'sometimes|numeric|min:1|max:100',
];
}
}

View file

@ -1,36 +0,0 @@
<?php
namespace App\Http\Requests\Api\V1;
use App\Models\ArcadiaBrand;
class XmlIncosIndexRequest extends PaginatorRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
$this->merge([
'brand' => $this->brand ? ArcadiaBrand::whereId($this->brand)->firstOrFail() : null
]);
return auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return \array_merge(
parent::rules(),
[
'brand' => 'nullable'
]
);
}
}

View file

@ -1,42 +0,0 @@
<?php
namespace App\Http\Resources\Api\V1;
use App\Enums\ApiStatus;
use Illuminate\Http\Resources\Json\JsonResource;
use stdClass;
class ApiResponseResource extends JsonResource
{
/** @var stdClass */
protected $data;
/** @var \App\Enums\ApiStatus */
protected $status;
/**
* @param stdClass $data
* @param ApiStatus $status
*/
public function __construct(stdClass $data = null, ApiStatus $status)
{
$this->status = $status;
$this->data = $data;
}
/**
* Transform the resource into an array.
*
* @param mixed $request
* @return array
*/
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.Missing
public function toArray($request): array
{
return [
'status' => $this->status->value,
'data' => (array)$this->data,
'version' => config('api.version')
];
}
}

View file

@ -1,66 +0,0 @@
<?php
namespace App\Http\Resources\Api\V1;
use App\Models\XmlInco;
use Illuminate\Http\Resources\Json\JsonResource;
class XmlIncoResource extends JsonResource
{
/** @var array */
private static $skeleton = [
'id' => '',
'no_art' => '',
'prod_saison' => '',
'allegations' => '',
'conseil_prepa' => '',
'astuces' => '',
'descriptif' => '',
'arg_vente' => '',
'nb_portion' => '',
'typ_portion' => '',
'pds_moy_theo' => '',
'lib_conso' => '',
'lst_ing' => '',
'lib_allergene' => '',
'nutritional_values' => '',
'pictures' => '',
];
/**
* XmlIncoResource
*
* @param XmlInco $xmlInco
*/
public function __construct(XmlInco $xmlInco)
{
$this->xmlInco = $xmlInco;
}
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request|null $request
* @return array
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function toArray($request = null)
{
$data = array_intersect_key(
$this->xmlInco->toArray(),
$this->getSkeleton()
);
return $data;
}
/**
* Returns the resource skeletton
*
* @return array
*/
public static function getSkeleton(): array
{
return self::$skeleton;
}
}

View file

@ -1,55 +0,0 @@
<?php
namespace App\Jobs\Arcadia;
use App\Models\ArcadiaBrand;
class XmlBrandReaderJob extends XmlJobs
{
/**
* The xsd file path used to validate files
*
* @var string|null
*/
protected $xsdSchemaPath = 'resources/documents/arcadia/marque.xsd';
/**
* Disk name from config/filesystems.php
*
* @var string
*/
protected $disk = 'arcadia_brand';
/**
* @var array Columns to take from the xml.
*/
protected $takeColumns = [
'codMarq' => 'arcadia_id',
'libMarq' => 'libelle',
];
/**
* Fields that are allowed to be null
*
* @var array
*/
protected $nullableFields = [];
/**
* Unique keys for updating rows
*
* @var array
*/
protected $uniqueKeyField = ['arcadia_id'];
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$this->parseData('dam', ArcadiaBrand::class);
}
}

View file

@ -1,81 +0,0 @@
<?php
namespace App\Jobs;
use App\Models\Service;
use App\Models\ServiceStat;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
/**
* @codeCoverageIgnore
*/
class SetServiceStats implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
private const KEY = '2202020';
/** @var \App\Models\Service */
protected $service;
/**
* Create a new job instance.
*
* @param Service $service
* @return void
*/
public function __construct(Service $service)
{
$this->service = $service;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
/** @var \App\Models\ServiceStat */
$serviceStat = ServiceStat::firstOrNew([
'date' => date('Y-m-d'),
'service_id' => $this->service->id,
]);
if (!$serviceStat->exists) {
$serviceStat->service()->associate($this->service);
}
$serviceStat->nb_calls += 1;
$serviceStat->saveOrFail();
}
/**
* Determine the time at which the job should timeout.
*
* @return \DateTime
*/
public function retryUntil()
{
return now()->addMinutes(rand(0, 360));
}
/**
* Get the middleware the job should pass through.
*
* @return array
*/
public function middleware()
{
return [
(new WithoutOverlapping(self::KEY))
->releaseAfter(rand(90, 180))
];
}
}

View file

@ -1,8 +1,9 @@
<?php <?php
namespace App\Jobs\Arcadia; namespace App\Jobs;
use App\Enums\LogType; use App\Enums\LogType;
use Exception;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Filesystem\Filesystem; use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
@ -29,23 +30,9 @@ abstract class XArcadiaFlux implements ShouldQueue
/** /**
* This is for Laravel Console usage * This is for Laravel Console usage
* @var \Illuminate\Console\Command|null
*/ */
public $console = null; public $console = null;
/**
* This is for Laravel Console usage
* @var \Symfony\Component\Console\Helper\ProgressBar|null
*/
public $progressBar = null;
/**
* invalid xml folder
*
* @var string
*/
protected $invalidFolderName = 'invalid';
/** /**
* The relative folder where to archive data * The relative folder where to archive data
* *
@ -66,7 +53,6 @@ abstract class XArcadiaFlux implements ShouldQueue
* Check if the file extension * Check if the file extension
* *
* @param string $filename * @param string $filename
* @param string $extension
* @return boolean * @return boolean
*/ */
protected function checkExtension(string $filename, string $extension): bool protected function checkExtension(string $filename, string $extension): bool
@ -83,81 +69,6 @@ abstract class XArcadiaFlux implements ShouldQueue
return $isExtension; return $isExtension;
} }
/**
* Move the file to invalid folder
*
* @param string $filename
* @return void
*/
protected function moveToInvalid(string $filename): void
{
$newFileName = $filename;
if (!$this->getDisk()->exists($filename)) {
$this->log(
sprintf(
'File %s could not be moved to invalid (not found)',
$filename
),
LogType::warning()
);
return;
}
if ($this->getDisk()->exists(sprintf('%s/%s', $this->invalidFolderName, $filename))) {
$ext = \pathinfo($filename, \PATHINFO_EXTENSION);
$newFileName = \sprintf(
'%s_%d.%s',
\substr($filename, 0, 0 - (strlen($ext) + 1)),
\time(),
$ext
);
}
try {
if (!$this->getDisk()->move($filename, sprintf('%s/%s', $this->invalidFolderName, $newFileName))) {
$this->log(
sprintf(
'File %s could not be moved to invalid',
$filename
),
LogType::warning()
);
}
} catch (\Exception $e) {
$this->log(
sprintf(
'File %s could not be moved to invalid',
$filename
),
LogType::warning()
);
}
}
/**
* Suppression des fichiers dans
* invalid qui ont plus de 6 mois
*
* @return void
*/
protected function clearOldInvalids(): void
{
$disk = $this->getDisk();
$invalids = $disk->files($this->invalidFolderName);
// /** @var File */
foreach ($invalids as $invalid) {
$pi = \pathinfo($invalid, \PATHINFO_BASENAME);
if (in_array($pi, $this->ignoreFiles)) {
continue;
}
if ($disk->lastModified($invalid) < strtotime(Carbon::now()->subMonth(6))) {
if (!$disk->delete($invalid)) {
Log::critical(sprintf('%s : Could not delete file %s', get_class($this), $invalid));
};
}
}
}
/** /**
* Move the file to archives * Move the file to archives
* *
@ -196,7 +107,7 @@ abstract class XArcadiaFlux implements ShouldQueue
LogType::warning() LogType::warning()
); );
} }
} catch (\Exception $e) { } catch (Exception $e) {
$this->log( $this->log(
sprintf( sprintf(
'File %s could not be moved to archives', 'File %s could not be moved to archives',
@ -249,7 +160,6 @@ abstract class XArcadiaFlux implements ShouldQueue
* @param string $message * @param string $message
* @param LogType $logtype * @param LogType $logtype
* @return void * @return void
* @throws \ErrorException If logtype is not handled.
*/ */
protected function log(string $message, LogType $logtype = null): void protected function log(string $message, LogType $logtype = null): void
{ {
@ -277,8 +187,8 @@ abstract class XArcadiaFlux implements ShouldQueue
Log::critical($message); Log::critical($message);
break; break;
default: default:
throw new \ErrorException(sprintf('%s : unhandled log type %s', get_class($this), $logtype->label)); throw new Exception(sprintf('%s : unhandled log type %s', get_class($this), $logtype->label));
} //end switch }//end switch
$this->consolePrint($message, $logtype); $this->consolePrint($message, $logtype);
} }
@ -288,11 +198,9 @@ abstract class XArcadiaFlux implements ShouldQueue
* @param string $message * @param string $message
* @param LogType $logtype * @param LogType $logtype
* @return void * @return void
* @throws \ErrorException If logtype is not handled.
*/ */
protected function consolePrint(string $message, LogType $logtype): void protected function consolePrint(string $message, LogType $logtype): void
{ {
$this->clearProgressBarFromLine();
if ($this->console) { if ($this->console) {
switch ($logtype->value) { switch ($logtype->value) {
case LogType::debug()->value: case LogType::debug()->value:
@ -308,59 +216,8 @@ abstract class XArcadiaFlux implements ShouldQueue
$this->console->error($message); $this->console->error($message);
break; break;
default: default:
throw new \ErrorException(sprintf('%s : unhandled log type %s', get_class($this), $logtype->label)); throw new Exception(sprintf('%s : unhandled log type %s', get_class($this), $logtype->label));
} }
} }
} }
/**
* Start ProgressBar
*
* @param integer $total
* @return void
*/
protected function startProgressBar(int $total)
{
if ($this->console) {
$this->progressBar = $this->console->getOutput()
->createProgressBar($total - 1);
$this->progressBar->start();
}
}
/**
* Clear the line to write someting
*
* @return void
*/
protected function clearProgressBarFromLine()
{
if ($this->progressBar) {
$this->progressBar->clear();
}
}
/**
* Increment 1 on progress bar
*
* @return void
*/
protected function incrementProgressBar()
{
if ($this->progressBar) {
$this->progressBar->advance();
}
}
/**
* End the progress bar
*
* @return void
*/
protected function endProgressBar()
{
if ($this->progressBar) {
$this->progressBar->finish();
}
}
} }

View file

@ -1,36 +1,20 @@
<?php <?php
namespace App\Jobs\Arcadia; namespace App\Jobs;
use App\Exceptions\AbortXmlImportException; use App\Exceptions\AbortXmlImportException;
use App\Models\XmlInco; use App\Models\XmlInco;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use SimpleXMLElement; use SimpleXMLElement;
class XmlIncoReaderJob extends XmlJobs class XmlIncoReader extends XmlJobs
{ {
/**
* The xsd file path used to validate files
*
* @var string|null
*/
protected $xsdSchemaPath = 'resources/documents/inco/incollector.xsd';
/**
* Disk name from config/filesystems.php
*
* @var string
*/
protected $disk = 'inco'; protected $disk = 'inco';
/**
* Storage path
*
* @var string
*/
protected $imagesPath = 'images'; protected $imagesPath = 'images';
protected $xsdFile = 'xsd/incollector.xsd';
/** /**
* éléments à la racine : nom du noeud * éléments à la racine : nom du noeud
* sous éléments d'un noeud PARENT : * sous éléments d'un noeud PARENT :
@ -45,35 +29,31 @@ class XmlIncoReaderJob extends XmlJobs
* 'EXPLOITANT' => 'exploitant', // Consider this sub array * 'EXPLOITANT' => 'exploitant', // Consider this sub array
* 'EXPLOITANT.ID_SOCIETE' => 'id_societe', * 'EXPLOITANT.ID_SOCIETE' => 'id_societe',
* 'EXPLOITANT.NOM_SOCIETE' => 'nom_societe', * 'EXPLOITANT.NOM_SOCIETE' => 'nom_societe',
* @var array Columns to take from the xml.
*/ */
protected $takeColumns = [ protected $takeColumns = [
'NO_ART' => 'id', 'NO_ART' => 'id', // primary key on model
// primary key on model
// this wil not return anything cf doc above //this wil not return anything cf doc above
'ID_SOCIETE' => 'id_societe', 'ID_SOCIETE' => 'id_societe',
'NOM_SOCIETE' => 'nom_societe', 'NOM_SOCIETE' => 'nom_societe',
'PROD_SAISON' => 'prod_saison', 'PROD_SAISON' => 'prod_saison',
'NOM' => 'nom', 'NOM' => 'nom',
'NUMERO' => 'numero', 'NUMERO' => 'numero',
'TAILLE_REF' => 'taille_ref', 'TAILLE_REF' => 'taille_ref', //$poidsRef censé être dans INCO_COMPO (et généralement 100g)
// $poidsRef censé être dans INCO_COMPO (et généralement 100g)
'ALLEGATIONS' => 'allegations', 'ALLEGATIONS' => 'allegations',
'CONSEIL_PREPA' => 'conseil_prepa', 'CONSEIL_PREPA' => 'conseil_prepa',
'ASTUCES' => 'astuces', 'ASTUCES' => 'astuces',
'DESCRIPTIF' => 'descriptif', 'DESCRIPTIF' => 'descriptif', //$descriptif
// $descriptif
'ARG_VENTE' => 'arg_vente', 'ARG_VENTE' => 'arg_vente',
'NB_PORTION' => 'nb_portion', 'NB_PORTION' => 'nb_portion',
'TYP_PORTION' => 'typ_portion', 'TYP_PORTION' => 'typ_portion',
'PDS_MOY_THEO' => 'pds_moy_theo', 'PDS_MOY_THEO' => 'pds_moy_theo',
'LIB_CONSO' => 'lib_conso', 'LIB_CONSO' => 'lib_conso',
'LST_ING' => 'lst_ing', 'LST_ING' => 'lst_ing', //$ingredients
// $ingredients
// list alergene // list alergene
'LST_ALLERGENE' => 'lst_allergene', 'LST_ALLERGENE' => 'lst_allergene', // Consider this sub array
// Consider this sub array
'LST_ALLERGENE.LIB_ALLERGENE' => 'lib_allergene', 'LST_ALLERGENE.LIB_ALLERGENE' => 'lib_allergene',
// Allegations // Allegations
@ -82,13 +62,11 @@ class XmlIncoReaderJob extends XmlJobs
'ALLEGAT_AUTRE' => 'allegat_autre', 'ALLEGAT_AUTRE' => 'allegat_autre',
'INCO_COMPO' => 'inco_compo', 'INCO_COMPO' => 'inco_compo', // Consider this sub array
// Consider this sub array
'INCO_COMPO.NOM' => 'nom', 'INCO_COMPO.NOM' => 'nom',
'INCO_COMPO.TAILLE_REF' => 'taille_ref', 'INCO_COMPO.TAILLE_REF' => 'taille_ref',
'INCO_COMPO.VAL_ENERG_KJ_NUT' => 'val_energ_kj_nut', 'INCO_COMPO.VAL_ENERG_KJ_NUT' => 'val_energ_kj_nut',
'INCO_COMPO.VAL_ENERG_KJ_R' => 'val_energ_kj_r', 'INCO_COMPO.VAL_ENERG_KJ_R' => 'val_energ_kj_r', //_R apports de la taille_ref
// _R apports de la taille_ref
'INCO_COMPO.VAL_ENERG_KCAL_R' => 'val_energ_kcal_r', 'INCO_COMPO.VAL_ENERG_KCAL_R' => 'val_energ_kcal_r',
'INCO_COMPO.VAL_ENERG_KCAL_NUT' => 'val_energ_kcal_nut', 'INCO_COMPO.VAL_ENERG_KCAL_NUT' => 'val_energ_kcal_nut',
'INCO_COMPO.MAT_GRASS_R' => 'mat_grass_r', 'INCO_COMPO.MAT_GRASS_R' => 'mat_grass_r',
@ -109,8 +87,7 @@ class XmlIncoReaderJob extends XmlJobs
'INCO_COMPO.ENER_E14_R' => 'ener_e14_r', 'INCO_COMPO.ENER_E14_R' => 'ener_e14_r',
'INCO_COMPO.FRUITS_R' => 'fruits_r', 'INCO_COMPO.FRUITS_R' => 'fruits_r',
'INCO_COMPO.FRUITS_COQUE_SECH_R' => 'fruits_coque_sech_r', 'INCO_COMPO.FRUITS_COQUE_SECH_R' => 'fruits_coque_sech_r',
'INCO_COMPO.POURCENT_APPORT_REF_E14_R' => 'pourcent_apport_ref_e14_r', 'INCO_COMPO.POURCENT_APPORT_REF_E14_R' => 'pourcent_apport_ref_e14_r', //POURCENT_*_P apports journaliers par portion
// POURCENT_*_P apports journaliers par portion
'INCO_COMPO.ENER_KJO_R' => 'ener_kjo_r', 'INCO_COMPO.ENER_KJO_R' => 'ener_kjo_r',
'INCO_COMPO.POURCENT_APPORT_REF_KJO_R' => 'pourcent_apport_ref_kjo_r', 'INCO_COMPO.POURCENT_APPORT_REF_KJO_R' => 'pourcent_apport_ref_kjo_r',
'INCO_COMPO.POURCENT_APPORT_REF_FAT_R' => 'pourcent_apport_ref_fat_r', 'INCO_COMPO.POURCENT_APPORT_REF_FAT_R' => 'pourcent_apport_ref_fat_r',
@ -127,10 +104,8 @@ class XmlIncoReaderJob extends XmlJobs
'INCO_COMPO.SALTEQ_R' => 'salteq_r', 'INCO_COMPO.SALTEQ_R' => 'salteq_r',
'INCO_COMPO.POURCENT_APPORT_REF_SALTEQ_R' => 'pourcent_apport_ref_salteq_r', 'INCO_COMPO.POURCENT_APPORT_REF_SALTEQ_R' => 'pourcent_apport_ref_salteq_r',
'INCO_COMPO.APPORT_REF' => 'apport_ref', 'INCO_COMPO.APPORT_REF' => 'apport_ref',
'INCO_COMPO.TAILLE_PORT' => 'taille_port', 'INCO_COMPO.TAILLE_PORT' => 'taille_port', //$poidsPortion
// $poidsPortion 'INCO_COMPO.VAL_ENERG_KJ_P' => 'val_energ_kj_p', //_P apports par portion
'INCO_COMPO.VAL_ENERG_KJ_P' => 'val_energ_kj_p',
// _P apports par portion
'INCO_COMPO.VAL_ENERG_KCAL_P' => 'val_energ_kcal_p', 'INCO_COMPO.VAL_ENERG_KCAL_P' => 'val_energ_kcal_p',
'INCO_COMPO.MAT_GRASS_P' => 'mat_grass_p', 'INCO_COMPO.MAT_GRASS_P' => 'mat_grass_p',
'INCO_COMPO.AGS_P' => 'ags_p', 'INCO_COMPO.AGS_P' => 'ags_p',
@ -172,10 +147,8 @@ class XmlIncoReaderJob extends XmlJobs
'INCO_COMPO.COMPOSANTE_N' => 'composante_n', 'INCO_COMPO.COMPOSANTE_N' => 'composante_n',
'INCO_COMPO.COMPOSANTE_P' => 'composante_p', 'INCO_COMPO.COMPOSANTE_P' => 'composante_p',
'INCO_COMPO.POURCENT_FRUITS' => 'pourcent_fruits', 'INCO_COMPO.POURCENT_FRUITS' => 'pourcent_fruits',
'INCO_COMPO.SCORE_NUTRI' => 'score_nutri', 'INCO_COMPO.SCORE_NUTRI' => 'score_nutri', //du coup nutriscore ?
// du coup nutriscore ? 'INCO_COMPO.CLASSEMENT' => 'classement', //$nutriscore mais pas censé être dans INCO_COMPO
'INCO_COMPO.CLASSEMENT' => 'classement',
// $nutriscore mais pas censé être dans INCO_COMPO
'INCO_COMPO.MAT_GRASS_R_PREC' => 'mat_grass_r_prec', 'INCO_COMPO.MAT_GRASS_R_PREC' => 'mat_grass_r_prec',
'INCO_COMPO.AGS_R_PREC' => 'ags_r_prec', 'INCO_COMPO.AGS_R_PREC' => 'ags_r_prec',
'INCO_COMPO.GLUCIDES_R_PREC' => 'glucides_r_prec', 'INCO_COMPO.GLUCIDES_R_PREC' => 'glucides_r_prec',
@ -188,11 +161,6 @@ class XmlIncoReaderJob extends XmlJobs
'INCO_COMPO.FRUITS_COQUE_SECH_R_PREC' => 'fruits_coque_sech_r_prec', 'INCO_COMPO.FRUITS_COQUE_SECH_R_PREC' => 'fruits_coque_sech_r_prec',
]; ];
/**
* Fields that are allowed to be null
*
* @var array
*/
protected $nullableFields = [ protected $nullableFields = [
'taille_ref', 'taille_ref',
'conseil_prepa', 'conseil_prepa',
@ -306,18 +274,8 @@ class XmlIncoReaderJob extends XmlJobs
'inco_compo.fruits_coque_sech_r_prec' 'inco_compo.fruits_coque_sech_r_prec'
]; ];
/**
* Unique keys for updating rows
*
* @var array
*/
protected $uniqueKeyField = ['id']; protected $uniqueKeyField = ['id'];
/**
* Columns to merge in
*
* @var array
*/
protected $mergeColumns = [ protected $mergeColumns = [
'allegations' => [ 'allegations' => [
'allegat_sante', 'allegat_sante',
@ -423,20 +381,15 @@ class XmlIncoReaderJob extends XmlJobs
] ]
]; ];
/**
* Execute the job.
*
* @return void
*/
public function handle() public function handle()
{ {
$this->parseData('INCO', XmlInco::class, function (SimpleXMLElement $xmlData, array &$line) { $this->parseData('INCO', XmlInco::class, function (SimpleXMLElement $xmlData, array &$line) {
// * merge columns // merge columns
foreach ($this->mergeColumns as $key => $values) { foreach ($this->mergeColumns as $key => $values) {
$line[$key] = []; $line[$key] = [];
// * merge columns and remove merged columns from line // merge columns and remove merged columns from line
array_map(function ($kValue) use (&$line, $key) { array_map(function ($kValue) use (&$line, $key) {
if (array_key_exists($kValue, $line)) { if (array_key_exists($kValue, $line)) {
$line[$key][$kValue] = $line[$kValue]; $line[$key][$kValue] = $line[$kValue];
@ -447,33 +400,22 @@ class XmlIncoReaderJob extends XmlJobs
$line[$key] = implode(',', array_filter($line[$key])); $line[$key] = implode(',', array_filter($line[$key]));
$line[$key] = strlen($line[$key]) ? $line[$key] : null; $line[$key] = strlen($line[$key]) ? $line[$key] : null;
} }
// json column cast into array in model => no need for encode //json column cast into array in model => no need for encode
// if ($key == 'nutritional_values') { // if ($key == 'nutritional_values') {
// $line[$key] = json_encode($line[$key], \JSON_FORCE_OBJECT); // $line[$key] = json_encode($line[$key], \JSON_FORCE_OBJECT);
// } // }
} }
// * Boolean cast prod_saison // Boolean cast prod_saison
$line['prod_saison'] = isset($line['prod_saison']) ? $line['prod_saison'] = isset($line['prod_saison']) ?
(strtolower($line['prod_saison']) == 'non' ? false : true) : false; (strtolower($line['prod_saison']) == 'non' ? false : true) : false;
/** @var \Illuminate\Database\Eloquent\Model|null $model */ $arImgPaths = $this->parseImage($xmlData);
$model = XmlInco::where($this->getUniqueValues($line))->first(); $line['picture'] = $arImgPaths;
$line['pictures'] = $this->updateOrCreateImagesFiles(
$this->parseImages($xmlData),
$model
);
}); });
} }
/** private function parseImage(SimpleXMLElement $xmlData)
* Parse images
*
* @param SimpleXMLElement $xmlData
* @return array List of arrays [imgNamePath, imageData]
*/
private function parseImages(SimpleXMLElement $xmlData): array
{ {
$images = $xmlData->INCO->MEDIA_VISUEL_EAI->MEDIA_VISUEL_EAI; $images = $xmlData->INCO->MEDIA_VISUEL_EAI->MEDIA_VISUEL_EAI;
$arImgPaths = array(); $arImgPaths = array();
@ -481,138 +423,51 @@ class XmlIncoReaderJob extends XmlJobs
foreach ($images as $image) { foreach ($images as $image) {
$imageData = trim((string)$image); $imageData = trim((string)$image);
if (strlen($imageData) and $imageData = base64_decode($imageData)) { if (strlen($imageData)) {
$imageData = base64_decode($imageData);
$imgName = strval($xmlData->INCO->INCO_COMPO->TBL_INCO_COMPO->ID_INCO); $imgName = strval($xmlData->INCO->INCO_COMPO->TBL_INCO_COMPO->ID_INCO);
if (empty($imgName)) { if(empty($imgName)) {
$imgName = strval($xmlData->INCO->NO_ART); $imgName = strval($xmlData->INCO->NO_ART);
} }
$imgName = $imgName . "_" . $index; $imgName = $imgName."_".$index;
$imgNamePath = sprintf('%s/%s', rtrim($this->imagesPath, '/'), $imgName); $imgNamePath = sprintf('%s/%s', rtrim($this->imagesPath, '/'), $imgName);
$disk = $this->getDisk();
$info = getimagesizefromstring($imageData); $info = getimagesizefromstring($imageData);
if ($info === false) { if($info !== false) {
Log::debug("Could not get file info from $imgName"); $mime = $info['mime'];
continue; switch ($mime) {
} case 'image/jpeg':
switch ($info['mime'] ?? '') { $imgExtension = 'jpg';
case 'image/jpeg': break;
$imgExtension = 'jpg'; case 'image/png':
break; $imgExtension = 'png';
case 'image/png': break;
$imgExtension = 'png'; case 'image/gif':
break; $imgExtension = 'gif';
case 'image/gif': break;
$imgExtension = 'gif'; default:
break; throw new AbortXmlImportException(sprintf('Unknown image type %s', $imgName));
default: }
Log::debug("Unknown image type from $imgName");
}
$imgNamePath = sprintf('%s.%s', $imgNamePath, $imgExtension); $imgNamePath = sprintf('%s.%s', $imgNamePath, $imgExtension);
$arImgPaths[$index] = compact('imgNamePath', 'imageData'); if (!$disk->put($imgNamePath, $imageData)) {
$index++; throw new AbortXmlImportException(sprintf('The image %s could not be saved', $imgNamePath));
} //end if }
} //end foreach
$arImgPaths[$index] = sprintf('%s/%s', $this->disk, $imgNamePath);
$index++;
} else {
//probably not an image could be a PDF, PPT, AI anything is possible
}
}
}
return $arImgPaths; return $arImgPaths;
} }
/**
* Update or create images
*
* @param array $images
* @param \Illuminate\Database\Eloquent\Model|null $model
* @return array Pictures pathes with checksums as keys that will be save into model.
*/
private function updateOrCreateImagesFiles(array $images, Model $model = null): array
{
$disk = $this->getDisk();
$oldChecksums = [];
$oldPicturesPaths = [];
if ($model) {
/** @var array $oldChecksums */
$oldChecksums = \array_keys($model->pictures ?? []);
/** @var array $oldPicturesPaths */
$oldPicturesPaths = $model->pictures ?? [];
}
/** @var array $oldPictures old pictures pathes with checksums as keys */
$oldPictures = \array_combine($oldChecksums, $oldPicturesPaths);
/** @var array $newPictures new pictures pathes with checksums as keys */
$newPictures = collect($images)->mapWithKeys(function (array $imageProps) {
/** @var string $imgNamePath */
/** @var string $imageData */
extract($imageProps);
$imageFinalPath = sprintf('%s/%s', $this->disk, $imgNamePath);
// ? Sucessfully calculate checksum ?
if (!($newFileChk = hash('crc32b', $imageFinalPath . $imageData))) {
throw new \ErrorException('crc32b doesnt seems to be supported.');
}
return [$newFileChk => $imageFinalPath];
});
/** @var array $modelPictures pictures that wont change */
$modelPictures = \array_intersect_key($oldPictures, $newPictures);
/** @var \Illuminate\Support\Collection $removePictures pictures that we will remove (delete from disk) */
$removePictures = collect(\array_diff_key($oldPictures, $newPictures));
/** @var \Illuminate\Support\Collection $addPictures pictures that we will create (save on disk) */
$addPictures = collect(\array_diff_key($newPictures, $oldPictures));
// * Save or remove pictures from storage as needed
collect($images)->mapWithKeys(function (
array $imageProps,
string $checksum
) use (
$disk,
$removePictures,
$addPictures
) {
/** @var string $imgNamePath */
/** @var string $imageData */
extract($imageProps);
if ($addPictures->has($checksum)) {
// * Save new picture
if (!$disk->put($imgNamePath, $imageData)) {
throw new AbortXmlImportException(sprintf('The image %s could not be saved', $imgNamePath));
}
}
if ($removePictures->has($checksum)) {
// * Remove old picture (if exists)
if ($disk->exists($imgNamePath) and !$disk->delete($imgNamePath)) {
throw new AbortXmlImportException(sprintf('The image %s could not be delete', $imgNamePath));
}
}
});
return $newPictures;
}
/**
* Get Unique Values for a specific file
*
* @param array $line
* @return array
*/
private function getUniqueValues(array $line): array
{
/** @var array Unique Key columns */
$uniqueColumnsKey = [];
foreach ($this->uniqueKeyField as $uField) {
$uniqueColumnsKey[$uField] = $line[$uField];
}
return $uniqueColumnsKey;
}
/** /**
* Recursive extract to array * Recursive extract to array
* introduce sort of Hook to transform * introduce sort of Hook to transform
@ -645,18 +500,15 @@ class XmlIncoReaderJob extends XmlJobs
if ($value->count()) { if ($value->count()) {
$extraction = $this->extract($value); $extraction = $this->extract($value);
if ( if(count($extraction)
count($extraction) && array_key_exists("code",$extraction)
&& array_key_exists("code", $extraction) && array_key_exists("libelle",$extraction)) {
&& array_key_exists("libelle", $extraction) $val = strval($extraction['libelle']);
) {
$val = strval($extraction['libelle']);
$extract[$key] = strlen($val) ? $val : null; $extract[$key] = strlen($val) ? $val : null;
continue; continue;
} }
$extract[$key][] = $extraction; $extract[$key][] = $extraction; //$this->extract($value);
// $this->extract($value);
continue; continue;
} }
$value = strval($value); $value = strval($value);
@ -665,7 +517,7 @@ class XmlIncoReaderJob extends XmlJobs
} else { } else {
$extract[$key] = strlen($value) ? $value : null; $extract[$key] = strlen($value) ? $value : null;
} }
} //end foreach }
return $extract; return $extract;
} }
} }

View file

@ -1,32 +1,38 @@
<?php <?php
namespace App\Jobs\Arcadia; namespace App\Jobs;
use App\Enums\LogType; use App\Enums\LogType;
use App\Exceptions\AbortXmlImportException; use App\Exceptions\AbortXmlImportException;
use App\Exceptions\InvalidXmlException; use App\Exceptions\InvalidXmlException;
use App\Lib\Utils;
use ErrorException;
use Illuminate\Contracts\Filesystem\FileNotFoundException; use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
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 RecursiveArrayIterator;
use RecursiveIteratorIterator;
use SimpleXMLElement;
use Throwable;
use TypeError;
abstract class XmlJobs extends XArcadiaFlux abstract class XmlJobs extends XArcadiaFlux
{ {
/** /**
* The xsd file path used to validate files * invalid xml folder
* *
* @var string|null * @var string
*/ */
protected $xsdSchemaPath = null; protected $invalidFolderName = 'invalid';
/** /**
* The xsd file content used to validate files * xsd file location
* *
* @var string|null * @var string
*/ */
protected $xsdSchema = null; protected $xsdFile = '';
/** /**
* The columns to take from the XML * The columns to take from the XML
@ -54,113 +60,80 @@ abstract class XmlJobs extends XArcadiaFlux
/** /**
* Parse Data from the XML and gives it to the callback * Parse Data from the XML and gives it to the callback
* *
* @param string $entityName * @param string $entityName
* @param string $modelClass * @param string $modelClass
* @param callable $afterParseCallback After parse is done.
* @param callable $saveCallback Instead of updateOrCreate, execute $saveCallback.
* @param callable $afterSaveCallback After save is done.
* @return void * @return void
* @throws InvalidXmlException If xml file is not valid.
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
*/ */
protected function parseData( // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
string $entityName, protected function parseData(string $entityName, string $modelClass, callable $callback = null): void
string $modelClass, {
callable $afterParseCallback = null,
callable $saveCallback = null,
callable $afterSaveCallback = null
): void {
/** @var Filesystem */ /** @var Filesystem */
$disk = $this->getDisk(); $disk = $this->getDisk();
$this->log('Démarrage du traitement'); $this->log('Démarrage du traitement');
$this->assertXsdIsHereIfAny();
$files = $disk->files(); $files = $disk->files();
$total = count(array_filter($files, function ($filename) { $progress = 1;
$total = count(array_filter($files, function ($filename) {
if ($this->fileHasToBeIgnored($filename)) { if ($this->fileHasToBeIgnored($filename)) {
return false; return false;
} }
return true; return true;
})); }));
$this->startProgressBar($total);
foreach ($files as $filename) { foreach ($files as $filename) {
if ($this->fileHasToBeIgnored($filename)) { if ($this->fileHasToBeIgnored($filename)) {
continue; continue;
} }
$this->incrementProgressBar(); $this->log(sprintf(' traitement %d sur %s ', $progress++, $total));
try { try {
/** @var string $data */ /** @var string $data */
$data = $disk->get($filename); $data = $disk->get($filename);
$this->validateXmlFile($filename, $data);
try { try {
$this->validateSchema($data);
if ($this->encapsulate) { if ($this->encapsulate) {
$data = sprintf('<Root>%s</Root>', $data); $data = sprintf('<Root>%s</Root>', $data);
/** @var \SimpleXMLElement|false */ /** @var SimpleXMLElement|false */
$xmlContent = simplexml_load_string($data); $xmlContent = simplexml_load_string($data);
} else { } else {
/** @var \SimpleXMLElement|false */ /** @var SimpleXMLElement|false */
$xmlContent = simplexml_load_string($data, null, LIBXML_NOCDATA | LIBXML_PARSEHUGE); $xmlContent = simplexml_load_string($data, null, LIBXML_NOCDATA | LIBXML_PARSEHUGE);
} }
if ($xmlContent === false) { if ($xmlContent === false) {
throw new InvalidXmlException('XML is Invalid (simplexml_load_string returned false)'); throw new InvalidXmlException('XML is Invalid (simplexml_load_string returned false)');
} }
} catch (\ErrorException $e) { } catch (ErrorException $e) {
throw new InvalidXmlException('XML is Invalid', 0, $e); throw new InvalidXmlException('XML is Invalid', 0, $e);
} }
$data = $this->extract($xmlContent); $data = $this->extract($xmlContent);
$lines = [];
// * Multiple Entities within file $lines = [];
if (isset($data[$entityName])) { foreach ($data[$entityName] as $traca) {
foreach ($data[$entityName] as $traca) { $line = $this->processFields($traca);
$line = $this->processFields($traca); if ($callback) {
if ($afterParseCallback) { $callback($xmlContent, $line);
$afterParseCallback($xmlContent, $line);
}
$lines[] = $line;
}
} else {
// * Only one entity within file
$line = $this->processFields($data);
if ($afterParseCallback) {
$afterParseCallback($xmlContent, $line);
} }
$lines[] = $line; $lines[] = $line;
} }
// Mise en base des données
// * Mise en base des données
foreach ($lines as $line) { foreach ($lines as $line) {
/** @var array Unique Key columns */ /** @var array Unique Key columns */
$uniqueColumnsKey = []; $uniqueColumnsKey = [];
foreach ($this->uniqueKeyField as $uField) { foreach ($this->uniqueKeyField as $uField) {
$uniqueColumnsKey[$uField] = $line[$uField]; $uniqueColumnsKey[$uField] = $line[$uField];
} }
if (count($uniqueColumnsKey)) { forward_static_call_array(
if ($saveCallback) { [$modelClass, 'updateOrCreate'],
$saveCallback($uniqueColumnsKey, $line); [$uniqueColumnsKey, $line]
} else { );
forward_static_call_array( }
[$modelClass, 'updateOrCreate'],
[$uniqueColumnsKey, $line]
);
}
if ($afterSaveCallback) {
$afterSaveCallback($xmlContent, $line);
}
}
} //end foreach
} catch (InvalidXmlException $e) { } catch (InvalidXmlException $e) {
$message = $e->getMessage(); $message = $e->getMessage();
if (get_class($e) === QueryException::class) {
$message = implode(' ', $e->errorInfo);
}
$this->log( $this->log(
sprintf( sprintf(
'File %s could not be parsed => %s on line %d', 'File %s could not be parsed => %s on line %d',
@ -173,6 +146,19 @@ abstract class XmlJobs extends XArcadiaFlux
$this->sendInvalidXmlEmail($filename, $e); $this->sendInvalidXmlEmail($filename, $e);
$this->moveToInvalid($filename); $this->moveToInvalid($filename);
continue; continue;
} catch (ErrorException | TypeError $e) {
$this->log(
sprintf(
'CRITICAL: File %s could not be parsed => %s on line %d',
$filename,
$e->getMessage(),
$e->getLine()
),
LogType::critical()
);
$this->sendErrorParseEmailToServiceWeb($e);
continue;
// ignore the file
} catch (AbortXmlImportException $e) { } catch (AbortXmlImportException $e) {
$this->log( $this->log(
sprintf( sprintf(
@ -183,16 +169,15 @@ abstract class XmlJobs extends XArcadiaFlux
), ),
LogType::error() LogType::error()
); );
report($e); $this->sendErrorParseEmailToServiceWeb($e);
continue; continue;
// * ignore the file // ignore the file
} catch (QueryException $e) { } catch (FileNotFoundException | QueryException $e) {
$this->log(implode(' ', $e->errorInfo), LogType::critical()); // This happens because of concurent xml jobs read
report($e);
continue;
} catch (FileNotFoundException $e) {
// This happens because of concurent xml jobs read.
$message = $e->getMessage(); $message = $e->getMessage();
if (get_class($e) === QueryException::class) {
$message = implode(' ', $e->errorInfo);
}
$this->log( $this->log(
sprintf( sprintf(
'ERROR: File %s could not be read (not found) => %s on line %d', 'ERROR: File %s could not be read (not found) => %s on line %d',
@ -203,31 +188,13 @@ abstract class XmlJobs extends XArcadiaFlux
LogType::debug() LogType::debug()
); );
continue; continue;
// * ignore the file // ignore the file
} catch (\Exception | \ErrorException | \TypeError $e) { }//end try
$this->log(
sprintf(
'File %s could not be parsed => %s on line %d',
$filename,
$e->getMessage(),
$e->getLine()
),
LogType::critical()
);
report($e);
continue;
// * ignore the file
} //end try
$this->moveToArchives($filename); $this->moveToArchives($filename);
} //end foreach }//end foreach
// Clear old invalids. // Clear old archives
$this->clearOldInvalids();
// Clear old archives.
$this->clearOldArchives(); $this->clearOldArchives();
$this->endProgressBar();
} }
/** /**
@ -238,7 +205,7 @@ abstract class XmlJobs extends XArcadiaFlux
*/ */
protected function extract($sxe = null): array protected function extract($sxe = null): array
{ {
if (!$sxe instanceof \SimpleXMLElement) { if (!$sxe instanceof SimpleXMLElement) {
return array(); return array();
} }
$extract = array(); $extract = array();
@ -262,7 +229,7 @@ abstract class XmlJobs extends XArcadiaFlux
* *
* @param array $fields * @param array $fields
* @return array * @return array
* @throws AbortXmlImportException If a field could not be validated. * @throws AbortXmlImportException
*/ */
protected function processFields(array $fields): array protected function processFields(array $fields): array
{ {
@ -275,8 +242,8 @@ abstract class XmlJobs extends XArcadiaFlux
throw new AbortXmlImportException(sprintf('The field %s is not allowed to be null', $key)); throw new AbortXmlImportException(sprintf('The field %s is not allowed to be null', $key));
} }
if (is_array($field)) { if (is_array($field)) {
// * Flatten data // Flatten data
$it = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($field)); $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($field));
foreach ($it as $k => $f) { foreach ($it as $k => $f) {
$ko = strtolower(sprintf('%s.%s', $key, $k)); $ko = strtolower(sprintf('%s.%s', $key, $k));
if (!$this->isFieldNullable($ko) && is_null($f)) { if (!$this->isFieldNullable($ko) && is_null($f)) {
@ -294,7 +261,7 @@ abstract class XmlJobs extends XArcadiaFlux
} else { } else {
$result[$key] = $field; $result[$key] = $field;
} }
} //end foreach }//end foreach
return $result; return $result;
} }
@ -342,6 +309,23 @@ abstract class XmlJobs extends XArcadiaFlux
return in_array($filename, $this->ignoreFiles) or !$this->checkExtension($filename, 'xml'); return in_array($filename, $this->ignoreFiles) or !$this->checkExtension($filename, 'xml');
} }
/**
* Validate xml data against xsd file if provided
*
* @return void
*/
protected function validateSchema($data) {
if($this->xsdFile) {
//check against XSD
$xsd = storage_path($this->disk."/".$this->xsdFile);
$domDocument= new \DOMDocument();
$domDocument->loadXML($data);
//free some memroy to avoid overload
unset($data);
$domDocument->schemaValidate($xsd);
}
}
/** /**
* Check if the file is an xml file * Check if the file is an xml file
* *
@ -357,81 +341,78 @@ abstract class XmlJobs extends XArcadiaFlux
return $isXml; return $isXml;
} }
/** protected function sendErrorParseEmailToServiceWeb(Throwable $e)
* Send invalid XML email {
* Utils::sendEmailErrorManually($e);
* @param string $filename }
* @param \Throwable $e
* @return void protected function sendInvalidXmlEmail(string $filename, Throwable $e)
*/
protected function sendInvalidXmlEmail(string $filename, \Throwable $e)
{ {
$message = $e->getPrevious()->getMessage(); $message = $e->getPrevious()->getMessage();
Mail::send('mails.invalidxml', [ Mail::send('emails.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',
$filename, $filename,
$message, $message,
$e->getLine() $e->getLine()
), ),
'appName' => config('app.name'),
'filename' => $filename, 'filename' => $filename,
'exception' => $e->getPrevious() 'exception' => $e->getPrevious()
], function ($m) { ], function ($m) {
$m->to( $m->to(
config('mail.contactsList.invalidInco'), config('mail.contactsList.invalidInco'),
sprintf('%s XML Exception Handler', config('app.name')) sprintf('%s Exception Handler', config('app.name'))
)->subject('You sent me an invalid XML file, please check its validity before resend ASAP.'); )->subject('You sent me an invalid XML file, please check its validity before resend ASAP.');
}); });
} }
/** /**
* Assert XSD is readable if configured * Move the file to invalid folder
* *
* @param string $filename
* @return void * @return void
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException If xsd file cant be read.
*/ */
private function assertXsdIsHereIfAny() protected function moveToInvalid(string $filename): void
{ {
if ($this->xsdSchemaPath) { $newFileName = $filename;
$this->xsdSchema = File::get($this->xsdSchemaPath); if (!$this->getDisk()->exists($filename)) {
$this->log(
sprintf(
'File %s could not be moved to invalid (not found)',
$filename
),
LogType::warning()
);
return;
}
if ($this->getDisk()->exists(sprintf('%s/%s', $this->invalidFolderName, $filename))) {
$ext = \pathinfo($filename, \PATHINFO_EXTENSION);
$newFileName = \sprintf(
'%s_%d.%s',
\substr($filename, 0, 0 - (strlen($ext) + 1)),
\time(),
$ext
);
}
try {
if (!$this->getDisk()->move($filename, sprintf('%s/%s', $this->invalidFolderName, $newFileName))) {
$this->log(
sprintf(
'File %s could not be moved to invalid',
$filename
),
LogType::warning()
);
}
} catch (Exception $e) {
$this->log(
sprintf(
'File %s could not be moved to invalid',
$filename
),
LogType::warning()
);
} }
} }
/**
* Validate Xml file against XSD if loaded
*
* @param string $fileName
* @param string $fileContent
* @return void
* @throws InvalidXmlException If XML could not be parsed or validated against XSD.
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
*/
private function validateXmlFile(string $fileName, string $fileContent)
{
if ($this->xsdSchema) {
$domDocument = new \DOMDocument('1.0', 'UTF-8');
try {
if (!$domDocument->loadXML($fileContent)) {
throw new InvalidXmlException("XML Validation $fileName content could not be loaded to validate.");
}
if (!$domDocument->schemaValidateSource($this->xsdSchema, LIBXML_SCHEMA_CREATE)) {
throw new InvalidXmlException(
"XML Validation $fileName content could not be validated against xsd."
);
}
} catch (\Exception $e) {
if (\get_class($e) === InvalidXmlException::class) {
throw $e;
}
throw new InvalidXmlException(
"XML Validation $fileName content could not be validated against xsd.",
0,
1,
__FILE__,
__LINE__,
$e
);
} //end try
} //end if
}
} }

View file

@ -1,180 +0,0 @@
<?php
namespace App\Lib;
use App\Exceptions\Api\ApplicationException;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
/**
* Helper Class
*/
class Helper
{
/**
* Package infos
*
* @var array
*/
private static $packageInfos;
/**
* Tells if the request is within apiV1 routes
*
* @param Request $request
* @return boolean
*/
public static function isRequestForApiV1(Request $request): bool
{
// * Small hack to ensure to know if route is From APIv1.
$routePrefix = (strpos(static::getRoutePrefix($request), 'api/v1') ? 'v1' : null) ??
(strpos($request->path(), 'api/v1') === 0 ? 'v1' : null) ?? 'none';
return strpos($routePrefix, 'v1') === 0;
}
/**
* Try to get current route name
*
* @param Request $request
* @return string|null
*/
public static function getRouteName(Request $request)
{
return Route::currentRouteName() ?? ($request->route() ? $request->route()->getName() : null);
}
/**
* Get the bearer token from request
*
* @param Request $request
* @return string|null
*/
public static function getBearerTokenFromRequest(Request $request): ?string
{
$header = $request->header('Authorization', '');
if (Str::contains($header, 'Bearer ')) {
$auths = \explode(',', $header);
foreach ($auths as $auth) {
if (Str::contains($auth, 'Bearer ')) {
return Str::substr($auth, 7);
}
}
}
return null;
}
/**
* Try to get current route prefix
*
* @param Request $request
* @return string|null
*/
public static function getRoutePrefix(Request $request)
{
return (Route::getCurrentRoute() ? Route::getCurrentRoute()->getPrefix() : null) ??
($request->route() ? $request->route()->getPrefix() : null);
}
/**
* Try to get route from request
*
* @param Request $request
* @return \Illuminate\Routing\Route|null
*/
public static function getRoute(Request $request)
{
return Route::getRoutes()->getByName(static::getRouteName($request));
}
/**
* Get composer.json infos
*
* @return array
*/
public static function getPackageInfo(): array
{
if (!static::$packageInfos) {
static::$packageInfos = \json_decode(\file_get_contents(__DIR__ . '/../../composer.json'), true);
}
return static::$packageInfos;
}
/**
* Calculate the request signature
*
* @param string $secret
* @param string $uri
* @param string $method
* @param array $parameters
* @return string request signature
* @throws ApplicationException If an error occurs.
*/
public static function signRequest(string $secret, string $uri, string $method, array $parameters): string
{
try {
$uri = collect(\parse_url($uri));
$method = \strtolower($method);
// * Remove signature from parameters to calculate the hashmac.
$signature = collect([
'uri' => sprintf(
'%s://%s%s',
$uri->get('scheme'),
$uri->get('host'),
$uri->get('path')
),
'method' => $method
]);
$flattenRequestArray = function (array $array) use (&$flattenRequestArray) {
$out = [];
foreach ($array as $key => $value) {
if (is_array($value)) {
$subArray = $flattenRequestArray($value);
foreach ($subArray as $subKey => $subValue) {
$out["$key.$subKey"] = $subValue;
}
continue;
}
$out[$key] = $value;
}
return $out;
};
$parameters = $flattenRequestArray($parameters);
$parameters = collect($parameters);
// * Remove signature from parameters.
$parameters->pull('signature');
// * Natural sort all parameters.
$parameters = $parameters->sortKeys(\SORT_NATURAL)
->map(function ($value, $key) {
return sprintf('%s=%s', \rawurlencode($key), \rawurlencode($value));
});
$signature->push($parameters->implode('&'));
$calculatedHash = base64_encode(hash_hmac(
'sha256',
$signature->implode('\n'),
Crypt::decryptString($secret),
true
));
if (!$calculatedHash) {
throw new ApplicationException('Failed to calculate requests hash');
}
return $calculatedHash;
} catch (DecryptException $e) {
throw new ApplicationException('Failed to decrypt service credentials', 0, $e);
} catch (\Exception $e) {
throw new ApplicationException('An error occured when authenticating service', 0, $e);
} //end try
}
}

210
app/Lib/Utils.php Normal file
View file

@ -0,0 +1,210 @@
<?php
namespace App\Lib;
use Exception;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Throwable;
/**
* Some utilities methods
*
* @author Jérémy Munsch <jeremy.munsch@ldc.fr>
*/
// phpcs:disable Generic.Files.LineLength.TooLong
class Utils
{
/**
* Replace stange accents
*
* https://stackoverflow.com/questions/3371697/replacing-accented-characters-php
* @author Jérémy Munsch <jeremy.munsch@jeremydev.ovh>
* @param string $subject
* @return string
*/
public static function replaceSpecChar(string $subject): string
{
$char_map = array(
"ъ" => "-", "ь" => "-", "Ъ" => "-", "Ь" => "-",
"А" => "A", "Ă" => "A", "Ǎ" => "A", "Ą" => "A", "À" => "A", "Ã" => "A", "Á" => "A", "Æ" => "A", "Â" => "A", "Å" => "A", "Ǻ" => "A", "Ā" => "A", "א" => "A",
"Б" => "B", "ב" => "B", "Þ" => "B",
"Ĉ" => "C", "Ć" => "C", "Ç" => "C", "Ц" => "C", "צ" => "C", "Ċ" => "C", "Č" => "C", "©" => "C", "ץ" => "C",
"Д" => "D", "Ď" => "D", "Đ" => "D", "ד" => "D", "Ð" => "D",
"È" => "E", "Ę" => "E", "É" => "E", "Ë" => "E", "Ê" => "E", "Е" => "E", "Ē" => "E", "Ė" => "E", "Ě" => "E", "Ĕ" => "E", "Є" => "E", "Ə" => "E", "ע" => "E",
"Ф" => "F", "Ƒ" => "F",
"Ğ" => "G", "Ġ" => "G", "Ģ" => "G", "Ĝ" => "G", "Г" => "G", "ג" => "G", "Ґ" => "G",
"ח" => "H", "Ħ" => "H", "Х" => "H", "Ĥ" => "H", "ה" => "H",
"I" => "I", "Ï" => "I", "Î" => "I", "Í" => "I", "Ì" => "I", "Į" => "I", "Ĭ" => "I", "I" => "I", "И" => "I", "Ĩ" => "I", "Ǐ" => "I", "י" => "I", "Ї" => "I", "Ī" => "I", "І" => "I",
"Й" => "J", "Ĵ" => "J",
"ĸ" => "K", "כ" => "K", "Ķ" => "K", "К" => "K", "ך" => "K",
"Ł" => "L", "Ŀ" => "L", "Л" => "L", "Ļ" => "L", "Ĺ" => "L", "Ľ" => "L", "ל" => "L",
"מ" => "M", "М" => "M", "ם" => "M",
"Ñ" => "N", "Ń" => "N", "Н" => "N", "Ņ" => "N", "ן" => "N", "Ŋ" => "N", "נ" => "N", "ʼn" => "N", "Ň" => "N",
"Ø" => "O", "Ó" => "O", "Ò" => "O", "Ô" => "O", "Õ" => "O", "О" => "O", "Ő" => "O", "Ŏ" => "O", "Ō" => "O", "Ǿ" => "O", "Ǒ" => "O", "Ơ" => "O",
"פ" => "P", "ף" => "P", "П" => "P",
"ק" => "Q",
"Ŕ" => "R", "Ř" => "R", "Ŗ" => "R", "ר" => "R", "Р" => "R", "®" => "R",
"Ş" => "S", "Ś" => "S", "Ș" => "S", "Š" => "S", "С" => "S", "Ŝ" => "S", "ס" => "S",
"Т" => "T", "Ț" => "T", "ט" => "T", "Ŧ" => "T", "ת" => "T", "Ť" => "T", "Ţ" => "T",
"Ù" => "U", "Û" => "U", "Ú" => "U", "Ū" => "U", "У" => "U", "Ũ" => "U", "Ư" => "U", "Ǔ" => "U", "Ų" => "U", "Ŭ" => "U", "Ů" => "U", "Ű" => "U", "Ǖ" => "U", "Ǜ" => "U", "Ǚ" => "U", "Ǘ" => "U",
"В" => "V", "ו" => "V",
"Ý" => "Y", "Ы" => "Y", "Ŷ" => "Y", "Ÿ" => "Y",
"Ź" => "Z", "Ž" => "Z", "Ż" => "Z", "З" => "Z", "ז" => "Z",
"а" => "a", "ă" => "a", "ǎ" => "a", "ą" => "a", "à" => "a", "ã" => "a", "á" => "a", "æ" => "a", "â" => "a", "å" => "a", "ǻ" => "a", "ā" => "a", "א" => "a",
"б" => "b", "ב" => "b", "þ" => "b",
"ĉ" => "c", "ć" => "c", "ç" => "c", "ц" => "c", "צ" => "c", "ċ" => "c", "č" => "c", "©" => "c", "ץ" => "c",
"Ч" => "ch", "ч" => "ch",
"д" => "d", "ď" => "d", "đ" => "d", "ד" => "d", "ð" => "d",
"è" => "e", "ę" => "e", "é" => "e", "ë" => "e", "ê" => "e", "е" => "e", "ē" => "e", "ė" => "e", "ě" => "e", "ĕ" => "e", "є" => "e", "ə" => "e", "ע" => "e",
"ф" => "f", "ƒ" => "f",
"ğ" => "g", "ġ" => "g", "ģ" => "g", "ĝ" => "g", "г" => "g", "ג" => "g", "ґ" => "g",
"ח" => "h", "ħ" => "h", "х" => "h", "ĥ" => "h", "ה" => "h",
"i" => "i", "ï" => "i", "î" => "i", "í" => "i", "ì" => "i", "į" => "i", "ĭ" => "i", "ı" => "i", "и" => "i", "ĩ" => "i", "ǐ" => "i", "י" => "i", "ї" => "i", "ī" => "i", "і" => "i",
"й" => "j", "Й" => "j", "Ĵ" => "j", "ĵ" => "j",
"ĸ" => "k", "כ" => "k", "ķ" => "k", "к" => "k", "ך" => "k",
"ł" => "l", "ŀ" => "l", "л" => "l", "ļ" => "l", "ĺ" => "l", "ľ" => "l", "ל" => "l",
"מ" => "m", "м" => "m", "ם" => "m",
"ñ" => "n", "ń" => "n", "н" => "n", "ņ" => "n", "ן" => "n", "ŋ" => "n", "נ" => "n", "ʼn" => "n", "ň" => "n",
"ø" => "o", "ó" => "o", "ò" => "o", "ô" => "o", "õ" => "o", "о" => "o", "ő" => "o", "ŏ" => "o", "ō" => "o", "ǿ" => "o", "ǒ" => "o", "ơ" => "o",
"פ" => "p", "ף" => "p", "п" => "p",
"ק" => "q",
"ŕ" => "r", "ř" => "r", "ŗ" => "r", "ר" => "r", "р" => "r", "®" => "r",
"ş" => "s", "ś" => "s", "ș" => "s", "š" => "s", "с" => "s", "ŝ" => "s", "ס" => "s",
"т" => "t", "ț" => "t", "ט" => "t", "ŧ" => "t", "ת" => "t", "ť" => "t", "ţ" => "t",
"ù" => "u", "û" => "u", "ú" => "u", "ū" => "u", "у" => "u", "ũ" => "u", "ư" => "u", "ǔ" => "u", "ų" => "u", "ŭ" => "u", "ů" => "u", "ű" => "u", "ǖ" => "u", "ǜ" => "u", "ǚ" => "u", "ǘ" => "u",
"в" => "v", "ו" => "v",
"ý" => "y", "ы" => "y", "ŷ" => "y", "ÿ" => "y",
"ź" => "z", "ž" => "z", "ż" => "z", "з" => "z", "ז" => "z", "ſ" => "z",
"™" => "tm",
"@" => "at",
"Ä" => "ae", "Ǽ" => "ae", "ä" => "ae", "æ" => "ae", "ǽ" => "ae",
"ij" => "ij", "IJ" => "ij",
"я" => "ja", "Я" => "ja",
"Э" => "je", "э" => "je",
"ё" => "jo", "Ё" => "jo",
"ю" => "ju", "Ю" => "ju",
"œ" => "oe", "Œ" => "oe", "ö" => "oe", "Ö" => "oe",
"щ" => "sch", "Щ" => "sch",
"ш" => "sh", "Ш" => "sh",
"ß" => "ss",
"Ü" => "ue",
"Ж" => "zh", "ж" => "zh",
);
return self::mbStrtr($subject, $char_map);
}
/**
* Multibyte strtr
*
* @param string $str
* @param string|array $from
* @param string|null $to
* @return string
*/
public static function mbStrtr($str, $from, $to = null): string
{
if (is_array($from)) {
$from = array_map('utf8_decode', $from);
$from = array_map('utf8_decode', array_flip($from));
return utf8_encode(strtr(utf8_decode($str), array_flip($from)));
}
return utf8_encode(strtr(utf8_decode($str), utf8_decode($from), utf8_decode($to)));
}
/**
* Manually send an exception to team instead of going trough the error handler
* (requires package kwaadpepper/exception-handler)
*
* @param Throwable $e
* @return void
*/
public static function sendEmailErrorManually(Throwable $e)
{
Mail::send([
'html' => 'exception-handler::emails.exception',
'text' => 'exception-handler::emails.exception-plain'
], [
'appName' => config('app.name'),
'code' => $e->getCode(),
'line' => $e->getLine(),
'ename' => \get_class($e),
'emessage' => self::getAnonymizedMessage($e->getMessage()),
'file' => str_replace(\realpath(\sprintf('%s/../', \app_path())), '', $e->getFile()),
'stackTrace' => self::getAnonymizedStackTrace($e),
'uri' => app()->runningInConsole() ?
'CONSOLE' : (
(request() and request()->fullUrl()) ?
request()->fullUrl() : 'none')
], function ($m) {
/** @var \Illuminate\Mail\Message $m */
$m->to(
config('mail.contactsList.serviceweb'),
sprintf('%s Exception Handler', config('app.name'))
)->subject('Need help !, an error occured in your application, please check Logs ASAP');
});
Log::alert(sprintf('Envoie d\'une erreur par mail : %s', json_encode($e)));
}
/**
* Anonymize at least Sql queries
*
* @param string $message
* @return string
*/
private static function getAnonymizedMessage(string $message): string
{
$message = \preg_replace('/^(.*)( \(SQL:.*\))$/', '$1', $message) ?? $message;
return $message;
}
/**
* Anonymize stack trace
*
* @param \Exception $e
* @return string
*/
private 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']
);
$traceStr .= "{$stack['class']}->{$stack['function']}(";
$traceArgs = '';
if (isset($stack['args'])) {
$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) ? ',' : '');
}
$traceStr .= $traceArgs;
}//end if
$traceStr .= ")\n";
}//end foreach
$maxStackStage++;
$traceStr .= "#$maxStackStage {main}";
return $traceStr;
}
}

View file

@ -1,90 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Rennokki\QueryCache\Traits\QueryCacheable;
class ArcadiaBrand extends Model
{
use HasFactory;
use QueryCacheable;
/**
* The timeout cache for this model
*
* @var integer
*/
protected $cacheFor = 0;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'arcadia_id',
'libelle'
];
/**
* ArcadiaBrand
*
* @param array $attributes
*/
public function __construct(array $attributes = [])
{
$this->cacheFor = config('api.arcadiaBrandsDBCache') * 60;
parent::__construct($attributes);
}
/**
* Set the base cache tags that will be present
* on all queries.
*
* ! This is used to flush caching
*
* @return array
*/
protected function getCacheBaseTags(): array
{
return [
'incollector_arcadia_brands',
];
}
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted()
{
static::created(function () {
// * Flush Eloquent cache.
self::flushQueryCache();
});
static::updated(function () {
// * Flush Eloquent cache.
self::flushQueryCache();
});
static::deleted(function () {
// * Flush Eloquent cache.
self::flushQueryCache();
});
}
// * RELATIONS
/**
* Service belongsToMany relation
*
* @return \Illuminate\Database\Eloquent\Relations\belongsToMany
*/
public function services()
{
return $this->belongsToMany(Service::class);
}
}

View file

@ -1,224 +0,0 @@
<?php
namespace App\Models;
use App\Jobs\SetServiceStats;
use App\Lib\Helper;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
use Rennokki\QueryCache\Traits\QueryCacheable;
class Service extends Model
{
use HasFactory;
use QueryCacheable;
/**
* The timeout cache for this model
*
* @var integer
*/
protected $cacheFor = 0;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = [
'name'
];
/**
* Service
*
* @param array $attributes
*/
public function __construct(array $attributes = [])
{
$this->cacheFor = config('api.servicesDBCache') * 60;
parent::__construct($attributes);
}
/**
* Set the base cache tags that will be present
* on all queries.
*
* ! This is used to flush caching
*
* @return array
*/
protected function getCacheBaseTags(): array
{
return [
'incollector_services',
];
}
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted()
{
static::creating(function (self $service) {
$service->generateBearerToken();
$service->generateBearerPassword();
});
static::created(function () {
// * Flush Eloquent cache.
self::flushQueryCache();
});
static::updated(function () {
// * Flush Eloquent cache.
self::flushQueryCache();
});
static::deleted(function () {
// * Flush Eloquent cache.
self::flushQueryCache();
});
}
// * RELATIONS
/**
* ArcadiaBrand belongsToMany relation
*
* @return \Illuminate\Database\Eloquent\Relations\belongsToMany
*/
public function arcadiaBrands()
{
return $this->belongsToMany(ArcadiaBrand::class);
}
/**
* ServiceStat hasMany relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function servicesStats()
{
return $this->hasMany(ServiceStat::class);
}
// * METHODS
/**
* Increment API CRM Stat
*
* @return void
*/
public function incrementStat(): void
{
SetServiceStats::dispatch($this)->afterResponse()
->onConnection('database')->onQueue('stats');
}
/**
* Generates new bearer token
*
* @return string
*/
public function generateBearerToken(): string
{
$this->bearer_token = hash('ripemd160', Str::uuid());
$this->bearer_token_date = now();
return $this->bearer_token;
}
/**
* Generates new bearer password
* It store the crypted password in model
* and returns the plain password
*
* @return string
*/
public function generateBearerPassword(): string
{
$pwd = hash('sha256', Str::uuid());
$this->bearer_pwd = Crypt::encryptString($pwd);
return $pwd;
}
/**
* Get Service from bearerToken with its brand
*
* @param string $bearerToken
* @return \App\Models\Service
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException If the token matches no known service.
*/
public static function getFromBearerToken(string $bearerToken): self
{
$services = static::all();
/** @var \App\Models\Service $service */
foreach ($services as $service) {
if ($service->bearer_token and $bearerToken === $service->bearer_token) {
return $service->load([
'arcadiaBrands' => function ($query) use ($service) {
return $query->cacheTags(["service:{$service->id}:arcadiaBrands"]);
},
]);
}
}
throw new ModelNotFoundException('Could not find service from Service Token');
}
/**
* Authenticate the request for this service
*
* This will check hash-mac and that the request is wellformed
*
* The request should have the minimum following parameters
* - timestamp using format Y-m-d H:i:s, and must be UTC (Greenwich Mean Time)
* - bearerToken the public token generated by the crm
* - signature the hashmac signature of the request
*
* ! Signature must be calculated with every parameter urlencode once only
* ! All parameters to calculate the signature must be sorted (natural sort asc)
*
* ! Signature should look like
* * httpVerb\n
* * uri\n
* * queryString
*
* ! httpVerb as well as uri must be lower case
* ! uri should include scheme, host and path and nothing else, if path is empty a trailing slash should be added
* ! eg: https://ldc-crm.fr/customer/1 or https://ldc-crm.fr/
* ! The query string shall be separated with '&', eg param1=value1&param2=value2
* ! Key names and values of the query string must be url encoded using RFC 3986
* ! http://www.faqs.org/rfcs/rfc3986.html
* ! Signature must be hmac sha256 using the private key generatedby the crm
*
* * ! They should then be concat in a string separated by \n
*
*
*
* @param \Illuminate\Http\Request $request
* @return boolean
* @throws \App\Exceptions\Api\V2\CrmException If an error occurs.
*/
public function authenticateApi(Request $request): bool
{
// ! Hack to prevent Laravel to cast empty strings to null or the opposite.
// ! If cannot decode json user legacy all() method.
$data = \json_decode($request->getContent(), true);
$data = (\is_array($data) and \json_last_error() === \JSON_ERROR_NONE) ?
array_replace_recursive($request->all(), $data) : $request->all();
$calculatedHash = Helper::signRequest(
$this->bearer_pwd,
$request->getUri(),
$request->getMethod(),
$data
);
// ! Très important hash_equals https://fr.wikipedia.org/wiki/Attaque_temporelle
return \hash_equals($calculatedHash, $request->signature);
}
}

View file

@ -1,39 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ServiceStat extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = ['date'];
/**
* The model's attributes.
*
* @var array
*/
protected $attributes = [
'nb_calls' => 0
];
// * RELATIONS
/**
* Service BelongsTo relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function service()
{
return $this->belongsTo(Service::class);
}
}

View file

@ -2,17 +2,15 @@
namespace App\Models; namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use Laravel\Sanctum\HasApiTokens; use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable class User extends Authenticatable
{ {
use HasApiTokens; use HasApiTokens, HasFactory, Notifiable;
use HasFactory;
use Notifiable;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
@ -43,21 +41,4 @@ class User extends Authenticatable
protected $casts = [ protected $casts = [
'email_verified_at' => 'datetime', 'email_verified_at' => 'datetime',
]; ];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted()
{
static::creating(function (self $user) {
$user->password = Hash::make($user->password);
});
static::updating(function (self $user) {
if (Hash::needsRehash($user->password)) {
$user->password = Hash::make($user->password);
}
});
}
} }

View file

@ -4,26 +4,15 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Facades\Storage;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Collection;
/**
* XmlInco
*
* pictures attribute is organized as following
* [
* 'checksum' => 'storageFilePath'
* ]
*
* ! checksum includes fullfilepath + data
*/
class XmlInco extends Model class XmlInco extends Model
{ {
use HasFactory; use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [ protected $fillable = [
'id', 'id',
'no_art', 'no_art',
@ -40,40 +29,72 @@ class XmlInco extends Model
'lst_ing', 'lst_ing',
'lib_allergene', 'lib_allergene',
'nutritional_values', 'nutritional_values',
'pictures', 'picture',
]; ];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [ protected $casts = [
'pictures' => 'array', 'picture' => 'array',
'nutritional_values' => 'array', 'nutritional_values' => 'array',
]; ];
// * GETTERS /**
* The Laravel disk name
*
* @var string
*/
protected $disk = 'inco';
protected $imagesPath = 'images';
/** /**
* Get niceString attribute * The files to ignore
* *
* @return string * @var array
*/ */
public function getNiceStringAttribute(): string protected $ignoreFiles = [
'.gitignore', '.gitkeep'
];
/**
* retrieve a collection of medias
*/
public function getMediasAttribute() {
/** @var Filesystem */
$disk = $this->getDisk();
$files = $disk->files($this->imagesPath);
$collFiles = new Collection();
// /** @var File */
foreach ($files as $file) {
$pi = \pathinfo($file, \PATHINFO_BASENAME);
if (in_array($pi, $this->ignoreFiles)) {
continue;
}
if (!in_array($pi, array($this->id))) {
continue;
}
$image = base64_encode($disk->get($file));
$element = array(
"filename" => $pi,
"imgdata" => $image
);
$collFiles->add($element);
}
return $collFiles;
}
/**
* Get the concerned disk
*
* @return Filesystem
*/
protected function getDisk(): Filesystem
{
return Storage::disk($this->disk);
}
public function getNiceStringAttribute()
{ {
return sprintf('%s - %s', $this->id, $this->descriptif); return sprintf('%s - %s', $this->id, $this->descriptif);
} }
// * RELATIONS
/**
* ArcadiaBrand belongsTo relation
*
* @return \Illuminate\Database\Eloquent\Relations\belongsTo
*/
public function arcadiaBrand()
{
return $this->belongsTo(ArcadiaBrand::class);
}
} }

View file

@ -1,52 +0,0 @@
<?php
namespace App\Policies;
use App\Models\ArcadiaBrand;
use App\Models\Service;
use App\Policies\Rules\UserStaticRules as USR;
use Illuminate\Auth\Access\HandlesAuthorization;
use Kwaadpepper\CrudPolicies\Policies\RootPolicy;
/**
* @codeCoverageIgnore
*/
class ArcadiaBrandPolicy extends RootPolicy
{
use HandlesAuthorization;
/**
* Init policies on call
*
* @return void
*/
public function setPolicies()
{
/**
* This first rule to return true in a policy action authorises the action
*/
$this->policies = [
'arcadia_brand' => [
'viewAny' => USR::make('everyOne'),
'view' => USR::make('everyOne'),
'create' => USR::make('noOne'),
'update' => USR::make('noOne'),
'delete' => USR::make('noOne')
]
];
}
/**
* Check if the customer belongs to the service
*
* @param Service $service
* @param ArcadiaBrand $arcadiaBrand
* @return boolean
*/
public function arcadiaBrandBelongsToService(Service $service, ArcadiaBrand $arcadiaBrand)
{
return $service->arcadiaBrands()->whereHas('services', function ($q) use ($arcadiaBrand) {
$q->whereId($arcadiaBrand->id);
})->exists();
}
}

View file

@ -1,32 +0,0 @@
<?php
namespace App\Policies\Rules;
use Kwaadpepper\CrudPolicies\Policies\Rules\StaticRules;
/**
* Userlevel Policiy Static Rules
* ! Rules has to return boolean value
* @codeCoverageIgnore
*/
abstract class UserStaticRules extends StaticRules
{
/**
* Allow everyone
*
* @return boolean
*/
protected static function everyOne(): bool
{
return true;
}
/**
* Allow no one
*
* @return boolean
*/
protected static function noOne(): bool
{
return false;
}
}

View file

@ -2,14 +2,6 @@
namespace App\Providers; namespace App\Providers;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
@ -21,6 +13,7 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function register() public function register()
{ {
//
} }
/** /**
@ -30,54 +23,6 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
// ! Important pourra etre retiré quand la V1 sera supprimé //
// Empeche l'encapsulation dans data .
JsonResource::withoutWrapping();
// * LOCAL HTTPS FIX.
if (!in_array(config('app.env'), ['local', 'testing'])) {
URL::forceScheme('https');
}
// * HA PROXY FIX.
App::singleton('clientIp', function () {
if (
config('app.env') === 'local'
) {
return request()->getClientIp();
} else {
return request()->server('HTTP_X_FORWARDED_FOR') ??
request()->getClientIp();
}
});
// * LOCAL FORCE eg: for Carbon
// * Remove numeric to prevent float seperator to breaking numeric transactions
\collect([\LC_TIME, \LC_MESSAGES, \LC_COLLATE, \LC_CTYPE, \LC_MONETARY])
->map(function ($contant) {
setlocale(
$contant,
\sprintf(
'%s_%s.UTF-8',
config('app.locale'),
\strtoupper(config('app.locale'))
)
);
});
Carbon::setLocale(config('app.locale'));
// * Force bootstrap paginator
Paginator::useBootstrap();
$appInfos = Cache::remember(
'composer',
360,
function () {
return json_decode(File::get(\app_path('../composer.json')));
}
);
View::share('name', $appInfos->name);
View::share('version', $appInfos->version);
View::share('license', $appInfos->license);
} }
} }

View file

@ -2,12 +2,8 @@
namespace App\Providers; namespace App\Providers;
use App\Lib\Helper;
use App\Models\Service;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider class AuthServiceProvider extends ServiceProvider
{ {
@ -16,7 +12,9 @@ class AuthServiceProvider extends ServiceProvider
* *
* @var array * @var array
*/ */
protected $policies = []; protected $policies = [
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
];
/** /**
* Register any authentication / authorization services. * Register any authentication / authorization services.
@ -27,50 +25,6 @@ class AuthServiceProvider extends ServiceProvider
{ {
$this->registerPolicies(); $this->registerPolicies();
Auth::viaRequest('api-hmac', function (Request $request) { //
/**
* Un token devrais être fourni pour chaque requete
*/
if (is_null($request->bearer_token)) {
return null;
}
// * Si la route actuelle n'as pas de nom alors on refuse de la traiter.
if (!(Helper::getRoute($request))) {
// @codeCoverageIgnoreStart
return null;
// @codeCoverageIgnoreEnd
}
$service = null;
try {
// * On récupère le service actuel correspondant au token fourni.
$service = Service::getFromBearerToken($request->bearer_token ?? '');
} catch (ModelNotFoundException $e) {
return null;
}
// * Preload the arcadiaBrands as we will access it often later.
$service = $service->load('arcadiaBrands');
/**
** All Api routes must pass ArcadiaBrand model to controller action since a ArcadiaBrand owns
** a service token, otherwise the api cannot be called.
** This hack is a custom binder instead of passing
** this to route as a parameter
*/
app()->bind(Service::class, function () use ($service) {
return $service;
});
// * On authenticate la request en vérifiant sa signature.
if ($service->authenticateApi($request)) {
return $service;
}
return null;
});
} }
} }

View file

@ -5,6 +5,7 @@ namespace App\Providers;
use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification; use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider class EventServiceProvider extends ServiceProvider
{ {
@ -26,5 +27,6 @@ class EventServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
//
} }
} }

View file

@ -19,6 +19,15 @@ class RouteServiceProvider extends ServiceProvider
*/ */
public const HOME = '/home'; public const HOME = '/home';
/**
* The controller namespace for the application.
*
* When present, controller route declarations will automatically be prefixed with this namespace.
*
* @var string|null
*/
// protected $namespace = 'App\\Http\\Controllers';
/** /**
* Define your route model bindings, pattern filters, etc. * Define your route model bindings, pattern filters, etc.
* *
@ -47,16 +56,8 @@ class RouteServiceProvider extends ServiceProvider
*/ */
protected function configureRateLimiting() protected function configureRateLimiting()
{ {
RateLimiter::for('web', function (Request $request) {
// @codeCoverageIgnoreStart
return Limit::perMinute(25)
->by(optional($request->user())->id ?: app('clientIp'));
// @codeCoverageIgnoreEnd
});
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
RateLimiter::for('api', function (Request $request) { RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(config('api.apiRequestRatePerMinute', 100)) return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
->by(app('clientIp'));
}); });
} }
} }

View file

@ -1,31 +1,19 @@
{ {
"name": "ldc/incollector", "name": "laravel/laravel",
"type": "project", "type": "project",
"version": "1.0.0", "description": "The Laravel Framework.",
"description": "LDC Incollector - A workaround of Arcadia", "keywords": ["framework", "laravel"],
"authors": [
{
"name": "Olivier Legat",
"email": "olivier.legat@ldc.fr"
},
{
"name": "Jérémy Munsch",
"email": "jeremy.munsch@ldc.fr",
"homepage": "https://jeremydev.ovh"
}
],
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^7.3|^8.0", "php": "^7.3|^8.0",
"fruitcake/laravel-cors": "^2.0", "fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1", "guzzlehttp/guzzle": "^7.0.1",
"kwaadpepper/crud-policies": "^0.3.5",
"kwaadpepper/enum": "^2.1", "kwaadpepper/enum": "^2.1",
"kwaadpepper/exception-handler": "^0.0.5", "kwaadpepper/exception-handler": "^0.0.5",
"laravel/framework": "^8.65", "laravel/framework": "^8.65",
"laravel/sanctum": "^2.11", "laravel/sanctum": "^2.11",
"laravel/tinker": "^2.5", "laravel/tinker": "^2.5",
"rennokki/laravel-eloquent-query-cache": "^3.3" "squizlabs/php_codesniffer": "^3.6"
}, },
"require-dev": { "require-dev": {
"facade/ignition": "^2.5", "facade/ignition": "^2.5",
@ -33,9 +21,7 @@
"laravel/sail": "^1.0.1", "laravel/sail": "^1.0.1",
"mockery/mockery": "^1.4.4", "mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^5.10", "nunomaduro/collision": "^5.10",
"phpunit/phpunit": "^9.5.10", "phpunit/phpunit": "^9.5.10"
"slevomat/coding-standard": "^7.1",
"squizlabs/php_codesniffer": "^3.6"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -50,16 +36,6 @@
} }
}, },
"scripts": { "scripts": {
"test": [
"@configclear",
"./test.sh"
],
"configclear": "@php artisan config:clear",
"runtestmigration": "@php artisan migrate:fresh --env=testing --seed",
"runtest": "@php artisan test --no-coverage --testsuite Api",
"runtestWithCoverage": "@php artisan test --testsuite Api",
"runserve": "@php artisan serve --host=127.0.0.1 --port=8888 --env=testing&",
"killserve": "kill $(ps -f | grep '[1]27.0.0.1:8888' | awk '{print $2}')",
"post-autoload-dump": [ "post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi" "@php artisan package:discover --ansi"
@ -82,10 +58,7 @@
"config": { "config": {
"optimize-autoloader": true, "optimize-autoloader": true,
"preferred-install": "dist", "preferred-install": "dist",
"sort-packages": true, "sort-packages": true
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true "prefer-stable": true

1140
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,30 +0,0 @@
<?php
use App\Lib\Helper;
return [
/**
* Api versions
** this value is sent in response
*/
'version' => Helper::getPackageInfo()['version'],
/**
* Timestamp timeout in seconds
* Request with timestamp older than 30sec
* will be rejected
*/
'timestampTimeout' => 30,
/**
* The number of request
* per user or ip per minutes
*/
'apiRequestRatePerMinute' => 256,
/**
* Service requests cache
* time in minutes
*/
'servicesDBCache' => 10
];

View file

@ -3,53 +3,53 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Name | Application Name
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This value is the name of your application. This value is used when the | This value is the name of your application. This value is used when the
| framework needs to place the application's name in a notification or | framework needs to place the application's name in a notification or
| any other location as required by the application or its packages. | any other location as required by the application or its packages.
| |
*/ */
'name' => env('APP_NAME', 'Laravel'), 'name' => env('APP_NAME', 'Laravel'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Environment | Application Environment
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This value determines the "environment" your application is currently | This value determines the "environment" your application is currently
| running in. This may determine how you prefer to configure various | running in. This may determine how you prefer to configure various
| services the application utilizes. Set this in your ".env" file. | services the application utilizes. Set this in your ".env" file.
| |
*/ */
'env' => env('APP_ENV', 'production'), 'env' => env('APP_ENV', 'production'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Debug Mode | Application Debug Mode
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| When your application is in debug mode, detailed error messages with | When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your | stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown. | application. If disabled, a simple generic error page is shown.
| |
*/ */
'debug' => (bool)env('APP_DEBUG', false), 'debug' => (bool) env('APP_DEBUG', false),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application URL | Application URL
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This URL is used by the console to properly generate URLs when using | This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of | the Artisan command line tool. You should set this to the root of
| your application so that it is used when running Artisan tasks. | your application so that it is used when running Artisan tasks.
| |
*/ */
'url' => env('APP_URL', 'http://localhost'), 'url' => env('APP_URL', 'http://localhost'),
@ -57,66 +57,66 @@ return [
'asset_url' => env('ASSET_URL', null), 'asset_url' => env('ASSET_URL', null),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Timezone | Application Timezone
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may specify the default timezone for your application, which | Here you may specify the default timezone for your application, which
| will be used by the PHP date and date-time functions. We have gone | will be used by the PHP date and date-time functions. We have gone
| ahead and set this to a sensible default for you out of the box. | ahead and set this to a sensible default for you out of the box.
| |
*/ */
'timezone' => 'Europe/Paris', 'timezone' => 'UTC',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Locale Configuration | Application Locale Configuration
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| The application locale determines the default locale that will be used | The application locale determines the default locale that will be used
| by the translation service provider. You are free to set this value | by the translation service provider. You are free to set this value
| to any of the locales which will be supported by the application. | to any of the locales which will be supported by the application.
| |
*/ */
'locale' => 'fr', 'locale' => 'en',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Fallback Locale | Application Fallback Locale
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| The fallback locale determines the locale to use when the current one | The fallback locale determines the locale to use when the current one
| is not available. You may change the value to correspond to any of | is not available. You may change the value to correspond to any of
| the language folders that are provided through your application. | the language folders that are provided through your application.
| |
*/ */
'fallback_locale' => 'en', 'fallback_locale' => 'en',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Faker Locale | Faker Locale
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This locale will be used by the Faker PHP library when generating fake | This locale will be used by the Faker PHP library when generating fake
| data for your database seeds. For example, this will be used to get | data for your database seeds. For example, this will be used to get
| localized telephone numbers, street address information and more. | localized telephone numbers, street address information and more.
| |
*/ */
'faker_locale' => 'fr_FR', 'faker_locale' => 'en_US',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Encryption Key | Encryption Key
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This key is used by the Illuminate encrypter service and should be set | This key is used by the Illuminate encrypter service and should be set
| to a random, 32 character string, otherwise these encrypted strings | to a random, 32 character string, otherwise these encrypted strings
| will not be safe. Please do this before deploying an application! | will not be safe. Please do this before deploying an application!
| |
*/ */
'key' => env('APP_KEY'), 'key' => env('APP_KEY'),
@ -124,14 +124,14 @@ return [
'cipher' => 'AES-256-CBC', 'cipher' => 'AES-256-CBC',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Autoloaded Service Providers | Autoloaded Service Providers
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| The service providers listed here will be automatically loaded on the | The service providers listed here will be automatically loaded on the
| request to your application. Feel free to add your own services to | request to your application. Feel free to add your own services to
| this array to grant expanded functionality to your applications. | this array to grant expanded functionality to your applications.
| |
*/ */
'providers' => [ 'providers' => [
@ -139,7 +139,6 @@ return [
/* /*
* Laravel Framework Service Providers... * Laravel Framework Service Providers...
*/ */
Illuminate\Auth\AuthServiceProvider::class, Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class, Illuminate\Bus\BusServiceProvider::class,
@ -170,23 +169,23 @@ return [
/* /*
* Application Service Providers... * Application Service Providers...
*/ */
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class, App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Class Aliases | Class Aliases
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This array of class aliases will be registered when this application | This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as | is started. However, feel free to register as many as you wish as
| the aliases are "lazy" loaded so they don't hinder performance. | the aliases are "lazy" loaded so they don't hinder performance.
| |
*/ */
'aliases' => [ 'aliases' => [
@ -219,6 +218,7 @@ return [
'Queue' => Illuminate\Support\Facades\Queue::class, 'Queue' => Illuminate\Support\Facades\Queue::class,
'RateLimiter' => Illuminate\Support\Facades\RateLimiter::class, 'RateLimiter' => Illuminate\Support\Facades\RateLimiter::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class,
// 'Redis' => Illuminate\Support\Facades\Redis::class,
'Request' => Illuminate\Support\Facades\Request::class, 'Request' => Illuminate\Support\Facades\Request::class,
'Response' => Illuminate\Support\Facades\Response::class, 'Response' => Illuminate\Support\Facades\Response::class,
'Route' => Illuminate\Support\Facades\Route::class, 'Route' => Illuminate\Support\Facades\Route::class,

View file

@ -3,14 +3,14 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Authentication Defaults | Authentication Defaults
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option controls the default authentication "guard" and password | This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults | reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications. | as required, but they're a perfect start for most applications.
| |
*/ */
'defaults' => [ 'defaults' => [
@ -19,20 +19,20 @@ return [
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Authentication Guards | Authentication Guards
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Next, you may define every authentication guard for your application. | Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you | Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider. | here which uses session storage and the Eloquent user provider.
| |
| All authentication drivers have a user provider. This defines how the | All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage | users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data. | mechanisms used by this application to persist your user's data.
| |
| Supported: "session" | Supported: "session"
| |
*/ */
'guards' => [ 'guards' => [
@ -40,48 +40,50 @@ return [
'driver' => 'session', 'driver' => 'session',
'provider' => 'users', 'provider' => 'users',
], ],
'api' => [
'driver' => 'api-hmac'
],
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| User Providers | User Providers
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| All authentication drivers have a user provider. This defines how the | All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage | users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data. | mechanisms used by this application to persist your user's data.
| |
| If you have multiple user tables or models you may configure multiple | If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then | sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined. | be assigned to any extra authentication guards you have defined.
| |
| Supported: "database", "eloquent" | Supported: "database", "eloquent"
| |
*/ */
'providers' => [ 'providers' => [
'users' => [ 'users' => [
'driver' => 'eloquent', 'driver' => 'eloquent',
'model' => App\Models\User::class, 'model' => App\Models\User::class,
] ],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Resetting Passwords | Resetting Passwords
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| You may specify multiple password reset configurations if you have more | You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have | than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types. | separate password reset settings based on the specific user types.
| |
| The expire time is the number of minutes that the reset token should be | The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so | considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed. | they have less time to be guessed. You may change this as needed.
| |
*/ */
'passwords' => [ 'passwords' => [
@ -94,14 +96,14 @@ return [
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Password Confirmation Timeout | Password Confirmation Timeout
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may define the amount of seconds before a password confirmation | Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the | times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours. | confirmation screen. By default, the timeout lasts for three hours.
| |
*/ */
'password_timeout' => 10800, 'password_timeout' => 10800,

View file

@ -3,29 +3,29 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Broadcaster | Default Broadcaster
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option controls the default broadcaster that will be used by the | This option controls the default broadcaster that will be used by the
| framework when an event needs to be broadcast. You may set this to | framework when an event needs to be broadcast. You may set this to
| any of the connections defined in the "connections" array below. | any of the connections defined in the "connections" array below.
| |
| Supported: "pusher", "ably", "redis", "log", "null" | Supported: "pusher", "ably", "redis", "log", "null"
| |
*/ */
'default' => env('BROADCAST_DRIVER', 'null'), 'default' => env('BROADCAST_DRIVER', 'null'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Broadcast Connections | Broadcast Connections
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may define all of the broadcast connections that will be used | Here you may define all of the broadcast connections that will be used
| to broadcast events to other systems or over websockets. Samples of | to broadcast events to other systems or over websockets. Samples of
| each available type of connection are provided inside this array. | each available type of connection are provided inside this array.
| |
*/ */
'connections' => [ 'connections' => [

View file

@ -5,30 +5,30 @@ use Illuminate\Support\Str;
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Cache Store | Default Cache Store
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option controls the default cache connection that gets used while | This option controls the default cache connection that gets used while
| using this caching library. This connection is used when another is | using this caching library. This connection is used when another is
| not explicitly specified when executing a given caching function. | not explicitly specified when executing a given caching function.
| |
*/ */
'default' => env('CACHE_DRIVER', 'file'), 'default' => env('CACHE_DRIVER', 'file'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Cache Stores | Cache Stores
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may define all of the cache "stores" for your application as | Here you may define all of the cache "stores" for your application as
| well as their drivers. You may even define multiple stores for the | well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches. | same cache driver to group types of items stored in your caches.
| |
| Supported drivers: "apc", "array", "database", "file", | Supported drivers: "apc", "array", "database", "file",
| "memcached", "redis", "dynamodb", "octane", "null" | "memcached", "redis", "dynamodb", "octane", "null"
| |
*/ */
'stores' => [ 'stores' => [
@ -95,16 +95,16 @@ return [
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Cache Key Prefix | Cache Key Prefix
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| When utilizing a RAM based store such as APC or Memcached, there might | When utilizing a RAM based store such as APC or Memcached, there might
| be other applications utilizing the same cache. So, we'll specify a | be other applications utilizing the same cache. So, we'll specify a
| value to get prefixed to all our keys so we can avoid collisions. | value to get prefixed to all our keys so we can avoid collisions.
| |
*/ */
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_cache'), 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
]; ];

View file

@ -3,16 +3,16 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Cross-Origin Resource Sharing (CORS) Configuration | Cross-Origin Resource Sharing (CORS) Configuration
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may configure your settings for cross-origin resource sharing | Here you may configure your settings for cross-origin resource sharing
| or "CORS". This determines what cross-origin operations may execute | or "CORS". This determines what cross-origin operations may execute
| in web browsers. You are free to adjust these settings as needed. | in web browsers. You are free to adjust these settings as needed.
| |
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
| |
*/ */
'paths' => ['api/*', 'sanctum/csrf-cookie'], 'paths' => ['api/*', 'sanctum/csrf-cookie'],

View file

@ -5,32 +5,32 @@ use Illuminate\Support\Str;
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Database Connection Name | Default Database Connection Name
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may specify which of the database connections below you wish | Here you may specify which of the database connections below you wish
| to use as your default connection for all database work. Of course | to use as your default connection for all database work. Of course
| you may use many connections at once using the Database library. | you may use many connections at once using the Database library.
| |
*/ */
'default' => env('DB_CONNECTION', 'mysql'), 'default' => env('DB_CONNECTION', 'mysql'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Database Connections | Database Connections
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here are each of the database connections setup for your application. | Here are each of the database connections setup for your application.
| Of course, examples of configuring each database platform that is | Of course, examples of configuring each database platform that is
| supported by Laravel is shown below to make development simple. | supported by Laravel is shown below to make development simple.
| |
| |
| All database work in Laravel is done through the PHP PDO facilities | All database work in Laravel is done through the PHP PDO facilities
| so make sure you have the driver for your particular database of | so make sure you have the driver for your particular database of
| choice installed on your machine before you begin development. | choice installed on your machine before you begin development.
| |
*/ */
'connections' => [ 'connections' => [
@ -94,27 +94,27 @@ return [
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Migration Repository Table | Migration Repository Table
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This table keeps track of all the migrations that have already run for | This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of | your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run in the database. | the migrations on disk haven't actually been run in the database.
| |
*/ */
'migrations' => 'migrations', 'migrations' => 'migrations',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Redis Databases | Redis Databases
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Redis is an open source, fast, and advanced key-value store that also | Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system | provides a richer body of commands than a typical key-value system
| such as APC or Memcached. Laravel makes it easy to dig right in. | such as APC or Memcached. Laravel makes it easy to dig right in.
| |
*/ */
'redis' => [ 'redis' => [
@ -123,7 +123,7 @@ return [
'options' => [ 'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'), 'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_') . '_database_'), 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
], ],
'default' => [ 'default' => [

View file

@ -11,7 +11,5 @@ return [
* Put a developper secured mailbox in here * Put a developper secured mailbox in here
* so you can receive email if things go mad * so you can receive email if things go mad
*/ */
'contactsList' => [ 'contactsList' => []
env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr')
]
]; ];

View file

@ -3,29 +3,29 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Filesystem Disk | Default Filesystem Disk
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may specify the default filesystem disk that should be used | Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud | by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application. Just store away! | based disks are available to your application. Just store away!
| |
*/ */
'default' => env('FILESYSTEM_DRIVER', 'local'), 'default' => env('FILESYSTEM_DRIVER', 'local'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Filesystem Disks | Filesystem Disks
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may configure as many filesystem "disks" as you wish, and you | Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have | may even configure multiple disks of the same driver. Defaults have
| been setup for each driver as an example of the required options. | been setup for each driver as an example of the required options.
| |
| Supported Drivers: "local", "ftp", "sftp", "s3" | Supported Drivers: "local", "ftp", "sftp", "s3"
| |
*/ */
'disks' => [ 'disks' => [
@ -38,7 +38,7 @@ return [
'public' => [ 'public' => [
'driver' => 'local', 'driver' => 'local',
'root' => storage_path('app/public'), 'root' => storage_path('app/public'),
'url' => env('APP_URL') . '/storage', 'url' => env('APP_URL').'/storage',
'visibility' => 'public', 'visibility' => 'public',
], ],
@ -57,21 +57,17 @@ return [
'driver' => 'local', 'driver' => 'local',
'root' => storage_path('inco'), 'root' => storage_path('inco'),
], ],
'arcadia_brand' => [
'driver' => 'local',
'root' => storage_path('marque'),
],
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Symbolic Links | Symbolic Links
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may configure the symbolic links that will be created when the | Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be | `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets. | the locations of the links and the values should be their targets.
| |
*/ */
'links' => [ 'links' => [

View file

@ -3,29 +3,29 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Hash Driver | Default Hash Driver
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option controls the default hash driver that will be used to hash | This option controls the default hash driver that will be used to hash
| passwords for your application. By default, the bcrypt algorithm is | passwords for your application. By default, the bcrypt algorithm is
| used; however, you remain free to modify this option if you wish. | used; however, you remain free to modify this option if you wish.
| |
| Supported: "bcrypt", "argon", "argon2id" | Supported: "bcrypt", "argon", "argon2id"
| |
*/ */
'driver' => 'bcrypt', 'driver' => 'bcrypt',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Bcrypt Options | Bcrypt Options
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may specify the configuration options that should be used when | Here you may specify the configuration options that should be used when
| passwords are hashed using the Bcrypt algorithm. This will allow you | passwords are hashed using the Bcrypt algorithm. This will allow you
| to control the amount of time it takes to hash the given password. | to control the amount of time it takes to hash the given password.
| |
*/ */
'bcrypt' => [ 'bcrypt' => [
@ -33,14 +33,14 @@ return [
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Argon Options | Argon Options
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may specify the configuration options that should be used when | Here you may specify the configuration options that should be used when
| passwords are hashed using the Argon algorithm. These will allow you | passwords are hashed using the Argon algorithm. These will allow you
| to control the amount of time it takes to hash the given password. | to control the amount of time it takes to hash the given password.
| |
*/ */
'argon' => [ 'argon' => [

View file

@ -1,5 +0,0 @@
<?php
return [
'project_uuid' => env('PROJECT_UUID')
];

View file

@ -7,44 +7,44 @@ use Monolog\Handler\SyslogUdpHandler;
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Log Channel | Default Log Channel
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option defines the default log channel that gets used when writing | This option defines the default log channel that gets used when writing
| messages to the logs. The name specified in this option should match | messages to the logs. The name specified in this option should match
| one of the channels defined in the "channels" configuration array. | one of the channels defined in the "channels" configuration array.
| |
*/ */
'default' => env('LOG_CHANNEL', 'stack'), 'default' => env('LOG_CHANNEL', 'stack'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Deprecations Log Channel | Deprecations Log Channel
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option controls the log channel that should be used to log warnings | This option controls the log channel that should be used to log warnings
| regarding deprecated PHP and library features. This allows you to get | regarding deprecated PHP and library features. This allows you to get
| your application ready for upcoming major versions of dependencies. | your application ready for upcoming major versions of dependencies.
| |
*/ */
'deprecations' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 'deprecations' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Log Channels | Log Channels
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may configure the log channels for your application. Out of | Here you may configure the log channels for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives | the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize. | you a variety of powerful log handlers / formatters to utilize.
| |
| Available Drivers: "single", "daily", "slack", "syslog", | Available Drivers: "single", "daily", "slack", "syslog",
| "errorlog", "monolog", | "errorlog", "monolog",
| "custom", "stack" | "custom", "stack"
| |
*/ */
'channels' => [ 'channels' => [

View file

@ -3,34 +3,34 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Mailer | Default Mailer
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option controls the default mailer that is used to send any email | This option controls the default mailer that is used to send any email
| messages sent by your application. Alternative mailers may be setup | messages sent by your application. Alternative mailers may be setup
| and used as needed; however, this mailer will be used by default. | and used as needed; however, this mailer will be used by default.
| |
*/ */
'default' => env('MAIL_MAILER', 'smtp'), 'default' => env('MAIL_MAILER', 'smtp'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Mailer Configurations | Mailer Configurations
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may configure all of the mailers used by your application plus | Here you may configure all of the mailers used by your application plus
| their respective settings. Several examples have been configured for | their respective settings. Several examples have been configured for
| you and you are free to add your own as your application requires. | you and you are free to add your own as your application requires.
| |
| Laravel supports a variety of mail "transport" drivers to be used while | Laravel supports a variety of mail "transport" drivers to be used while
| sending an e-mail. You will specify which one you are using for your | sending an e-mail. You will specify which one you are using for your
| mailers below. You are free to add additional mailers as required. | mailers below. You are free to add additional mailers as required.
| |
| Supported: "smtp", "sendmail", "mailgun", "ses", | Supported: "smtp", "sendmail", "mailgun", "ses",
| "postmark", "log", "array", "failover" | "postmark", "log", "array", "failover"
| |
*/ */
'mailers' => [ 'mailers' => [
@ -81,14 +81,14 @@ return [
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Global "From" Address | Global "From" Address
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| You may wish for all e-mails sent by your application to be sent from | You may wish for all e-mails sent by your application to be sent from
| the same address. Here, you may specify a name and address that is | the same address. Here, you may specify a name and address that is
| used globally for all e-mails that are sent by your application. | used globally for all e-mails that are sent by your application.
| |
*/ */
'from' => [ 'from' => [
@ -97,20 +97,19 @@ return [
], ],
'contactsList' => [ 'contactsList' => [
'serviceweb' => explode(',', env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr')), 'serviceweb' => explode(",", env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr')),
// phpcs:ignore Generic.Files.LineLength.TooLong 'invalidInco' => explode(",", env('MAIL_LIST_INVALIDINCO', 'equipe.web@ldc.fr')),
'invalidInco' => explode(',', env('MAIL_LIST_INVALIDINCO', 'equipe.web@ldc.fr,vincent.pierre@ldc.fr,christelle.manceau@ldc.fr')),
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Markdown Mail Settings | Markdown Mail Settings
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| If you are using Markdown based email rendering, you may configure your | If you are using Markdown based email rendering, you may configure your
| theme and component paths here, allowing you to customize the design | theme and component paths here, allowing you to customize the design
| of the emails. Or, you may simply stick with the Laravel defaults! | of the emails. Or, you may simply stick with the Laravel defaults!
| |
*/ */
'markdown' => [ 'markdown' => [

View file

@ -3,29 +3,29 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Queue Connection Name | Default Queue Connection Name
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Laravel's queue API supports an assortment of back-ends via a single | Laravel's queue API supports an assortment of back-ends via a single
| API, giving you convenient access to each back-end using the same | API, giving you convenient access to each back-end using the same
| syntax for every one. Here you may define a default connection. | syntax for every one. Here you may define a default connection.
| |
*/ */
'default' => env('QUEUE_CONNECTION', 'sync'), 'default' => env('QUEUE_CONNECTION', 'sync'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Queue Connections | Queue Connections
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may configure the connection information for each server that | Here you may configure the connection information for each server that
| is used by your application. A default configuration has been added | is used by your application. A default configuration has been added
| for each back-end shipped with Laravel. You are free to add more. | for each back-end shipped with Laravel. You are free to add more.
| |
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
| |
*/ */
'connections' => [ 'connections' => [
@ -74,14 +74,14 @@ return [
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Failed Queue Jobs | Failed Queue Jobs
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| These options configure the behavior of failed queue job logging so you | These options configure the behavior of failed queue job logging so you
| can control which database and table are used to store the jobs that | can control which database and table are used to store the jobs that
| have failed. You may change them to any database / table you wish. | have failed. You may change them to any database / table you wish.
| |
*/ */
'failed' => [ 'failed' => [

View file

@ -3,58 +3,58 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Stateful Domains | Stateful Domains
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Requests from the following domains / hosts will receive stateful API | Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local | authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA. | and production domains which access your API via a frontend SPA.
| |
*/ */
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( 'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s', '%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
env('APP_URL') ? ',' . parse_url(env('APP_URL'), PHP_URL_HOST) : '' env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))), ))),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Sanctum Guards | Sanctum Guards
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This array contains the authentication guards that will be checked when | This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards | Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer | are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication. | token that's present on an incoming request for authentication.
| |
*/ */
'guard' => ['web'], 'guard' => ['web'],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Expiration Minutes | Expiration Minutes
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This value controls the number of minutes until an issued token will be | This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do | considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions. | not expire. This won't tweak the lifetime of first-party sessions.
| |
*/ */
'expiration' => null, 'expiration' => null,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Sanctum Middleware | Sanctum Middleware
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| When authenticating your first-party SPA with Sanctum you may need to | When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the | customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required. | request. You may change the middleware listed below as required.
| |
*/ */
'middleware' => [ 'middleware' => [

View file

@ -3,15 +3,15 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Third Party Services | Third Party Services
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This file is for storing the credentials for third party services such | This file is for storing the credentials for third party services such
| as Mailgun, Postmark, AWS and more. This file provides the de facto | as Mailgun, Postmark, AWS and more. This file provides the de facto
| location for this type of information, allowing packages to have | location for this type of information, allowing packages to have
| a conventional file to locate the various service credentials. | a conventional file to locate the various service credentials.
| |
*/ */
'mailgun' => [ 'mailgun' => [

View file

@ -5,30 +5,30 @@ use Illuminate\Support\Str;
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default Session Driver | Default Session Driver
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option controls the default session "driver" that will be used on | This option controls the default session "driver" that will be used on
| requests. By default, we will use the lightweight native driver but | requests. By default, we will use the lightweight native driver but
| you may specify any of the other wonderful drivers provided here. | you may specify any of the other wonderful drivers provided here.
| |
| Supported: "file", "cookie", "database", "apc", | Supported: "file", "cookie", "database", "apc",
| "memcached", "redis", "dynamodb", "array" | "memcached", "redis", "dynamodb", "array"
| |
*/ */
'driver' => env('SESSION_DRIVER', 'file'), 'driver' => env('SESSION_DRIVER', 'file'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Lifetime | Session Lifetime
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may specify the number of minutes that you wish the session | Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them | to be allowed to remain idle before it expires. If you want them
| to immediately expire on the browser closing, set that option. | to immediately expire on the browser closing, set that option.
| |
*/ */
'lifetime' => env('SESSION_LIFETIME', 120), 'lifetime' => env('SESSION_LIFETIME', 120),
@ -36,164 +36,164 @@ return [
'expire_on_close' => false, 'expire_on_close' => false,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Encryption | Session Encryption
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option allows you to easily specify that all of your session data | This option allows you to easily specify that all of your session data
| should be encrypted before it is stored. All encryption will be run | should be encrypted before it is stored. All encryption will be run
| automatically by Laravel and you can use the Session like normal. | automatically by Laravel and you can use the Session like normal.
| |
*/ */
'encrypt' => false, 'encrypt' => false,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session File Location | Session File Location
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| When using the native session driver, we need a location where session | When using the native session driver, we need a location where session
| files may be stored. A default has been set for you but a different | files may be stored. A default has been set for you but a different
| location may be specified. This is only needed for file sessions. | location may be specified. This is only needed for file sessions.
| |
*/ */
'files' => storage_path('framework/sessions'), 'files' => storage_path('framework/sessions'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Database Connection | Session Database Connection
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| When using the "database" or "redis" session drivers, you may specify a | When using the "database" or "redis" session drivers, you may specify a
| connection that should be used to manage these sessions. This should | connection that should be used to manage these sessions. This should
| correspond to a connection in your database configuration options. | correspond to a connection in your database configuration options.
| |
*/ */
'connection' => env('SESSION_CONNECTION', null), 'connection' => env('SESSION_CONNECTION', null),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Database Table | Session Database Table
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| When using the "database" session driver, you may specify the table we | When using the "database" session driver, you may specify the table we
| should use to manage the sessions. Of course, a sensible default is | should use to manage the sessions. Of course, a sensible default is
| provided for you; however, you are free to change this as needed. | provided for you; however, you are free to change this as needed.
| |
*/ */
'table' => 'sessions', 'table' => 'sessions',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Cache Store | Session Cache Store
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| While using one of the framework's cache driven session backends you may | While using one of the framework's cache driven session backends you may
| list a cache store that should be used for these sessions. This value | list a cache store that should be used for these sessions. This value
| must match with one of the application's configured cache "stores". | must match with one of the application's configured cache "stores".
| |
| Affects: "apc", "dynamodb", "memcached", "redis" | Affects: "apc", "dynamodb", "memcached", "redis"
| |
*/ */
'store' => env('SESSION_STORE', null), 'store' => env('SESSION_STORE', null),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Sweeping Lottery | Session Sweeping Lottery
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Some session drivers must manually sweep their storage location to get | Some session drivers must manually sweep their storage location to get
| rid of old sessions from storage. Here are the chances that it will | rid of old sessions from storage. Here are the chances that it will
| happen on a given request. By default, the odds are 2 out of 100. | happen on a given request. By default, the odds are 2 out of 100.
| |
*/ */
'lottery' => [2, 100], 'lottery' => [2, 100],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Cookie Name | Session Cookie Name
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may change the name of the cookie used to identify a session | Here you may change the name of the cookie used to identify a session
| instance by ID. The name specified here will get used every time a | instance by ID. The name specified here will get used every time a
| new session cookie is created by the framework for every driver. | new session cookie is created by the framework for every driver.
| |
*/ */
'cookie' => env( 'cookie' => env(
'SESSION_COOKIE', 'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_') . '_session' Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
), ),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Cookie Path | Session Cookie Path
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| The session cookie path determines the path for which the cookie will | The session cookie path determines the path for which the cookie will
| be regarded as available. Typically, this will be the root path of | be regarded as available. Typically, this will be the root path of
| your application but you are free to change this when necessary. | your application but you are free to change this when necessary.
| |
*/ */
'path' => '/', 'path' => '/',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Session Cookie Domain | Session Cookie Domain
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here you may change the domain of the cookie used to identify a session | Here you may change the domain of the cookie used to identify a session
| in your application. This will determine which domains the cookie is | in your application. This will determine which domains the cookie is
| available to in your application. A sensible default has been set. | available to in your application. A sensible default has been set.
| |
*/ */
'domain' => env('SESSION_DOMAIN', null), 'domain' => env('SESSION_DOMAIN', null),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| HTTPS Only Cookies | HTTPS Only Cookies
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| By setting this option to true, session cookies will only be sent back | By setting this option to true, session cookies will only be sent back
| to the server if the browser has a HTTPS connection. This will keep | to the server if the browser has a HTTPS connection. This will keep
| the cookie from being sent to you when it can't be done securely. | the cookie from being sent to you when it can't be done securely.
| |
*/ */
'secure' => env('SESSION_SECURE_COOKIE'), 'secure' => env('SESSION_SECURE_COOKIE'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| HTTP Access Only | HTTP Access Only
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Setting this value to true will prevent JavaScript from accessing the | Setting this value to true will prevent JavaScript from accessing the
| value of the cookie and the cookie will only be accessible through | value of the cookie and the cookie will only be accessible through
| the HTTP protocol. You are free to modify this option if needed. | the HTTP protocol. You are free to modify this option if needed.
| |
*/ */
'http_only' => true, 'http_only' => true,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Same-Site Cookies | Same-Site Cookies
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option determines how your cookies behave when cross-site requests | This option determines how your cookies behave when cross-site requests
| take place, and can be used to mitigate CSRF attacks. By default, we | take place, and can be used to mitigate CSRF attacks. By default, we
| will set this value to "lax" since this is a secure default value. | will set this value to "lax" since this is a secure default value.
| |
| Supported: "lax", "strict", "none", null | Supported: "lax", "strict", "none", null
| |
*/ */
'same_site' => 'lax', 'same_site' => 'lax',

View file

@ -1,58 +0,0 @@
<?php
return [
/*
* Set trusted proxy IP addresses.
*
* Both IPv4 and IPv6 addresses are
* supported, along with CIDR notation.
*
* The "*" character is syntactic sugar
* within TrustedProxy to trust any proxy
* that connects directly to your server,
* a requirement when you cannot know the address
* of your proxy (e.g. if using ELB or similar).
*
*/
'proxies' => [
// * HA PROXY prod "Virtual IP".
'192.168.31.9',
// * HA PROXY prod "Virtual IP" redondance.
'192.168.31.10',
// * HA PROXY dev "Virtual IP".
'192.168.34.15'
],
/*
* To trust one or more specific proxies that connect
* directly to your server, use an array or a string separated by comma of IP addresses:
*/
/*
* Or, to trust all proxies that connect
* directly to your server, use a "*"
*/
/*
* Which headers to use to detect proxy related data (For, Host, Proto, Port)
*
* Options include:
*
* - Illuminate\Http\Request::HEADER_X_FORWARDED_ALL (use all x-forwarded-* headers to establish trust)
* - Illuminate\Http\Request::HEADER_FORWARDED (use the FORWARDED header to establish trust)
* - Illuminate\Http\Request::HEADER_X_FORWARDED_AWS_ELB (If you are using AWS Elastic Load Balancer)
*
* - 'HEADER_X_FORWARDED_ALL' (use all x-forwarded-* headers to establish trust)
* - 'HEADER_FORWARDED' (use the FORWARDED header to establish trust)
* - 'HEADER_X_FORWARDED_AWS_ELB' (If you are using AWS Elastic Load Balancer)
*
* @link https://symfony.com/doc/current/deployment/proxies.html
*/
'headers' => Illuminate\Http\Request::HEADER_X_FORWARDED_FOR |
Illuminate\Http\Request::HEADER_X_FORWARDED_HOST |
Illuminate\Http\Request::HEADER_X_FORWARDED_PORT |
Illuminate\Http\Request::HEADER_X_FORWARDED_PROTO,
];

View file

@ -3,14 +3,14 @@
return [ return [
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| View Storage Paths | View Storage Paths
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Most templating systems load templates from disk. Here you may specify | Most templating systems load templates from disk. Here you may specify
| an array of paths that should be checked for your views. Of course | an array of paths that should be checked for your views. Of course
| the usual Laravel view path has already been registered for you. | the usual Laravel view path has already been registered for you.
| |
*/ */
'paths' => [ 'paths' => [
@ -18,14 +18,14 @@ return [
], ],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Compiled View Path | Compiled View Path
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| This option determines where all the compiled Blade templates will be | This option determines where all the compiled Blade templates will be
| stored for your application. Typically, this is within the storage | stored for your application. Typically, this is within the storage
| directory. However, as usual, you are free to change this value. | directory. However, as usual, you are free to change this value.
| |
*/ */
'compiled' => env( 'compiled' => env(

View file

@ -1,21 +0,0 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class ArcadiaBrandFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'arcadia_id' => $this->faker->unique()->numberBetween(1, 999),
'libelle' => $this->faker->unique()->company()
];
}
}

View file

@ -1,20 +0,0 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class ServiceFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->unique()->name() . ' Service'
];
}
}

View file

@ -18,7 +18,7 @@ class UserFactory extends Factory
'name' => $this->faker->name(), 'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(), 'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(), 'email_verified_at' => now(),
'password' => 'password', 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10), 'remember_token' => Str::random(10),
]; ];
} }
@ -30,7 +30,6 @@ class UserFactory extends Factory
*/ */
public function unverified() public function unverified()
{ {
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
return $this->state(function (array $attributes) { return $this->state(function (array $attributes) {
return [ return [
'email_verified_at' => null, 'email_verified_at' => null,

View file

@ -1,105 +0,0 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class XmlIncoFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
*/
public function definition()
{
return [
'nom' => $this->faker->unique()->words(rand(2, 3), true),
'prod_saison' => $this->faker->boolean(),
'allegations' => $this->faker->boolean(75) ? $this->faker->sentence(7) : null,
'descriptif' => $this->faker->boolean(75) ? 'descriptif ' . $this->faker->text(150) : null,
'pictures' => [],
'astuces' => $this->faker->boolean(75) ? 'astuces ' . $this->faker->text(150) : null,
'lib_conso' => $this->faker->boolean(75) ? $this->faker->sentence(7) : null,
'nb_portion' => $this->faker->boolean(75) ? $this->faker->text(20) : null,
'typ_portion' => $this->faker->boolean(75) ? 'typ_portion ' . $this->faker->text(150) : null,
'pds_moy_theo' => $this->faker->boolean(75) ? $this->faker->numberBetween(0, 250) : null,
'conseil_prepa' => $this->faker->boolean(75) ? 'conseil_prepa ' . $this->faker->text(150) : null,
'arg_vente' => $this->faker->boolean(75) ? 'arg_vente ' . $this->faker->text(150) : null,
'lst_ing' => $this->faker->boolean(75) ? 'lst_ing ' . $this->faker->text(150) : null,
'lib_allergene' => $this->faker->boolean(75) ? 'lib_allergene ' . $this->faker->text(150) : null,
'nutritional_values' => [
'val_energ_kj_r' => $this->faker->numberBetween(250, 1200),
'val_energ_kcal_r' => $this->faker->numberBetween(50, 400),
'mat_grass_r' => $this->faker->numberBetween(6, 30),
'ags_r' => '5.3',
'glucides_r' => '2',
'sucre_r' => '1.4',
'fib_alim_r' => '0.8',
'proteine_r' => '17',
'sel_r' => '0.47',
'sodium_r' => '188',
'fruits_r' => '0',
'fruits_coque_sech_r' => '0',
'pourcent_apport_ref_e14_r' => '11.4',
'pourcent_apport_ref_kjo_r' => '11.5',
'pourcent_apport_ref_fat_r' => '24.7',
'pourcent_apport_ref_fatsat_r' => '29.8',
'pourcent_apport_ref_choval_r' => '0.6',
'pourcent_apport_ref_sugar_r' => '1.7',
'pourcent_apport_ref_fibtg_r' => null,
'pourcent_apport_ref_pro_r' => '33',
'pourcent_apport_ref_salteq_r' => '6.7',
'taille_port' => null,
'val_energ_kj_p' => null,
'val_energ_kcal_p' => null,
'mat_grass_p' => null,
'ags_p' => null,
'glucides_p' => null,
'sucre_p' => null,
'fib_alim_p' => null,
'proteine_p' => null,
'sodium_p' => null,
'fruits_p' => null,
'sel_p' => null,
'fruits_coque_sech_p' => null,
'pourcent_apport_ref_e14_p' => null,
'pourcent_apport_ref_kjo_p' => null,
'pourcent_apport_ref_fat_p' => null,
'pourcent_apport_ref_fatsat_p' => null,
'pourcent_apport_ref_choval_p' => null,
'pourcent_apport_ref_sugar_p' => null,
'pourcent_apport_ref_fibtg_p' => null,
'pourcent_apport_ref_pro_p' => null,
'pourcent_apport_ref_salteq_p' => null,
'apport_port' => 'Apport de r\u00e9f\u00e9rence pour un adulte type (8400Kj-2000Kcal)',
'part_p' => '32',
'part_g' => '4',
'part_l' => '63',
'p_sur_l' => '1.13',
'pourcent_ags' => '35',
'pourcent_agi' => '65',
'pourcent_ss' => '70',
'pourcent_amidon' => '30',
'composante_n' => '9',
'composante_p' => '5',
'pourcent_fruits' => '0',
'score_nutri' => '4',
'classement' => 'C',
'mat_grass_r_prec' => '=',
'ags_r_prec' => '=',
'glucides_r_prec' => '=',
'sucre_r_prec' => '=',
'fib_alim_r_prec' => '=',
'proteine_r_prec' => '=',
'sel_r_prec' => '=',
'sodium_r_prec' => null,
'fruits_r_prec' => null,
'fruits_coque_sech_r_prec' => null
]
];
}
}

View file

@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
class CreateServicesTable extends Migration class CreatePersonalAccessTokensTable extends Migration
{ {
/** /**
* Run the migrations. * Run the migrations.
@ -13,14 +13,13 @@ class CreateServicesTable extends Migration
*/ */
public function up() public function up()
{ {
Schema::create('services', function (Blueprint $table) { Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id(); $table->id();
$table->morphs('tokenable');
$table->string('name'); $table->string('name');
$table->string('bearer_token')->unique(); $table->string('token', 64)->unique();
$table->string('bearer_pwd', 312); $table->text('abilities')->nullable();
$table->timestamp('bearer_token_date'); $table->timestamp('last_used_at')->nullable();
$table->timestamps(); $table->timestamps();
}); });
} }
@ -32,6 +31,6 @@ class CreateServicesTable extends Migration
*/ */
public function down() public function down()
{ {
Schema::dropIfExists('services'); Schema::dropIfExists('personal_access_tokens');
} }
} }

View file

@ -15,13 +15,13 @@ class CreateXmlIncosTable extends Migration
public function up() public function up()
{ {
Schema::create('xml_incos', function (Blueprint $table) { Schema::create('xml_incos', function (Blueprint $table) {
$table->id()->comment('Inco ID (NO_ART)'); $table->id();
$table->string('nom')->nullable(); $table->string('nom')->nullable();
$table->boolean('prod_saison'); $table->boolean('prod_saison');
$table->string('allegations')->nullable(); $table->string('allegations')->nullable();
$table->text('descriptif')->nullable(); $table->text('descriptif')->nullable();
$table->json('pictures'); $table->json('picture');
$table->text('astuces')->nullable(); $table->text('astuces')->nullable();
$table->string('lib_conso')->nullable(); $table->string('lib_conso')->nullable();
$table->string('nb_portion', 20)->nullable(); $table->string('nb_portion', 20)->nullable();
@ -35,8 +35,6 @@ class CreateXmlIncosTable extends Migration
$table->json('nutritional_values'); $table->json('nutritional_values');
$table->foreignId('arcadia_brand_id')->constrained('arcadia_brands');
$table->timestamps(); $table->timestamps();
}); });
} }

View file

@ -1,35 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateArcadiaBrandsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('arcadia_brands', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('arcadia_id')->unique();
$table->string('libelle');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('arcadia_brands');
}
}

View file

@ -1,31 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateArcadiaBrandServiceTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('arcadia_brand_service', function (Blueprint $table) {
$table->foreignId('service_id')->constrained('services');
$table->foreignId('arcadia_brand_id')->constrained('arcadia_brands');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('arcadia_brand_service');
}
}

View file

@ -1,37 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
// phpcs:ignore PSR1.Classes.ClassDeclaration.MissingNamespace
class CreateServiceStats extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('service_stats', function (Blueprint $table) {
$table->id();
$table->foreignId('service_id')->constrained('services');
$table->date('date');
$table->unsignedBigInteger('nb_calls')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('service_stats');
}
}

View file

@ -2,13 +2,7 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\ArcadiaBrand;
use App\Models\Service;
use App\Models\XmlInco;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use SplFileInfo;
class DatabaseSeeder extends Seeder class DatabaseSeeder extends Seeder
{ {
@ -19,35 +13,6 @@ class DatabaseSeeder extends Seeder
*/ */
public function run() public function run()
{ {
/** @var \Illuminate\Database\Eloquent\Collection $services */ // \App\Models\User::factory(10)->create();
$services = Service::factory(5)->create();
/** @var \Illuminate\Database\Eloquent\Collection $brands */
$brands = ArcadiaBrand::factory(10)->create();
// * Associate brands to services
$services->map(function (Service $service) use (&$brands) {
$pullBrands = $brands->random(rand(1, 2));
$service->arcadiaBrands()->sync($pullBrands);
$brands = $brands->diff($pullBrands);
});
$disk = Storage::disk('inco');
$brands->map(function (ArcadiaBrand $brand) use ($disk) {
XmlInco::factory(rand(150, 355))->make()
->each(function (XmlInco $xmlInco) use ($disk, $brand) {
$xmlInco->pictures = collect([
new SplFileInfo(resource_path('seeders/xml_inco/fakeimage1.png')),
new SplFileInfo(resource_path('seeders/xml_inco/fakeimage2.png'))
])->random(rand(0, 2))->map(function (SplFileInfo $image) use ($disk) {
$imgNamePath = $image->getFilename();
$imageFinalPath = "images/inco/$imgNamePath";
$disk->put($imgNamePath, File::get($image->getPathname()));
return $imageFinalPath;
})->all();
$xmlInco->arcadiaBrand()->associate($brand);
$xmlInco->saveOrFail();
});
});
} }
} }

16468
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,9 +11,7 @@
}, },
"devDependencies": { "devDependencies": {
"axios": "^0.21", "axios": "^0.21",
"clean-webpack-plugin": "^4.0.0",
"laravel-mix": "^6.0.6", "laravel-mix": "^6.0.6",
"laravel-mix-polyfill": "^3.0.1",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"postcss": "^8.1.14" "postcss": "^8.1.14"
} }

View file

@ -1,31 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/schema/9.2.xsd" bootstrap="vendor/autoload.php" colors="true"> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites> <testsuites>
<testsuite name="Api"> <testsuite name="Unit">
<directory suffix="Test.php">./tests/Api</directory> <directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
<filter> <coverage processUncoveredFiles="true">
<whitelist processUncoveredFilesFromWhitelist="true"> <include>
<directory>./app</directory> <directory suffix=".php">./app</directory>
</whitelist> </include>
</filter> </coverage>
<logging>
<log type="coverage-html" target="tests/coverage" />
</logging>
<php> <php>
<server name="APP_ENV" value="testing" /> <server name="APP_ENV" value="testing"/>
<server name="APP_URL" value="http://127.0.0.1:8888" /> <server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="BCRYPT_ROUNDS" value="4" /> <!-- <server name="DB_CONNECTION" value="sqlite"/> -->
<server name="CACHE_DRIVER" value="array" /> <!-- <server name="DB_DATABASE" value=":memory:"/> -->
<server name="MAIL_MAILER" value="array"/>
<server name="MAIL_MAILER" value="array" /> <server name="QUEUE_CONNECTION" value="sync"/>
<env name="QUEUE_DRIVER" value="database" /> <server name="SESSION_DRIVER" value="array"/>
<server name="QUEUE_CONNECTION" value="database" /> <server name="TELESCOPE_ENABLED" value="false"/>
<server name="SESSION_DRIVER" value="array" />
<server name="TELESCOPE_ENABLED" value="false" />
</php> </php>
</phpunit> </phpunit>

View file

@ -1,270 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Technologies Online Tools 1.0 (https://www.liquid-technologies.com) -->
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="INCO">
<xs:complexType>
<xs:sequence>
<xs:element name="typemouvementinformatique" type="xs:string" />
<xs:element name="NO_ART" type="xs:string" />
<xs:element name="INCO_COMPO">
<xs:complexType>
<xs:sequence>
<xs:element name="TBL_INCO_COMPO">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string" />
<xs:element name="ID_INCO" type="xs:string" />
<xs:element name="NOM" type="xs:string" />
<xs:element name="NUMERO" type="xs:string" />
<xs:element name="TAILLE_REF" type="xs:string" />
<xs:element name="VAL_ENERG_KJ_R" type="xs:string" />
<xs:element name="VAL_ENERG_KCAL_R" type="xs:string" />
<xs:element name="MAT_GRASS_R" type="xs:string" />
<xs:element name="AGS_R" type="xs:string" />
<xs:element name="GLUCIDES_R" type="xs:string" />
<xs:element name="SUCRE_R" type="xs:string" />
<xs:element name="FIB_ALIM_R" type="xs:string" />
<xs:element name="PROTEINE_R" type="xs:string" />
<xs:element name="SEL_R" type="xs:string" />
<xs:element name="SODIUM_R" type="xs:string" />
<xs:element name="FRUITS_R" type="xs:string" />
<xs:element name="FRUITS_COQUE_SECH_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_E14_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_KJO_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FAT_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FATSAT_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_CHOVAL_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_SUGAR_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FIBTG_R" />
<xs:element name="POURCENT_APPORT_REF_PRO_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_SALTEQ_R" type="xs:string" />
<xs:element name="TAILLE_PORT" type="xs:string" />
<xs:element name="VAL_ENERG_KJ_P" type="xs:string" />
<xs:element name="VAL_ENERG_KCAL_P" type="xs:string" />
<xs:element name="MAT_GRASS_P" type="xs:string" />
<xs:element name="AGS_P" type="xs:string" />
<xs:element name="GLUCIDES_P" type="xs:string" />
<xs:element name="SUCRE_P" type="xs:string" />
<xs:element name="FIB_ALIM_P" type="xs:string" />
<xs:element name="PROTEINE_P" type="xs:string" />
<xs:element name="SEL_P" type="xs:string" />
<xs:element name="SODIUM_P" type="xs:string" />
<xs:element name="FRUITS_P" type="xs:string" />
<xs:element name="FRUITS_COQUE_SECH_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_E14_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_KJO_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FAT_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FATSAT_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_CHOVAL_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_SUGAR_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FIBTG_P" />
<xs:element name="POURCENT_APPORT_REF_PRO_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_SALTEQ_P" type="xs:string" />
<xs:element name="APPORT_PORT" type="xs:string" />
<xs:element name="PART_P" type="xs:string" />
<xs:element name="PART_G" type="xs:string" />
<xs:element name="PART_L" type="xs:string" />
<xs:element name="P_SUR_L" type="xs:string" />
<xs:element name="POURCENT_AGS" type="xs:string" />
<xs:element name="POURCENT_AGI" type="xs:string" />
<xs:element name="POURCENT_SS" type="xs:string" />
<xs:element name="POURCENT_AMIDON" type="xs:string" />
<xs:element name="COMPOSANTE_N" type="xs:string" />
<xs:element name="COMPOSANTE_P" type="xs:string" />
<xs:element name="POURCENT_FRUITS" type="xs:string" />
<xs:element name="SCORE_NUTRI" type="xs:string" />
<xs:element name="CLASSEMENT" type="xs:string" />
<xs:element name="MAT_GRASS_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="AGS_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GLUCIDES_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SUCRE_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FIB_ALIM_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="PROTEINE_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SEL_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SODIUM_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" />
<xs:element name="libelle" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FRUITS_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" />
<xs:element name="libelle" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FRUITS_COQUE_SECH_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" />
<xs:element name="libelle" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="PROD_SAISON">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CONSEIL_PREPA" type="xs:string" />
<xs:element name="ALLEGATIONS" />
<xs:element name="ASTUCES" />
<xs:element name="DESCRIPTIF" type="xs:string" />
<xs:element name="ARG_VENTE" type="xs:string" />
<xs:element name="NB_PORTION" type="xs:string" />
<xs:element name="TYP_PORTION">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FAMILLE_VTE">
<xs:complexType>
<xs:sequence>
<xs:element name="COD_FAMVTE">
<xs:complexType>
<xs:sequence>
<xs:element name="FAM_VENTE">
<xs:complexType>
<xs:sequence>
<xs:element name="COD_FAMVTE" type="xs:string" />
<xs:element name="LIB_FAMVTE" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DATE_STATUT_CHEF_PRODUIT" type="xs:string" />
<xs:element name="EXPLOITANT">
<xs:complexType>
<xs:sequence>
<xs:element name="SOCIETE">
<xs:complexType>
<xs:sequence>
<xs:element name="ID_SOCIETE" type="xs:string" />
<xs:element name="NOM_SOCIETE" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="PDS_MOY_THEO" />
<xs:element name="LIB_CONSO" />
<xs:element name="LST_ING" />
<xs:element name="LST_ALLERGENE" />
<xs:element name="ALLEGAT_SANTE" />
<xs:element name="ALLEGAT_NUTRIT" />
<xs:element name="ALLEGAT_AUTRE" />
<xs:element name="MEDIA_VISUEL_EAI">
<xs:complexType>
<xs:sequence>
<xs:element name="MEDIA_VISUEL_EAI">
<xs:complexType>
<xs:sequence>
<xs:element name="NumeroArticle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="version" type="xs:string" />
<xs:element name="DATEVERSION" type="xs:string" />
<xs:element name="STATUT_CHEF_PRODUIT">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CHEF_PRODUIT">
<xs:complexType>
<xs:sequence>
<xs:element name="UTILISATEURS">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

View file

@ -1,11 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<title>XML Exception Handler: Invalid XML</title> <title>{{ $appName }} Exception Handler: Unvalid XML</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head> </head>
<body> <body>
<h1>{{ config('app.name') }} à reçu un fichier xml non valide</h1> <h1>{{ $appName }} à reçu un fichier xml non valide !!</h1>
<h3>{{ $strError }}</h3> <h3>{{ $strError }}</h3>
<h4>FICHIER: `{{ $filename }}`</h4> <h4>FICHIER: `{{ $filename }}`</h4>
<p>{{ $exception->getMessage() }}</p> <p>{{ $exception->getMessage() }}</p>
@ -15,7 +15,7 @@
<b>file</b> : {{$exception->getFile() }}<br> <b>file</b> : {{$exception->getFile() }}<br>
<b>line</b> : {{$exception->getLine() }}<br> <b>line</b> : {{$exception->getLine() }}<br>
<p> <p>
<b>Merci de corriger les données, puis de renvoyer le fichier en provoquant un mouvement EAI.</b><br><br> <b>Merci de corriger le flux, puis de renvoyer le fichier en provoquant un mouvement EAI.</b><br><br>
<b>Pour rappel</b>&nbsp;: Il est recommandé de valider un fichier XML à l'aide d'un <b>DTD</b><br> <b>Pour rappel</b>&nbsp;: Il est recommandé de valider un fichier XML à l'aide d'un <b>DTD</b><br>
<a href="https://www.w3schools.com/xml/xml_dtd.asp">https://www.w3schools.com/xml/xml_dtd.asp</a><br> <a href="https://www.w3schools.com/xml/xml_dtd.asp">https://www.w3schools.com/xml/xml_dtd.asp</a><br>
ou bien <b>XSD</b> <a href="https://www.w3schools.com/xml/schema_intro.asp">https://www.w3schools.com/xml/schema_intro.asp</a><br><br> ou bien <b>XSD</b> <a href="https://www.w3schools.com/xml/schema_intro.asp">https://www.w3schools.com/xml/schema_intro.asp</a><br><br>

View file

@ -1,19 +1,19 @@
<?php <?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\V1\ApiController as V1ApiController;
use App\Http\Controllers\Api\V1\XmlIncoController as V1XmlIncoController;
Route::prefix('v1')->name('apiV1.')->group(function () { /*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
// * PUBLIC Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
Route::get('/ping', [V1ApiController::class, 'ping'])->name('ping'); return $request->user();
// * PRIVATE
Route::middleware('auth:api')->group(function () {
Route::prefix('inco')->name('incos.')->group(function () {
Route::get('/', [V1XmlIncoController::class, 'index'])->name('index');
Route::get('/{xmlinco}', [V1XmlIncoController::class, 'show'])->name('show');
});
});
}); });

18
routes/channels.php Normal file
View file

@ -0,0 +1,18 @@
<?php
use Illuminate\Support\Facades\Broadcast;
/*
|--------------------------------------------------------------------------
| Broadcast Channels
|--------------------------------------------------------------------------
|
| Here you may register all of the event broadcasting channels that your
| application supports. The given channel authorization callbacks are
| used to check if an authenticated user can listen to the channel.
|
*/
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});

19
routes/console.php Normal file
View file

@ -0,0 +1,19 @@
<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
/*
|--------------------------------------------------------------------------
| Console Routes
|--------------------------------------------------------------------------
|
| This file is where you may define all of your Closure based console
| commands. Each Closure is bound to a command instance allowing a
| simple approach to interacting with each command's IO methods.
|
*/
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');

View file

@ -3,14 +3,14 @@
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Web Routes | Web Routes
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| |
| Here is where you can register web routes for your application. These | Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which | routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great! | contains the "web" middleware group. Now create something great!
| |
*/ */
Route::get('/', function () { Route::get('/', function () {

1
storage/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
inco/*

View file

@ -0,0 +1,273 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Technologies Online Tools 1.0 (https://www.liquid-technologies.com) -->
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="LIST">
<xs:complexType>
<xs:sequence>
<xs:element name="INCO">
<xs:complexType>
<xs:sequence>
<xs:element name="typemouvementinformatique" type="xs:string" />
<xs:element name="NO_ART" type="xs:string" />
<xs:element name="INCO_COMPO">
<xs:complexType>
<xs:sequence>
<xs:element name="TBL_INCO_COMPO">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string" />
<xs:element name="ID_INCO" type="xs:string" />
<xs:element name="NOM" type="xs:string" />
<xs:element name="NUMERO" type="xs:string" />
<xs:element name="TAILLE_REF" type="xs:string" />
<xs:element name="VAL_ENERG_KJ_R" type="xs:string" />
<xs:element name="VAL_ENERG_KCAL_R" type="xs:string" />
<xs:element name="MAT_GRASS_R" type="xs:string" />
<xs:element name="AGS_R" type="xs:string" />
<xs:element name="GLUCIDES_R" type="xs:string" />
<xs:element name="SUCRE_R" type="xs:string" />
<xs:element name="FIB_ALIM_R" type="xs:string" />
<xs:element name="PROTEINE_R" type="xs:string" />
<xs:element name="SEL_R" type="xs:string" />
<xs:element name="SODIUM_R" type="xs:string" />
<xs:element name="FRUITS_R" type="xs:string" />
<xs:element name="FRUITS_COQUE_SECH_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_E14_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_KJO_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FAT_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FATSAT_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_CHOVAL_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_SUGAR_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FIBTG_R" />
<xs:element name="POURCENT_APPORT_REF_PRO_R" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_SALTEQ_R" type="xs:string" />
<xs:element name="TAILLE_PORT" type="xs:string" />
<xs:element name="VAL_ENERG_KJ_P" type="xs:string" />
<xs:element name="VAL_ENERG_KCAL_P" type="xs:string" />
<xs:element name="MAT_GRASS_P" type="xs:string" />
<xs:element name="AGS_P" type="xs:string" />
<xs:element name="GLUCIDES_P" type="xs:string" />
<xs:element name="SUCRE_P" type="xs:string" />
<xs:element name="FIB_ALIM_P" type="xs:string" />
<xs:element name="PROTEINE_P" type="xs:string" />
<xs:element name="SEL_P" type="xs:string" />
<xs:element name="SODIUM_P" type="xs:string" />
<xs:element name="FRUITS_P" type="xs:string" />
<xs:element name="FRUITS_COQUE_SECH_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_E14_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_KJO_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FAT_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FATSAT_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_CHOVAL_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_SUGAR_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_FIBTG_P" />
<xs:element name="POURCENT_APPORT_REF_PRO_P" type="xs:string" />
<xs:element name="POURCENT_APPORT_REF_SALTEQ_P" type="xs:string" />
<xs:element name="APPORT_PORT" type="xs:string" />
<xs:element name="PART_P" type="xs:string" />
<xs:element name="PART_G" type="xs:string" />
<xs:element name="PART_L" type="xs:string" />
<xs:element name="P_SUR_L" type="xs:string" />
<xs:element name="POURCENT_AGS" type="xs:string" />
<xs:element name="POURCENT_AGI" type="xs:string" />
<xs:element name="POURCENT_SS" type="xs:string" />
<xs:element name="POURCENT_AMIDON" type="xs:string" />
<xs:element name="COMPOSANTE_N" type="xs:string" />
<xs:element name="COMPOSANTE_P" type="xs:string" />
<xs:element name="POURCENT_FRUITS" type="xs:string" />
<xs:element name="SCORE_NUTRI" type="xs:string" />
<xs:element name="CLASSEMENT" type="xs:string" />
<xs:element name="MAT_GRASS_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="AGS_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GLUCIDES_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SUCRE_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FIB_ALIM_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="PROTEINE_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SEL_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SODIUM_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" />
<xs:element name="libelle" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FRUITS_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" />
<xs:element name="libelle" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FRUITS_COQUE_SECH_R_PREC">
<xs:complexType>
<xs:sequence>
<xs:element name="code" />
<xs:element name="libelle" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="PROD_SAISON">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CONSEIL_PREPA" type="xs:string" />
<xs:element name="ALLEGATIONS" />
<xs:element name="ASTUCES" />
<xs:element name="DESCRIPTIF" type="xs:string" />
<xs:element name="ARG_VENTE" type="xs:string" />
<xs:element name="NB_PORTION" type="xs:string" />
<xs:element name="TYP_PORTION">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="FAMILLE_VTE">
<xs:complexType>
<xs:sequence>
<xs:element name="COD_FAMVTE">
<xs:complexType>
<xs:sequence>
<xs:element name="FAM_VENTE">
<xs:complexType>
<xs:sequence>
<xs:element name="COD_FAMVTE" type="xs:string" />
<xs:element name="LIB_FAMVTE" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DATE_STATUT_CHEF_PRODUIT" type="xs:string" />
<xs:element name="EXPLOITANT">
<xs:complexType>
<xs:sequence>
<xs:element name="SOCIETE">
<xs:complexType>
<xs:sequence>
<xs:element name="ID_SOCIETE" type="xs:string" />
<xs:element name="NOM_SOCIETE" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="PDS_MOY_THEO" />
<xs:element name="LIB_CONSO" />
<xs:element name="LST_ING" />
<xs:element name="LST_ALLERGENE" />
<xs:element name="ALLEGAT_SANTE" />
<xs:element name="ALLEGAT_NUTRIT" />
<xs:element name="ALLEGAT_AUTRE" />
<xs:element name="MEDIA_VISUEL_EAI">
<xs:complexType>
<xs:sequence>
<xs:element name="MEDIA_VISUEL_EAI">
<xs:complexType>
<xs:sequence>
<xs:element name="NumeroArticle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="version" type="xs:string" />
<xs:element name="DATEVERSION" type="xs:string" />
<xs:element name="STATUT_CHEF_PRODUIT">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CHEF_PRODUIT">
<xs:complexType>
<xs:sequence>
<xs:element name="UTILISATEURS">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="libelle" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

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