- composer require kwaadpepper/serial-int-caster

- add code parameters into config
- add code length parameter into settings
- add total possible codes to generate in generation page
- add GenerateRequest validation
- changed job ProcessUniqueCode to increase performances using mass insert and pagination
- changed singletoned Settings instance to increase performances
- Fix process export code put datetime in file name
- aded storage to gitignore file
- fixed export to guess export codes, also non recursive now
- changed refactorize a bit EnterCodeController::participate + add request
- Add request to export and generate codes requests
This commit is contained in:
Jérémy Munsch 2022-01-07 19:00:30 +01:00
parent 7f557963ab
commit 9ee2123928
No known key found for this signature in database
GPG key ID: 55196BEE445F6049
32 changed files with 775 additions and 227 deletions

1
.gitignore vendored
View file

@ -26,3 +26,4 @@ package-lock.json
composer.lock
resources/front
.vscode
storage

View file

@ -103,7 +103,7 @@ class ExportCodesUniques extends Command
$this->info("L'archive CodesUniques_" . date('dmY') . ".zip a ete creer.");
// Envoi de mail à MAIL_ADMIN avec le nom du ZIP "CodesUniques_". date('dmY') .".zip"
Mail::to(config('mail.MAIL_ADMIN'))->send(new MailExportCodesUniques(Settings::find(1)->name, $nbCodeFic, $nbCodeTot, $nbCodeLigne));
Mail::to(config('mail.MAIL_ADMIN'))->send(new MailExportCodesUniques(app(Settings::class)->name, $nbCodeFic, $nbCodeTot, $nbCodeLigne));
}
private function process($nbCodeFic, $nbCodeTot, $nbCodeLigne, $totalExportedCodes, $currentFilename, $currentExportedCodes, $currentLineCodes, $lastExportedCodeId = null)

View file

@ -8,7 +8,7 @@ class EndPageController extends Controller
{
public function index()
{
$settings = Settings::find(1)->select('start_date', 'end_date', 'activated_close_page', 'close_page_active_date', 'redirect_close')->first();
$settings = app(Settings::class)->select('start_date', 'end_date', 'activated_close_page', 'close_page_active_date', 'redirect_close')->first();
if ($settings->end_date < now() && $settings->activated_close_page === 1 && $settings->close_page_active_date > now()) {
return view('front.basic.end', compact('settings'));
}

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Http\Requests\ParticipateRequest;
use App\Mail\CourrierArcadiaError;
use App\Mail\NotifAdmin;
use App\Mail\NotifWinAdmin;
@ -34,27 +35,21 @@ class EnterCodeController extends Controller
public function index()
{
$nbParticipations = Participation::where('user_id', Auth::user()->id)->count();
$settings = Settings::find(1)->select('use_ean_codes', 'nb_participation_player')->first();
$settings = app(Settings::class)->select('use_ean_codes', 'nb_participation_player')->first();
if ($nbParticipations >= $settings->nb_participation_player) {
return view('front.basic.participation-exhausted', compact('settings'));
}
return view('front.basic.enter-code', compact('settings'));
}
public function participate(Request $request)
public function participate(ParticipateRequest $request)
{
// TODO : VALIDATE avec / sans code ean
// Récupération des données à utilisées
$code = strtoupper($request->code);
$codeBase = Codes::where('code_unique', $code)->first();
$settings = Settings::find(1);
// Récupération des données à utilisées.
$codeBase = Codes::whereId(Codes::serialToInt($request->code))->first();
$settings = app(Settings::class);
$rules = $request->accept_rules === null ? false : true;
if (!$rules) {
return back()->withErrors("Pour participer, vous devez accepter le règlement du jeu.");
}
// Cas IP bannie
// * Cas IP bannie.
if (config('app.env') == "local") {
$ipBanned = BannedIP::where('ip', $_SERVER['REMOTE_ADDR'])->first() === null ? 0 : 1;
} else {
@ -64,13 +59,13 @@ class EnterCodeController extends Controller
return view('front.basic.participation-exhausted', compact('settings'));
}
// Cas nombre de participation maximale atteint
// * Cas nombre de participation maximale atteint.
$nbParticipations = Participation::where('user_id', Auth::user()->id)->count();
if ($nbParticipations >= $settings->nb_participation_player) {
return view('front.basic.participation-exhausted', compact('settings'));
}
// Check le code pour savoir s'il est encore utilisable
// * Check le code pour savoir s'il est encore utilisable.
if (!$codeBase) {
return back()->withErrors("Code incorrect, veuillez réessayer.");
}
@ -78,7 +73,7 @@ class EnterCodeController extends Controller
return back()->withErrors("Ce code n'est plus utilisable.");
}
// Check si l'utilisateur n'a pas déjà utiliser ce code
// * Check si l'utilisateur n'a pas déjà utiliser ce code.
$participUser = Participation::where([
['code_unique_id', $codeBase->id],
['user_id', Auth::user()->id]
@ -87,7 +82,7 @@ class EnterCodeController extends Controller
return back()->withErrors("Vous avez déjà utilisé ce code.");
}
// Check si les codes ean sont utilisés, auquel cas on test celui envoyé pour savoir s'il est correct
// * Check si les codes ean sont utilisés, auquel cas on test celui envoyé pour savoir s'il est correct.
$codeEan = null;
// TODO : Task Algo Sebastien
if ($settings->use_ean_codes === 1) {
@ -103,7 +98,7 @@ class EnterCodeController extends Controller
$codeNbUsage = Participation::where('code_unique_id', $codeBase->id)->count();
// Gestion du nombre d'utilisation d'un code
// * Gestion du nombre d'utilisation d'un code.
if ($codeNbUsage >= $settings->nb_unique_code_use) {
$codeBase->code_used = 1;
$codeBase->save();
@ -114,7 +109,7 @@ class EnterCodeController extends Controller
}
}
// Tous les cas "bloquants" sont passé, l'utilisateur participe à partir d'ici
// * Tous les cas "bloquants" sont passé, l'utilisateur participe à partir d'ici.
$participation = new Participation();
$participation->user_id = Auth::user()->id;
$participation->code_unique_id = $codeBase->id;
@ -126,13 +121,13 @@ class EnterCodeController extends Controller
}
$participation->save();
// Gestion des instants gagnants
// * Gestion des instants gagnants.
$userAlreadyWon = Participation::where([
['user_id', Auth::user()->id],
['instant_win_id', '<>', null]
])->first();
// Si l'utilisateur actuel à déjà gagné un gros lot, pas d'instant gagnant
// * Si l'utilisateur actuel à déjà gagné un gros lot, pas d'instant gagnant.
if ($userAlreadyWon) {
return $this->serveCouponWin($settings,$participation);
} else {

View file

@ -220,7 +220,7 @@ class LoginController extends Controller
$user->password_token = Str::uuid();
$user->save();
$settings = Settings::find(1);
$settings = app(Settings::class);
Mail::to($email)->send(new PasswordReset($user, $settings));
return redirect()->route('login')->with('success', 'Un mail de réinitialisation de votre mot de passe vous a été envoyé(e).');
}

View file

@ -8,7 +8,7 @@ class TeaserController extends Controller
{
public function index()
{
$settings = Settings::find(1)->select('start_date', 'end_date', 'activated_teaser', 'teaser_end_activity')->first();
$settings = app(Settings::class)->select('start_date', 'end_date', 'activated_teaser', 'teaser_end_activity')->first();
if ($settings->activated_teaser === 1 && $settings->teaser_end_activity > now()) {
return view('front.basic.teaser', compact('settings'));
}

View file

@ -99,7 +99,7 @@ class WinningProofController extends Controller
$participation->barcode = $barcodeFileName;
$participation->save();
$settings = Settings::find(1);
$settings = app(Settings::class);
$mails = json_decode($settings->notification_emails);
foreach ($mails as $mail) {
Mail::to($mail->email)->send(new WinningProof($stickerPath, $ticketPath, $barcodePath, $participation, $user, $settings));

View file

@ -3,42 +3,74 @@
namespace App\Http\Controllers\bo;
use App\Http\Controllers\Controller;
use App\Http\Requests\ExportCodesRequest;
use App\Http\Requests\GenerateCodesRequest;
use App\Jobs\ProcessExportCodesUniques;
use App\Jobs\ProcessUniqueCode;
use App\Models\Codes;
use App\Models\Settings;
use Illuminate\Http\Request;
class CodesController extends Controller
{
/**
* Show code form to generate and export
*
* @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
public function index()
{
$settings = app(Settings::class);
$nbCodeBase = Codes::count();
$nbCodeUsed = Codes::where('code_used', 1)->count();
$nbCodeExported = Codes::where('code_exported', 1)->count();
$nbCodeRemainingToExport = Codes::where('code_exported', 0)->count();
return view('bo.codes.index', compact('nbCodeBase', 'nbCodeUsed', 'nbCodeExported', 'nbCodeRemainingToExport'));
return view('bo.codes.index', compact(
'settings',
'nbCodeBase',
'nbCodeUsed',
'nbCodeExported',
'nbCodeRemainingToExport'
));
}
public function generate(Request $request)
/**
* Run generate codes action
*
* @param GenerateCodesRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function generate(GenerateCodesRequest $request)
{
$quantity = $request->quantity;
$codeLength = $request->code_length;
$settings = Settings::find(1);
ProcessUniqueCode::dispatch(
$request->quantity,
$request->code_length
);
ProcessUniqueCode::dispatch($quantity, $codeLength, $settings);
return back()->with('success', "La génération à commencée, un mail de notification sera envoyé à l'adresse " . config('mail.MAIL_ADMIN') . " lorsque le traitement sera terminé.");
return back()->with(
'success',
"La génération à commencée, un mail de notification sera envoyé à l'adresse " .
config('mail.MAIL_ADMIN') . " lorsque le traitement sera terminé."
);
}
public function export(Request $request)
/**
* Run export codes
*
* @param ExportCodesRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function export(ExportCodesRequest $request)
{
$nbCodeFic = intval($request->nb_code_fic);
$nbCodeTot = intval($request->nb_code_tot);
$nbCodeLigne = intval($request->nb_code_ligne);
ProcessExportCodesUniques::dispatch(
intval($request->nb_code_fic),
intval($request->nb_code_tot),
intval($request->nb_code_ligne)
);
ProcessExportCodesUniques::dispatch($nbCodeFic, $nbCodeTot, $nbCodeLigne);
return back()->with('success', "L'export des codes à commencé, un mail de notification sera envoyé à l'adresse " . config('mail.MAIL_ADMIN') . " lorsque le traitement sera terminé.");
return back()->with(
'success',
"L'export des codes à commencé, un mail de notification sera envoyé à l'adresse " .
config('mail.MAIL_ADMIN') . " lorsque le traitement sera terminé."
);
}
}

View file

@ -13,7 +13,7 @@ class DashboardController extends Controller
public function index()
{
// Pour les stats
$settings = Settings::find(1);
$settings = app(Settings::class);
$participations = Participation::selectRaw("COUNT(*) AS count, DATE(created_at) AS date")->groupByRaw("DATE(created_at)")->get();
$participationsUniquePerDay = Participation::selectRaw("DISTINCT user_id AS user, COUNT(*) AS count, DATE(created_at) AS date")->groupByRaw("DATE(created_at), user")->get();
$statsUnique = [];

View file

@ -12,7 +12,7 @@ class SettingsController extends Controller
{
public function manage(Request $request)
{
$settings = Settings::find(1);
$settings = app(Settings::class);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $request->name;
@ -76,7 +76,7 @@ class SettingsController extends Controller
$settings->save();
$settingsGlobal = Settings::find(1)->select('name', 'company', 'analytics', 'start_date', 'end_date')->first();
$settingsGlobal = app(Settings::class)->select('name', 'company', 'analytics', 'start_date', 'end_date')->first();
Cache::put('settingsGlobal', $settingsGlobal);
$success = "Modifications enregistrés !";

View file

@ -96,7 +96,7 @@ class WinnersListController extends Controller
]
];
$settings = Settings::find(1);
$settings = app(Settings::class);
if ($settings->use_ean_codes === 1) {
$fields['orderLine'][] = [
'fieldName' => 'code_on_pack',

View file

@ -14,7 +14,7 @@ class re7Controller extends Controller
public function teaser()
{
$settings = Settings::find(1)->select('start_date', 'end_date', 'activated_teaser', 'teaser_end_activity')->first();
$settings = app(Settings::class)->select('start_date', 'end_date', 'activated_teaser', 'teaser_end_activity')->first();
return view('front.basic.teaser', compact('settings'));
}
@ -30,7 +30,7 @@ class re7Controller extends Controller
public function br()
{
$settings = Settings::find(1);
$settings = app(Settings::class);
$coupon = $this->getRandomCoupon($settings);
$crmCoupon = new Reductions();
return view('front.basic.reduction', compact('coupon', 'crmCoupon'));

View file

@ -16,7 +16,7 @@ class GameCheckDate
*/
public function handle($request, Closure $next)
{
$settings = Settings::find(1);
$settings = app(Settings::class);
// Check si le teaser est actif
if ($settings->start_date > now()) {

View file

@ -0,0 +1,62 @@
<?php
namespace App\Http\Requests;
use App\Models\Codes;
use Illuminate\Foundation\Http\FormRequest;
class ExportCodesRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
/** @var \Illuminate\Database\Eloquent\Builder */
$codesAvailableToExport = Codes::whereCodeExported(false);
$lastExportedId = Codes::whereCodeExported(true)
->orderBy('id', 'desc')->first()->id ?? null;
if ($lastExportedId) {
$codesAvailableToExport = $codesAvailableToExport
->where('id', '>', $lastExportedId);
}
$this->merge([
'available_export' => $codesAvailableToExport->count()
]);
// ? Is auth and super admin, also is json ?
return auth()->check() and
auth()->user()->role === 1 and $this->json();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'nb_code_fic' => 'required|integer|min:1',
'nb_code_tot' => 'required|integer|min:1',
'nb_code_ligne' => 'required|integer|min:1',
'available_export' => 'required|integer|gte:nb_code_tot'
];
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes(): array
{
return [
'nb_code_fic' => 'Nombre total de codes à exporter',
'nb_code_tot' => 'Nombre de codes par fichier',
'nb_code_ligne' => 'Nombre de codes par ligne',
'available_export' => 'Nombre de codes restant à exporté(s)'
];
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class GenerateCodesRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
// ? Is auth and super admin
return auth()->check() and auth()->user()->role === 1;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'quantity' => 'required|integer|min:1',
'code_length' => 'required|integer|min:1',
];
}
}

View file

@ -0,0 +1,62 @@
<?php
namespace App\Http\Requests;
use App\Models\Codes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Kwaadpepper\Serial\Exceptions\SerialCasterException;
class ParticipateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return boolean
*/
public function authorize()
{
$this->merge([
'code' => is_string($this->code) ? Str::upper($this->code) : $this->code,
'accept_rules' => $this->accept_rules ? true : false
]);
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'accept_rules' => [
'required', 'boolean',
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
function ($attribute, $value, $fail) {
if (!$value) {
$fail('Pour participer, vous devez accepter le règlement du jeu.');
}
}
],
'code' => [
'required', 'string',
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
function ($attribute, $value, $fail) {
try {
$int = Codes::serialToInt($value);
if (!Codes::whereId(Codes::serialToInt($value))->exists()) {
throw new SerialCasterException();
}
} catch (SerialCasterException $e) {
dd($e);
Log::debug($e->getMessage(), $e->getTrace());
$fail('Code incorrect, veuillez réessayer.');
}
}
]
];
}
}

View file

@ -5,13 +5,13 @@ namespace App\Jobs;
use App\Mail\ExportCodesUniques;
use App\Mail\JobFailed;
use App\Models\Codes;
use App\Models\Settings;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Mail;
class ProcessExportCodesUniques implements ShouldQueue
@ -21,14 +21,51 @@ class ProcessExportCodesUniques implements ShouldQueue
use Queueable;
use SerializesModels;
private $nbCodeFic, $nbCodeTot, $nbCodeLigne;
/**
* The number of seconds the job can run before timing out.
*
* 7200 seconds (2 hours)
*
* @var integer
*/
public $timeout = 7200;
/**
* Nombre de codes par fichiers.
* @var integer
*/
private $nbCodeFic;
/**
* Nombre total de codes à exporter.
*
* @var integer
*/
private $nbCodeTot;
/**
* Nombre de codes par ligne.
*
* @var integer
*/
private $nbCodeLigne;
/**
* The export file name
*
* @var string
*/
private $exportFileName = null;
/**
* Create a new job instance.
*
* @param integer $nbCodeFic Nombre de codes par fichiers.
* @param integer $nbCodeTot Nombre total de codes à exporter.
* @param integer $nbCodeLigne Nombre de codes par ligne.
* @return void
*/
public function __construct($nbCodeFic, $nbCodeTot, $nbCodeLigne)
public function __construct(int $nbCodeFic, int $nbCodeTot, int $nbCodeLigne)
{
$this->nbCodeFic = $nbCodeFic;
$this->nbCodeTot = $nbCodeTot;
@ -42,108 +79,134 @@ class ProcessExportCodesUniques implements ShouldQueue
*/
public function handle()
{
$nbCodeFic = $this->nbCodeFic; // Nombre de code par fichier
$nbCodeTot = $this->nbCodeTot; // Nombre total de code à exporter
$nbCodeLigne = $this->nbCodeLigne; // Nombre de code par ligne
$totalExportedCodes = 0;
$currentFilename = 1;
$currentExportedCodes = 0;
$currentLineCodes = ($nbCodeLigne === 1 ? 1 : 0);
$this->exportFileName = sprintf(
'CodesUniques_%s',
date('dmY_His')
);
$this->process($nbCodeFic, $nbCodeTot, $nbCodeLigne, $totalExportedCodes, $currentFilename, $currentExportedCodes, $currentLineCodes);
$lastExportedCodeId = Codes::whereCodeExported(true)
->orderBy('id', 'desc')->first()->id ?? null;
// Compression des fichiers
$filesPath = $this->generateCsvFiles($lastExportedCodeId);
// * Compression des fichiers.
$zip = new \ZipArchive();
if ($zip->open(storage_path('export_codes_uniques/') . "CodesUniques_" . date('dmY') . ".zip", \ZipArchive::CREATE) === true) {
if ($handle = opendir(storage_path('export_codes_uniques/tmp'))) {
while (false !== ($file_to_zip = readdir($handle))) {
if (pathinfo($file_to_zip, PATHINFO_EXTENSION) != 'csv') {
continue;
}
$zip->addFile(storage_path('export_codes_uniques/tmp/') . $file_to_zip, "$file_to_zip");
if (
$zip->open(
storage_path(sprintf('export_codes_uniques/%s.zip', $this->exportFileName)),
\ZipArchive::CREATE
) === true
) {
foreach ($filesPath as $filePath) {
if (File::exists($filePath)) {
$zip->addFile($filePath, \pathinfo($filePath, \PATHINFO_BASENAME));
}
closedir($handle);
}
$zip->close();
}
// On vide le dossier temporaire des fichiers csv
if ($handle = opendir(storage_path('export_codes_uniques/tmp'))) {
while (false !== ($file_to_zip = readdir($handle))) {
if (pathinfo($file_to_zip, PATHINFO_EXTENSION) != 'csv') {
continue;
}
unlink(storage_path('export_codes_uniques/tmp/') . $file_to_zip);
// * On vide le dossier temporaire des fichiers csv.
foreach ($filesPath as $filePath) {
if (File::exists($filePath)) {
File::delete($filePath);
}
closedir($handle);
}
// Envoi de mail à MAIL_ADMIN avec le nom du ZIP "CodesUniques_". date('dmY') .".zip"
Mail::to(config('mail.MAIL_ADMIN'))->send(new ExportCodesUniques(Settings::find(1)->name, $nbCodeFic, $nbCodeTot, $nbCodeLigne));
// * Envoi de mail à MAIL_ADMIN avec le nom du ZIP "CodesUniques_". date('dmY_His') .".zip".
Mail::to(config('mail.MAIL_ADMIN'))
->send(new ExportCodesUniques(
$this->nbCodeFic,
$this->nbCodeTot,
$this->nbCodeLigne
));
}
private function process($nbCodeFic, $nbCodeTot, $nbCodeLigne, $totalExportedCodes, $currentFilename, $currentExportedCodes, $currentLineCodes, $lastExportedCodeId = null)
/**
* Generate CSV File using the job parameters
*
* @param integer|null $lastExportedCodeId
* @return array Array of temp files
*/
private function generateCsvFiles($lastExportedCodeId = null): array
{
$paginate = config('codes.paginate');
$outPaths = [];
$totalExportedCodes = 0;
$currentFilename = 1;
$currentExportedCodes = 0;
$currentLineCodes = ($this->nbCodeLigne === 1 ? 1 : 0);
if ($nbCodeTot < $paginate) {
$nbCodeToRetrieve = $nbCodeTot;
} else {
if ($totalExportedCodes + $paginate > $nbCodeTot) {
$nbCodeToRetrieve = $nbCodeTot - $totalExportedCodes;
} else {
$nbCodeToRetrieve = $paginate;
}
$paginate = intval(config('codes.paginate', 65535));
// ! Guess code ids instead of getting thme from base.
$codes = [];
$id = ($lastExportedCodeId ?? 0) + 1;
for ($i = 0; $i < $this->nbCodeTot; $i++) {
$codes[] = $id++;
}
if ($lastExportedCodeId === null) {
$codes = Codes::where('code_exported', 0)->take($nbCodeToRetrieve)->get();
} else {
$codes = Codes::where([
['code_exported', '=', 0],
['id', '>', $lastExportedCodeId]
])->take($nbCodeToRetrieve)->get();
}
$countCodes = count($codes);
$exportedCodesId = [];
foreach ($codes as $k => $code) {
if ($currentExportedCodes < $nbCodeTot) {
if ($currentLineCodes === ($nbCodeLigne === 1 ? 1 : $nbCodeLigne - 1)) {
file_put_contents(storage_path('export_codes_uniques/tmp/') . $currentFilename . ".csv", $code->code_unique . PHP_EOL, FILE_APPEND);
$totalExportedCodes++;
$currentExportedCodes++;
$currentLineCodes = ($nbCodeLigne === 1 ? 1 : 0);
$tempFilePath = \storage_path(\sprintf(
'export_codes_uniques/tmp/%s_%s.csv',
$this->exportFileName,
$currentFilename
));
$outPaths[] = $tempFilePath;
foreach ($codes as $code) {
if ($currentExportedCodes < $this->nbCodeTot) {
if ($currentLineCodes === ($this->nbCodeLigne === 1 ? 1 : $this->nbCodeLigne - 1)) {
File::append($tempFilePath, Codes::intToSerial($code) . "\n");
$currentLineCodes = ($this->nbCodeLigne === 1 ? 1 : 0);
} else {
file_put_contents(storage_path('export_codes_uniques/tmp/') . $currentFilename . ".csv", $code->code_unique . ";", FILE_APPEND);
$totalExportedCodes++;
$currentExportedCodes++;
File::append($tempFilePath, Codes::intToSerial($code) . ';');
$currentLineCodes++;
}
} //end if
array_push($exportedCodesId, $code->id);
$lastExportedCodeId = $code->id;
$totalExportedCodes++;
$currentExportedCodes++;
if ($currentExportedCodes === $nbCodeFic) {
$exportedCodesId[] = $code;
if ($currentExportedCodes === $this->nbCodeFic) {
$currentFilename++;
$currentExportedCodes = 0;
$tempFilePath = \storage_path(\sprintf(
'export_codes_uniques/tmp/%s_%s.csv',
$this->exportFileName,
$currentFilename
));
$outPaths[] = $tempFilePath;
}
if ((($k + 1) === $countCodes) && $totalExportedCodes < $nbCodeTot) {
// ? Have we reached pagination limit for mass saving ?
if (count($exportedCodesId) === $paginate) {
Codes::whereIn('id', $exportedCodesId)->update(['code_exported' => 1]);
return $this->process($nbCodeFic, $nbCodeTot, $nbCodeLigne, $totalExportedCodes, $currentFilename, $currentExportedCodes, $currentLineCodes, $lastExportedCodeId);
$exportedCodesId = [];
}
if (($k + 1) === $countCodes) {
Codes::whereIn('id', $exportedCodesId)->update(['code_exported' => 1]);
}
}
} //end if
} //end foreach
// ? Are there exported codes to save ?
if (count($exportedCodesId)) {
Codes::whereIn('id', $exportedCodesId)->update(['code_exported' => 1]);
}
return $outPaths;
}
/**
* In case of job failure
*
* @param Exception $exception
* @return void
*/
public function failed(Exception $exception)
{
Mail::to(config('mail.MAIL_ADMIN'))->send(new JobFailed("ProcessExportCodeUnique", ['message' => $exception->getMessage(), 'trace' => $exception->getTraceAsString()]));
Mail::to(config('mail.MAIL_ADMIN'))
->send(new JobFailed("ProcessExportCodeUnique", [
'message' => $exception->getMessage(),
'trace' => $exception->getTraceAsString()
]));
}
}

View file

@ -5,12 +5,14 @@ namespace App\Jobs;
use App\Mail\CodeGenerationEnd;
use App\Mail\JobFailed;
use App\Models\Codes;
use App\Models\Settings;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
class ProcessUniqueCode implements ShouldQueue
@ -20,71 +22,107 @@ class ProcessUniqueCode implements ShouldQueue
use Queueable;
use SerializesModels;
/**
* The number of seconds the job can run before timing out.
*
* 7200 seconds (2 hours)
*
* @var integer
*/
public $timeout = 7200;
/**
* Quantity of code to generate
*
* @var integer
*/
private $quantity;
/**
* Length of code to generate
*
* @var integer
*/
private $length;
private $settings;
/**
* Create a new job instance.
*
* @param integer $quantity
* @param integer $length
* @return void
*/
public function __construct($quantity, $length, $settings)
public function __construct(int $quantity, int $length)
{
$this->quantity = $quantity;
$this->length = $length;
$this->settings = $settings;
}
/**
* Execute the job.
* TODO: Mettre tout ce bordel dans une transaction quand les serveur de leurs morts auront été mis à jour Uu.
*
* @return void
*/
public function handle()
{
set_time_limit(0);
for ($ib = 1; $ib <= $this->quantity;) {
try {
$code = new Codes();
$code->code_unique = $this->getCode($this->length);
$code->date_creation = now();
$code->save();
if ($code) {
$ib++;
}
} catch (\PDOException $e) {
if (!strpos($e->getMessage(), 'Duplicate entry')) {
Mail::to(config('mail.MAIL_ADMIN'))->send(new JobFailed("ProcessUniqueCode", ['message' => $e->getMessage(), 'trace' => $e->getTraceAsString()]));
die();
}
}
$settings = app(Settings::class);
$maxSQLPlaceholders = 65535;
$insertColumns = collect(DB::getSchemaBuilder()
->getColumnListing((new Codes())->getTable()))
->filter(function ($name) {
// * Ignorer les colonnes avec valeurs par défaut sur la table.
return !in_array($name, ['id', 'code_used', 'code_exported']);
})->count();
/**
* Nombre d'insertions max sur un seule requète
* @var integer $perPage
*/
$perPage = $maxSQLPlaceholders / $insertColumns;
/**
* Nombre de page totale à insérer.
* @var integer $totalPages
*/
$totalPages = \ceil($this->quantity / $perPage);
$totalGeneratedInserts = 0;
for ($currentPage = 1; $currentPage <= $totalPages; $currentPage++) {
$inserts = [];
$insertToGenerate = min($perPage, $this->quantity - $totalGeneratedInserts);
do {
$inserts[] = [
'date_creation' => now()->format('Y-m-d'),
];
} while ($totalGeneratedInserts < $this->quantity and --$insertToGenerate);
// * Mass insert
Codes::insert($inserts);
$totalGeneratedInserts += count($inserts);
}
// ---- Fin de la génération
Mail::to(config('mail.MAIL_ADMIN'))->send(new CodeGenerationEnd($this->quantity, $this->settings));
}
private function getCode($car)
{
$chaine = "ABCDEFGHJKMNPQRSTUWXYZ123456789"; // Caractères autorisés
$valprec = "";
$string = "";
srand();
for ($i = 0; $i < $car;) {
$val = $chaine[rand() % strlen($chaine)];
if ($val != $valprec) {
$string .= $val;
$valprec = $val;
$i++;
}
}
return $string;
// * Fin de la génération.
Mail::to(config('mail.MAIL_ADMIN'))
->send(new CodeGenerationEnd($this->quantity, $settings->name));
}
/**
* In case of job failure
*
* @param Exception $exception
* @return void
*/
public function failed(Exception $exception)
{
Mail::to(config('mail.MAIL_ADMIN'))->send(new JobFailed("ProcessUniqueCode", ['message' => $exception->getMessage(), 'trace' => $exception->getTraceAsString()]));
Mail::to(config('mail.MAIL_ADMIN'))
->send(new JobFailed("ProcessUniqueCode", [
'message' => $exception->getMessage(),
'trace' => $exception->getTraceAsString()
]));
}
}

View file

@ -11,16 +11,31 @@ class CodeGenerationEnd extends Mailable
use Queueable;
use SerializesModels;
/**
* Number of codes generated
*
* @var integer
*/
private $quantity;
/**
* The game name
*
* @var string
*/
private $gameName;
/**
* Create a new message instance.
*
* @param integer $quantity
* @param string $gameName
* @return void
*/
public function __construct($quantity, $settings)
public function __construct(int $quantity, string $gameName)
{
$this->quantity = $quantity;
$this->settings = $settings;
$this->gameName = $gameName;
}
/**
@ -30,6 +45,8 @@ class CodeGenerationEnd extends Mailable
*/
public function build()
{
return $this->subject('Fin de génération des codes uniques')->view('bo.mails.generate-end-email')->with(['quantity' => $this->quantity, 'settings' => $this->settings]);
return $this->subject('Fin de génération des codes uniques')
->view('bo.mails.generate-end-email')
->with(['quantity' => $this->quantity, 'gameName' => $this->gameName]);
}
}

View file

@ -2,6 +2,7 @@
namespace App\Mail;
use App\Models\Settings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
@ -12,16 +13,36 @@ class ExportCodesUniques extends Mailable implements ShouldQueue
use Queueable;
use SerializesModels;
private $name, $nbCodeFic, $nbCodeTot, $nbCodeLigne;
/**
* Nombre de codes par fichiers.
* @var integer
*/
private $nbCodeFic;
/**
* Nombre total de codes à exporter.
*
* @var integer
*/
private $nbCodeTot;
/**
* Nombre de codes par ligne.
*
* @var integer
*/
private $nbCodeLigne;
/**
* Create a new message instance.
*
* @param integer $nbCodeFic Nombre de codes par fichiers.
* @param integer $nbCodeTot Nombre total de codes à exporter.
* @param integer $nbCodeLigne Nombre de codes par ligne.
* @return void
*/
public function __construct($name, $nbCodeFic, $nbCodeTot, $nbCodeLigne)
public function __construct(int $nbCodeFic, int $nbCodeTot, int $nbCodeLigne)
{
$this->name = $name;
$this->nbCodeFic = $nbCodeFic;
$this->nbCodeTot = $nbCodeTot;
$this->nbCodeLigne = $nbCodeLigne;
@ -37,7 +58,7 @@ class ExportCodesUniques extends Mailable implements ShouldQueue
$nbCodeFic = $this->nbCodeFic;
$nbCodeTot = $this->nbCodeTot;
$nbCodeLigne = $this->nbCodeLigne;
return $this->subject("Fin de l'export des codes uniques pour " . $this->name)
return $this->subject("Fin de l'export des codes uniques pour " . app(Settings::class)->name)
->view('bo.mails.export-codes-unique-email', compact('nbCodeFic', 'nbCodeTot', 'nbCodeLigne'));
}
}

View file

@ -3,16 +3,83 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Kwaadpepper\Serial\SerialCaster;
class Codes extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'code_used', 'code_exported',
'date_creation'
];
protected $fillable = ['code_unique', 'code_used', 'code_exported', 'date_creation'];
/**
* Indicates if the model should be timestamped.
*
* @var boolean
*/
public $timestamps = false;
// * RELATIONS
/**
* Has many Participation relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function participations()
{
return $this->hasMany('App\Models\Participation', 'code_unique_id');
return $this->hasMany(Participation::class, 'code_unique_id');
}
// * FUNCTIONS
/**
* Generate code_unique attribute
*
* @return string|null
*/
public function getCodeUniqueAttribute()
{
if (!$this->id or !\is_integer($this->id) or $this->id < 1) {
return null;
}
return self::intToSerial($this->id);
}
/**
* Generate a serial from an int.
*
* @param integer $int
* @return string The serial
* @throws SerialCasterException If an error happens du to config.
*/
public static function intToSerial(int $int): string
{
return SerialCaster::encode(
$int,
\abs(\crc32(config('app.key'))),
app(Settings::class)->code_length,
config('codes.codeCharList')
);
}
/**
* Generate a serial from an int.
*
* @param string $serial
* @return integer The ID represented
* @throws SerialCasterException If an error happens due to config or wrong serial is given.
*/
public static function serialToInt(string $serial): int
{
return SerialCaster::decode(
$serial,
\abs(\crc32(config('app.key'))),
config('codes.codeCharList')
);
}
}

View file

@ -34,11 +34,18 @@ class AppServiceProvider extends ServiceProvider
setlocale(LC_TIME, config('app.locale') . "_" . strtoupper(config('app.locale')) . '.utf8');
app()->singleton(Settings::class, function () {
if (!($settings = Settings::find(1))) {
throw new \ErrorException('Settings not found in DB');
}
return $settings;
});
if (!app()->runningInConsole()) {
// On ramène le nom du jeu et le nom de la société sur toute les pages
$settingsGlobal = Cache::get('settingsGlobal');
if (!$settingsGlobal) {
$settingsGlobal = Settings::find(1)->select('name', 'company', 'analytics', 'start_date', 'end_date')->first();
$settingsGlobal = app(Settings::class)->select('name', 'company', 'analytics', 'start_date', 'end_date')->first();
Cache::put('settingsGlobal', $settingsGlobal);
}
View::share('settingsGlobal', $settingsGlobal);

View file

@ -14,6 +14,7 @@
"fideloper/proxy": "^4.2",
"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^6.3",
"kwaadpepper/serial-int-caster": "^1.0",
"laravel/framework": "^7.24",
"laravel/tinker": "^2.0",
"laravel/ui": "2.4"

82
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "556b0ac601a71abe129f7ed12da116f6",
"content-hash": "a1071d5ef8b5a8f12e458a6866973b27",
"packages": [
{
"name": "asm89/stack-cors",
@ -765,6 +765,50 @@
},
"time": "2021-04-26T09:17:50+00:00"
},
{
"name": "kwaadpepper/serial-int-caster",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/Kwaadpepper/serial-int-caster.git",
"reference": "bbba003ff5379576f05114386b5ebe8b33bc4705"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Kwaadpepper/serial-int-caster/zipball/bbba003ff5379576f05114386b5ebe8b33bc4705",
"reference": "bbba003ff5379576f05114386b5ebe8b33bc4705",
"shasum": ""
},
"require": {
"php": ">=7.3.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "^3.6"
},
"type": "library",
"autoload": {
"psr-4": {
"Kwaadpepper\\Serial\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jérémy Munsch",
"email": "github@jeremydev.ovh"
}
],
"description": "Convert int To as serial number and reverse",
"support": {
"issues": "https://github.com/Kwaadpepper/serial-int-caster/issues",
"source": "https://github.com/Kwaadpepper/serial-int-caster/tree/1.0.1"
},
"time": "2021-05-16T15:50:37+00:00"
},
{
"name": "laravel/framework",
"version": "v7.30.4",
@ -7351,32 +7395,32 @@
},
{
"name": "slevomat/coding-standard",
"version": "7.0.13",
"version": "7.0.15",
"source": {
"type": "git",
"url": "https://github.com/slevomat/coding-standard.git",
"reference": "122a9bf9a4a2195f74100f47dfb8375982f43cc9"
"reference": "cc80e59f9b4ca642f02dc1b615c37a9afc2a0f80"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slevomat/coding-standard/zipball/122a9bf9a4a2195f74100f47dfb8375982f43cc9",
"reference": "122a9bf9a4a2195f74100f47dfb8375982f43cc9",
"url": "https://api.github.com/repos/slevomat/coding-standard/zipball/cc80e59f9b4ca642f02dc1b615c37a9afc2a0f80",
"reference": "cc80e59f9b4ca642f02dc1b615c37a9afc2a0f80",
"shasum": ""
},
"require": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7",
"php": "^7.1 || ^8.0",
"phpstan/phpdoc-parser": "0.5.1 - 0.5.5",
"phpstan/phpdoc-parser": "0.5.1 - 0.5.6",
"squizlabs/php_codesniffer": "^3.6.0"
},
"require-dev": {
"phing/phing": "2.16.4",
"php-parallel-lint/php-parallel-lint": "1.3.0",
"phpstan/phpstan": "0.12.93",
"phing/phing": "2.17.0",
"php-parallel-lint/php-parallel-lint": "1.3.1",
"phpstan/phpstan": "0.12.98",
"phpstan/phpstan-deprecation-rules": "0.12.6",
"phpstan/phpstan-phpunit": "0.12.21",
"phpstan/phpstan-strict-rules": "0.12.10",
"phpunit/phpunit": "7.5.20|8.5.5|9.5.7"
"phpstan/phpstan-phpunit": "0.12.22",
"phpstan/phpstan-strict-rules": "0.12.11",
"phpunit/phpunit": "7.5.20|8.5.5|9.5.9"
},
"type": "phpcodesniffer-standard",
"extra": {
@ -7396,7 +7440,7 @@
"description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.",
"support": {
"issues": "https://github.com/slevomat/coding-standard/issues",
"source": "https://github.com/slevomat/coding-standard/tree/7.0.13"
"source": "https://github.com/slevomat/coding-standard/tree/7.0.15"
},
"funding": [
{
@ -7408,20 +7452,20 @@
"type": "tidelift"
}
],
"time": "2021-07-29T14:30:22+00:00"
"time": "2021-09-09T10:29:09+00:00"
},
{
"name": "squizlabs/php_codesniffer",
"version": "3.6.0",
"version": "3.6.2",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625"
"reference": "5e4e71592f69da17871dba6e80dd51bce74a351a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"reference": "ffced0d2c8fa8e6cdc4d695a743271fab6c38625",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a",
"reference": "5e4e71592f69da17871dba6e80dd51bce74a351a",
"shasum": ""
},
"require": {
@ -7464,7 +7508,7 @@
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
"time": "2021-04-09T00:54:41+00:00"
"time": "2021-12-12T21:44:58+00:00"
},
{
"name": "theseer/tokenizer",

View file

@ -1,5 +1,11 @@
<?php
return [
'paginate' => env('CODE_PAGINATE', 65530)
// Export pagination.
'paginate' => env('CODE_PAGINATE', 65530),
// Dictionnary of chars to use fo generating unique codes.
'codeCharList' => 'ABCDEFGHJKMNPQRSTUWXYZ123456789',
// Code length.
'codeLength' => 8
];

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class RemoveCodeUniqueFromCodes extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('codes', function (Blueprint $table) {
$table->dropColumn('code_unique');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('codes', function (Blueprint $table) {
$table->string('code_unique')->unique();
});
}
}

View file

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddCodeLengthToSettingsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('settings', function (Blueprint $table) {
$table->smallInteger('code_length')
->default(config('codes.codeLength'))->after('nb_unique_code_use');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('settings', function (Blueprint $table) {
$table->dropColumn('code_length');
});
}
}

View file

@ -3,10 +3,10 @@
@section('content')
<div class="card">
<div class="card-header">
Gestion des codes uniques
{{ __('Gestion des codes uniques') }}
<!-- Button modal -->
<button type="button" class="btn btn-sm btn-success float-right" data-toggle="modal" data-target="#exportModal">
<i class="fas fa-file-export"></i> Export
<i class="fas fa-file-export"></i>&nbsp;{{ __('Export') }}
</button>
<!-- Modal -->
@ -14,7 +14,7 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exportModalLabel">Export des codes uniques</h5>
<h5 class="modal-title" id="exportModalLabel">{{ __('Export des codes uniques') }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
@ -23,21 +23,21 @@
@csrf
<div class="modal-body">
<div class="form-group form-row">
<label class="col-form-label col" for="nb_code_tot">Nombre total de codes à exporter</label>
<label class="col-form-label col" for="nb_code_tot">{{ __('Nombre total de codes à exporter') }}</label>
<input type="number" name="nb_code_tot" id="nb_code_tot" class="form-control col" required>
</div>
<div class="form-group form-row">
<label class="col-form-label col" for="nb_code_fic">Nombre de codes par fichier</label>
<label class="col-form-label col" for="nb_code_fic">{{ __('Nombre de codes par fichier') }}</label>
<input type="number" name="nb_code_fic" id="nb_code_fic" class="form-control col" required>
</div>
<div class="form-group form-row">
<label class="col-form-label col" for="nb_code_ligne">Nombre de codes par ligne</label>
<label class="col-form-label col" for="nb_code_ligne">{{ __('Nombre de codes par ligne') }}</label>
<input type="number" name="nb_code_ligne" id="nb_code_ligne" class="form-control col" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Fermer</button>
<button type="submit" class="btn btn-sm btn-success">Lancer l'export</button>
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">{{ __('Fermer') }}</button>
<button type="submit" class="btn btn-sm btn-success">{{ __('Lancer l\'export') }}</button>
</div>
</div>
</form>
@ -48,38 +48,61 @@
<form action="{{route('bo.codes')}}" method="POST" enctype="multipart/form-data">
@csrf
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@if (session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
<p>Nombre de code(s)</p>
<p>{{__('Nombre de code(s)') }}</p>
<ul>
<li>en base : {{$nbCodeBase}}</li>
<li>utilisé(s) : {{$nbCodeUsed}}</li>
<li>déjà exporté(s) : {{ $nbCodeExported }}</li>
<li>restant à exporté(s) : {{$nbCodeRemainingToExport}}</li>
<li>{{ __('en base') }}&nbsp;:&nbsp;{{$nbCodeBase}}</li>
<li>{{ __('utilisé(s)') }}&nbsp;:&nbsp;{{$nbCodeUsed}}</li>
<li>{{ __('déjà exporté(s)') }}&nbsp;:&nbsp;{{ $nbCodeExported }}</li>
<li>{{ __('restant à exporté(s)') }}&nbsp;:&nbsp;{{$nbCodeRemainingToExport}}</li>
</ul>
<hr/>
<div class="form-group form-row">
<label class="col-form-label text-center col">Nombre de codes à générer <span class="required-asterisk">*</span></label>
<label class="col-form-label text-center col">{{ __('Nombre de codes à générer') }}&nbsp;<span class="required-asterisk">*</span></label>
<input class="form-control col" type="number" name="quantity" min="0">
<label class="col-form-label text-center col">Longueur des codes <span class="required-asterisk">*</span></label>
<input class="form-control col" type="number" name="code_length" min="0">
<label class="col-form-label text-center col">{{__('Longueur des codes') }}&nbsp;<span class="required-asterisk">*</span></label>
<input id="codeLengthInput" class="form-control col" type="number" name="code_length" min="0" value="{{ $settings->code_length ?? config('codes.codeLength') }}">
</div>
<small >{{ __('Il est possible de générer') }}&nbsp;<span id="maxCodes" class="text-danger">0</span>&nbsp;{{ __('codes uniques.') }}</small><br>
<small class="text-muted">{{ __('!! Si la longueur des codes est changé l\'export pourra prendre plus de temps. !!') }}</small>
</div>
<div class="card-footer text-center">
<button type="submit" class="btn btn-success"><i class="fas fa-cog"></i> Générer</button>
<button type="submit" class="btn btn-success"><i class="fas fa-cog"></i>&nbsp;{{ __('Générer') }}</button>
</div>
</form>
</div>
@endsection
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', () => {
let codeLenghtInput = document.getElementById('codeLengthInput'),
smallWarning = document.getElementById('maxCodes')
/**
* Fonction factorielle
*/
let fact = (nbr) => {
let i, f = 1
for(i = 1; i <= nbr; i++)
{
f = f * i; // ou f *= i;
}
return f;
}
let calculateMax = () => {
let p = Number.parseInt({{ strlen(config('codes.codeCharList')) }}),
n = codeLenghtInput.value
return Math.pow(p, n)-1 - Number.parseInt({{ $nbCodeBase }});
}
let numberWithCommas = (x) => {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
smallWarning.innerText = numberWithCommas(calculateMax())
codeLenghtInput.addEventListener('input', () => {
smallWarning.innerText = numberWithCommas(calculateMax())
})
});
</script>
@endpush

View file

@ -48,4 +48,4 @@
console.error( error );
} );
</script>
@endsection
@endpush

View file

@ -51,4 +51,4 @@
}
});
</script>
@endsection
@endpush

View file

@ -1 +1 @@
<p>Génération des {{$quantity}} codes uniques terminés sur le jeu {{$settings->name}}.</p>
<p>Génération des {{$quantity}} codes uniques terminés sur le jeu {{$gameName}}.</p>

View file

@ -72,12 +72,24 @@
<td>
<label class="col-form-label" for="nb_unique_code_use">
Nombre d'utilisation du code unique <span class="required-asterisk">*</span><br/>
<small class="text-muted">{{ __('Nombre d\'utilisations possible au total d\'un code unique.') }}</small>
</label>
</td>
<td class="align-middle">
<input class="form-control" type="number" name="nb_unique_code_use" value="{{$settings->nb_unique_code_use}}" required>
</td>
</tr>
<tr class="form-group">
<td>
<label class="col-form-label" for="code_length">
{{ __('Longueur des code uniques') }}&nbsp;<span class="required-asterisk">*</span><br/>
<small class="text-muted">{{ __('!! Cette valeur ne doit pas varier en cour de jeu !!') }}</small>
</label>
</td>
<td class="align-middle">
<input class="form-control" type="number" name="code_length" value="{{$settings->code_length}}" readonly>
</td>
</tr>
<tr class="form-group">
<td>
<label class="col-form-label" for="ean_codes">
@ -334,7 +346,7 @@
</div>
@endsection
@section('scripts')
@push('scripts')
<script type="text/javascript" defer>
// Gestion du tableau pour reduction
@ -382,4 +394,4 @@
}
});
</script>
@endsection
@endpush