Compare commits
No commits in common. "develop" and "1-api" have entirely different histories.
436 changed files with 0 additions and 49474 deletions
|
|
@ -1,21 +0,0 @@
|
||||||
.git
|
|
||||||
.git/
|
|
||||||
.gitlab/
|
|
||||||
.gitlab-ci.yml
|
|
||||||
*.md
|
|
||||||
node_modules/
|
|
||||||
npm-debug.log
|
|
||||||
.npmrc
|
|
||||||
tests/
|
|
||||||
Dockerfile*
|
|
||||||
.dockerignore
|
|
||||||
.git
|
|
||||||
.gitignore
|
|
||||||
README.md
|
|
||||||
LICENSE
|
|
||||||
.vscode
|
|
||||||
public/build/
|
|
||||||
auth.json
|
|
||||||
manifest.yaml
|
|
||||||
production-resources.yaml
|
|
||||||
staging-resources.yaml
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.md]
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
||||||
[*.{yml,yaml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.vue]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[docker-compose.yml]
|
|
||||||
indent_size = 4
|
|
||||||
37
.env.example
37
.env.example
|
|
@ -1,37 +0,0 @@
|
||||||
APP_NAME=Laravel
|
|
||||||
APP_ENV=local
|
|
||||||
APP_KEY=
|
|
||||||
APP_DEBUG=true
|
|
||||||
APP_URL=http://localhost
|
|
||||||
|
|
||||||
LOG_CHANNEL=stack
|
|
||||||
LOG_LEVEL=debug
|
|
||||||
|
|
||||||
DB_HOST=127.0.0.1
|
|
||||||
DB_DATABASE=laravel
|
|
||||||
DB_USERNAME=root
|
|
||||||
DB_PASSWORD=
|
|
||||||
|
|
||||||
MAIL_HOST=mailhog
|
|
||||||
MAIL_PORT=1025
|
|
||||||
MAIL_USERNAME=null
|
|
||||||
MAIL_PASSWORD=null
|
|
||||||
MAIL_ENCRYPTION=null
|
|
||||||
MAIL_FROM_ADDRESS=null
|
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
|
||||||
|
|
||||||
# SENTRY
|
|
||||||
SENTRY_LARAVEL_DSN=
|
|
||||||
|
|
||||||
# UWIL ADMIN SECURE
|
|
||||||
# - LIST SEPARATED WITH ',' (Required)
|
|
||||||
UWIL_ADMIN_SECURE_CIDR_LIST=""
|
|
||||||
# - LIST SEPARATED WITH ',' (Optional)
|
|
||||||
UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST=""
|
|
||||||
|
|
||||||
# SAML
|
|
||||||
SAML2_DEFAULT_TENANT_UUID=
|
|
||||||
SAML2_SP_CERT_x509=
|
|
||||||
SAML2_SP_CERT_PRIVATEKEY=
|
|
||||||
SAML2_CONTACT_TECHNICAL_EMAIL=
|
|
||||||
SAML2_CONTACT_SUPPORT_EMAIL=
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2021": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:vue/vue3-strongly-recommended",
|
|
||||||
"@vue/eslint-config-typescript"
|
|
||||||
],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.vue"],
|
|
||||||
"rules": {
|
|
||||||
"no-undef": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["*.vue"],
|
|
||||||
"rules": {
|
|
||||||
"indent": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parser": "vue-eslint-parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"ecmaVersion": "latest",
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": ["vue", "@typescript-eslint"],
|
|
||||||
"ignorePatterns": [
|
|
||||||
"webpack.mix.js",
|
|
||||||
"**/*.php",
|
|
||||||
"**/*.svg",
|
|
||||||
"**/vendor/*.js",
|
|
||||||
"**/vendor/**/*.js",
|
|
||||||
"**/vendor/**/*.scss"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
|
||||||
"linebreak-style": ["error", "unix"],
|
|
||||||
"quotes": ["error", "double"],
|
|
||||||
"semi": ["error", "always"],
|
|
||||||
"vue/script-indent": ["error", 2, { "baseIndent": 0, "switchCase": 1 }],
|
|
||||||
"vue/one-component-per-file": "off"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"import/resolver": {
|
|
||||||
"node": {
|
|
||||||
"extensions": [".js", ".vue", ".ts", ".d.ts"]
|
|
||||||
},
|
|
||||||
"alias": {
|
|
||||||
"extensions": [".vue", ".js", ".ts", ".scss", ".d.ts"],
|
|
||||||
"map": [
|
|
||||||
["~", "./resources/assets"],
|
|
||||||
["@", "./node_modules"]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
.gitattributes
vendored
10
.gitattributes
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
* text=auto
|
|
||||||
|
|
||||||
*.blade.php diff=html
|
|
||||||
*.css diff=css
|
|
||||||
*.html diff=html
|
|
||||||
*.md diff=markdown
|
|
||||||
*.php diff=php
|
|
||||||
|
|
||||||
/.github export-ignore
|
|
||||||
CHANGELOG.md export-ignore
|
|
||||||
21
.gitignore
vendored
21
.gitignore
vendored
|
|
@ -1,21 +0,0 @@
|
||||||
/node_modules
|
|
||||||
/public/hot
|
|
||||||
/public/storage
|
|
||||||
/public/build
|
|
||||||
/public/medias
|
|
||||||
/public/uploads
|
|
||||||
/public/cache
|
|
||||||
/public/sitemap.xml
|
|
||||||
/storage/*.key
|
|
||||||
/vendor
|
|
||||||
.env
|
|
||||||
.phpunit.result.cache
|
|
||||||
docker-compose.override.yml
|
|
||||||
Homestead.json
|
|
||||||
Homestead.yaml
|
|
||||||
npm-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
/.idea
|
|
||||||
/.vscode
|
|
||||||
auth.json
|
|
||||||
.npmrc
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
include:
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "lint/lint.yml"
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "security/security.yml"
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "build/docker-multistage.yml"
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "test/test.yml"
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "deploy/deploy.yml"
|
|
||||||
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- lint
|
|
||||||
- security
|
|
||||||
- build
|
|
||||||
- test
|
|
||||||
- deploy
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
npx --no -- commitlint --config node_modules/@uwil/husky-config/commitlint.config.cjs --edit $1
|
|
||||||
14
.styleci.yml
14
.styleci.yml
|
|
@ -1,14 +0,0 @@
|
||||||
php:
|
|
||||||
preset: laravel
|
|
||||||
version: 8
|
|
||||||
disabled:
|
|
||||||
- no_unused_imports
|
|
||||||
finder:
|
|
||||||
not-name:
|
|
||||||
- index.php
|
|
||||||
- server.php
|
|
||||||
js:
|
|
||||||
finder:
|
|
||||||
not-name:
|
|
||||||
- webpack.mix.js
|
|
||||||
css: true
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
{
|
|
||||||
"extends": [
|
|
||||||
"stylelint-config-standard-scss",
|
|
||||||
"stylelint-config-sass-guidelines",
|
|
||||||
"stylelint-config-idiomatic-order"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"stylelint-scss"
|
|
||||||
],
|
|
||||||
"files": [
|
|
||||||
"**/*.css",
|
|
||||||
"**/*.scss"
|
|
||||||
],
|
|
||||||
"ignoreFiles": [
|
|
||||||
"**/vendor/*.css",
|
|
||||||
"**/vendor/**/*.css",
|
|
||||||
"**/vendor/*.scss",
|
|
||||||
"**/vendor/**/*.scss",
|
|
||||||
"**/vendor/*.sass",
|
|
||||||
"**/vendor/**/*.sass",
|
|
||||||
"**/vendor/*.less",
|
|
||||||
"**/vendor/**/*.less"
|
|
||||||
],
|
|
||||||
"customSyntax": "postcss-scss",
|
|
||||||
"rules": {
|
|
||||||
"declaration-property-value-no-unknown": true,
|
|
||||||
"selector-max-id": null,
|
|
||||||
"color-no-invalid-hex": true,
|
|
||||||
"order/properties-alphabetical-order": null,
|
|
||||||
"max-nesting-depth": 5,
|
|
||||||
"selector-max-compound-selectors": 5,
|
|
||||||
"declaration-colon-newline-after": null,
|
|
||||||
"value-list-comma-newline-after": null,
|
|
||||||
"scss/double-slash-comment-empty-line-before": [
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
"ignore": [
|
|
||||||
"between-comments",
|
|
||||||
"stylelint-commands",
|
|
||||||
"inside-block"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
47
Dockerfile
47
Dockerfile
|
|
@ -1,47 +0,0 @@
|
||||||
FROM composer:2.9.2 AS vendor
|
|
||||||
|
|
||||||
ARG GITLAB_USER
|
|
||||||
ARG GITLAB_PASSWORD
|
|
||||||
|
|
||||||
COPY database/ database/
|
|
||||||
|
|
||||||
COPY composer.json composer.json
|
|
||||||
COPY composer.lock composer.lock
|
|
||||||
|
|
||||||
RUN composer config gitlab-token.lab.s-web.fr ${GITLAB_USER} ${GITLAB_PASSWORD}
|
|
||||||
RUN composer install \
|
|
||||||
--ignore-platform-reqs \
|
|
||||||
--no-interaction \
|
|
||||||
--no-plugins \
|
|
||||||
--no-scripts \
|
|
||||||
--no-dev \
|
|
||||||
--prefer-dist
|
|
||||||
|
|
||||||
FROM node:20.18 AS frontend
|
|
||||||
|
|
||||||
ARG GITLAB_PASSWORD
|
|
||||||
|
|
||||||
RUN mkdir -p /app/public/build
|
|
||||||
|
|
||||||
COPY package*.json tsconfig.json vite.config.ts .eslintrc.json .stylelintrc.json /app/
|
|
||||||
COPY resources/ /app/resources/
|
|
||||||
WORKDIR /app
|
|
||||||
RUN npm config set @ldc-web:registry https://lab.s-web.fr/api/v4/packages/npm/
|
|
||||||
RUN npm config set -- '//lab.s-web.fr/api/v4/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
|
|
||||||
RUN npm config set @uwil:registry=https://lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/
|
|
||||||
RUN npm config set -- '//lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
|
|
||||||
RUN npm ci --no-audit --no-fund --loglevel=error && npm run prod
|
|
||||||
|
|
||||||
|
|
||||||
FROM registry.s-web.fr/ldc-web/projets/ldc-web-images-docker/uwil-production-8.5:${PHP_8_5_TAG}
|
|
||||||
|
|
||||||
ARG USER=www-data
|
|
||||||
|
|
||||||
COPY --chown=${USER}:${USER} . /app/srcs
|
|
||||||
COPY --chown=${USER}:${USER} ./resources/favicon /app/srcs/public
|
|
||||||
COPY --from=vendor --chown=${USER}:${USER} /app/vendor/ /app/srcs/vendor/
|
|
||||||
COPY --from=frontend --chown=${USER}:${USER} /app/public/build/ /app/srcs/public/build/
|
|
||||||
|
|
||||||
USER root
|
|
||||||
RUN chmod -R 755 /app/srcs/storage
|
|
||||||
USER ${USER}
|
|
||||||
13
README.md
13
README.md
|
|
@ -1,13 +0,0 @@
|
||||||
# Nexurl
|
|
||||||
## Installation
|
|
||||||
```
|
|
||||||
cp .env.example .env
|
|
||||||
php artisan key:generate
|
|
||||||
php artisan migrate
|
|
||||||
php artisan storage:link
|
|
||||||
npm i && npm run prod
|
|
||||||
```
|
|
||||||
Création d'un administrateur :
|
|
||||||
```
|
|
||||||
php artisan user:create
|
|
||||||
```
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Illuminate\Validation\ValidationException;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class UserCreate extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'uwil:user:create';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Create a backend admin user';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The first name of the new user.
|
|
||||||
*
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $first_name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last name of the new user.
|
|
||||||
*
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $last_name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The email of the new user.
|
|
||||||
*
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $email;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The role of the new user.
|
|
||||||
*
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $role;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handle(): void
|
|
||||||
{
|
|
||||||
$this->first_name = null;
|
|
||||||
$this->addFirstName();
|
|
||||||
|
|
||||||
$this->last_name = null;
|
|
||||||
$this->addLastName();
|
|
||||||
|
|
||||||
$this->email = null;
|
|
||||||
$this->addEmail();
|
|
||||||
|
|
||||||
$this->role = null;
|
|
||||||
$this->addRole();
|
|
||||||
|
|
||||||
$user = new User([
|
|
||||||
'firstname' => $this->first_name,
|
|
||||||
'lastname' => $this->last_name,
|
|
||||||
'email' => $this->email,
|
|
||||||
'role' => $this->role,
|
|
||||||
]);
|
|
||||||
$user->saveOrFail();
|
|
||||||
|
|
||||||
$this->info('User created 👌');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a first name to the user.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function addFirstName(): void
|
|
||||||
{
|
|
||||||
while (is_null($this->first_name)) {
|
|
||||||
try {
|
|
||||||
$tmp = $this->ask('Type the wanted user first name', 'Admin');
|
|
||||||
$validator = Validator::make(['first_name' => $tmp], [
|
|
||||||
'first_name' => 'required|min:3|max:255'
|
|
||||||
]);
|
|
||||||
$validator->validate();
|
|
||||||
$this->first_name = $tmp;
|
|
||||||
} catch (ValidationException $e) {
|
|
||||||
$this->error(sprintf(
|
|
||||||
'Please provide a valid first name %s',
|
|
||||||
\implode(',', collect($e->errors())->flatten()->all())
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
} //end try
|
|
||||||
}; //end while
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a last name to the user.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function addLastName(): void
|
|
||||||
{
|
|
||||||
while (is_null($this->last_name)) {
|
|
||||||
try {
|
|
||||||
$tmp = $this->ask('Type the wanted user last name', 'Saïtama');
|
|
||||||
$validator = Validator::make(['last_name' => $tmp], [
|
|
||||||
'last_name' => 'required|min:3|max:255'
|
|
||||||
]);
|
|
||||||
$validator->validate();
|
|
||||||
$this->last_name = $tmp;
|
|
||||||
} catch (ValidationException $e) {
|
|
||||||
$this->error(sprintf(
|
|
||||||
'Please provide a valid last_name %s',
|
|
||||||
\implode(',', collect($e->errors())->flatten()->all())
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
} //end try
|
|
||||||
}; //end while
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an email to the user.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function addEmail(): void
|
|
||||||
{
|
|
||||||
while (is_null($this->email)) {
|
|
||||||
try {
|
|
||||||
$tmp = $this->ask('Type the wanted user email', 'equipe.web@ldc.fr');
|
|
||||||
$validator = Validator::make(['email' => $tmp], [
|
|
||||||
'email' => 'required|unique:users,email|email:rfc,dns'
|
|
||||||
]);
|
|
||||||
$validator->validate();
|
|
||||||
$this->email = $tmp;
|
|
||||||
} catch (ValidationException $e) {
|
|
||||||
$this->error(sprintf(
|
|
||||||
'Please provide a valid email %s',
|
|
||||||
\implode(',', collect($e->errors())->flatten()->all())
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
} //end try
|
|
||||||
}; //end while
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a role to the user.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function addRole(): void
|
|
||||||
{
|
|
||||||
while (is_null($this->role)) {
|
|
||||||
try {
|
|
||||||
$tmp = $this->choice(
|
|
||||||
'Select his role',
|
|
||||||
[
|
|
||||||
Str::ucFirst(RoleEnum::conceptor->label()),
|
|
||||||
Str::ucFirst(RoleEnum::admin->label()),
|
|
||||||
Str::ucFirst(RoleEnum::visitor->label())
|
|
||||||
],
|
|
||||||
Str::ucFirst(RoleEnum::visitor->label()),
|
|
||||||
);
|
|
||||||
if ($tmp === Str::ucFirst(RoleEnum::conceptor->label())) {
|
|
||||||
$tmp = RoleEnum::conceptor;
|
|
||||||
}
|
|
||||||
if ($tmp === Str::ucFirst(RoleEnum::admin->label())) {
|
|
||||||
$tmp = RoleEnum::admin;
|
|
||||||
}
|
|
||||||
if ($tmp === Str::ucFirst(RoleEnum::visitor->label())) {
|
|
||||||
$tmp = RoleEnum::visitor;
|
|
||||||
}
|
|
||||||
$validator = Validator::make(['role' => $tmp], [
|
|
||||||
'role' => 'required'
|
|
||||||
]);
|
|
||||||
$validator->validate();
|
|
||||||
$this->role = $tmp;
|
|
||||||
} catch (ValidationException $e) {
|
|
||||||
$this->error(sprintf(
|
|
||||||
'Please choose from the selection %s',
|
|
||||||
\implode(',', collect($e->errors())->flatten()->all())
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
} //end try
|
|
||||||
}; //end while
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console;
|
|
||||||
|
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
|
||||||
|
|
||||||
class Kernel extends ConsoleKernel
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Define the application's command schedule.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function schedule(Schedule $schedule)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the commands for the application.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function commands()
|
|
||||||
{
|
|
||||||
$this->load(__DIR__ . '/Commands');
|
|
||||||
|
|
||||||
require base_path('routes/console.php');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\ActivityLogs;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ActivityLogsEventEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case created = 1;
|
|
||||||
case updated = 2;
|
|
||||||
case duplicated = 3;
|
|
||||||
case deleted = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition
|
|
||||||
*
|
|
||||||
* @phpstan-ignore-next-line
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::created->name => 'Création',
|
|
||||||
self::updated->name => 'Mise à jour',
|
|
||||||
self::duplicated->name => 'Duplication',
|
|
||||||
self::deleted->name => 'Suppression',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom added classes definition
|
|
||||||
*/
|
|
||||||
private const BOOTSTRAPCLASS = [
|
|
||||||
self::created->name => 'success',
|
|
||||||
self::updated->name => 'warning',
|
|
||||||
self::duplicated->name => 'secondary',
|
|
||||||
self::deleted->name => 'danger',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Class
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function bootstrapClass(): string
|
|
||||||
{
|
|
||||||
return self::BOOTSTRAPCLASS[$this->name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Api;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ApiPeriodEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case day = 1;
|
|
||||||
case week = 2;
|
|
||||||
case month = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition.
|
|
||||||
*
|
|
||||||
* @phpstan-ignore-next-line
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::day->name => 'jour',
|
|
||||||
self::week->name => 'semaine',
|
|
||||||
self::month->name => 'mois',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Pagination;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ItemsPerPaginationEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case five = 5;
|
|
||||||
case twelve = 12;
|
|
||||||
case twentyfive = 25;
|
|
||||||
case fifty = 50;
|
|
||||||
case onehundred = 100;
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum PeriodEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case day = 1;
|
|
||||||
case week = 2;
|
|
||||||
case month = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition.
|
|
||||||
*
|
|
||||||
* @phpstan-ignore-next-line
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::day->name => 'jour',
|
|
||||||
self::week->name => 'semaine',
|
|
||||||
self::month->name => 'mois',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Users;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum RoleEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case conceptor = 1;
|
|
||||||
case admin = 2;
|
|
||||||
case marketing = 3;
|
|
||||||
case visitor = 99;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition.
|
|
||||||
*
|
|
||||||
* @phpstan-ignore-next-line
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::conceptor->name => 'enums.user-role.conceptor',
|
|
||||||
self::admin->name => 'enums.user-role.admin',
|
|
||||||
self::marketing->name => 'enums.user-role.marketing',
|
|
||||||
self::visitor->name => 'enums.user-role.visitor',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Exceptions;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A list of exception types with their corresponding custom log levels.
|
|
||||||
*
|
|
||||||
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
|
|
||||||
*/
|
|
||||||
protected $levels = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of the exception types that are not reported.
|
|
||||||
*
|
|
||||||
* @var array<int, class-string<\Throwable>>
|
|
||||||
*/
|
|
||||||
protected $dontReport = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of the inputs that are never flashed to the session on validation exceptions.
|
|
||||||
*
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $dontFlash = [
|
|
||||||
'current_password',
|
|
||||||
'password',
|
|
||||||
'password_confirmation',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the exception handling callbacks for the application.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function register()
|
|
||||||
{
|
|
||||||
$this->reportable(function (Throwable $e) {
|
|
||||||
if (app()->bound('sentry')) {
|
|
||||||
app('sentry')->captureException($e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Resources\BrandCollection;
|
|
||||||
use App\Http\Resources\BrandResource;
|
|
||||||
use App\Http\Resources\UrlCollection;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\Service;
|
|
||||||
|
|
||||||
class BrandController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns a listing of the brands.
|
|
||||||
*
|
|
||||||
* @return \App\Http\Resources\BrandCollection
|
|
||||||
*/
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
return new BrandCollection(Brand::paginate(25));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the specified brand.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param Brand $brand
|
|
||||||
* @return \App\Http\Resources\BrandResource
|
|
||||||
*
|
|
||||||
* @throws \Exception If the brand isn't the brand associated to the service.
|
|
||||||
*/
|
|
||||||
public function show(\Illuminate\Http\Request $request, Brand $brand)
|
|
||||||
{
|
|
||||||
$service = Service::query()->where('bearer_token', $request->bearer_token)->firstOrFail();
|
|
||||||
if ($brand != $service->brand) {
|
|
||||||
throw new \Exception('Invalid brand.');
|
|
||||||
};
|
|
||||||
|
|
||||||
return new BrandResource($brand);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the urls for a given brand.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param Brand $brand
|
|
||||||
* @return \App\Http\Resources\UrlCollection
|
|
||||||
*
|
|
||||||
* @throws \Exception If the brand isn't the brand associated to the service.
|
|
||||||
*/
|
|
||||||
public function getUrls(\Illuminate\Http\Request $request, Brand $brand)
|
|
||||||
{
|
|
||||||
$service = Service::query()->where('bearer_token', $request->bearer_token)->firstOrFail();
|
|
||||||
if ($brand != $service->brand) {
|
|
||||||
throw new \Exception('Invalid brand.');
|
|
||||||
};
|
|
||||||
return new UrlCollection($brand->urls);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
|
||||||
|
|
||||||
use App\Enums\Api\ApiPeriodEnum;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Api\GetStatsRequest;
|
|
||||||
use App\Http\Resources\UrlCollection;
|
|
||||||
use App\Http\Resources\UrlHistoryCollection;
|
|
||||||
use App\Http\Resources\UrlResource;
|
|
||||||
use App\Models\Url;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Carbon\CarbonPeriod;
|
|
||||||
use DateTime;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class UrlController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns a listing of the urls.
|
|
||||||
*
|
|
||||||
* @return \App\Http\Resources\UrlCollection
|
|
||||||
*/
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
return new UrlCollection(Url::paginate(25));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the specified url.
|
|
||||||
*
|
|
||||||
* @param Url $url
|
|
||||||
* @return \App\Http\Resources\UrlResource
|
|
||||||
*/
|
|
||||||
public function show(Url $url)
|
|
||||||
{
|
|
||||||
return new UrlResource($url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the history for a given url.
|
|
||||||
*
|
|
||||||
* @param Url $url
|
|
||||||
* @param Request $request
|
|
||||||
* @return \Illuminate\Http\Response|\App\Http\Resources\UrlHistoryCollection
|
|
||||||
*/
|
|
||||||
public function getHistory(Url $url, Request $request)
|
|
||||||
{
|
|
||||||
// Set start date with request or now - 1 year.
|
|
||||||
if ($request->start) {
|
|
||||||
$start = $request->start;
|
|
||||||
$start = DateTime::createFromFormat('dmY', $start);
|
|
||||||
} else {
|
|
||||||
$start = now()->modify('-1 year');
|
|
||||||
}
|
|
||||||
// Set end date with request or now.
|
|
||||||
if ($request->end) {
|
|
||||||
$end = $request->end;
|
|
||||||
$end = DateTime::createFromFormat('dmY', $end)->modify('+1 day');
|
|
||||||
} else {
|
|
||||||
$end = now();
|
|
||||||
}
|
|
||||||
// Check if the difference bewteen end and start is < than 1 year.
|
|
||||||
if ($start->diff($end)->days > 366) {
|
|
||||||
return response('Date interval too long', 403);
|
|
||||||
};
|
|
||||||
$history = $url->history()
|
|
||||||
->where('start_date', '>', $start)
|
|
||||||
->where('end_date', '<', $end)
|
|
||||||
->get();
|
|
||||||
return new UrlHistoryCollection($history);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the stats for the given url.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\GetStatsRequest $request
|
|
||||||
* @param Url $url
|
|
||||||
* @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function getStats(GetStatsRequest $request, Url $url)
|
|
||||||
{
|
|
||||||
$period = ApiPeriodEnum::make($request->period, 'name');
|
|
||||||
$start = Carbon::make($request->start);
|
|
||||||
$end = Carbon::make($request->end);
|
|
||||||
// Check if the difference bewteen end and start is < than 1 year.
|
|
||||||
if ($start->diff($end)->days > 366) {
|
|
||||||
return response('Date interval too long', 403);
|
|
||||||
};
|
|
||||||
|
|
||||||
$stats = [];
|
|
||||||
switch ($period->label()) {
|
|
||||||
case \App\Enums\Api\ApiPeriodEnum::day->label():
|
|
||||||
$carbonPeriod = CarbonPeriod::create(
|
|
||||||
$start->format('Y-m-d'),
|
|
||||||
$end->format('Y-m-d')
|
|
||||||
)->toArray();
|
|
||||||
$dbStats = $url->stats()
|
|
||||||
->whereDate('date', '>', $start)
|
|
||||||
->whereDate('date', '<=', $end)
|
|
||||||
->get(['date', 'calls']);
|
|
||||||
|
|
||||||
foreach ($carbonPeriod as $day) {
|
|
||||||
$stats[] = $dbStats->where('date', $day)->isNotEmpty() ?
|
|
||||||
$dbStats->where('date', $day)->first()->calls :
|
|
||||||
0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case \App\Enums\Api\ApiPeriodEnum::week->label():
|
|
||||||
// Create a Carbon Period for weeks to make only one query per week.
|
|
||||||
$carbonPeriod = CarbonPeriod::create(
|
|
||||||
$start->startOfWeek()->format('Y-m-d'),
|
|
||||||
$end->endOfWeek()->format('Y-m-d')
|
|
||||||
)->weeks()->toArray();
|
|
||||||
|
|
||||||
foreach ($carbonPeriod as $week) {
|
|
||||||
$stats[] = $url->stats()
|
|
||||||
->whereIn(
|
|
||||||
'date',
|
|
||||||
CarbonPeriod::create(
|
|
||||||
$week->startOfWeek(Carbon::MONDAY)->format('Y-m-d'),
|
|
||||||
$week->endOfWeek(Carbon::SUNDAY)->format('Y-m-d')
|
|
||||||
)->toArray()
|
|
||||||
)
|
|
||||||
->sum('calls');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case \App\Enums\Api\ApiPeriodEnum::month->label():
|
|
||||||
// Create a Carbon Period for months to make only one query per month.
|
|
||||||
$carbonPeriod = CarbonPeriod::create(
|
|
||||||
$start->startOfMonth()->format('Y-m-d'),
|
|
||||||
$end->endOfMonth()->format('Y-m-d')
|
|
||||||
)->months()->toArray();
|
|
||||||
|
|
||||||
foreach ($carbonPeriod as $month) {
|
|
||||||
$stats[] = $url->stats()
|
|
||||||
->whereIn(
|
|
||||||
'date',
|
|
||||||
CarbonPeriod::create(
|
|
||||||
$month->startOfMonth()->format('Y-m-d'),
|
|
||||||
$month->endOfMonth()->format('Y-m-d')
|
|
||||||
)->toArray()
|
|
||||||
)
|
|
||||||
->sum('calls');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} //end switch
|
|
||||||
|
|
||||||
return \response()->json($stats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\ActivityLog;
|
|
||||||
use App\Traits\Controllers\ChangesModelOrder;
|
|
||||||
use App\Traits\Controllers\UpdateModelPublished;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class ActivityLogController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$this->authorize('isConceptor');
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
|
||||||
$query = ActivityLog::query()->with('user');
|
|
||||||
|
|
||||||
/** @var \App\Models\User|null $userModel */
|
|
||||||
$userModel = $request->route()->parameter('user');
|
|
||||||
if ($userModel) {
|
|
||||||
$query->where('user_id', $userModel->getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var string $search Search field */
|
|
||||||
$search = $request->search;
|
|
||||||
if ($search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$search,
|
|
||||||
null,
|
|
||||||
'model_class',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$searchFields = \implode(', ', [
|
|
||||||
trans('validation.custom.target'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
/** Sort columns with a query */
|
|
||||||
$this->sortQuery($query);
|
|
||||||
|
|
||||||
/** Custom pagination */
|
|
||||||
$activitylogModels = $this->paginate($query);
|
|
||||||
|
|
||||||
return view('bo.pages.activity_logs.index', compact(
|
|
||||||
'activitylogModels',
|
|
||||||
'search',
|
|
||||||
'searchFields',
|
|
||||||
'userModel'
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ActivityLog $activity_log
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function show(ActivityLog $activity_log): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$this->authorize('isConceptor');
|
|
||||||
$targetModelClass = $activity_log->model_class;
|
|
||||||
$targetModel = $activity_log->model_class::where(
|
|
||||||
(new $targetModelClass())->getRouteKeyName(),
|
|
||||||
$activity_log->model_id
|
|
||||||
)->first();
|
|
||||||
|
|
||||||
return view('bo.pages.activity_logs.show', [
|
|
||||||
'activitylogModel' => $activity_log,
|
|
||||||
'targetModel' => $targetModel,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class LoginController extends Controller
|
|
||||||
{
|
|
||||||
use AuthenticatesUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->middleware('guest:backend')->except('logout');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the guard to be used during authentication.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
|
||||||
*/
|
|
||||||
protected function guard()
|
|
||||||
{
|
|
||||||
return Auth::guard('backend');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the application's login form.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\View\View
|
|
||||||
*/
|
|
||||||
public function showLoginForm()
|
|
||||||
{
|
|
||||||
return view('bo.auth.login');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after login.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function redirectTo(): string
|
|
||||||
{
|
|
||||||
return response()->redirectToIntended()->getTargetUrl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class ResetPasswordController extends Controller
|
|
||||||
{
|
|
||||||
use ResetsPasswords;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the guard to be used during authentication.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
|
||||||
*/
|
|
||||||
protected function guard()
|
|
||||||
{
|
|
||||||
return Auth::guard('backend');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after login.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function redirectTo(): string
|
|
||||||
{
|
|
||||||
return \route('bo.login');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,178 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\Brands\GetBrandUrlsRequest;
|
|
||||||
use App\Http\Requests\Bo\Brands\StoreBrandRequest;
|
|
||||||
use App\Http\Requests\Bo\Brands\UpdateBrandRequest;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class BrandController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Brand::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(Request $request)
|
|
||||||
{
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $brands */
|
|
||||||
$brands = Brand::query();
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$brands,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'name',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($brands);
|
|
||||||
$searchFields = trans('Nom');
|
|
||||||
|
|
||||||
$brands = $this->paginate($brands);
|
|
||||||
|
|
||||||
return view('bo.pages.brands.index', compact('brands', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create()
|
|
||||||
{
|
|
||||||
return view('bo.pages.brands.create');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Brands\StoreBrandRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreBrandRequest $request)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$brand = new Brand();
|
|
||||||
$brand->fill($request->validated());
|
|
||||||
|
|
||||||
if ($brand->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.brands.edit', $brand)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Brand $brand
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(Brand $brand)
|
|
||||||
{
|
|
||||||
return view('bo.pages.brands.edit', [
|
|
||||||
'brandModel' => $brand,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Brands\UpdateBrandRequest $request
|
|
||||||
* @param \App\Models\Brand $brand
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateBrandRequest $request, Brand $brand)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $brand) {
|
|
||||||
$brand->fill($request->validated());
|
|
||||||
if ($brand->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.brands.edit', $brand)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Brand $brand
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(Brand $brand)
|
|
||||||
{
|
|
||||||
if ($brand->deleteOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.brands.index')
|
|
||||||
->with('warning', trans(
|
|
||||||
':model a bien été supprimée',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été supprimée',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get urls from a given brand.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Brands\GetBrandUrlsRequest $request
|
|
||||||
* @param \App\Models\Brand $brand
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function getUrls(GetBrandUrlsRequest $request, Brand $brand)
|
|
||||||
{
|
|
||||||
if (!$request->wantsJson()) {
|
|
||||||
return abort(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()
|
|
||||||
->json($brand->urls);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
|
|
||||||
class DashboardController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Dashboard Page
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
return view('bo.pages.dashboard');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,200 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\Services\StoreServiceRequest;
|
|
||||||
use App\Http\Requests\Bo\Services\UpdateServiceRequest;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\Service;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class ServiceController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Service::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(Request $request)
|
|
||||||
{
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $services */
|
|
||||||
$services = Service::query();
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$services,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'name',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($services);
|
|
||||||
$searchFields = trans('Nom');
|
|
||||||
|
|
||||||
$services = $this->paginate($services);
|
|
||||||
|
|
||||||
return view('bo.pages.services.index', compact('services', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create()
|
|
||||||
{
|
|
||||||
$brandModels = Brand::orderBy('name', 'ASC')->get();
|
|
||||||
return view('bo.pages.services.create', compact('brandModels'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Services\StoreServiceRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreServiceRequest $request)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$service = new Service();
|
|
||||||
$service->fill($request->validated());
|
|
||||||
|
|
||||||
if ($service->saveOrFail()) {
|
|
||||||
$this->generateServicePassword($service);
|
|
||||||
return redirect()
|
|
||||||
->route('bo.services.edit', $service)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
))
|
|
||||||
->with(
|
|
||||||
'warning',
|
|
||||||
"ATTENTION : METTEZ À JOUR LES SITES UTILISANT L'API ! \n
|
|
||||||
Nouvel id de marque pour le service $service->name : $request->brand_id"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(Service $service)
|
|
||||||
{
|
|
||||||
$brandModels = Brand::orderBy('name', 'ASC')->get();
|
|
||||||
return view('bo.pages.services.edit', [
|
|
||||||
'serviceModel' => $service,
|
|
||||||
'brandModels' => $brandModels
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Services\UpdateServiceRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateServiceRequest $request, Service $service)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $service) {
|
|
||||||
$oldBrandId = $service->brand->id;
|
|
||||||
$service->fill($request->validated());
|
|
||||||
if ($service->saveOrFail()) {
|
|
||||||
if ($request->bearer_pwd === 'on') {
|
|
||||||
$this->generateServicePassword($service);
|
|
||||||
}
|
|
||||||
if ($oldBrandId != $request->brand_id) {
|
|
||||||
$changeBrandMessage = "ATTENTION : METTEZ À JOUR LES SITES UTILISANT L'API ! \n
|
|
||||||
Nouvel id de marque pour le service $service->name : $request->brand_id";
|
|
||||||
};
|
|
||||||
return redirect()
|
|
||||||
->route('bo.services.edit', $service)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
))
|
|
||||||
->with(
|
|
||||||
'warning',
|
|
||||||
$changeBrandMessage ?? ''
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(Service $service)
|
|
||||||
{
|
|
||||||
if ($service->deleteOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.services.index')
|
|
||||||
->with('warning', trans(
|
|
||||||
':model a bien été supprimée',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été supprimée',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Regen service credentials
|
|
||||||
*
|
|
||||||
* @param Service $service
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
private function generateServicePassword(Service $service)
|
|
||||||
{
|
|
||||||
$bearerPwd = $service->generateBearerPassword();
|
|
||||||
$service->bearer_token_date = now();
|
|
||||||
$service->saveOrFail();
|
|
||||||
return redirect()->route('bo.services.edit', $service)
|
|
||||||
->with(
|
|
||||||
'error',
|
|
||||||
"ATTENTION : METTEZ À JOUR LES SITES UTILISANT L'API ! \n
|
|
||||||
Nouveau token d'API de $service->name : '$service->bearer_token' et mot de passe '$bearerPwd'"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,279 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Enums\PeriodEnum;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\StatsRequest;
|
|
||||||
use App\Lib\Helpers\ChartJsHelper;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\Url;
|
|
||||||
use App\Models\UrlStats;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Carbon\CarbonPeriod;
|
|
||||||
use Illuminate\Support\Arr;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Colors\RandomColor;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class StatsController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(UrlStats::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var array Colors used in charts */
|
|
||||||
private $colors = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a resource.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\StatsRequest $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(StatsRequest $request): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = auth('backend')->user();
|
|
||||||
$brandModels = $user->getRelatedBrands();
|
|
||||||
|
|
||||||
// Check if it's a post request or not to get data.
|
|
||||||
if ($request->post()) {
|
|
||||||
$requestValidated = $request->validated();
|
|
||||||
$start = $requestValidated['start'] ? Carbon::parse($requestValidated['start']) : null;
|
|
||||||
$end = $requestValidated['end'] ? Carbon::parse($requestValidated['end']) : null;
|
|
||||||
$chart = $this->getChart($requestValidated);
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('bo.pages.stats', [
|
|
||||||
'brandModels' => $brandModels,
|
|
||||||
'chart' => $chart ?? null,
|
|
||||||
'start' => $start ?? null,
|
|
||||||
'end' => $end ?? null,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a chart from ChartJs.
|
|
||||||
*
|
|
||||||
* @param array $requestValidated
|
|
||||||
* @return \IcehouseVentures\LaravelChartjs\Builder
|
|
||||||
*/
|
|
||||||
private function getChart(array $requestValidated): \IcehouseVentures\LaravelChartjs\Builder
|
|
||||||
{
|
|
||||||
// Get PeriodEnum from Request. Default = PeriodEnum::day.
|
|
||||||
$periodEnum = PeriodEnum::tryFrom($requestValidated['period']) ?? PeriodEnum::day;
|
|
||||||
$periodInterval = $this->getDateInterval(
|
|
||||||
$requestValidated['start'],
|
|
||||||
$requestValidated['end'],
|
|
||||||
$periodEnum,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get all labels contained in the interval period.
|
|
||||||
$labels = [];
|
|
||||||
foreach ($periodInterval as $date) {
|
|
||||||
$labels[] = $this->getChartLabels($date, $periodEnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get data from an entity :
|
|
||||||
* - total of all urls from a brand
|
|
||||||
* - total of specific url from a brand
|
|
||||||
* - total of all urls for each brand
|
|
||||||
*/
|
|
||||||
$datasets = match (true) {
|
|
||||||
!$requestValidated['brand'] => $this->buildDatasets(
|
|
||||||
Brand::all(),
|
|
||||||
$periodInterval,
|
|
||||||
$periodEnum,
|
|
||||||
fn($brand, $date, $period) => $this->getCallsSum($brand, $date, $period),
|
|
||||||
fn($brand) => $brand->name
|
|
||||||
),
|
|
||||||
!$requestValidated['url'] => $this->buildDatasets(
|
|
||||||
Brand::find($requestValidated['brand'])->urls,
|
|
||||||
$periodInterval,
|
|
||||||
$periodEnum,
|
|
||||||
fn($url, $date, $period) => $this->getCallsSum($url, $date, $period),
|
|
||||||
fn($url) => $url->value
|
|
||||||
),
|
|
||||||
default => $this->buildDatasets(
|
|
||||||
[Url::find($requestValidated['url'])],
|
|
||||||
$periodInterval,
|
|
||||||
$periodEnum,
|
|
||||||
fn($url, $date, $period) => $this->getCallsSum($url, $date, $period),
|
|
||||||
fn($url) => $url->value
|
|
||||||
),
|
|
||||||
}; //end match
|
|
||||||
|
|
||||||
// Get the type of graph when there are several data or only one.
|
|
||||||
$chartType = count(Arr::first($datasets)['data'] ?? []) > 1 ? 'line' : 'bar';
|
|
||||||
|
|
||||||
return (new ChartJsHelper())
|
|
||||||
->name('stats')
|
|
||||||
->type($chartType)
|
|
||||||
->labels($labels)
|
|
||||||
->datasets($datasets);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get data from an entity.
|
|
||||||
*
|
|
||||||
* @param iterable $entities
|
|
||||||
* @param \Carbon\CarbonPeriod $periodInterval
|
|
||||||
* @param \App\Enums\PeriodEnum $period
|
|
||||||
* @param callable $getStats
|
|
||||||
* @param callable $getLabel
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function buildDatasets(
|
|
||||||
iterable $entities,
|
|
||||||
CarbonPeriod $periodInterval,
|
|
||||||
PeriodEnum $period,
|
|
||||||
callable $getStats,
|
|
||||||
callable $getLabel
|
|
||||||
): array {
|
|
||||||
$datasets = [];
|
|
||||||
foreach ($entities as $entity) {
|
|
||||||
$data = [];
|
|
||||||
foreach ($periodInterval as $date) {
|
|
||||||
$data[] = $getStats($entity, $date, $period);
|
|
||||||
}
|
|
||||||
$color = $this->getUniqueColor();
|
|
||||||
$datasets[] = [
|
|
||||||
'label' => $getLabel($entity),
|
|
||||||
'backgroundColor' => $color,
|
|
||||||
'borderColor' => $color,
|
|
||||||
'pointBorderColor' => $color,
|
|
||||||
'pointBackgroundColor' => $color,
|
|
||||||
'data' => $data,
|
|
||||||
'lineTension' => 0.4,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return $datasets;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the sum of all calls.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Model $entity
|
|
||||||
* @param \Carbon\Carbon $date
|
|
||||||
* @param \App\Enums\PeriodEnum $period
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
private function getCallsSum(Model $entity, Carbon $date, PeriodEnum $period): int
|
|
||||||
{
|
|
||||||
$urlKeys = method_exists($entity, 'urls') && $entity->urls()->exists()
|
|
||||||
? $entity->urls()->pluck('key')
|
|
||||||
: collect([$entity->key]);
|
|
||||||
|
|
||||||
return UrlStats::query()
|
|
||||||
->when(
|
|
||||||
$period === PeriodEnum::day,
|
|
||||||
fn($query) => $query->whereDate('date', $date)
|
|
||||||
)
|
|
||||||
->when(
|
|
||||||
$period === PeriodEnum::week,
|
|
||||||
fn($query) => $query->whereBetween('date', [
|
|
||||||
$date->copy()->startOfWeek(),
|
|
||||||
$date->copy()->endOfWeek()
|
|
||||||
])
|
|
||||||
)
|
|
||||||
->when(
|
|
||||||
$period === PeriodEnum::month,
|
|
||||||
fn($query) => $query->whereBetween('date', [
|
|
||||||
$date->copy()->startOfMonth(),
|
|
||||||
$date->copy()->endOfMonth()
|
|
||||||
])
|
|
||||||
)
|
|
||||||
->whereIn('url_key', $urlKeys)
|
|
||||||
->sum('calls');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the CarbonPeriod for the given period.
|
|
||||||
*
|
|
||||||
* @param string $start
|
|
||||||
* @param string $end
|
|
||||||
* @param \App\Enums\PeriodEnum $period
|
|
||||||
* @return \Carbon\CarbonPeriod
|
|
||||||
*/
|
|
||||||
private function getDateInterval(string $start, string $end, PeriodEnum $period): \Carbon\CarbonPeriod
|
|
||||||
{
|
|
||||||
$startDate = Carbon::parse($start);
|
|
||||||
$endDate = Carbon::parse($end);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set config for each enum names.
|
|
||||||
* methods: specific methods needed.
|
|
||||||
* interval: specific interval defined.
|
|
||||||
*/
|
|
||||||
$unitMap = [
|
|
||||||
PeriodEnum::day->value => [
|
|
||||||
'methods' => null,
|
|
||||||
'interval' => null
|
|
||||||
],
|
|
||||||
PeriodEnum::week->value => [
|
|
||||||
'methods' => ['startOfWeek', 'endOfWeek'],
|
|
||||||
'interval' => '1 week'
|
|
||||||
],
|
|
||||||
PeriodEnum::month->value => [
|
|
||||||
'methods' => ['startOfMonth', 'endOfMonth'],
|
|
||||||
'interval' => '1 month'
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Check if config exist for the given period, get the day config by default.
|
|
||||||
$config = $unitMap[$period->value] ?? $unitMap[PeriodEnum::day->value];
|
|
||||||
|
|
||||||
// Execute configuration methods where available.
|
|
||||||
if ($config['methods']) {
|
|
||||||
[$startMethod, $endMethod] = $config['methods'];
|
|
||||||
$startDate = $startDate->$startMethod();
|
|
||||||
$endDate = $endDate->$endMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
return CarbonPeriod::create($startDate, $config['interval'], $endDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get labels for charts.
|
|
||||||
*
|
|
||||||
* @param \Carbon\Carbon $date
|
|
||||||
* @param \App\Enums\PeriodEnum $period
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function getChartLabels(Carbon $date, PeriodEnum $period): array
|
|
||||||
{
|
|
||||||
// Match given period with enum names.
|
|
||||||
return match ($period) {
|
|
||||||
PeriodEnum::week => array_unique([sprintf(
|
|
||||||
'Du %s au %s',
|
|
||||||
$date->startOfWeek()->format('Y-m-d'),
|
|
||||||
$date->endOfWeek()->format('Y-m-d')
|
|
||||||
)]),
|
|
||||||
PeriodEnum::month => array_unique([
|
|
||||||
Str::ucfirst($date->monthName)
|
|
||||||
]),
|
|
||||||
default => array_unique([$date->format('d-m-Y')]),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get unique color.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function getUniqueColor(): string
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
$color = RandomColor::one();
|
|
||||||
// Check if color is already used.
|
|
||||||
} while (in_array($color, $this->colors));
|
|
||||||
$this->colors[] = $color;
|
|
||||||
return $color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,244 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\Urls\StoreUrlRequest;
|
|
||||||
use App\Http\Requests\Bo\Urls\UpdateUrlRequest;
|
|
||||||
use App\Models\Url;
|
|
||||||
use App\Models\UrlHistory;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\UploadedFile;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Uwil\LaravelCommon\Helpers\FileHelper;
|
|
||||||
|
|
||||||
class UrlController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Url::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(Request $request)
|
|
||||||
{
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = auth('backend')->user();
|
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $urls */
|
|
||||||
$urls = $user->role->equals(RoleEnum::conceptor) ?
|
|
||||||
Url::query() :
|
|
||||||
Url::query()->whereIn('brand_id', $user->brands->pluck('id'));
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$urls,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'key',
|
|
||||||
'value',
|
|
||||||
'title',
|
|
||||||
'brand_id'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($urls);
|
|
||||||
$searchFields = trans('Clé, Redirection, Titre, Marque');
|
|
||||||
|
|
||||||
$urls = $this->paginate($urls);
|
|
||||||
|
|
||||||
return view('bo.pages.urls.index', compact('urls', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Url $url
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create(Url $url)
|
|
||||||
{
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = auth('backend')->user();
|
|
||||||
$brandModels = $user->getRelatedBrands();
|
|
||||||
|
|
||||||
return view('bo.pages.urls.create', [
|
|
||||||
'brands' => $brandModels,
|
|
||||||
'urlModel' => $url
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param StoreUrlRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreUrlRequest $request)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$url = new Url();
|
|
||||||
$url->fill($request->validated());
|
|
||||||
|
|
||||||
// When duplicated, $url->logo is the path of the logo from the original model.
|
|
||||||
$url->logo = is_string($url->logo) ?
|
|
||||||
new UploadedFile(
|
|
||||||
FileHelper::getPublicAbsolutePath($url->logo),
|
|
||||||
sprintf(
|
|
||||||
'%s.%s',
|
|
||||||
Str::uuid(),
|
|
||||||
new \SplFileInfo(asset($url->logo))->getExtension()
|
|
||||||
)
|
|
||||||
) :
|
|
||||||
$url->logo;
|
|
||||||
|
|
||||||
$url->saveOrFail();
|
|
||||||
|
|
||||||
// Reassign the logo in image settings to save only the path.
|
|
||||||
// Do it after the first saveOrFail to get the real logo path, not tmp.
|
|
||||||
$settings = json_decode($request->validated('image_settings'));
|
|
||||||
$settings->image = $url->logo;
|
|
||||||
$url->image_settings = $settings;
|
|
||||||
|
|
||||||
if ($url->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.urls.edit', $url)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé',
|
|
||||||
['model' => Str::singular(trans('models.classes.urls'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé',
|
|
||||||
['model' => Str::singular(trans('models.classes.urls'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Url $url
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(Url $url)
|
|
||||||
{
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = auth('backend')->user();
|
|
||||||
$brandModels = $user->getRelatedBrands();
|
|
||||||
|
|
||||||
return view('bo.pages.urls.edit', [
|
|
||||||
'urlModel' => $url,
|
|
||||||
'brands' => $brandModels
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
* @param UpdateUrlRequest $request
|
|
||||||
* @param Url $url
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateUrlRequest $request, Url $url)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $url) {
|
|
||||||
$oldUrl = $url->value;
|
|
||||||
$data = $request->validated();
|
|
||||||
|
|
||||||
// Reassign the logo in image settings to save only the path.
|
|
||||||
// Do it after the first saveOrFail to get the real logo path, not tmp.
|
|
||||||
$settings = json_decode($request->validated('image_settings'));
|
|
||||||
|
|
||||||
if (empty($settings->image)) {
|
|
||||||
$url->logo = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$url->fill($data);
|
|
||||||
$url->saveOrFail();
|
|
||||||
|
|
||||||
if ($oldUrl !== $url->value) {
|
|
||||||
$this->saveUrlHistory($url, $oldUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
$settings->image = $url->logo;
|
|
||||||
$url->image_settings = $settings;
|
|
||||||
|
|
||||||
if ($url->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.urls.edit', $url)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour',
|
|
||||||
['model' => Str::singular(trans('models.classes.urls'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour',
|
|
||||||
['model' => Str::singular(trans('models.classes.urls'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param Url $url
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(Url $url)
|
|
||||||
{
|
|
||||||
foreach ($url->history as $history) {
|
|
||||||
$history->deleteOrFail();
|
|
||||||
}
|
|
||||||
|
|
||||||
$url->deleteOrFail();
|
|
||||||
return redirect()->route('bo.urls.index')
|
|
||||||
->with(['warning' => 'L\'url pour la clé ' . $url->key . ' a bien été supprimée.']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Duplicate the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Url $url
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function duplicate(Url $url): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$duplicatedUrl = $url->replicate(['key']);
|
|
||||||
|
|
||||||
return $this->create($duplicatedUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save url history when updating url.
|
|
||||||
* @param Url $url
|
|
||||||
* @param string $oldValue
|
|
||||||
* @return \App\Models\UrlHistory
|
|
||||||
*/
|
|
||||||
private function saveUrlHistory(Url $url, string $oldValue)
|
|
||||||
{
|
|
||||||
$history = new UrlHistory();
|
|
||||||
$history->value = $oldValue;
|
|
||||||
$history->start_date = $url->updated_at;
|
|
||||||
$history->end_date = now();
|
|
||||||
$history->url_id = $url->id;
|
|
||||||
$history->saveOrFail();
|
|
||||||
return $history;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\Users\StoreUserRequest;
|
|
||||||
use App\Http\Requests\Bo\Users\UpdateUserRequest;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class UserController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(User::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(Request $request)
|
|
||||||
{
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $users */
|
|
||||||
$users = User::query();
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$users,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'firstname',
|
|
||||||
'lastname',
|
|
||||||
'email'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($users);
|
|
||||||
$searchFields = \implode(', ', [
|
|
||||||
trans('validation.custom.firstname'),
|
|
||||||
trans('validation.custom.lastname'),
|
|
||||||
trans('validation.custom.email'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
|
||||||
$users = $this->paginate($users);
|
|
||||||
|
|
||||||
return view('bo.pages.users.index', compact('users', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create()
|
|
||||||
{
|
|
||||||
$brandModels = Brand::query()->get();
|
|
||||||
return view('bo.pages.users.create', compact('brandModels'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Users\StoreUserRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreUserRequest $request)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$user = new User();
|
|
||||||
$user->fill($request->validated());
|
|
||||||
|
|
||||||
if ($user->saveOrFail()) {
|
|
||||||
$user->brands()->sync(collect($request->brands)->pluck('id'));
|
|
||||||
return redirect()
|
|
||||||
->route('bo.users.edit', $user)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé',
|
|
||||||
['model' => trans('models.classes.user')]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé',
|
|
||||||
['model' => trans('models.classes.user')]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $user
|
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(User $user)
|
|
||||||
{
|
|
||||||
$brandModels = Brand::query()->get();
|
|
||||||
return view('bo.pages.users.edit', [
|
|
||||||
'userModel' => $user,
|
|
||||||
'brandModels' => $brandModels
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Users\UpdateUserRequest $request
|
|
||||||
* @param \App\Models\User $user
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateUserRequest $request, User $user)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $user) {
|
|
||||||
$user->fill($request->validated());
|
|
||||||
$user->brands()->sync(collect($request->brands)->pluck('id'));
|
|
||||||
if ($user->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.users.edit', $user)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour',
|
|
||||||
['model' => trans('models.classes.user')]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour',
|
|
||||||
['model' => trans('models.classes.user')]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $user
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(User $user)
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($user) {
|
|
||||||
$user->brands()->detach();
|
|
||||||
if ($user->deleteOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.users.index')
|
|
||||||
->with('warning', trans(
|
|
||||||
':model a bien été supprimé',
|
|
||||||
['model' => trans('models.classes.user')]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été supprimé',
|
|
||||||
['model' => trans('models.classes.user')]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
|
||||||
use Uwil\LaravelCommon\Controllers\Controller as BaseController;
|
|
||||||
|
|
||||||
class Controller extends BaseController
|
|
||||||
{
|
|
||||||
use AuthorizesRequests;
|
|
||||||
use DispatchesJobs;
|
|
||||||
use ValidatesRequests;
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Fo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
|
|
||||||
class HomeController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
return view('fo.pages.home');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Fo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Jobs\IncrementUrlStat;
|
|
||||||
use App\Models\Url;
|
|
||||||
|
|
||||||
class UrlController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Redirect an url to its value.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Url $url
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function redirect(Url $url)
|
|
||||||
{
|
|
||||||
IncrementUrlStat::dispatch($url)->onConnection('database')->onQueue('database');
|
|
||||||
|
|
||||||
return \redirect($url->value, 301)
|
|
||||||
->header('Cache-Control', 'no-store, no-cache, must-revalidate');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
|
||||||
|
|
||||||
class Kernel extends HttpKernel
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The application's global HTTP middleware stack.
|
|
||||||
*
|
|
||||||
* These middleware are run during every request to your application.
|
|
||||||
*
|
|
||||||
* @var array<int, class-string|string>
|
|
||||||
*/
|
|
||||||
protected $middleware = [
|
|
||||||
\App\Http\Middleware\TrustHosts::class,
|
|
||||||
\App\Http\Middleware\TrustProxies::class,
|
|
||||||
\Illuminate\Http\Middleware\HandleCors::class,
|
|
||||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
|
||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
|
||||||
\App\Http\Middleware\TrimStrings::class,
|
|
||||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The application's route middleware groups.
|
|
||||||
*
|
|
||||||
* @var array<string, array<int, class-string|string>>
|
|
||||||
*/
|
|
||||||
protected $middlewareGroups = [
|
|
||||||
'web' => [
|
|
||||||
'htmlsanitize',
|
|
||||||
\App\Http\Middleware\EncryptCookies::class,
|
|
||||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
|
||||||
\Illuminate\Session\Middleware\StartSession::class,
|
|
||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
|
||||||
\App\Http\Middleware\SecureHeaders::class
|
|
||||||
],
|
|
||||||
|
|
||||||
'saml' => [
|
|
||||||
\App\Http\Middleware\EncryptCookies::class,
|
|
||||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
|
||||||
\Illuminate\Session\Middleware\StartSession::class,
|
|
||||||
],
|
|
||||||
|
|
||||||
'api' => [
|
|
||||||
'throttle:api',
|
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
|
||||||
\App\Http\Middleware\JsonOnly::class,
|
|
||||||
\App\Http\Middleware\ApiCheckTimeStamps::class,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The application's route middleware.
|
|
||||||
*
|
|
||||||
* These middleware may be assigned to groups or used individually.
|
|
||||||
*
|
|
||||||
* @var array<string, class-string|string>
|
|
||||||
*/
|
|
||||||
protected $routeMiddleware = [
|
|
||||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
|
||||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
|
||||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
|
||||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
|
||||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
|
||||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
|
||||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
|
||||||
'htmlsanitize' => \App\Http\Middleware\HtmlSanitizer::class,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
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 \Symfony\Component\HttpKernel\Exception\HttpException If timestamp has an incorrect
|
|
||||||
* format or is timed out.
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, \Closure $next)
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
!\is_string($request->input('timestamp')) or
|
|
||||||
!Carbon::hasFormat($request->input('timestamp'), 'Y-m-d H:i:s')
|
|
||||||
) {
|
|
||||||
abort(401, 'Timestamp isn\'t correctly formatted');
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
Carbon::parse($request->input('timestamp'), 'utc')
|
|
||||||
->isBefore(Carbon::now('UTC')->subSeconds(config('api.timestampTimeout', 10)))
|
|
||||||
) {
|
|
||||||
abort(401, 'Timestamp is too old');
|
|
||||||
}
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
|
|
||||||
class Authenticate extends Middleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the path the user should be redirected to when they are not authenticated.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return string|null
|
|
||||||
*/
|
|
||||||
protected function redirectTo(Request $request)
|
|
||||||
{
|
|
||||||
$logins = [
|
|
||||||
// Dans tous les cas bo.login.
|
|
||||||
'frontend' => route('bo.login'),
|
|
||||||
'backend' => route('bo.login')
|
|
||||||
];
|
|
||||||
if (!$request->expectsJson()) {
|
|
||||||
// * Notify must login
|
|
||||||
Session::flash('warning', trans('Veuillez vous connecter pour continuer'));
|
|
||||||
foreach ($request->route()->gatherMiddleware() as $middleware) {
|
|
||||||
if (\is_string($middleware) and strpos($middleware, 'auth:') !== false) {
|
|
||||||
$route = $logins[str_replace('auth:', '', $middleware)] ?? null;
|
|
||||||
if ($route) {
|
|
||||||
return $route;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return route('bo.login');
|
|
||||||
}
|
|
||||||
abort(401);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
|
||||||
|
|
||||||
class EncryptCookies extends Middleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The names of the cookies that should not be encrypted.
|
|
||||||
*
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $except = [
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use App\Lib\Helpers\ToolboxHelper;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class HtmlSanitizer
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Closure $next
|
|
||||||
* @param string|array ...$params
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, \Closure $next, string|array ...$params)
|
|
||||||
{
|
|
||||||
$inputs = $request->all();
|
|
||||||
/** @var callable|null */
|
|
||||||
$cleanInput = null;
|
|
||||||
$cleanInput = function (&$input, $name, $rootName = null) use ($params, &$cleanInput) {
|
|
||||||
// * Nested element array
|
|
||||||
if (is_array($input)) {
|
|
||||||
array_walk_recursive($input, $cleanInput, $name);
|
|
||||||
}
|
|
||||||
if (!is_string($input)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (in_array($name, $params) or in_array($rootName ?? $name, $params)) {
|
|
||||||
// ? Is a json input ?
|
|
||||||
if ($isJson = \json_decode($input, true) and is_array($isJson)) {
|
|
||||||
// ! Decode each json field recursive.
|
|
||||||
\array_walk_recursive($isJson, function (&$item) {
|
|
||||||
if (\is_string($item)) {
|
|
||||||
$item = clean($item);
|
|
||||||
$item = ToolboxHelper::stripCkEditorSchemesOnMediaInputs($item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$input = clean($input);
|
|
||||||
$input = ToolboxHelper::stripCkEditorSchemesOnMediaInputs($input);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$input = strip_tags($input);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
\array_walk($inputs, $cleanInput);
|
|
||||||
$request->merge($inputs);
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +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()))
|
|
||||||
) {
|
|
||||||
abort(400, 'Invalid JSON');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
|
|
||||||
|
|
||||||
class PreventRequestsDuringMaintenance extends Middleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The URIs that should be reachable while maintenance mode is enabled.
|
|
||||||
*
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $except = [];
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class RedirectIfAuthenticated
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.Files.LineLength.TooLong
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
|
||||||
* @param string|null ...$guards
|
|
||||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
|
||||||
* @throws \RuntimeException If guard is unhandled.
|
|
||||||
* @phpcs:enable
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, Closure $next, ...$guards)
|
|
||||||
{
|
|
||||||
$guards = empty($guards) ? [null] : $guards;
|
|
||||||
|
|
||||||
foreach ($guards as $guard) {
|
|
||||||
if (Auth::guard($guard)->check()) {
|
|
||||||
switch ($guard) {
|
|
||||||
case 'frontend':
|
|
||||||
return \redirect()->route('home');
|
|
||||||
case 'backend':
|
|
||||||
return \redirect()->route('bo.dashboard');
|
|
||||||
default:
|
|
||||||
throw new \RuntimeException("Unhandled guard `{$guard}` .");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Route;
|
|
||||||
use Illuminate\Support\Facades\View;
|
|
||||||
use Illuminate\Support\Facades\Vite;
|
|
||||||
|
|
||||||
class SecureHeaders
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Enumerate headers which you do not want in your application's responses.
|
|
||||||
* Great starting point would be to go check out @Scott_Helme's:
|
|
||||||
* https://securityheaders.com/
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $unwantedHeaderList = [
|
|
||||||
'X-Powered-By',
|
|
||||||
'Server',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Closure $next
|
|
||||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function handle(Request $request, Closure $next)
|
|
||||||
{
|
|
||||||
// * For Vite DEV
|
|
||||||
$host = \parse_url(\config('app.url'), \PHP_URL_HOST);
|
|
||||||
View::share('nonce', $nonce = Vite::useCspNonce());
|
|
||||||
// * For VueJS dev tool to execute
|
|
||||||
$jsDev = config('app.debug') ? "'unsafe-eval' 'unsafe-inline'" : "'nonce-{$nonce}' 'strict-dynamic'";
|
|
||||||
$scheme = config('app.env') === 'local' ? 'http' : 'https';
|
|
||||||
$reportUri = Route::has('cspReportUri') ?
|
|
||||||
\sprintf(' report-uri %s ;', \parse_url(route('cspReportUri'), \PHP_URL_PATH)) : '';
|
|
||||||
$this->removeUnwantedHeaders($this->unwantedHeaderList);
|
|
||||||
$response = $next($request);
|
|
||||||
$response->headers->set('Referrer-Policy', 'no-referrer-when-downgrade');
|
|
||||||
$response->headers->set('X-Content-Type-Options', 'nosniff');
|
|
||||||
$response->headers->set('X-XSS-Protection', '1; mode=block');
|
|
||||||
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
|
|
||||||
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains;');
|
|
||||||
$cspPolicies = [
|
|
||||||
"default-src 'none';",
|
|
||||||
"manifest-src 'self';",
|
|
||||||
// * CKEDITOR Specific https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/csp.html
|
|
||||||
"connect-src 'self' blob: data: " . implode(' ', [
|
|
||||||
// * VITE DEV
|
|
||||||
config('app.debug') ? "wss://{$host}:4443" : '',
|
|
||||||
config('app.debug') ? "https://{$host}:4443" : '',
|
|
||||||
]) . ';',
|
|
||||||
"img-src 'self' data: blob: " . implode(' ', [
|
|
||||||
// * VITE DEV
|
|
||||||
config('app.debug') ? "https://{$host}:4443" : '',
|
|
||||||
]) . ';',
|
|
||||||
"object-src 'self' " . implode(' ', []) . ';',
|
|
||||||
'frame-src ' . implode(' ', []) . ';',
|
|
||||||
"font-src 'self' data: " . \implode(' ', [
|
|
||||||
// * VITE DEV
|
|
||||||
config('app.debug') ? "https://{$host}:4443" : '',
|
|
||||||
]) . ';',
|
|
||||||
// ! Using CKEditor will must have unsafe-inline style
|
|
||||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
|
||||||
"style-src 'self' 'unsafe-inline' " . \implode(' ', [
|
|
||||||
// * File Manager
|
|
||||||
'https://cdn.jsdelivr.net',
|
|
||||||
'https://use.fontawesome.com',
|
|
||||||
'https://fonts.googleapis.com'
|
|
||||||
]) . ';',
|
|
||||||
// ! If you dont use ckeditor use this
|
|
||||||
// "style-src 'self' 'nonce-$nonce';",
|
|
||||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
|
||||||
"script-src 'self' {$jsDev} " . \implode(' ', [
|
|
||||||
'https: blob:',
|
|
||||||
'https://cdnjs.cloudflare.com',
|
|
||||||
// * VITE DEV
|
|
||||||
config('app.debug') ? "https://{$host}:4443" : '',
|
|
||||||
]) . ';'
|
|
||||||
];
|
|
||||||
|
|
||||||
$response->headers->set(
|
|
||||||
'Content-Security-Policy',
|
|
||||||
implode(' ', $cspPolicies) . $reportUri
|
|
||||||
);
|
|
||||||
$response->headers->set('Feature-Policy', 'fullscreen \'self\';');
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove unwanted headers
|
|
||||||
*
|
|
||||||
* @param array $headerList
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function removeUnwantedHeaders(array $headerList)
|
|
||||||
{
|
|
||||||
foreach ($headerList as $header) {
|
|
||||||
header_remove($header);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
|
|
||||||
|
|
||||||
class TrimStrings extends Middleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The names of the attributes that should not be trimmed.
|
|
||||||
*
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $except = [
|
|
||||||
'current_password',
|
|
||||||
'password',
|
|
||||||
'password_confirmation',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Illuminate\Http\Middleware\TrustHosts as Middleware;
|
|
||||||
|
|
||||||
class TrustHosts extends Middleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the host patterns that should be trusted.
|
|
||||||
*
|
|
||||||
* @return array<int, string|null>
|
|
||||||
*/
|
|
||||||
public function hosts()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
$this->allSubdomainsOfApplicationUrl(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class TrustProxies extends Middleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The trusted proxies for this application.
|
|
||||||
*
|
|
||||||
* @var array<int, string>|string|null
|
|
||||||
*/
|
|
||||||
protected $proxies;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The headers that should be used to detect proxies.
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
protected $headers =
|
|
||||||
Request::HEADER_X_FORWARDED_FOR |
|
|
||||||
Request::HEADER_X_FORWARDED_HOST |
|
|
||||||
Request::HEADER_X_FORWARDED_PORT |
|
|
||||||
Request::HEADER_X_FORWARDED_PROTO |
|
|
||||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
|
||||||
|
|
||||||
class VerifyCsrfToken extends Middleware
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The URIs that should be excluded from CSRF verification.
|
|
||||||
*
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $except = ['/csp-report'];
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Api;
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class GetStatsRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Prepare the data for validation.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function prepareForValidation(): void
|
|
||||||
{
|
|
||||||
$this->merge([
|
|
||||||
'period' => $this->input('period') ? $this->input('period') : 'day',
|
|
||||||
'start' => $this->input('start') ? Carbon::create($this->input('start')) : now()->modify('-1 year'),
|
|
||||||
'end' => $this->input('end') ? Carbon::create($this->input('end')) : now(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Brands;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class GetBrandUrlsRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return auth('backend')->check();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Brands;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class StoreBrandRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return auth('backend')->check();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'string|max:255|required|unique:brands,name'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Brands;
|
|
||||||
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
|
|
||||||
class UpdateBrandRequest extends StoreBrandRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => [
|
|
||||||
'string',
|
|
||||||
'max:255',
|
|
||||||
'required',
|
|
||||||
Rule::unique('brands', 'name')->ignore($this->brand->id)
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Services;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class StoreServiceRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return auth('backend')->check();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'string|max:255|required',
|
|
||||||
'brand_id' => 'required|exists:brands,id'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Services;
|
|
||||||
|
|
||||||
class UpdateServiceRequest extends StoreServiceRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'string|max:255|required',
|
|
||||||
'brand_id' => 'required|exists:brands,id'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo;
|
|
||||||
|
|
||||||
use App\Enums\PeriodEnum;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\Url;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
|
|
||||||
class StatsRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function authorize(): bool
|
|
||||||
{
|
|
||||||
return auth('backend')->check();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare the data for validation.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function prepareForValidation(): void
|
|
||||||
{
|
|
||||||
$now = Carbon::now();
|
|
||||||
$urlId = $this->input('url');
|
|
||||||
$brandId = $this->input('brand');
|
|
||||||
$startDate = Carbon::parse($this->input('start'));
|
|
||||||
$endDate = Carbon::parse($this->input('end'));
|
|
||||||
$adjustedEndDate = $endDate->greaterThan($now) ? $now : $endDate;
|
|
||||||
|
|
||||||
$period = PeriodEnum::tryFrom($this->input('period'));
|
|
||||||
|
|
||||||
// Get start & end dates by period.
|
|
||||||
[$adjustedStart, $adjustedEnd] = match ($period) {
|
|
||||||
PeriodEnum::week => [$startDate->copy()->startOfWeek(), $endDate->copy()->endOfWeek()],
|
|
||||||
PeriodEnum::month => [$startDate->copy()->startOfMonth(), $endDate->copy()->endOfMonth()],
|
|
||||||
default => [$startDate, $adjustedEndDate],
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->merge([
|
|
||||||
'url' => Url::find($urlId) ? $urlId : null,
|
|
||||||
'brand' => Brand::find($brandId) ? $brandId : null,
|
|
||||||
'start' => $adjustedStart->toDateString(),
|
|
||||||
'end' => $adjustedEnd->toDateString(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return (request()->post()) ? [
|
|
||||||
'period' => [
|
|
||||||
'required',
|
|
||||||
'string',
|
|
||||||
Rule::enum(PeriodEnum::class)
|
|
||||||
],
|
|
||||||
'start' => 'required|date|date_format:Y-m-d|before_or_equal:today|after_or_equal:'
|
|
||||||
. Carbon::parse($this->input('end'))->modify('-1 year'),
|
|
||||||
'end' => 'required|date|date_format:Y-m-d|after_or_equal:start',
|
|
||||||
'brand' => 'nullable|integer|exists:App\Models\Brand,id',
|
|
||||||
'url' => 'nullable|integer|exists:App\Models\Url,id'
|
|
||||||
] : [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Urls;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Traits\Requests\HasPictureWithSvgSupport;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
use Uwil\LaravelCommon\Traits\Requests\HasPicture;
|
|
||||||
|
|
||||||
class StoreUrlRequest extends FormRequest
|
|
||||||
{
|
|
||||||
use HasPicture;
|
|
||||||
use HasPictureWithSvgSupport;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return auth('backend')->check();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare the data for validation.
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function prepareForValidation(): void
|
|
||||||
{
|
|
||||||
$this->mergePicture('logo');
|
|
||||||
$this->merge([
|
|
||||||
'key' => Str::slug($this->key),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
$user = auth('backend')->user();
|
|
||||||
|
|
||||||
$rules = [
|
|
||||||
'key' => 'required|string|max:45|unique:App\Models\Url,key',
|
|
||||||
'value' => 'required|url:http,https|max:255',
|
|
||||||
'title' => 'required|string|min:3|max:255',
|
|
||||||
'brand_id' => [
|
|
||||||
'required',
|
|
||||||
'integer',
|
|
||||||
'exists:App\Models\Brand,id',
|
|
||||||
!$user->role->equals(RoleEnum::conceptor) ? Rule::in($user->brands->pluck('id')) : ''
|
|
||||||
],
|
|
||||||
'image_settings' => 'required|json',
|
|
||||||
];
|
|
||||||
|
|
||||||
return \array_merge(
|
|
||||||
$rules,
|
|
||||||
$this->pictureRulesWithSvgSupport('logo', 100, 100, 500, 500, true),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Urls;
|
|
||||||
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
|
|
||||||
class UpdateUrlRequest extends StoreUrlRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Prepare the data for validation.
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function prepareForValidation(): void
|
|
||||||
{
|
|
||||||
$this->merge([
|
|
||||||
'key' => $this->url->key,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
$rules = [
|
|
||||||
'key' => [
|
|
||||||
'required',
|
|
||||||
'string',
|
|
||||||
'max:45',
|
|
||||||
Rule::unique('urls', 'key')->ignore($this->url->id)
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
return \array_merge(
|
|
||||||
parent::rules(),
|
|
||||||
$rules,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Users;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
use Illuminate\Support\Facades\Gate;
|
|
||||||
use Illuminate\Validation\Rules\Enum;
|
|
||||||
|
|
||||||
class StoreUserRequest extends FormRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return Gate::check('create', User::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'firstname' => 'required|string|min:3|max:255',
|
|
||||||
'lastname' => 'required|string|min:3|max:255',
|
|
||||||
'email' => 'required|email:rfc,strict,dns,spoof,filter|unique:users,email',
|
|
||||||
'role' => ['required', new Enum(RoleEnum::class)],
|
|
||||||
'brands' => 'nullable|array|min:1',
|
|
||||||
'brands.*' => 'nullable|array',
|
|
||||||
'brands.*.id' => 'nullable|exists:\App\Models\Brand,id',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get custom attributes for validator errors.
|
|
||||||
*
|
|
||||||
* @return array<string, string>
|
|
||||||
*/
|
|
||||||
public function attributes(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'first_name' => trans('validation.attributes.first_name'),
|
|
||||||
'last_name' => trans('validation.attributes.last_name'),
|
|
||||||
'email' => trans('validation.attributes.email'),
|
|
||||||
'role' => trans('validation.attributes.role'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Bo\Users;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use Illuminate\Support\Facades\Gate;
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
|
|
||||||
class UpdateUserRequest extends StoreUserRequest
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function authorize(): bool
|
|
||||||
{
|
|
||||||
return Gate::check('update', $this->route('user'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare the data for validation.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function prepareForValidation(): void
|
|
||||||
{
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = $this->route('user');
|
|
||||||
if (!$user->role->equals(RoleEnum::conceptor)) {
|
|
||||||
$this->merge(['email' => $user->email]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = $this->route('user');
|
|
||||||
return array_merge(parent::rules(), [
|
|
||||||
'email' => [
|
|
||||||
'required',
|
|
||||||
'email:rfc,strict,dns,spoof,filter',
|
|
||||||
Rule::unique('users', 'email')->ignore($user->getRouteKey()),
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
|
||||||
|
|
||||||
class BrandCollection extends ResourceCollection
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource collection into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.TypeHintMissing
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'data' => $this->collection
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mixin \App\Models\Brand
|
|
||||||
*/
|
|
||||||
class BrandResource extends JsonResource
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.TypeHintMissing
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => $this->id,
|
|
||||||
'name' => $this->name,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
|
||||||
|
|
||||||
class UrlCollection extends ResourceCollection
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource collection into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.TypeHintMissing
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'data' => $this->collection
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
|
||||||
|
|
||||||
class UrlHistoryCollection extends ResourceCollection
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource collection into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.TypeHintMissing
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'data' => $this->collection
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mixin \App\Models\UrlHistory
|
|
||||||
*/
|
|
||||||
class UrlHistoryResource extends JsonResource
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.TypeHintMissing
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => $this->id,
|
|
||||||
'value' => $this->value,
|
|
||||||
'start' => $this->start_date,
|
|
||||||
'end' => $this->end_date,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mixin \App\Models\Url
|
|
||||||
*/
|
|
||||||
class UrlResource extends JsonResource
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.TypeHintMissing
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => $this->id,
|
|
||||||
'key' => $this->key,
|
|
||||||
'value' => $this->value,
|
|
||||||
'brand' => new BrandResource($this->brand)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
|
||||||
|
|
||||||
class UrlStatsCollection extends ResourceCollection
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource collection into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.TypeHintMissing
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
|
||||||
// phpcs:enable
|
|
||||||
return [
|
|
||||||
'data' => $this->collection
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mixin \App\Models\UrlStats
|
|
||||||
*/
|
|
||||||
class UrlStatsResource extends JsonResource
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource into an array.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, Squiz.Commenting.FunctionComment.TypeHintMissing
|
|
||||||
*/
|
|
||||||
public function toArray($request)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => $this->id,
|
|
||||||
'calls' => $this->calls,
|
|
||||||
'date' => $this->date,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Jobs;
|
|
||||||
|
|
||||||
use App\Models\Url;
|
|
||||||
use App\Models\UrlStats;
|
|
||||||
use Illuminate\Bus\Queueable;
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
class IncrementUrlStat implements ShouldQueue
|
|
||||||
{
|
|
||||||
use Dispatchable;
|
|
||||||
use InteractsWithQueue;
|
|
||||||
use Queueable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To be serialized by jobs system
|
|
||||||
*
|
|
||||||
* @var Url
|
|
||||||
* */
|
|
||||||
private $url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new job instance.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Url $url
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(Url $url)
|
|
||||||
{
|
|
||||||
$this->url = $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the job.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$urlStat = UrlStats::query()
|
|
||||||
->whereDate('date', now())
|
|
||||||
->firstOrNew(
|
|
||||||
[
|
|
||||||
'url_key' => $this->url->key,
|
|
||||||
'url' => $this->url->value,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
$urlStat->calls += 1;
|
|
||||||
|
|
||||||
$urlStat->saveOrFail();
|
|
||||||
|
|
||||||
Log::debug(sprintf('Stats incremented for URL : %s', $this->url->key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,182 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Lib\Helpers;
|
|
||||||
|
|
||||||
use IcehouseVentures\LaravelChartjs\Builder;
|
|
||||||
use Illuminate\Support\Arr;
|
|
||||||
|
|
||||||
class ChartJsHelper extends Builder
|
|
||||||
{
|
|
||||||
// phpcs:disable
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public $charts = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $defaults = [
|
|
||||||
'datasets' => [],
|
|
||||||
'labels' => [],
|
|
||||||
'type' => 'line',
|
|
||||||
'options' => [],
|
|
||||||
'size' => ['width' => null, 'height' => null]
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $types = [
|
|
||||||
'bar',
|
|
||||||
'horizontalBar',
|
|
||||||
'bubble',
|
|
||||||
'scatter',
|
|
||||||
'doughnut',
|
|
||||||
'line',
|
|
||||||
'pie',
|
|
||||||
'polarArea',
|
|
||||||
'radar'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $name
|
|
||||||
*
|
|
||||||
* @return $this|Builder
|
|
||||||
*/
|
|
||||||
public function name($name)
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
$this->charts[$name] = $this->defaults;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $element
|
|
||||||
*
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
public function element($element)
|
|
||||||
{
|
|
||||||
return $this->set('element', $element);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $labels
|
|
||||||
*
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
public function labels(array $labels)
|
|
||||||
{
|
|
||||||
return $this->set('labels', $labels);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $datasets
|
|
||||||
*
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
public function datasets(array $datasets)
|
|
||||||
{
|
|
||||||
return $this->set('datasets', $datasets);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $type
|
|
||||||
*
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
public function type($type)
|
|
||||||
{
|
|
||||||
if (!in_array($type, $this->types)) {
|
|
||||||
throw new \InvalidArgumentException('Invalid Chart type.');
|
|
||||||
}
|
|
||||||
return $this->set('type', $type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $size
|
|
||||||
*
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
public function size($size)
|
|
||||||
{
|
|
||||||
return $this->set('size', $size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $options
|
|
||||||
*
|
|
||||||
* @return $this|Builder
|
|
||||||
*/
|
|
||||||
public function options(array $options)
|
|
||||||
{
|
|
||||||
foreach ($options as $key => $value) {
|
|
||||||
$this->set('options.' . $key, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param string|array $optionsRaw
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function optionsRaw($optionsRaw)
|
|
||||||
{
|
|
||||||
if (is_array($optionsRaw)) {
|
|
||||||
$this->set('optionsRaw', json_encode($optionsRaw));
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->set('optionsRaw', $optionsRaw);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
$chart = $this->charts[$this->name];
|
|
||||||
|
|
||||||
return view('vendor.chart-template')
|
|
||||||
->with('datasets', $chart['datasets'])
|
|
||||||
->with('element', $this->name)
|
|
||||||
->with('labels', $chart['labels'])
|
|
||||||
->with('options', isset($chart['options']) ? $chart['options'] : '')
|
|
||||||
->with('optionsRaw', isset($chart['optionsRaw']) ? $chart['optionsRaw'] : '')
|
|
||||||
->with('type', $chart['type'])
|
|
||||||
->with('size', $chart['size']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $key
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function get($key)
|
|
||||||
{
|
|
||||||
return Arr::get($this->charts[$this->name], $key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $key
|
|
||||||
* @param $value
|
|
||||||
*
|
|
||||||
* @return $this|Builder
|
|
||||||
*/
|
|
||||||
public function set($key, $value)
|
|
||||||
{
|
|
||||||
Arr::set($this->charts[$this->name], $key, $value);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
// phpcs:enable
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Lib\Helpers;
|
|
||||||
|
|
||||||
use Illuminate\Contracts\Encryption\DecryptException;
|
|
||||||
use Illuminate\Support\Facades\Crypt;
|
|
||||||
use Uwil\LaravelCommon\Helpers\ToolboxHelper as BaseToolboxHelper;
|
|
||||||
|
|
||||||
class ToolboxHelper extends BaseToolboxHelper
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Calculate the request signature
|
|
||||||
*
|
|
||||||
* @param string $secret
|
|
||||||
* @param string $uri
|
|
||||||
* @param string $method
|
|
||||||
* @param array $parameters
|
|
||||||
* @return string request signature
|
|
||||||
* @throws \RuntimeException 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 \RuntimeException('Failed to calculate requests hash');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $calculatedHash;
|
|
||||||
} catch (DecryptException $e) {
|
|
||||||
throw new \RuntimeException('Failed to decrypt service credentials', 0, $e);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
throw new \RuntimeException('An error occured when authenticating service', 0, $e);
|
|
||||||
} //end try
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,176 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use App\Enums\ActivityLogs\ActivityLogsEventEnum;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @property string $model Target model.
|
|
||||||
* @property string $model_id Id of the target model.
|
|
||||||
* @property \App\Enums\ActivityLogs\ActivityLogsEventEnum $event Event of this activity (ActivityLogsEventEnum).
|
|
||||||
* @property array $data Changes.
|
|
||||||
* @property-read \Illuminate\Support\Carbon $created_at Created date.
|
|
||||||
*
|
|
||||||
* @property-read \App\Models\User $user User BelongsTo relation.
|
|
||||||
*/
|
|
||||||
class ActivityLog extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if the model should be timestamped.
|
|
||||||
*
|
|
||||||
* @var boolean
|
|
||||||
*/
|
|
||||||
public $timestamps = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'is_anonymous',
|
|
||||||
'model_class',
|
|
||||||
'model_id',
|
|
||||||
'event',
|
|
||||||
'data',
|
|
||||||
'created_at',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that should be cast.
|
|
||||||
*
|
|
||||||
* @var array<string, string>
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'is_anonymous' => 'boolean',
|
|
||||||
'event' => ActivityLogsEventEnum::class,
|
|
||||||
'data' => 'json',
|
|
||||||
'created_at' => 'datetime',
|
|
||||||
];
|
|
||||||
|
|
||||||
// * METHODS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add new activity to the activity logs list.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Model $model
|
|
||||||
* @param \App\Enums\ActivityLogs\ActivityLogsEventEnum $eventEnum
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function addActivity(Model $model, ActivityLogsEventEnum $eventEnum): void
|
|
||||||
{
|
|
||||||
$isAnonymous = true;
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Model|null */
|
|
||||||
$userModel = auth('backend')->user();
|
|
||||||
if (is_object($userModel)) {
|
|
||||||
$userModel = $userModel->getKeyForSelectQuery();
|
|
||||||
$isAnonymous = false;
|
|
||||||
}
|
|
||||||
$activity = new self();
|
|
||||||
$activity->user_id = $userModel;
|
|
||||||
$activity->is_console = app()->runningInConsole();
|
|
||||||
$activity->is_anonymous = $isAnonymous;
|
|
||||||
$activity->model_class = \get_class($model);
|
|
||||||
$activity->model_id = $model->getKey();
|
|
||||||
$activity->event = $eventEnum;
|
|
||||||
$activity->data = static::getChangedColumns($activity, $model, $eventEnum);
|
|
||||||
// @phpstan-ignore-next-line
|
|
||||||
$activity->created_at = now();
|
|
||||||
$activity->saveOrFail();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get old, new columns that has changed.
|
|
||||||
*
|
|
||||||
* @param self $activity
|
|
||||||
* @param \Illuminate\Database\Eloquent\Model $model
|
|
||||||
* @param \App\Enums\ActivityLogs\ActivityLogsEventEnum $eventEnum
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function getChangedColumns(self $activity, Model $model, ActivityLogsEventEnum $eventEnum): array
|
|
||||||
{
|
|
||||||
$modelClassName = $activity->model_class;
|
|
||||||
/** Get type of each fields of the target model */
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Model|null $targetModel */
|
|
||||||
$targetModel = $activity->model_class::where(
|
|
||||||
(new $modelClassName())->getRouteKeyName(),
|
|
||||||
$activity->model_id
|
|
||||||
)->first();
|
|
||||||
|
|
||||||
if (\is_null($targetModel)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
$targetModelTypes = collect($targetModel->toArray())
|
|
||||||
->map(fn ($value) => self::getValueType($value))
|
|
||||||
->toArray();
|
|
||||||
/** Return old, new and type of values changed */
|
|
||||||
return match ($eventEnum) {
|
|
||||||
ActivityLogsEventEnum::created => array_intersect_key($targetModelTypes, $model->toArray()),
|
|
||||||
ActivityLogsEventEnum::duplicated => array_intersect_key($targetModelTypes, $model->toArray()),
|
|
||||||
ActivityLogsEventEnum::updated => array_intersect_key($targetModelTypes, $model->getChanges()),
|
|
||||||
default => []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a value type as a string
|
|
||||||
* ! Use this for display purpose only
|
|
||||||
*
|
|
||||||
* @param mixed $value
|
|
||||||
* @return string
|
|
||||||
* @throws \RuntimeException If type is unhlanded.
|
|
||||||
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
|
||||||
*/
|
|
||||||
private static function getValueType(mixed $value): string
|
|
||||||
{
|
|
||||||
// phpcs:enable
|
|
||||||
$type = \gettype($value);
|
|
||||||
switch ($type) {
|
|
||||||
// phpcs:ignore PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
|
|
||||||
case 'string':
|
|
||||||
return match (true) {
|
|
||||||
Str::length(\strip_tags($value)) !== Str::length($value) => 'html',
|
|
||||||
Str::startsWith($value, 'storage/modelfiles') => 'file',
|
|
||||||
Str::isUuid($value) => 'uuid',
|
|
||||||
Str::isUlid($value) => 'ulid',
|
|
||||||
Str::isUrl($value) => 'url',
|
|
||||||
Str::isMatch('/^[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]$/', $value) => 'youtube_video_id',
|
|
||||||
\is_numeric($value) => 'numeric',
|
|
||||||
Str::isJson($value) and
|
|
||||||
(Str::startsWith($value, '[') or Str::startsWith($value, '{')) => 'json',
|
|
||||||
default => 'string'
|
|
||||||
};
|
|
||||||
case 'NULL':
|
|
||||||
case 'object':
|
|
||||||
case 'array':
|
|
||||||
case 'integer':
|
|
||||||
case 'boolean':
|
|
||||||
return $type;
|
|
||||||
case 'double':
|
|
||||||
return is_float($value) ? 'float' : 'double';
|
|
||||||
case 'resource (closed)':
|
|
||||||
case 'resource':
|
|
||||||
throw new \RuntimeException('Laravel model properties should not contain resources !');
|
|
||||||
case 'unknown type':
|
|
||||||
default:
|
|
||||||
throw new \RuntimeException('Unhandled Type ' . \gettype($value));
|
|
||||||
} //end switch
|
|
||||||
}
|
|
||||||
|
|
||||||
// * RELATIONS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User BelongsTo relation.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
*/
|
|
||||||
public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use App\Traits\Models\ActivityLog;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
||||||
|
|
||||||
class Brand extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
use ActivityLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'name'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The "booted" method of the model.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected static function boot(): void
|
|
||||||
{
|
|
||||||
parent::boot();
|
|
||||||
|
|
||||||
static::deleting(function (self $model) {
|
|
||||||
$model->users()->detach();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// * RELATIONSHIPS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the urls for the brand.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\Url, $this>
|
|
||||||
*/
|
|
||||||
public function urls()
|
|
||||||
{
|
|
||||||
return $this->hasMany(Url::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the urls for the brand.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\Service, $this>
|
|
||||||
*/
|
|
||||||
public function services()
|
|
||||||
{
|
|
||||||
return $this->hasMany(Service::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The users that belong to the brand.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<\App\Models\User,
|
|
||||||
* $this,
|
|
||||||
* \Illuminate\Database\Eloquent\Relations\Pivot>
|
|
||||||
*/
|
|
||||||
public function users(): BelongsToMany
|
|
||||||
{
|
|
||||||
return $this->belongsToMany(User::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,156 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use App\Lib\Helpers\ToolboxHelper;
|
|
||||||
use App\Traits\Models\ActivityLog;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Crypt;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class Service extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
use ActivityLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'name',
|
|
||||||
'bearer_token',
|
|
||||||
'bearer_pwd',
|
|
||||||
'brand_id'
|
|
||||||
];
|
|
||||||
|
|
||||||
// * EVENTS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any actions required after the model boots.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected static function booted()
|
|
||||||
{
|
|
||||||
static::creating(function (self $model) {
|
|
||||||
self::assertFieldIsUnique('name', $model->name);
|
|
||||||
$model->generateBearerToken();
|
|
||||||
$model->generateBearerPassword();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// * METHODS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts using validation that the field is unique.
|
|
||||||
*
|
|
||||||
* @param string $nameField
|
|
||||||
* @param string $valueField
|
|
||||||
* @param integer|null $id
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private static function assertFieldIsUnique(string $nameField, string $valueField, ?int $id = null)
|
|
||||||
{
|
|
||||||
$table = (new self())->getTable();
|
|
||||||
ToolboxHelper::assertFieldIsUnique($table, $nameField, $valueField, $id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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¶m2=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 \RuntimeException 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();
|
|
||||||
|
|
||||||
$uri = $request->getUri();
|
|
||||||
if (app()->environment(['staging', 'production']) and Str::of($uri)->startsWith('http:')) {
|
|
||||||
$uri = (string)Str::of($uri)->replaceFirst('http:', 'https:');
|
|
||||||
}
|
|
||||||
$calculatedHash = ToolboxHelper::signRequest(
|
|
||||||
$this->bearer_pwd,
|
|
||||||
$uri,
|
|
||||||
$request->getMethod(),
|
|
||||||
$data
|
|
||||||
);
|
|
||||||
|
|
||||||
// ! Très important hash_equals https://fr.wikipedia.org/wiki/Attaque_temporelle
|
|
||||||
return \hash_equals($calculatedHash, $request->signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
// * RELATIONSHIPS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the brand that owns the service.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\Brand, $this>
|
|
||||||
*/
|
|
||||||
public function brand()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Brand::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use App\Traits\Models\ActivityLog;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Uwil\LaravelCommon\Helpers\FileHelper;
|
|
||||||
|
|
||||||
class Url extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
use ActivityLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'key',
|
|
||||||
'value',
|
|
||||||
'title',
|
|
||||||
'image_settings',
|
|
||||||
'logo',
|
|
||||||
'brand_id'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that should be cast.
|
|
||||||
*
|
|
||||||
* @var array<string, string>
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'image_settings' => 'array',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The "booted" method of the model.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected static function boot(): void
|
|
||||||
{
|
|
||||||
static::creating(function (self $model) {
|
|
||||||
$model->logo = FileHelper::storeFile($model, $model->logo, true);
|
|
||||||
});
|
|
||||||
static::updating(function (self $model) {
|
|
||||||
$model->logo = FileHelper::storeFile($model, $model->logo, true);
|
|
||||||
});
|
|
||||||
static::updated(function (self $model) {
|
|
||||||
FileHelper::removeOldFile($model, 'logo');
|
|
||||||
});
|
|
||||||
static::deleted(function (self $model) {
|
|
||||||
FileHelper::removeFile($model, 'logo');
|
|
||||||
});
|
|
||||||
parent::boot();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the brand that owns the url.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\Brand, $this>
|
|
||||||
*/
|
|
||||||
public function brand()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Brand::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the history for the url.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\UrlHistory, $this>
|
|
||||||
*/
|
|
||||||
public function history()
|
|
||||||
{
|
|
||||||
return $this->hasMany(UrlHistory::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class UrlHistory extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'value',
|
|
||||||
'start_date',
|
|
||||||
'end_date'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the url that owns the stats.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\Url, $this>
|
|
||||||
*/
|
|
||||||
public function url()
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Url::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class UrlStats extends Model
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'calls',
|
|
||||||
'date',
|
|
||||||
'url_key',
|
|
||||||
'url',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that should be cast.
|
|
||||||
*
|
|
||||||
* @var array<string, string>
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'date' => 'date',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any actions required after the model boots.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected static function booted(): void
|
|
||||||
{
|
|
||||||
static::creating(function (self $model) {
|
|
||||||
$model->calls = 1;
|
|
||||||
$model->date = now();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Traits\Models\ActivityLog;
|
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
|
||||||
use Illuminate\Notifications\Notifiable;
|
|
||||||
|
|
||||||
class User extends Authenticatable
|
|
||||||
{
|
|
||||||
use HasFactory;
|
|
||||||
use Notifiable;
|
|
||||||
use ActivityLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'firstname',
|
|
||||||
'lastname',
|
|
||||||
'email',
|
|
||||||
'role',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that should be hidden for serialization.
|
|
||||||
*
|
|
||||||
* @var list<string>
|
|
||||||
*/
|
|
||||||
protected $hidden = [
|
|
||||||
'remember_token',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that should be cast.
|
|
||||||
*
|
|
||||||
* @var array<string, string>
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
|
||||||
'role' => RoleEnum::class,
|
|
||||||
'last_connection' => 'date',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any actions required after the model boots.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected static function booted()
|
|
||||||
{
|
|
||||||
static::creating(function (self $model) {
|
|
||||||
self::checkElevationPrivileges($model);
|
|
||||||
});
|
|
||||||
static::updating(function (self $model) {
|
|
||||||
self::checkElevationPrivileges($model);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent user elevation privileges.
|
|
||||||
*
|
|
||||||
* @param self $user
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private static function checkElevationPrivileges(self $user): void
|
|
||||||
{
|
|
||||||
throw_if(
|
|
||||||
auth('backend')->user() and auth('backend')->user()->role->value() > $user->role->value(),
|
|
||||||
AuthorizationException::class
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get related brands or all the brands if the user is consceptor.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection<int, \App\Models\Brand>|
|
|
||||||
* \Illuminate\Database\Eloquent\Relations\BelongsToMany<\App\Models\Brand,
|
|
||||||
* $this,
|
|
||||||
* \Illuminate\Database\Eloquent\Relations\Pivot>
|
|
||||||
*/
|
|
||||||
public function getRelatedBrands()
|
|
||||||
{
|
|
||||||
return $this->role->equals(RoleEnum::conceptor) ?
|
|
||||||
Brand::all() :
|
|
||||||
$this->brands;
|
|
||||||
}
|
|
||||||
|
|
||||||
// * RELATIONSHIPS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The brands that belong to the user.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<\App\Models\Brand,
|
|
||||||
* $this,
|
|
||||||
* \Illuminate\Database\Eloquent\Relations\Pivot>
|
|
||||||
*/
|
|
||||||
public function brands(): BelongsToMany
|
|
||||||
{
|
|
||||||
return $this->belongsToMany(Brand::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Observers;
|
|
||||||
|
|
||||||
use App\Enums\ActivityLogs\ActivityLogsEventEnum;
|
|
||||||
use App\Models\ActivityLog;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class ModelObserver
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Handle the model "created" event.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Model $model
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function created(Model $model): void
|
|
||||||
{
|
|
||||||
ActivityLog::addActivity($model, ActivityLogsEventEnum::created);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the model "updated" event.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Model $model
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function updated(Model $model): void
|
|
||||||
{
|
|
||||||
ActivityLog::addActivity($model, ActivityLogsEventEnum::updated);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the model "duplicated" event.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Model $model
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function duplicated(Model $model): void
|
|
||||||
{
|
|
||||||
ActivityLog::addActivity($model, ActivityLogsEventEnum::duplicated);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the model "deleted" event.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Model $model
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function deleted(Model $model): void
|
|
||||||
{
|
|
||||||
ActivityLog::addActivity($model, ActivityLogsEventEnum::deleted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Policies;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Policies\Rules\UserStaticRules;
|
|
||||||
|
|
||||||
class BrandPolicy
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view any models.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function viewAny(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function view(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can create a new model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function create(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can update the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function update(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can delete the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function delete(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Policies\Rules;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Userlevel Policiy Static Rules
|
|
||||||
*
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
abstract class UserStaticRules
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Allow everyone.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static function everyOne(): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow no one.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static function noOne(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* At least a minimum role
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Model $authModel
|
|
||||||
* @param \App\Enums\Users\RoleEnum $minRole
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static function atLeastRole(Model $authModel, RoleEnum $minRole): bool
|
|
||||||
{
|
|
||||||
// phpcs:enable
|
|
||||||
return isset($authModel->role) && $authModel->role->value() <= $minRole->value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Policies;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Policies\Rules\UserStaticRules;
|
|
||||||
|
|
||||||
class ServicePolicy
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view any models.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function viewAny(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function view(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can create a new model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function create(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can update the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function update(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can delete the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function delete(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Policies;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\Url;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Policies\Rules\UserStaticRules;
|
|
||||||
|
|
||||||
class UrlPolicy
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view any models.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function viewAny(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::marketing);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @param \App\Models\Url $url
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function view(User $authUser, Url $url): bool
|
|
||||||
{
|
|
||||||
return (UserStaticRules::atLeastRole($authUser, RoleEnum::marketing) &&
|
|
||||||
\collect($authUser->brands->pluck('id'))->contains($url->brand->id)) ||
|
|
||||||
UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can create a new model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function create(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::marketing);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can update the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @param \App\Models\Url $url
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function update(User $authUser, Url $url): bool
|
|
||||||
{
|
|
||||||
return (UserStaticRules::atLeastRole($authUser, RoleEnum::marketing) &&
|
|
||||||
\collect($authUser->brands->pluck('id'))->contains($url->brand->id)) ||
|
|
||||||
UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can duplicate the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @param \App\Models\Url $url
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function duplicate(User $authUser, Url $url): bool
|
|
||||||
{
|
|
||||||
return (UserStaticRules::atLeastRole($authUser, RoleEnum::marketing) &&
|
|
||||||
\collect($authUser->brands->pluck('id'))->contains($url->brand->id)) ||
|
|
||||||
UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can delete the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function delete(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Policies;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Policies\Rules\UserStaticRules;
|
|
||||||
|
|
||||||
class UrlStatsPolicy
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view any models.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function viewAny(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function view(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can create a new model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function create(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can update the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function update(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can delete the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function delete(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Policies;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Policies\Rules\UserStaticRules;
|
|
||||||
|
|
||||||
class UserPolicy
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view any models.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function viewAny(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function view(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can create a new model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function create(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can update the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function update(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can delete the model.
|
|
||||||
*
|
|
||||||
* @param \App\Models\User $authUser
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function delete(User $authUser): bool
|
|
||||||
{
|
|
||||||
return UserStaticRules::atLeastRole($authUser, RoleEnum::conceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Providers;
|
|
||||||
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Illuminate\Support\Facades\App;
|
|
||||||
use Illuminate\Support\Facades\URL;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Bootstrap any application services.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot()
|
|
||||||
{
|
|
||||||
// * HTTPS FIX
|
|
||||||
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
|
|
||||||
setlocale(LC_ALL, \sprintf(
|
|
||||||
'%s_%s.UTF-8',
|
|
||||||
config('app.locale'),
|
|
||||||
\strtoupper(config('app.locale'))
|
|
||||||
));
|
|
||||||
Carbon::setLocale(config('app.locale'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Providers;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\Service;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|
||||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Gate;
|
|
||||||
|
|
||||||
class AuthServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Register any authentication / authorization services.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot()
|
|
||||||
{
|
|
||||||
$this->registerPolicies();
|
|
||||||
|
|
||||||
Gate::define('isConceptor', function (Model $authModel) {
|
|
||||||
return isset($authModel->role) && $authModel->role === RoleEnum::conceptor;
|
|
||||||
});
|
|
||||||
|
|
||||||
Auth::viaRequest('api-hmac', function (Request $request) {
|
|
||||||
$service = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// * On récupère le service actuel correspondant au token fourni.
|
|
||||||
$service = Service::query()->where('bearer_token', $request->input('bearer_token'))->firstOrFail();
|
|
||||||
} catch (ModelNotFoundException $e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// * On authenticate la request en vérifiant sa signature.
|
|
||||||
if ($service->authenticateApi($request)) {
|
|
||||||
return $service;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Providers;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Auth\Events\Registered;
|
|
||||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
|
||||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\Facades\Event;
|
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
use Slides\Saml2\Events\SignedIn;
|
|
||||||
|
|
||||||
class EventServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The event listener mappings for the application.
|
|
||||||
*
|
|
||||||
* @var array<class-string, array<int, class-string>>
|
|
||||||
*/
|
|
||||||
protected $listen = [
|
|
||||||
Registered::class => [
|
|
||||||
SendEmailVerificationNotification::class,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if events and listeners should be automatically discovered.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function shouldDiscoverEvents(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register any events for your application.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot()
|
|
||||||
{
|
|
||||||
Event::listen('Slides\Saml2\Events\SignedIn', function (SignedIn $event) {
|
|
||||||
$messageId = $event->getAuth()->getLastMessageId();
|
|
||||||
|
|
||||||
if (Cache::get(config('cache.prefix') . "_saml_message_id_" . $messageId)) {
|
|
||||||
logger()->error(
|
|
||||||
'SAML MESSAGE ID HANDLER',
|
|
||||||
['error' => 'Message ID : ' . $messageId . " replayed !"]
|
|
||||||
);
|
|
||||||
abort(403);
|
|
||||||
} else {
|
|
||||||
// Cache for 8h.
|
|
||||||
Cache::put(config('cache.prefix') . "_saml_message_id_" . $messageId, $messageId, 28800);
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = $event->getSaml2User();
|
|
||||||
$email = $user->getNameId();
|
|
||||||
$lUser = User::query()->where('email', $email)->first();
|
|
||||||
|
|
||||||
if (!$lUser) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
Auth::guard('backend')->login($lUser);
|
|
||||||
session(['sessionIndex' => $user->getSessionIndex()]);
|
|
||||||
$lUser->last_connection = now();
|
|
||||||
$lUser->saveQuietly();
|
|
||||||
});
|
|
||||||
|
|
||||||
Event::listen('Slides\Saml2\Events\SignedOut', function () {
|
|
||||||
Auth::guard('backend')->logout();
|
|
||||||
Session::save();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Providers;
|
|
||||||
|
|
||||||
use App\Models\Service;
|
|
||||||
use Illuminate\Cache\RateLimiting\Limit;
|
|
||||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\RateLimiter;
|
|
||||||
use Illuminate\Support\Facades\Route;
|
|
||||||
|
|
||||||
class RouteServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The path to the "home" route for your application.
|
|
||||||
*
|
|
||||||
* This is used by Laravel authentication to redirect users after login.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public const HOME = '/';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define your route model bindings, pattern filters, etc.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot()
|
|
||||||
{
|
|
||||||
$this->configureRateLimiting();
|
|
||||||
|
|
||||||
$this->cspReportRoute();
|
|
||||||
|
|
||||||
$this->routes(function () {
|
|
||||||
Route::middleware('web')
|
|
||||||
->namespace($this->namespace)
|
|
||||||
->group(base_path('routes/web-bo.php'));
|
|
||||||
|
|
||||||
Route::middleware('web')
|
|
||||||
->namespace($this->namespace)
|
|
||||||
->group(base_path('routes/web-fo.php'));
|
|
||||||
|
|
||||||
Route::middleware('api')
|
|
||||||
->namespace($this->namespace)
|
|
||||||
->group(base_path('routes/api.php'));
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::model('service', Service::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the rate limiters for the application.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function configureRateLimiting()
|
|
||||||
{
|
|
||||||
RateLimiter::for('api', function (Request $request) {
|
|
||||||
return Limit::perMinute(150)->by(optional($request->user())->id ?: app('clientIp'));
|
|
||||||
});
|
|
||||||
RateLimiter::for('web', function (Request $request) {
|
|
||||||
return Limit::perMinute(150)->by(optional($request->user())->id ?: app('clientIp'));
|
|
||||||
});
|
|
||||||
RateLimiter::for('credentials', function (Request $request) {
|
|
||||||
return Limit::perMinute(30)->by(optional($request->user())->id ?: $request->ip());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * Register CSP report URI
|
|
||||||
*
|
|
||||||
* Put this function inside RouteServiceProvider,
|
|
||||||
* and call it in RouteServiceProvider::boot
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function cspReportRoute()
|
|
||||||
{
|
|
||||||
// * CSP REPORT URI, Please add /csp-report to VerifyCsrfToken $except middleware
|
|
||||||
\Illuminate\Support\Facades\Route::post('/csp-report', function () {
|
|
||||||
$isCspRequest = request()->header('Content-Type') === 'application/csp-report';
|
|
||||||
if (!$isCspRequest or !request()->json('csp-report') or !is_array(request()->json('csp-report'))) {
|
|
||||||
abort(401);
|
|
||||||
}
|
|
||||||
// * Flatten if needed
|
|
||||||
$cspReport = collect(request()->json('csp-report'))
|
|
||||||
->flatMap(function ($v, $k) {
|
|
||||||
return [$k => is_array($v) ? collect($v)->flatten()->implode(', ') : $v];
|
|
||||||
})->all();
|
|
||||||
// * Filter array keys
|
|
||||||
$cspReport = collect(array_intersect_key($cspReport, [
|
|
||||||
'blocked-uri' => '', 'document-uri' => '', 'original-policy' => '',
|
|
||||||
'referrer' => '', 'violated-directive' => ''
|
|
||||||
]));
|
|
||||||
\Illuminate\Support\Facades\Log::warning(sprintf(
|
|
||||||
"CSP REPORT for %s : \n %s",
|
|
||||||
$cspReport->get('document-uri'),
|
|
||||||
$cspReport->implode("\n")
|
|
||||||
));
|
|
||||||
})->middleware('throttle:5,2')
|
|
||||||
->withoutMiddleware(\App\Http\Middleware\VerifyCsrfToken::class)
|
|
||||||
->name('cspReportUri');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Providers;
|
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\File;
|
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
|
||||||
use Symfony\Component\Finder\SplFileInfo;
|
|
||||||
|
|
||||||
class TranslationServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Bootstrap the application services.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot()
|
|
||||||
{
|
|
||||||
foreach ($this->collectLocalesStrings() as $locale) {
|
|
||||||
// * Suported locales
|
|
||||||
Cache::rememberForever(sprintf('translations.%s', $locale), function () use ($locale) {
|
|
||||||
$translations = [
|
|
||||||
'php' => $this->phpTranslations($locale),
|
|
||||||
'json' => $this->jsonTranslations($locale),
|
|
||||||
];
|
|
||||||
return $translations;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gather provided langs checking from files
|
|
||||||
*
|
|
||||||
* @return Collection
|
|
||||||
*/
|
|
||||||
private function collectLocalesStrings(): Collection
|
|
||||||
{
|
|
||||||
return collect(File::allFiles(resource_path('lang/')))->flatMap(function (SplFileInfo $file) {
|
|
||||||
if ($file->getRelativePath() and \strpos($file->getRelativePath(), 'vendor') !== 0) {
|
|
||||||
return [$file->getRelativePath() => ''];
|
|
||||||
}
|
|
||||||
})->keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gather all php translations
|
|
||||||
*
|
|
||||||
* @param string $locale
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function phpTranslations(string $locale): array
|
|
||||||
{
|
|
||||||
$path = resource_path("lang/$locale");
|
|
||||||
|
|
||||||
return collect(File::allFiles($path))->flatMap(function ($file) use ($locale) {
|
|
||||||
$translation = $file->getBasename('.php');
|
|
||||||
return [$translation => trans($translation, [], $locale)];
|
|
||||||
})->all();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gather json translations
|
|
||||||
*
|
|
||||||
* @param string $locale
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function jsonTranslations(string $locale): array
|
|
||||||
{
|
|
||||||
$path = resource_path("lang/$locale.json");
|
|
||||||
|
|
||||||
if (!File::exists($path) or !File::isReadable($path)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return json_decode(File::get($path), true) ?? [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Providers;
|
|
||||||
|
|
||||||
use Illuminate\Pagination\Paginator;
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
|
||||||
|
|
||||||
class ViewServiceProvider extends ServiceProvider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Bootstrap any application services.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function boot()
|
|
||||||
{
|
|
||||||
if (!app()->runningInConsole()) {
|
|
||||||
// * FORCE BOOTSTRAP PAGINATOR (or custom if in front)
|
|
||||||
// Early boot, request wont be filled as expected.
|
|
||||||
switch (collect(explode('/', \request()->getPathInfo()))->get(1)) {
|
|
||||||
case 'bo':
|
|
||||||
Paginator::defaultView('bo.modules.pagination');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Paginator::useBootstrapFive();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} //end if
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Traits\Models;
|
|
||||||
|
|
||||||
use App\Observers\ModelObserver;
|
|
||||||
use App\Models\ActivityLog as ActivityLogModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If there is a static function in a trait (named boot[TraitName]),
|
|
||||||
* it will be executed as the boot() function would on an Eloquent model.
|
|
||||||
* Futhermore, event in the Model observer doesn't erase actual events in the model,
|
|
||||||
* but adds them.
|
|
||||||
*/
|
|
||||||
trait ActivityLog
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function bootActivityLog(): void
|
|
||||||
{
|
|
||||||
static::observe(ModelObserver::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
// * RELATIONS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activities logs HasMany relationship.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
|
||||||
*/
|
|
||||||
public function activityLogs(): \Illuminate\Database\Eloquent\Relations\HasMany
|
|
||||||
{
|
|
||||||
return $this->hasMany(ActivityLogModel::class, 'model_id')->with('user');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Traits\Requests;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Illuminate\Support\Facades\File;
|
|
||||||
|
|
||||||
|
|
||||||
trait HasPictureWithSvgSupport
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Minimum width
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $minWidth = 400;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum width
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $maxWidth = 1800;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimum height
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $minHeight = 300;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum height
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
private $maxHeight = 1800;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Image rules
|
|
||||||
*
|
|
||||||
* @param string $name
|
|
||||||
* @param integer|null $minWidth
|
|
||||||
* @param integer|null $minHeight
|
|
||||||
* @param integer|null $maxWidth
|
|
||||||
* @param integer|null $maxHeight
|
|
||||||
* @param boolean $nullable
|
|
||||||
* @param integer|null $size
|
|
||||||
* @param string|null $requiredWith
|
|
||||||
* @param string|null $requiredWithout
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function pictureRulesWithSvgSupport(
|
|
||||||
string $name = 'picture',
|
|
||||||
?int $minWidth = null,
|
|
||||||
?int $minHeight = null,
|
|
||||||
?int $maxWidth = null,
|
|
||||||
?int $maxHeight = null,
|
|
||||||
bool $nullable = false,
|
|
||||||
?int $size = null,
|
|
||||||
?string $requiredWith = null,
|
|
||||||
?string $requiredWithout = null,
|
|
||||||
): array {
|
|
||||||
$dimensions = (object)[
|
|
||||||
'minWidth' => $minWidth ?? $this->minWidth,
|
|
||||||
'minHeight' => $minHeight ?? $this->minHeight,
|
|
||||||
'maxWidth' => $maxWidth ?? $this->maxWidth,
|
|
||||||
'maxHeight' => $maxHeight ?? $this->maxHeight
|
|
||||||
];
|
|
||||||
return [
|
|
||||||
$name => [
|
|
||||||
!$nullable ? 'required' : 'nullable',
|
|
||||||
(strlen($requiredWith)) ? 'required_with:' . $requiredWith : '',
|
|
||||||
(strlen($requiredWithout)) ? 'required_without:' . $requiredWithout : '',
|
|
||||||
($size) ? 'max:' . $size : '',
|
|
||||||
function (string $attribute, $value, callable $fail) use ($dimensions) {
|
|
||||||
self::validatePicture($attribute, $value, $fail, $dimensions);
|
|
||||||
}
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate picture
|
|
||||||
*
|
|
||||||
* @param string $attribute
|
|
||||||
* @param string|null $value
|
|
||||||
* @param callable $fail
|
|
||||||
* @param object $sizes
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function validatePicture(string $attribute, string|null $value, callable $fail, object $sizes): void
|
|
||||||
{
|
|
||||||
if (!($useStorage = Storage::exists($value)) && !File::exists($value)) {
|
|
||||||
$fail(trans(':attribute n\'existe pas dans le système de fichier', [
|
|
||||||
'attribute' => $attribute
|
|
||||||
]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$fileFullPath = self::getUploadedFileFullPath($value, $useStorage);
|
|
||||||
if (
|
|
||||||
!\in_array(self::getUploadedFileMimeType($value, $useStorage), [
|
|
||||||
'image/jpeg',
|
|
||||||
'image/jpg',
|
|
||||||
'image/png',
|
|
||||||
'image/gif',
|
|
||||||
'image/svg+xml'
|
|
||||||
])
|
|
||||||
) {
|
|
||||||
$fail(trans(':attribute doit être une image de type \'image/jpeg,image/jpg,image/png,image/gif\',image/svg\'', [
|
|
||||||
'attribute' => $attribute
|
|
||||||
]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::getUploadedFileMimeType($value, $useStorage) !== "image/svg+xml") {
|
|
||||||
if (!($dimensions = \getimagesize($fileFullPath))) {
|
|
||||||
$fail(trans(':attribute impossible de valider les dimensions', [
|
|
||||||
'attribute' => $attribute
|
|
||||||
]));
|
|
||||||
} else {
|
|
||||||
$width = intval($dimensions[0]);
|
|
||||||
$height = intval($dimensions[1]);
|
|
||||||
|
|
||||||
$xMessage = trans(
|
|
||||||
":attribute la largeur doit être comprise entre {$sizes->minWidth}px et {$sizes->maxWidth}px"
|
|
||||||
);
|
|
||||||
if ($sizes->minWidth === $sizes->maxWidth) {
|
|
||||||
$xMessage = trans(":attribute la largeur doit être de {$sizes->minWidth}px");
|
|
||||||
}
|
|
||||||
$yMessage = trans(
|
|
||||||
":attribute la hauteur doit être comprise entre {$sizes->minHeight}px et {$sizes->maxHeight}px"
|
|
||||||
);
|
|
||||||
if ($sizes->minHeight === $sizes->maxHeight) {
|
|
||||||
$yMessage = trans(":attribute la hauteur doit être de {$sizes->minHeight}px");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($width < $sizes->minWidth) || ($width > $sizes->maxWidth)) {
|
|
||||||
$fail($xMessage);
|
|
||||||
}
|
|
||||||
if (($height < $sizes->minHeight) || ($height > $sizes->maxHeight)) {
|
|
||||||
$fail($yMessage);
|
|
||||||
}
|
|
||||||
} //end if
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the file full path
|
|
||||||
*
|
|
||||||
* @param string $value
|
|
||||||
* @param boolean $useStorage
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private static function getUploadedFileFullPath(string $value, bool $useStorage): string
|
|
||||||
{
|
|
||||||
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
|
||||||
$disk = Storage::disk();
|
|
||||||
return !$useStorage ? (realpath($value) ?: $value) : $disk->path($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the file mimetype
|
|
||||||
*
|
|
||||||
* @param string $value
|
|
||||||
* @param boolean $useStorage
|
|
||||||
* @return string|false
|
|
||||||
*/
|
|
||||||
private static function getUploadedFileMimeType(string $value, bool $useStorage)
|
|
||||||
{
|
|
||||||
return !$useStorage ? File::mimeType($value) : Storage::mimeType($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
53
artisan
53
artisan
|
|
@ -1,53 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
define('LARAVEL_START', microtime(true));
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Register The Auto Loader
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Composer provides a convenient, automatically generated class loader
|
|
||||||
| for our application. We just need to utilize it! We'll require it
|
|
||||||
| into the script here so that we do not have to worry about the
|
|
||||||
| loading of any of our classes manually. It's great to relax.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
require __DIR__.'/vendor/autoload.php';
|
|
||||||
|
|
||||||
$app = require_once __DIR__.'/bootstrap/app.php';
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Run The Artisan Application
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| When we run the console application, the current CLI command will be
|
|
||||||
| executed in this console and the response sent back to a terminal
|
|
||||||
| or another output device for the developers. Here goes nothing!
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
|
||||||
|
|
||||||
$status = $kernel->handle(
|
|
||||||
$input = new Symfony\Component\Console\Input\ArgvInput,
|
|
||||||
new Symfony\Component\Console\Output\ConsoleOutput
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Shutdown The Application
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Once Artisan has finished running, we will fire off the shutdown events
|
|
||||||
| so that any final work may be done by the application before we shut
|
|
||||||
| down the process. This is the last thing to happen to the request.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
$kernel->terminate($input, $status);
|
|
||||||
|
|
||||||
exit($status);
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Create The Application
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The first thing we will do is create a new Laravel application instance
|
|
||||||
| which serves as the "glue" for all the components of Laravel, and is
|
|
||||||
| the IoC container for the system binding all of the various parts.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
$app = new Illuminate\Foundation\Application(
|
|
||||||
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Bind Important Interfaces
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Next, we need to bind some important interfaces into the container so
|
|
||||||
| we will be able to resolve them when needed. The kernels serve the
|
|
||||||
| incoming requests to this application from both the web and CLI.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
$app->singleton(
|
|
||||||
Illuminate\Contracts\Http\Kernel::class,
|
|
||||||
App\Http\Kernel::class
|
|
||||||
);
|
|
||||||
|
|
||||||
$app->singleton(
|
|
||||||
Illuminate\Contracts\Console\Kernel::class,
|
|
||||||
App\Console\Kernel::class
|
|
||||||
);
|
|
||||||
|
|
||||||
$app->singleton(
|
|
||||||
Illuminate\Contracts\Debug\ExceptionHandler::class,
|
|
||||||
App\Exceptions\Handler::class
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Return The Application
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This script returns the application instance. The instance is given to
|
|
||||||
| the calling script so we can separate the building of the instances
|
|
||||||
| from the actual running of the application and sending responses.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
return $app;
|
|
||||||
2
bootstrap/cache/.gitignore
vendored
2
bootstrap/cache/.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
*
|
|
||||||
!.gitignore
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
module.exports = require('@uwil/husky-config/commitlint.config.cjs');
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
{
|
|
||||||
"name": "uwil/qrcollector-back",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"type": "project",
|
|
||||||
"description": "Administration interface for QRCollector",
|
|
||||||
"license": "MIT",
|
|
||||||
"require": {
|
|
||||||
"php": "^8.5",
|
|
||||||
"24slides/laravel-saml2": "^2.4",
|
|
||||||
"diglactic/laravel-breadcrumbs": "^10.0",
|
|
||||||
"guzzlehttp/guzzle": "^7.5.0",
|
|
||||||
"icehouse-ventures/laravel-chartjs": "^4.2",
|
|
||||||
"kwaadpepper/image-resizer": "^3.0",
|
|
||||||
"laravel/framework": "^12.0",
|
|
||||||
"laravel/tinker": "^2.5",
|
|
||||||
"laravel/ui": "^4.0",
|
|
||||||
"mews/purifier": "^3.4",
|
|
||||||
"mistic100/randomcolor": "^1.0",
|
|
||||||
"sentry/sentry-laravel": "^4.20",
|
|
||||||
"uwil/admin-secure-laravel": "^5.0",
|
|
||||||
"uwil/k8s-laravel": "^2.0",
|
|
||||||
"uwil/laravel-common": "^4.1"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"fakerphp/faker": "^1.9.1",
|
|
||||||
"larastan/larastan": "^3.9",
|
|
||||||
"laravel/sail": "^1.18",
|
|
||||||
"mockery/mockery": "^1.4.4",
|
|
||||||
"nunomaduro/collision": "^8.1",
|
|
||||||
"phpunit/phpunit": "^11.0",
|
|
||||||
"slevomat/coding-standard": "^8.10"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"App\\": "app/",
|
|
||||||
"Database\\Factories\\": "database/factories/",
|
|
||||||
"Database\\Seeders\\": "database/seeders/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload-dev": {
|
|
||||||
"psr-4": {
|
|
||||||
"Tests\\": "tests/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"post-autoload-dump": [
|
|
||||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
|
||||||
"@php artisan package:discover --ansi"
|
|
||||||
],
|
|
||||||
"post-update-cmd": [
|
|
||||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
|
||||||
],
|
|
||||||
"post-root-package-install": [
|
|
||||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
|
||||||
],
|
|
||||||
"post-create-project-cmd": [
|
|
||||||
"@php artisan key:generate --ansi"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"extra": {
|
|
||||||
"laravel": {
|
|
||||||
"dont-discover": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"optimize-autoloader": true,
|
|
||||||
"preferred-install": "dist",
|
|
||||||
"sort-packages": true,
|
|
||||||
"allow-plugins": {
|
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": true,
|
|
||||||
"php-http/discovery": true
|
|
||||||
},
|
|
||||||
"gitlab-domains": [
|
|
||||||
"lab.s-web.fr"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"minimum-stability": "dev",
|
|
||||||
"prefer-stable": true,
|
|
||||||
"repositories": {
|
|
||||||
"lab.s-web.fr": {
|
|
||||||
"type": "composer",
|
|
||||||
"url": "https://lab.s-web.fr/api/v4/group/23/-/packages/composer/packages.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue