[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,})|(?P@\w*)|(?P(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/', function ($matches) { $match = collect($matches)->first() ?? ''; if (filter_var($match, FILTER_VALIDATE_EMAIL)) { return strlen($match) ? "$match" : $match; } elseif (isset($matches['user']) and strlen($matches['user'])) { return sprintf( '%s', $matches['user'] ); } else { $url = $match; if (\strpos($url, 'http') === false and \strpos($url, 'https') === false) { $url = sprintf( '%s://%s', config('app.env') !== 'local' ? 'https' : 'http', $url ); } $fsligthbox = self::isImageFile($url) ? 'data-fslightbox="gallery"' : ''; return strlen($match) ? "$match" : $match; } }, $text ); return nl2br($text); } /** * Check uri points to image file * * @param string $url * @return boolean */ public static function isImageFile(string $url): bool { $m = []; return \preg_match('/(\.png|\.jpg|\.jpeg|\.gif)$/', $url, $m) === 1; } /** * delais 7 jours 168h * travaillé 5 jours 37h * temps tickets 1 jours 7.4h * * personnes 4 (TpP) 3.7h / semaine * prs * * délais moyen ticket (Dmt) 0.75h * * délais max attente pour 1 ticket (Dam) 7jours * * niveaux de charge 4: - faible * - stable * - élevée * - saturation * * états tickets(Et) : - nouveaux (non traités) * - en attente (charge pendante) * - traités * * Algo : linéaire * * TpP : 3.7h * P : 4 * * Et(nvx) * Dam * * Nv Charge = (P * TpP) / (Et(nvx) * Dam) - (P * TpP) / (Et(nvx) * DmT) - (Et(att) * DmT) * * * Si nv Charge < 0 => saturation * * @return \App\Enums\LoadLevel */ public static function computeWorkload(): LoadLevel { $Tnew = View::shared('ticketsNew'); $Tprogress = View::shared('ticketsInProgress'); $Twaiting = View::shared('ticketsWaiting'); $worked = config('tickets.workedHoursInAWeek'); $workedDays = config('tickets.workedDaysInAWeek'); // * in hours $morningWorkTime = ($worked / $workedDays / 2); // * Devs handlings tickets per week $workingDevsPerWeek = config('tickets.workingDevsPerWeek'); // * Worktime per week to handle tickets $timePerWeekDev = $workingDevsPerWeek * $morningWorkTime; // * 45min for a ticket $avgTimeForTicket = config('tickets.avgTimeForTicket'); // * The time needed to handle new ticket (average) $todoListDelay = $Tnew * $avgTimeForTicket; // * The time needed to handle new ticket (average) $waitingListDelay = $Twaiting * $avgTimeForTicket; // * The time needed to handle new ticket (average) $progressListDelay = $Tprogress * $avgTimeForTicket; $totalTicketsDelay = $todoListDelay + $progressListDelay + $waitingListDelay; // * in weeks $ETAForAnewTicket = $totalTicketsDelay / $timePerWeekDev; switch ((int)round($ETAForAnewTicket)) { case LoadLevel::weak()->value: case LoadLevel::stable()->value: case LoadLevel::high()->value: return LoadLevel::make((int)round($ETAForAnewTicket)); default: return LoadLevel::overload(); } } /** * Strip scheme (https) on oembed urls * Only embed allowed are for MP4 self hosted videos right now * * https is force by ckeditor MediaElements which natively supports * only cloud hosted medias (youtube, spotify etc..) * * @param string $input * @return string */ public static function stripCkEditorSchemesOnMediaInputs(string $input): string { $input = \preg_replace('/(?<=)/m', '', $input); return $input; } /** * Assert That no Back Office url is present on txt * * @param string $field * @param string $text * @return string * @throws \Illuminate\Validation\ValidationException If url is a bo url. */ public static function assertNoInternalBoUrls(string $field, string $text): string { $routes = Route::getRoutes(); // * Url replace and email replace. $text = preg_replace_callback( // phpcs:ignore Generic.Files.LineLength.TooLong '/(?P(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/', function ($matches) use ($routes, $field) { $match = collect($matches)->first() ?? ''; $url = $match; try { $request = Request::create($url); // If a route is match then it do not throws exception. if ( \parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) && trim($routes->match($request)->getPrefix() ?? '', '/') === 'bo' ) { // Removes the matched url. throw ValidationException::withMessages([ $field => sprintf( '%s : Il est interdit de coller une url du back office dans ce champ', trans($field) ) ]); } return $match; } catch (NotFoundHttpException $e) { return $match; } }, $text ); return $text; } /** * Store an image of different types * * @param string $table * @param \Illuminate\Http\UploadedFile|\SplFileInfo|string $image * @return string * @throws \ErrorException If file copy fails. */ public static function storeImage(string $table, $image): string { /** @var \Illuminate\Http\UploadedFile $image */ if (\is_object($image) and get_class($image) === UploadedFile::class) { $newPath = self::prepareMoveFile($table, $image->getClientOriginalName()); $newPath = str_replace(storage_path('app'), '', $newPath); $image->storePubliclyAs( pathinfo($newPath, \PATHINFO_DIRNAME), pathinfo($newPath, \PATHINFO_BASENAME) ); return 'storage' . str_replace('/public', '', $newPath); } /** @var \SplFileInfo $image */ if (\is_object($image) and get_class($image) === \SplFileInfo::class) { $newPath = self::prepareMoveFile($table, $image->getBaseName()); if (!File::copy($image->getRealPath(), $newPath)) { throw new \ErrorException(sprintf( 'Failed to copy file %s to %s', $image->getRealPath(), $newPath )); } return \ltrim(str_replace(\storage_path('app/public'), '/storage', $newPath), '/'); } if (\is_string($image)) { return $image; } } /** * Prepare storage path and return * the image full path * * @param string $table Model table name. * @param string $filename The basename for the file. * @return string */ private static function prepareMoveFile(string $table, string $filename): string { $pathFolder = \storage_path(sprintf('app/public/images/%s', $table)); if (!File::exists($pathFolder)) { File::makeDirectory($pathFolder, 0755, true); } $filename = sprintf('%s-%s', Str::uuid(), $filename); $fullPath = sprintf('%s/%s', $pathFolder, $filename); if (File::exists($fullPath)) { File::delete($fullPath); } return $fullPath; } /** * Assert Is Unique * * @param \Illuminate\Database\Eloquent\Model $model * @param array $columns * @return void * @throws \Illuminate\Validation\ValidationException If a model like this already exists. */ public static function assertIsUnique(Model $model, array $columns): void { $columns = collect($columns); /** @var string|null */ $firstColumn = $columns->pull($columns->keys()->first()); if (!$firstColumn) { return; } $modelClass = \get_class($model); $uniqueRule = Rule::unique((new $modelClass())->getTable()); if ($model->id) { $uniqueRule->ignore($model->id); } $uniqueRule->where(function ($q) use ($model, $columns) { $columns->map(function (string $column) use ($model, $q) { $q->where($column, $model->{$column}); }); }); Validator::make([$firstColumn => $model->{$firstColumn}], [ $firstColumn => ['required', $uniqueRule] ])->validate(); } }