Compare commits
100 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa2579bb58 | ||
|
|
fa19add314 | ||
|
|
d9834acbe0 | ||
|
|
aca6082fc3 | ||
|
|
6fc7ce4144 | ||
|
|
c5b0154a78 | ||
|
|
d9855a6aa7 | ||
|
|
b5851d75b4 | ||
|
|
919550c1f2 | ||
|
|
ade271b88b | ||
|
|
d67440770a | ||
|
|
39ff3e0fd8 | ||
|
|
fd936efebb | ||
|
|
202fcf73c9 | ||
|
|
706fb14dff | ||
|
|
cef4f9764c | ||
|
|
220cbe642a | ||
|
|
d0b5805676 | ||
|
|
34d919ee69 | ||
|
|
7b8000f9ba | ||
|
|
0e504be45f | ||
|
|
42f3f08172 | ||
|
|
941c10b6f2 | ||
|
|
3eed68a9c3 | ||
|
|
a2e0a60d08 | ||
|
|
3ead13a5a1 | ||
|
|
597f5f91cf | ||
|
|
eeea8014d0 | ||
|
|
0f87cb1ee4 | ||
|
|
77a2b3f12d | ||
|
|
051cb55324 | ||
|
|
b49d34ee07 | ||
|
|
d80863c9a7 | ||
|
|
5bba7b87f4 | ||
|
|
b999d29bb1 | ||
|
|
3ce421aff9 | ||
|
|
615cc69892 | ||
|
|
8be12b6e9e | ||
|
|
39631fb272 | ||
|
|
02bcda59e3 | ||
|
|
080e4f5959 | ||
|
|
cfe84bb9f8 | ||
|
|
bc0c018995 | ||
|
|
74d89da1fa | ||
|
|
7be9395ae4 | ||
|
|
304f3b4e7f | ||
|
|
ded2a8da88 | ||
|
|
a9925ee8dc | ||
|
|
b569e4ae43 | ||
|
|
24b0c449c5 | ||
|
|
b08b0d49cc | ||
|
|
773924c250 | ||
|
|
7b8216fc33 | ||
|
|
fb1f641bb2 | ||
|
|
73615cdf1f | ||
|
|
adf5717110 | ||
|
|
3b93c4c49b | ||
|
|
0121ee8bdb | ||
|
|
8696765b7e | ||
|
|
728568d812 | ||
|
|
d4c72ed804 | ||
|
|
122151da28 | ||
|
|
5f372c71cd | ||
|
|
7bc2b900c1 | ||
|
|
f0f1458a0d | ||
|
|
ffe16335e5 | ||
|
|
5035732542 | ||
|
|
14cc8dd5b3 | ||
|
|
6613606575 | ||
|
|
b59672f465 | ||
|
|
ecadc53170 | ||
|
|
741d4be1bf | ||
|
|
a978e6536c | ||
|
|
d51c40b17e | ||
|
|
56e9c03574 | ||
|
|
8d1156382c | ||
|
|
ea87502ba4 | ||
|
|
2e8ca74962 | ||
|
|
d393b39d98 | ||
|
|
b13a4ced30 | ||
|
|
b5d46f54ee | ||
|
|
49cef77cb8 | ||
|
|
ec031ec3ec | ||
|
|
eb642c85eb | ||
|
|
e173a6670b | ||
|
|
8860afc566 | ||
|
|
ebc8e37b28 | ||
|
|
3021f60054 | ||
|
|
3f3ab0df5e | ||
|
|
1342a97f9c | ||
|
|
7d0541abdf | ||
|
|
a60e562ce8 | ||
|
|
5ae59be976 | ||
|
|
5ace87520e | ||
|
|
16cd1d09fd | ||
|
|
ea9924faa1 | ||
|
|
930457e5ee | ||
|
|
ddc9b57c5f | ||
|
|
636918b9d5 | ||
|
|
5563dc1814 |
358 changed files with 23698 additions and 21662 deletions
13
.browserslistrc
Normal file
13
.browserslistrc
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Browsers that we support
|
||||
|
||||
# https://github.com/browserslist/browserslist#readme
|
||||
|
||||
>= 0.5%
|
||||
last 2 major versions
|
||||
not dead
|
||||
Chrome >= 60
|
||||
Firefox >= 60
|
||||
Firefox ESR
|
||||
iOS >= 12
|
||||
Safari >= 12
|
||||
not Explorer <= 11
|
||||
16
.dockerignore
Normal file
16
.dockerignore
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
.git
|
||||
*.md
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
.npmrc
|
||||
tests/
|
||||
Dockerfile*
|
||||
.dockerignore
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
LICENSE
|
||||
.vscode
|
||||
vendor/
|
||||
public/build/
|
||||
auth.json
|
||||
|
|
@ -3,9 +3,9 @@ root = true
|
|||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
|
|
@ -14,8 +14,8 @@ trim_trailing_whitespace = false
|
|||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.vue]
|
||||
indent_size = 2
|
||||
|
||||
[docker-compose.yml]
|
||||
indent_size = 4
|
||||
|
||||
[*.vue]
|
||||
indent_size = 2
|
||||
|
|
|
|||
18
.env.example
18
.env.example
|
|
@ -5,8 +5,6 @@ APP_DEBUG=true
|
|||
APP_URL=http://localhost
|
||||
API_TOKEN=toto
|
||||
|
||||
BRAND=
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
|
@ -33,10 +31,20 @@ MAIL_PASSWORD=null
|
|||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=null
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
MAIL_ADMIN_ADDRESS=null
|
||||
|
||||
# SENTRY
|
||||
SENTRY_LARAVEL_DSN=
|
||||
|
||||
# LDC WEB STATUS CHECKER
|
||||
LDC_STATUS_CHECKER_API_KEY="MY_KEY"
|
||||
LDC_STATUS_CHECKER_UUID="UUID_PROJECT"
|
||||
# SAML
|
||||
SAML2_DEFAULT_TENANT_UUID=
|
||||
SAML2_SP_CERT_x509=
|
||||
SAML2_SP_CERT_PRIVATEKEY=
|
||||
SAML2_CONTACT_TECHNICAL_EMAIL=
|
||||
SAML2_CONTACT_SUPPORT_EMAIL=
|
||||
|
||||
# UWIL ADMIN SECURE
|
||||
# - LIST SEPARATED WITH ',' (Required)
|
||||
UWIL_ADMIN_SECURE_CIDR_LIST=""
|
||||
# - LIST SEPARATED WITH ',' (Optional)
|
||||
UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST=""
|
||||
|
|
|
|||
|
|
@ -29,7 +29,14 @@
|
|||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["vue", "@typescript-eslint"],
|
||||
"ignorePatterns": ["webpack.mix.js", "**/vendor/*.js", "**/vendor/**/*.js"],
|
||||
"ignorePatterns": [
|
||||
"webpack.mix.js",
|
||||
"**/*.php",
|
||||
"**/*.svg",
|
||||
"**/vendor/*.js",
|
||||
"**/vendor/**/*.js",
|
||||
"**/vendor/**/*.scss"
|
||||
],
|
||||
"rules": {
|
||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
|
|
@ -37,5 +44,19 @@
|
|||
"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"]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
3
.gitattributes
vendored
3
.gitattributes
vendored
|
|
@ -1,4 +1,4 @@
|
|||
* text=auto
|
||||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
|
|
@ -8,3 +8,4 @@
|
|||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
.styleci.yml export-ignore
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -25,3 +25,6 @@ npm-debug.log
|
|||
yarn-error.log
|
||||
.vscode/settings.json
|
||||
.npmrc
|
||||
.zshrc
|
||||
.composer/
|
||||
.npm/
|
||||
23
.gitlab-ci.yml
Normal file
23
.gitlab-ci.yml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
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
|
||||
11
.gitlab/issue_templates/bug.md
Normal file
11
.gitlab/issue_templates/bug.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
## Comportement constaté
|
||||
|
||||
|
||||
## Comportement attendu
|
||||
|
||||
|
||||
## Solution envisagée
|
||||
|
||||
|
||||
## Étapes pour la reproduction du bug
|
||||
*
|
||||
7
.gitlab/issue_templates/feature.md
Normal file
7
.gitlab/issue_templates/feature.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
## Présentation du besoin
|
||||
|
||||
|
||||
## Implémentation
|
||||
|
||||
|
||||
## Maquettes, documentations...
|
||||
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
|
||||
|
|
@ -18,8 +18,7 @@
|
|||
],
|
||||
"customSyntax": "postcss-scss",
|
||||
"rules": {
|
||||
"indentation": 4,
|
||||
"string-quotes": "double",
|
||||
"declaration-property-value-no-unknown": true,
|
||||
"selector-max-id": null,
|
||||
"color-no-invalid-hex": true,
|
||||
"order/properties-alphabetical-order": null,
|
||||
|
|
|
|||
46
Dockerfile
Normal file
46
Dockerfile
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
FROM composer:2.8 AS vendor
|
||||
|
||||
ARG GITLAB_USER
|
||||
ARG GITLAB_PASSWORD
|
||||
ARG PHP_8_5_TAG=latest
|
||||
|
||||
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/
|
||||
COPY --from=vendor /app/vendor/ /app/vendor/
|
||||
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 ci && 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}
|
||||
|
|
@ -8,3 +8,6 @@
|
|||
|
||||
- continue migrations :
|
||||
`php artisan migrate`
|
||||
|
||||
TODO:
|
||||
- sur les méthodes GET le token est visible dans les logs server..
|
||||
|
|
|
|||
|
|
@ -6,44 +6,42 @@ use App\Enums\Formularies\InputTypeEnum;
|
|||
use App\Lib\Inputs\Definition\Input;
|
||||
use App\Lib\Inputs\Definition\InputData;
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AsInput implements CastsAttributes
|
||||
{
|
||||
/**
|
||||
* Cast the given value.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param array $attributes
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param array $attributes
|
||||
* @return \App\Lib\Inputs\Definition\Input
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
|
||||
*/
|
||||
public function get($model, string $key, $value, array $attributes): Input
|
||||
public function get(Model $model, string $key, mixed $value, array $attributes): Input
|
||||
{
|
||||
// phpcs:enable
|
||||
/** @var string $class */
|
||||
/** @var array<integer|string|boolean> $data */
|
||||
/** @var array<string, integer|string|boolean> $inputData */
|
||||
$inputData = \json_decode($value, true);
|
||||
$inputClass = InputTypeEnum::make($inputData['type'])->inputClass;
|
||||
$inputClass = InputTypeEnum::make($inputData['type'])->getInputClass();
|
||||
return $inputClass::from(InputData::make(...\array_values($inputData)), $inputData['required'] ?? false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given value for storage.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param \App\Lib\Inputs\Definition\Input $value
|
||||
* @param array $attributes
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param array $attributes
|
||||
* @return string Json encoded \App\Lib\Inputs\Definition\Input
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
|
||||
*/
|
||||
public function set($model, string $key, $value, array $attributes)
|
||||
public function set(Model $model, string $key, mixed $value, array $attributes): string
|
||||
{
|
||||
// phpcs:enable
|
||||
$this->assertIsInput($value);
|
||||
|
|
@ -53,11 +51,12 @@ class AsInput implements CastsAttributes
|
|||
|
||||
/**
|
||||
* Assert is instance of \App\Lib\Inputs\Definition\Input
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @throws \RuntimeException If the value is not an input.
|
||||
*/
|
||||
private function assertIsInput($value): void
|
||||
private function assertIsInput(mixed $value): void
|
||||
{
|
||||
if (!\is_object($value) or !\in_array(Input::class, \class_parents($value))) {
|
||||
$value = \json_encode($value);
|
||||
|
|
|
|||
|
|
@ -28,37 +28,30 @@ class CreateAdmin extends Command
|
|||
protected $description = 'Create a backend admin user';
|
||||
|
||||
/**
|
||||
* The firstname of the new user.
|
||||
* The first name of the new user.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $firstname;
|
||||
protected $first_name;
|
||||
|
||||
/**
|
||||
* The lastname of the new user.
|
||||
* The last name of the new user.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $lastname;
|
||||
protected $last_name;
|
||||
|
||||
/**
|
||||
* The email of the new user.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $email;
|
||||
|
||||
/**
|
||||
* The password of the new user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $password;
|
||||
|
||||
/**
|
||||
* The role of the new user.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $role;
|
||||
|
||||
|
|
@ -67,30 +60,26 @@ class CreateAdmin extends Command
|
|||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function handle()
|
||||
public function handle(): int
|
||||
{
|
||||
$this->firstname = null;
|
||||
$this->first_name = null;
|
||||
$this->addFirstname();
|
||||
|
||||
$this->lastname = null;
|
||||
$this->last_name = null;
|
||||
$this->addLastname();
|
||||
|
||||
$this->email = null;
|
||||
$this->addEmail();
|
||||
|
||||
$this->password = null;
|
||||
$this->addPassword();
|
||||
|
||||
$this->role = null;
|
||||
$this->addRole();
|
||||
|
||||
$user = new User([
|
||||
'firstname' => $this->firstname,
|
||||
'lastname' => $this->lastname,
|
||||
'email' => $this->email,
|
||||
'first_name' => $this->first_name,
|
||||
'last_name' => $this->last_name,
|
||||
'email' => $this->email,
|
||||
'email_verified_at' => now(),
|
||||
'password' => $this->password,
|
||||
'role' => $this->role
|
||||
'role' => $this->role,
|
||||
]);
|
||||
$user->saveOrFail();
|
||||
|
||||
|
|
@ -106,14 +95,14 @@ class CreateAdmin extends Command
|
|||
*/
|
||||
private function addFirstname(): void
|
||||
{
|
||||
while (is_null($this->firstname)) {
|
||||
while (is_null($this->first_name)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user firstname', 'Admin');
|
||||
$validator = Validator::make(['firstname' => $tmp], [
|
||||
'firstname' => 'required|min:3|max:255'
|
||||
]);
|
||||
$validator->validate();
|
||||
$this->firstname = $tmp;
|
||||
$this->first_name = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please provide a valid firstname %s',
|
||||
|
|
@ -131,14 +120,14 @@ class CreateAdmin extends Command
|
|||
*/
|
||||
private function addLastname(): void
|
||||
{
|
||||
while (is_null($this->lastname)) {
|
||||
while (is_null($this->last_name)) {
|
||||
try {
|
||||
$tmp = $this->ask('Type the wanted user lastname', 'Saïtama');
|
||||
$validator = Validator::make(['lastname' => $tmp], [
|
||||
'lastname' => 'required|min:3|max:255'
|
||||
]);
|
||||
$validator->validate();
|
||||
$this->lastname = $tmp;
|
||||
$this->last_name = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please provide a valid lastname %s',
|
||||
|
|
@ -174,22 +163,6 @@ class CreateAdmin extends Command
|
|||
}; //end while
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a password to the user.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addPassword(): void
|
||||
{
|
||||
while (
|
||||
($this->password = $this->secret(
|
||||
(!\is_null($this->password) ? 'Failed to confirm, ' : '') . 'Type the wanted user password'
|
||||
)) !== $this->secret('Confirm the password')
|
||||
) {
|
||||
continue;
|
||||
}; //end while
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a role to the user.
|
||||
*
|
||||
|
|
@ -201,16 +174,16 @@ class CreateAdmin extends Command
|
|||
try {
|
||||
$tmp = $this->choice(
|
||||
'Select his role',
|
||||
[UserRolesEnum::admin()->label, UserRolesEnum::client()->label],
|
||||
UserRolesEnum::client()->label,
|
||||
[UserRolesEnum::admin->label(), UserRolesEnum::client->label()],
|
||||
UserRolesEnum::client->label(),
|
||||
$maxAttempts = null,
|
||||
$allowMultipleSelections = false
|
||||
);
|
||||
if ($tmp === UserRolesEnum::admin()->label) {
|
||||
$tmp = UserRolesEnum::admin();
|
||||
if ($tmp === UserRolesEnum::admin->label()) {
|
||||
$tmp = UserRolesEnum::admin;
|
||||
}
|
||||
if ($tmp === UserRolesEnum::client()->label) {
|
||||
$tmp = UserRolesEnum::client();
|
||||
if ($tmp === UserRolesEnum::client->label()) {
|
||||
$tmp = UserRolesEnum::client;
|
||||
}
|
||||
$validator = Validator::make(['role' => $tmp], [
|
||||
'role' => 'required'
|
||||
|
|
@ -219,7 +192,7 @@ class CreateAdmin extends Command
|
|||
$this->role = $tmp;
|
||||
} catch (ValidationException $e) {
|
||||
$this->error(sprintf(
|
||||
'Please choose from the selection',
|
||||
'Please choose from the selection %s',
|
||||
\implode(',', collect($e->errors())->flatten()->all())
|
||||
));
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -2,30 +2,17 @@
|
|||
|
||||
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()
|
||||
protected function commands(): void
|
||||
{
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,37 +2,22 @@
|
|||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @method static self total() total role
|
||||
* @method static self user() user role
|
||||
*/
|
||||
final class AppUserRolesEnum extends BaseEnumRoutable
|
||||
enum AppUserRolesEnum: int
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'total' => 1,
|
||||
'user' => 2,
|
||||
];
|
||||
}
|
||||
use BaseEnum;
|
||||
|
||||
case total = 1;
|
||||
case user = 2;
|
||||
|
||||
/**
|
||||
* enum labels
|
||||
* @return array
|
||||
* Optionnal labels definition.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'total' => 'Total',
|
||||
'user' => 'Utilisateur',
|
||||
];
|
||||
}
|
||||
private const LABELS = [
|
||||
self::total->name => 'Total',
|
||||
self::user->name => 'Utilisateur',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,43 +2,26 @@
|
|||
|
||||
namespace App\Enums\Documents;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @method static self fr()
|
||||
* @method static self en()
|
||||
* @method static self de()
|
||||
* @method static self nl()
|
||||
*/
|
||||
final class LangEnum extends BaseEnumRoutable
|
||||
enum LangEnum: int
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'fr' => 1,
|
||||
'en' => 2,
|
||||
'de' => 3,
|
||||
'nl' => 4,
|
||||
];
|
||||
}
|
||||
use BaseEnum;
|
||||
|
||||
case fr = 1;
|
||||
case en = 2;
|
||||
case de = 3;
|
||||
case nl = 4;
|
||||
|
||||
/**
|
||||
* enum labels
|
||||
* @return array
|
||||
* Optionnal labels definition.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'fr' => 'Français (FR)',
|
||||
'en' => 'Anglais (EN)',
|
||||
'de' => 'Allemand (DE)',
|
||||
'nl' => 'Néerlandais (NL)',
|
||||
];
|
||||
}
|
||||
private const LABELS = [
|
||||
self::fr->name => 'Français (FR)',
|
||||
self::en->name => 'Anglais (EN)',
|
||||
self::de->name => 'Allemand (DE)',
|
||||
self::nl->name => 'Néerlandais (NL)',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,37 +2,36 @@
|
|||
|
||||
namespace App\Enums\Documents;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @method static self pdf()
|
||||
* @method static self mp4()
|
||||
*/
|
||||
final class TypeEnum extends BaseEnumRoutable
|
||||
enum TypeEnum: int
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'pdf' => 'pdf',
|
||||
'mp4' => 'mp4',
|
||||
];
|
||||
}
|
||||
use BaseEnum;
|
||||
|
||||
case pdf = 1;
|
||||
case mp4 = 2;
|
||||
|
||||
|
||||
/**
|
||||
* enum labels
|
||||
* @return array
|
||||
* Optionnal labels definition.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
protected static function labels(): array
|
||||
private const LABELS = [
|
||||
self::pdf->name => 'PDF',
|
||||
self::mp4->name => 'MP4',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get translation key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function icon(): string
|
||||
{
|
||||
return [
|
||||
'pdf' => 'PDF',
|
||||
'mp4' => 'MP4',
|
||||
];
|
||||
return match ($this) {
|
||||
self::pdf => 'file',
|
||||
self::mp4 => 'video',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,40 +2,24 @@
|
|||
|
||||
namespace App\Enums\Formularies;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @method static self system() input system
|
||||
* @method static self locked() input locked
|
||||
* @method static self default() input default
|
||||
*/
|
||||
final class InputStatusEnum extends BaseEnumRoutable
|
||||
enum InputStatusEnum: int
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'system' => 1,
|
||||
'locked' => 2,
|
||||
'default' => 3,
|
||||
];
|
||||
}
|
||||
use BaseEnum;
|
||||
|
||||
case system = 1;
|
||||
case locked = 2;
|
||||
case default = 3;
|
||||
|
||||
/**
|
||||
* enum labels
|
||||
* @return array
|
||||
* Optionnal labels definition.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'system' => __('system'),
|
||||
'locked' => __('verrouillé'),
|
||||
'default' => __('default'),
|
||||
];
|
||||
}
|
||||
private const LABELS = [
|
||||
self::system->name => 'system',
|
||||
self::locked->name => 'verrouillé',
|
||||
self::default->name => 'default',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,87 +9,50 @@ use App\Lib\Inputs\InputRadio;
|
|||
use App\Lib\Inputs\InputSelect;
|
||||
use App\Lib\Inputs\InputSelectMultiple;
|
||||
use App\Lib\Inputs\InputText;
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @property-read integer value
|
||||
* @property-read string label
|
||||
* @property-read string inputClass InputType class.
|
||||
*
|
||||
* @method static self text() input text
|
||||
* @method static self email() input email
|
||||
* @method static self phone() input phone
|
||||
* @method static self radio() input radio
|
||||
* @method static self select() input select
|
||||
* @method static self selectMultiple() input selectMultiple
|
||||
* @method static self checkbox() input checkbox
|
||||
*/
|
||||
final class InputTypeEnum extends BaseEnumRoutable
|
||||
enum InputTypeEnum: int
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'text' => 1,
|
||||
'email' => 2,
|
||||
'phone' => 3,
|
||||
'radio' => 4,
|
||||
'select' => 5,
|
||||
'selectMultiple' => 6,
|
||||
'checkbox' => 7,
|
||||
];
|
||||
}
|
||||
use BaseEnum;
|
||||
|
||||
case text = 1;
|
||||
case email = 2;
|
||||
case phone = 3;
|
||||
case radio = 4;
|
||||
case select = 5;
|
||||
case selectMultiple = 6;
|
||||
case checkbox = 7;
|
||||
|
||||
/**
|
||||
* enum labels
|
||||
* @return array
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'text' => __('texte'),
|
||||
'email' => __('e-mail'),
|
||||
'phone' => __('téléphone'),
|
||||
'radio' => __('radio'),
|
||||
'select' => __('liste déroulante'),
|
||||
'selectMultiple' => __('liste déroulante à choix multiple'),
|
||||
'checkbox' => __('case à cocher'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum input Types
|
||||
* Optionnal labels definition.
|
||||
*
|
||||
* @return array
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
protected static function inputTypes(): array
|
||||
{
|
||||
return [
|
||||
'text' => InputText::class,
|
||||
'email' => InputEmail::class,
|
||||
'phone' => InputPhone::class,
|
||||
'radio' => InputRadio::class,
|
||||
'select' => InputSelect::class,
|
||||
'selectMultiple' => InputSelectMultiple::class,
|
||||
'checkbox' => InputCheckbox::class,
|
||||
];
|
||||
}
|
||||
private const LABELS = [
|
||||
self::text->name => 'texte',
|
||||
self::email->name => 'email',
|
||||
self::phone->name => 'téléphone',
|
||||
self::radio->name => 'radio',
|
||||
self::select->name => 'liste déroulante',
|
||||
self::selectMultiple->name => 'liste déroulante à choix multiple',
|
||||
self::checkbox->name => 'case à cocher',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @return integer|string
|
||||
* @throws \Kwaadpepper\Enum\Exceptions\UnknownEnumProperty If the prop cannot be found.
|
||||
* Get InputType class based on the enum value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __get(string $attribute)
|
||||
public function getInputClass(): string
|
||||
{
|
||||
if ($attribute === 'inputClass') {
|
||||
return $this->inputTypes()[$this->getDefinition()];
|
||||
}
|
||||
return parent::__get($attribute);
|
||||
return match ($this) {
|
||||
self::text => InputText::class,
|
||||
self::email => InputEmail::class,
|
||||
self::phone => InputPhone::class,
|
||||
self::radio => InputRadio::class,
|
||||
self::select => InputSelect::class,
|
||||
self::selectMultiple => InputSelectMultiple::class,
|
||||
self::checkbox => InputCheckbox::class,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
21
app/Enums/ItemsPerPaginationEnum.php
Normal file
21
app/Enums/ItemsPerPaginationEnum.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
/**
|
||||
* Defines the available pagination page size options.
|
||||
*/
|
||||
enum ItemsPerPaginationEnum: int
|
||||
{
|
||||
use BaseEnum;
|
||||
|
||||
case five = 5;
|
||||
case twelve = 12;
|
||||
case twentyfive = 25;
|
||||
case fifty = 50;
|
||||
case onehundred = 100;
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums\Pagination;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* @method static self five()
|
||||
* @method static self twelve()
|
||||
* @method static self twentyfive()
|
||||
* @method static self fifty()
|
||||
* @method static self onehundred()
|
||||
*/
|
||||
final class ItemsPerPaginationEnum extends BaseEnumRoutable
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'five' => 5,
|
||||
'twelve' => 12,
|
||||
'twentyfive' => 25,
|
||||
'fifty' => 50,
|
||||
'onehundred' => 100
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -2,52 +2,32 @@
|
|||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @method static self string() string type
|
||||
* @method static self numeric() numeric type
|
||||
* @method static self picture() picture type
|
||||
* @method static self json() string type
|
||||
* @method static self boolean() boolean type
|
||||
* @method static self color() color type
|
||||
* @method static self directory() directory type
|
||||
*/
|
||||
final class SettingTypesEnum extends BaseEnumRoutable
|
||||
enum SettingTypesEnum: int
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'string' => 1,
|
||||
'numeric' => 2,
|
||||
'picture' => 3,
|
||||
'json' => 4,
|
||||
'boolean' => 5,
|
||||
'color' => 6,
|
||||
'directory' => 7
|
||||
];
|
||||
}
|
||||
use BaseEnum;
|
||||
|
||||
case string = 1;
|
||||
case numeric = 2;
|
||||
case picture = 3;
|
||||
case json = 4;
|
||||
case boolean = 5;
|
||||
case color = 6;
|
||||
case directory = 7;
|
||||
|
||||
/**
|
||||
* enum labels
|
||||
* @return array
|
||||
* Optionnal labels definition.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'string' => 'String (Hexa)',
|
||||
'numeric' => 'Numeric',
|
||||
'picture' => 'Picture',
|
||||
'json' => 'Json',
|
||||
'boolean' => 'Boolean',
|
||||
'color' => 'Color',
|
||||
'directory' => 'Directory',
|
||||
];
|
||||
}
|
||||
private const LABELS = [
|
||||
self::string->name => 'String (Hexa)',
|
||||
self::numeric->name => 'Numeric',
|
||||
self::picture->name => 'Picture',
|
||||
self::json->name => 'Json',
|
||||
self::boolean->name => 'Boolean',
|
||||
self::color->name => 'Color',
|
||||
self::directory->name => 'Directory',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,37 +2,22 @@
|
|||
|
||||
namespace App\Enums;
|
||||
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @method static self admin() admin role
|
||||
* @method static self client() client role
|
||||
*/
|
||||
final class UserRolesEnum extends BaseEnumRoutable
|
||||
enum UserRolesEnum: int
|
||||
{
|
||||
/**
|
||||
* enum values
|
||||
* @return array
|
||||
*/
|
||||
protected static function values(): array
|
||||
{
|
||||
return [
|
||||
'admin' => 1,
|
||||
'client' => 2,
|
||||
];
|
||||
}
|
||||
use BaseEnum;
|
||||
|
||||
case admin = 1;
|
||||
case client = 2;
|
||||
|
||||
/**
|
||||
* enum labels
|
||||
* @return array
|
||||
* Optionnal labels definition.
|
||||
*
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
'admin' => 'Administrateur',
|
||||
'client' => 'Client',
|
||||
];
|
||||
}
|
||||
private const LABELS = [
|
||||
self::admin->name => 'Administrateur',
|
||||
self::client->name => 'Client',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class Handler extends ExceptionHandler
|
|||
/**
|
||||
* A list of the inputs that are never flashed for validation exceptions.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'current_password',
|
||||
|
|
@ -30,9 +30,12 @@ class Handler extends ExceptionHandler
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
public function register(): void
|
||||
{
|
||||
$this->reportable(function (Throwable $e) {
|
||||
if (app()->bound('sentry')) {
|
||||
app('sentry')->captureException($e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,21 @@ class AppController extends Controller
|
|||
{
|
||||
/**
|
||||
* Get App Config.
|
||||
* @return ApiResponseResource
|
||||
*
|
||||
* @return \App\Http\Resources\ApiResponseResource
|
||||
*/
|
||||
public function get()
|
||||
public function get(): \App\Http\Resources\ApiResponseResource
|
||||
{
|
||||
/** @var string $tenantKey */
|
||||
$tenantKey = request()->tenant;
|
||||
|
||||
$response = [];
|
||||
$settings = Setting::where('key', 'Button1')->orWhere('key', 'Button2')->orWhere('key', 'Button3')->get();
|
||||
$settings = Setting::query()
|
||||
->where('tenant_id', $tenantKey)
|
||||
->orWhere('key', 'Button1')
|
||||
->orWhere('key', 'Button2')
|
||||
->orWhere('key', 'Button3')
|
||||
->get();
|
||||
|
||||
foreach ($settings as $setting) {
|
||||
$directory = Directory::find($setting->value)->only('id', 'name');
|
||||
|
|
|
|||
|
|
@ -12,17 +12,17 @@ class SettingsController extends Controller
|
|||
/**
|
||||
* Get Settings.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
* @return \App\Http\Resources\ApiResponseResource
|
||||
*/
|
||||
public function get()
|
||||
public function get(): \App\Http\Resources\ApiResponseResource
|
||||
{
|
||||
$response = [];
|
||||
$settings = Setting::all();
|
||||
foreach ($settings as $setting) {
|
||||
$response[$setting->key] =
|
||||
SettingTypesEnum::numeric()->equals($setting->type) ||
|
||||
SettingTypesEnum::boolean()->equals($setting->type) ||
|
||||
SettingTypesEnum::directory()->equals($setting->type)
|
||||
SettingTypesEnum::numeric->equals($setting->type) ||
|
||||
SettingTypesEnum::boolean->equals($setting->type) ||
|
||||
SettingTypesEnum::directory->equals($setting->type)
|
||||
? \intval($setting->value)
|
||||
: $setting->value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use App\Models\Directory;
|
|||
use App\Models\Document;
|
||||
use App\Models\Formulary;
|
||||
use App\Models\Setting;
|
||||
use Google\Cloud\Vision\V1\ImageAnnotatorClient;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
|
|
@ -32,13 +31,13 @@ use Illuminate\Support\Facades\URL;
|
|||
class SyncController extends Controller
|
||||
{
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \App\Http\Resources\AppUserCollection
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function getUsers(Request $request)
|
||||
public function getUsers(): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
{
|
||||
return AppUserResource::collection(AppUser::where('status', 1)->get());
|
||||
return AppUserResource::collection(
|
||||
AppUser::query()->where('tenant_id', \tenant()->getKey())->where('status', 1)->get()
|
||||
);
|
||||
}
|
||||
|
||||
// *** --- START CONTACTS ---
|
||||
|
|
@ -49,11 +48,11 @@ class SyncController extends Controller
|
|||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function getContacts(AppUser $app_user)
|
||||
public function getContacts(AppUser $app_user): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
{
|
||||
return ContactResource::collection(
|
||||
Contact::query()->whereHas('appUser', function (Builder $q) use ($app_user) {
|
||||
$q->where('id', $app_user->id);
|
||||
$q->where('tenant_id', \tenant()->getKey())->where('id', $app_user->id);
|
||||
})->get()
|
||||
);
|
||||
}
|
||||
|
|
@ -63,43 +62,49 @@ class SyncController extends Controller
|
|||
*
|
||||
* @param \App\Http\Requests\Api\Contacts\UpsertContactsRequest $request
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function upsertContact(UpsertContactsRequest $request, AppUser $app_user)
|
||||
{
|
||||
public function upsertContact(
|
||||
UpsertContactsRequest $request,
|
||||
AppUser $app_user
|
||||
): \Illuminate\Http\JsonResponse {
|
||||
/** @var \Illuminate\Support\Collection<string,integer> */
|
||||
$formularies = Formulary::query()->pluck('slug')->flip();
|
||||
$contactQuery = Contact::query()->whereHas('appUser', function (Builder $q) use ($app_user) {
|
||||
$q->where('id', $app_user->id);
|
||||
$q->where('tenant_id', \tenant()->getKey())->where('id', $app_user->getKey());
|
||||
});
|
||||
|
||||
\collect($request->contacts)->each(function (array $contactRequestData) use ($contactQuery, $formularies) {
|
||||
/** @var \App\Models\Contact */
|
||||
$model = (clone $contactQuery)->where('id', Arr::get($contactRequestData, 'id'))->firstOrNew();
|
||||
\collect($request->contacts)->each(
|
||||
function (array $contactRequestData) use ($contactQuery, $formularies, $app_user) {
|
||||
/** @var \App\Models\Contact $model */
|
||||
$model = (clone $contactQuery)->where('id', Arr::get($contactRequestData, 'id'))->firstOrNew();
|
||||
|
||||
$contactRequestData['timestamp'] = Carbon::parse($contactRequestData['timestamp'], 'UTC')
|
||||
->setTimezone(\now()->getTimezone());
|
||||
if ($model->timestamp and $model->timestamp->gte($contactRequestData['timestamp'])) {
|
||||
return;
|
||||
$contactRequestData['timestamp'] = Carbon::parse($contactRequestData['timestamp'], 'UTC')
|
||||
->setTimezone(\now()->getTimezone());
|
||||
// @phpstan-ignore logicalAnd.leftAlwaysTrue
|
||||
if ($model->timestamp and $model->timestamp->gte($contactRequestData['timestamp'])) {
|
||||
return;
|
||||
}
|
||||
// * Set parse values on data prop to fill in model.
|
||||
$contactRequestData['data'] = \collect($contactRequestData['dataParsed'])
|
||||
// * FILTER CONTACT DATA WITH ACTUAL FORMULARY
|
||||
->filter(function (Input $input) use ($formularies) {
|
||||
return $formularies->has($input->data->formSlug);
|
||||
});
|
||||
$model->fill($contactRequestData);
|
||||
$model->app_user_id = $app_user->getKey();
|
||||
|
||||
// * Send contact to Feature
|
||||
if (
|
||||
!empty($contactRequestData['send_to_app_user_id']) and
|
||||
($destUser = AppUser::query()->where('id', $contactRequestData['send_to_app_user_id'])->first())
|
||||
) {
|
||||
$model->appUser()->associate($destUser);
|
||||
}
|
||||
|
||||
$model->saveOrFail();
|
||||
}
|
||||
// * Set parse values on data prop to fill in model.
|
||||
$contactRequestData['data'] = \collect($contactRequestData['dataParsed'])
|
||||
// * FILTER CONTACT DATA WITH ACTUAL FORMULARY
|
||||
->filter(function (Input $input) use ($formularies) {
|
||||
return $formularies->has($input->data->formSlug);
|
||||
});
|
||||
$model->fill($contactRequestData);
|
||||
|
||||
// * Send contact to Feature
|
||||
if (
|
||||
!empty($contactRequestData['send_to_app_user_id']) and
|
||||
($destUser = AppUser::query()->where('id', $contactRequestData['send_to_app_user_id'])->first())
|
||||
) {
|
||||
$model->appUser()->associate($destUser);
|
||||
}
|
||||
|
||||
$model->saveOrFail();
|
||||
});
|
||||
);
|
||||
|
||||
// * HTTP 200 is ok.
|
||||
return \response()->json();
|
||||
|
|
@ -110,13 +115,13 @@ class SyncController extends Controller
|
|||
*
|
||||
* @param \App\Http\Requests\Api\Contacts\DestroyContactsRequest $request
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Resources\Json
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function destroyContacts(DestroyContactsRequest $request, AppUser $app_user)
|
||||
public function destroyContacts(DestroyContactsRequest $request, AppUser $app_user): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
Contact::query()->whereIn('id', $request->contactUuidList)
|
||||
Contact::query()->whereIn('id', $request->validated()['contactUuidList'])
|
||||
->whereHas('appUser', function (Builder $q) use ($app_user) {
|
||||
$q->where('id', $app_user->id);
|
||||
$q->where('tenant_id', \tenant()->getKey())->where('id', $app_user->id);
|
||||
})->delete();
|
||||
|
||||
// * HTTP 200 is ok.
|
||||
|
|
@ -126,72 +131,42 @@ class SyncController extends Controller
|
|||
// *** --- END CONTACTS ---
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \App\Http\Resources\DirectoriesCollection
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function getDirectories(Request $request)
|
||||
public function getDirectories(): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
{
|
||||
return DirectoryResource::collection(Directory::query()->orderBy('order')->get());
|
||||
return DirectoryResource::collection(
|
||||
Directory::query()->where('tenant_id', \tenant()->getKey())->orderBy('order')->get()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \App\Http\Resources\DocumentsCollection
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function getDocuments(Request $request)
|
||||
public function getDocuments(): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
{
|
||||
return DocumentResource::collection(Document::where('status', 1)->get());
|
||||
return DocumentResource::collection(
|
||||
Document::query()->where('tenant_id', \tenant()->getKey())->where('status', 1)->get()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function getVersion(Request $request)
|
||||
public function getFormularies(): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
{
|
||||
$app_uuid = $request->app_uuid;
|
||||
$app_version = $request->app_version;
|
||||
$version = Setting::select('value AS version')->where('key', 'version')->first();
|
||||
$ShowIsActive = Setting::select('value AS ShowIsActive')->where('key', 'ShowIsActive')->first();
|
||||
|
||||
try {
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$response = $client->request(
|
||||
'GET',
|
||||
'https://store.ldc.fr/api/get-version?token=@P$oi6or!bL2-r%3C&app_uuid=' . $app_uuid
|
||||
);
|
||||
$body = $response->getBody();
|
||||
$storeVersion = json_decode($body)->version;
|
||||
} catch (ClientException $e) {
|
||||
$storeVersion = $app_version;
|
||||
}
|
||||
|
||||
if ($storeVersion > $app_version) {
|
||||
$newApp = true;
|
||||
} else {
|
||||
$newApp = false;
|
||||
}
|
||||
|
||||
return ['version' => $version->version, 'ShowIsActive' => $ShowIsActive->ShowIsActive, 'newApp' => $newApp];
|
||||
return FormularyResource::collection(
|
||||
Formulary::query()->where('tenant_id', \tenant()->getKey())->orderBy('order')->get()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \App\Http\Resources\ContactsCollection
|
||||
*/
|
||||
public function getFormularies()
|
||||
{
|
||||
return FormularyResource::collection(Formulary::query()->orderBy('order')->get());
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: This should be refactored, on app side also.
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \App\Http\Requests\Api\SendFlyerRequest $request
|
||||
* @return string
|
||||
*/
|
||||
public function sendFlyer(Request $request)
|
||||
public function sendFlyer(Request $request): string
|
||||
{
|
||||
// FIXME: This should be validated OMG.
|
||||
$requestData = \json_decode($request->emails, true);
|
||||
$requestData = $request->emails;
|
||||
$email = $requestData['email'];
|
||||
$subject = $requestData['subject'];
|
||||
$message = $requestData['message'];
|
||||
|
|
@ -204,12 +179,14 @@ class SyncController extends Controller
|
|||
$filesName = [];
|
||||
$noExists = [];
|
||||
foreach ($docs as $doc) {
|
||||
$exists = Storage::disk('public')->exists('docs/' . $doc['uuid'] . '.' . $doc['type']);
|
||||
$exists = Storage::disk('public')
|
||||
->exists(sprintf('docs/%s/%s.%s', \tenant()->getKey(), $doc['uuid'], $doc['type']));
|
||||
if ($exists) {
|
||||
array_push($attach, URL::temporarySignedRoute(
|
||||
array_push($attach, config('app.url') . URL::temporarySignedRoute(
|
||||
'docs.download',
|
||||
now()->addDays(30),
|
||||
['uuid' => $doc['uuid']]
|
||||
['tenant' => \tenant()->getKey(), 'uuid' => $doc['uuid']],
|
||||
false
|
||||
));
|
||||
array_push($filesName, $doc['title']);
|
||||
} else {
|
||||
|
|
@ -217,56 +194,26 @@ class SyncController extends Controller
|
|||
}
|
||||
}
|
||||
if (count($noExists) === 0) {
|
||||
$message = new SendFlyer([
|
||||
'body' => $message,
|
||||
'from' => $user->email,
|
||||
'fromName' => $user->firstname . ' ' . $user->lastname,
|
||||
'subject' => '[' . config('app.BRAND') . '] - ' . $subject,
|
||||
'attach' => $attach,
|
||||
$mail = new SendFlyer([
|
||||
'body' => $message,
|
||||
'fromName' => $user->firstname . ' ' . $user->lastname,
|
||||
'subject' => $subject,
|
||||
'attach' => $attach,
|
||||
'filesName' => $filesName,
|
||||
]);
|
||||
|
||||
Mail::to($email)
|
||||
->cc($user->email)
|
||||
->queue($message);
|
||||
Mail::to($email)->cc($user->email)->send($mail);
|
||||
} else {
|
||||
$message = new SendFlyerFailed([
|
||||
'email' => $email,
|
||||
'message' => $message,
|
||||
'subject' => $subject,
|
||||
$mail = new SendFlyerFailed([
|
||||
'email' => $email,
|
||||
'message' => $message,
|
||||
'subject' => $subject,
|
||||
'filesName' => $filesName,
|
||||
'noExists' => $noExists
|
||||
'noExists' => $noExists
|
||||
]);
|
||||
|
||||
Mail::to($user->email)
|
||||
->queue($message);
|
||||
Mail::to($user->email)->send($mail);
|
||||
} //end if
|
||||
return 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function processOcr(Request $request)
|
||||
{
|
||||
// Instantiates a client.
|
||||
$imageAnnotator = new ImageAnnotatorClient([
|
||||
'credentials' => public_path() . '/credentials.json'
|
||||
]);
|
||||
|
||||
// The name of the image file to annotate.
|
||||
$fileName = 'test.jpg';
|
||||
|
||||
// Prepare the image to be annotated.
|
||||
$image = file_get_contents(public_path() . "/" . $fileName);
|
||||
|
||||
// Performs label detection on the image file.
|
||||
$response = $imageAnnotator->textDetection($image);
|
||||
$labels = $response->getTextAnnotations();
|
||||
|
||||
foreach ($labels as $label) {
|
||||
echo $label->getDescription() . "<br>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,25 +12,31 @@ use App\Models\Directory;
|
|||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class AppUserController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
|
||||
/**
|
||||
* Create the controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(AppUser::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
public function index(Request $request): \Illuminate\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
||||
$query = AppUser::query();
|
||||
|
||||
/** @var string $search Search field */
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
|
|
@ -41,36 +47,45 @@ class AppUserController extends Controller
|
|||
'email'
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Nom, Prénom, Email');
|
||||
$searchFields = \implode(', ', [
|
||||
trans('validation.attributes.last_name'),
|
||||
trans('validation.attributes.first_name'),
|
||||
trans('validation.attributes.email'),
|
||||
]);
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($query);
|
||||
|
||||
$app_users = $this->paginate($query);
|
||||
$appUserModels = $this->paginate($query);
|
||||
|
||||
return view('bo.pages.app-users.index', compact('app_users', 'searchFields'));
|
||||
return view('bo.pages.app_users.index', compact('appUserModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
public function create(AppUser $app_user): \Illuminate\View\View
|
||||
{
|
||||
$directories = Directory::renderDirectories(Directory::where('needAuthorization', 1)
|
||||
->orderBy('name', 'ASC')->get());
|
||||
$directories = Directory::renderDirectories(
|
||||
Directory::query()->where('needAuthorization', 1)->orderBy('name', 'asc')->get()
|
||||
);
|
||||
|
||||
return view('bo.pages.app-users.create', compact('directories'));
|
||||
return view('bo.pages.app_users.create', [
|
||||
'appUserModel' => $app_user,
|
||||
'directories' => $directories
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\AppUser\StoreAppUserRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\AppUser\StoreAppUserRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreAppUserRequest $request)
|
||||
public function store(StoreAppUserRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$app_user = new AppUser();
|
||||
|
|
@ -79,10 +94,10 @@ class AppUserController extends Controller
|
|||
if ($app_user->saveOrFail()) {
|
||||
$app_user->directories()->sync(collect($request->directories)->pluck('id'));
|
||||
return redirect()
|
||||
->route('bo.app-users.edit', $app_user)
|
||||
->route('bo.app_users.edit', ['tenant' => \tenant(), 'app_user' => $app_user])
|
||||
->with('success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.app_users'))]
|
||||
['model' => trans('models.classes.app_user')]
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +105,7 @@ class AppUserController extends Controller
|
|||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été créé',
|
||||
['model' => Str::singular(trans('models.classes.app_users'))]
|
||||
['model' => trans('models.classes.app_user')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -99,17 +114,19 @@ class AppUserController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(AppUser $app_user)
|
||||
public function edit(AppUser $app_user): \Illuminate\View\View
|
||||
{
|
||||
$directories = Directory::renderDirectories(Directory::query()->where('needAuthorization', 1)
|
||||
->orderBy('name', 'ASC')->get());
|
||||
$directories = Directory::renderDirectories(
|
||||
Directory::query()->where('needAuthorization', 1)->orderBy('name', 'asc')->get()
|
||||
);
|
||||
// @phpstan-ignore assign.propertyReadOnly
|
||||
$app_user->directories = Directory::renderDirectories($app_user->directories);
|
||||
|
||||
return view('bo.pages.app-users.edit', [
|
||||
'app_userModel' => $app_user,
|
||||
'directories' => $directories
|
||||
return view('bo.pages.app_users.edit', [
|
||||
'appUserModel' => $app_user,
|
||||
'directories' => $directories
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -118,9 +135,9 @@ class AppUserController extends Controller
|
|||
*
|
||||
* @param \App\Http\Requests\Bo\AppUser\UpdateAppUserRequest $request
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateAppUserRequest $request, AppUser $app_user)
|
||||
public function update(UpdateAppUserRequest $request, AppUser $app_user): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$app_user->directories()->sync(collect($request->directories)->pluck('id'));
|
||||
$params = $request->validated();
|
||||
|
|
@ -132,17 +149,17 @@ class AppUserController extends Controller
|
|||
|
||||
if ($app_user->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.app-users.edit', $app_user)
|
||||
->route('bo.app_users.edit', ['tenant' => \tenant(), 'app_user' => $app_user])
|
||||
->with('success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.app_users'))]
|
||||
['model' => trans('models.classes.app_user')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.app_users'))]
|
||||
['model' => trans('models.classes.app_user')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -150,17 +167,17 @@ class AppUserController extends Controller
|
|||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(AppUser $app_user)
|
||||
public function destroy(AppUser $app_user): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
if ($app_user->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.app-users.index')
|
||||
->route('bo.app_users.index', ['tenant' => \tenant()])
|
||||
->with('warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.app_users'))]
|
||||
['model' => trans('models.classes.app_user')]
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -168,10 +185,21 @@ class AppUserController extends Controller
|
|||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.app_users'))]
|
||||
['model' => trans('models.classes.app_user')]
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate the specified resource.
|
||||
*
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function duplicate(AppUser $app_user): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return $this->create($app_user->replicate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass import by CSV.
|
||||
* matricule;lastname;firstname;email
|
||||
|
|
@ -180,10 +208,11 @@ class AppUserController extends Controller
|
|||
* @param \App\Http\Requests\Bo\ImportRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function import(ImportRequest $request)
|
||||
public function import(ImportRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
Excel::import(new AppUserImport(), $request->import, null, \Maatwebsite\Excel\Excel::CSV);
|
||||
|
||||
return redirect()->route('bo.app-users.index')->with('success', 'Import terminé.');
|
||||
return redirect()->route('bo.app_users.index', ['tenant' => \tenant()])
|
||||
->with('success', 'Import terminé.');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class LoginController extends Controller
|
|||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard()
|
||||
protected function guard(): \Illuminate\Contracts\Auth\StatefulGuard
|
||||
{
|
||||
return Auth::guard('backend');
|
||||
}
|
||||
|
|
@ -35,13 +35,14 @@ class LoginController extends Controller
|
|||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showLoginForm()
|
||||
public function showLoginForm(): \Illuminate\View\View
|
||||
{
|
||||
return view('bo.auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo(): string
|
||||
|
|
|
|||
|
|
@ -15,13 +15,14 @@ class ResetPasswordController extends Controller
|
|||
*
|
||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
||||
*/
|
||||
protected function guard()
|
||||
protected function guard(): \Illuminate\Contracts\Auth\StatefulGuard
|
||||
{
|
||||
return Auth::guard('backend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo(): string
|
||||
|
|
|
|||
|
|
@ -11,20 +11,27 @@ use Illuminate\Database\Eloquent\Builder;
|
|||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create the controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Contact::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\FilterCustomerRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(FilterCustomerRequest $request)
|
||||
public function index(FilterCustomerRequest $request): \Illuminate\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
||||
$query = Contact::query();
|
||||
$query = Contact::query()->with('appUser')->whereHas('appUser', function ($query) {
|
||||
$query->where('tenant_id', tenant('id'));
|
||||
});
|
||||
|
||||
$query->with('appUser');
|
||||
|
||||
/** @var string $search Search field */
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
|
|
@ -35,7 +42,11 @@ class ContactController extends Controller
|
|||
'email',
|
||||
);
|
||||
}
|
||||
$searchFields = \implode(',', [trans('Nom'), trans('Prénom'), trans('Email')]);
|
||||
$searchFields = \implode(', ', [
|
||||
trans('validation.attributes.last_name'),
|
||||
trans('validation.attributes.email'),
|
||||
trans('validation.attributes.phone'),
|
||||
]);
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($query);
|
||||
|
|
@ -46,26 +57,26 @@ class ContactController extends Controller
|
|||
});
|
||||
}
|
||||
|
||||
$contactModelList = $this->paginate($query);
|
||||
$contactModels = $this->paginate($query);
|
||||
|
||||
$appUsers = AppUser::query()->select(['id', 'lastname', 'firstname'])->get();
|
||||
$appUsers = AppUser::query()->select(['id', 'lastname', 'firstname'])->orderBy('lastname')->get();
|
||||
|
||||
return view('bo.pages.contacts.index', compact('contactModelList', 'searchFields', 'appUsers'));
|
||||
return view('bo.pages.contacts.index', compact('contactModels', 'searchFields', 'appUsers'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \App\Models\Contact $contact
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show(Contact $contact)
|
||||
public function show(Contact $contact): \Illuminate\View\View
|
||||
{
|
||||
$contact->load('appUser.directories');
|
||||
$fomularies = Formulary::all()->keyBy('name');
|
||||
return \view('bo.pages.contacts.show', [
|
||||
return view('bo.pages.contacts.show', [
|
||||
'contactModel' => $contact,
|
||||
'fomularies' => $fomularies
|
||||
'fomularies' => $fomularies
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class DashboardController extends Controller
|
|||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.dashboard');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,51 +6,55 @@ use App\Http\Controllers\Controller;
|
|||
use App\Http\Requests\Bo\Directories\StoreDirectoryRequest;
|
||||
use App\Http\Requests\Bo\Directories\UpdateDirectoryRequest;
|
||||
use App\Models\Directory;
|
||||
use App\Models\Document;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class DirectoriesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create the controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Directory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$directories = $this->getDirectoriesForComponent();
|
||||
|
||||
return \view('bo.pages.directories.index', \compact('directories'));
|
||||
$directoryModels = $this->getDirectoriesForComponent();
|
||||
return \view('bo.pages.directories.index', \compact('directoryModels'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Directory\StoreDirectoryRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\Directories\StoreDirectoryRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreDirectoryRequest $request)
|
||||
public function store(StoreDirectoryRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$directory = new Directory();
|
||||
$directory->fill($request->validated());
|
||||
if ($directory->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.directories.index')
|
||||
->route('bo.directories.index', ['tenant' => \tenant()])
|
||||
->with('success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.directories'))]
|
||||
['model' => trans('models.classes.directory')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été créé',
|
||||
['model' => Str::singular(trans('models.classes.directories'))]
|
||||
['model' => trans('models.classes.directory')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -59,11 +63,10 @@ class DirectoriesController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Directory $directory
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Directory $directory)
|
||||
public function edit(Directory $directory): \Illuminate\View\View
|
||||
{
|
||||
$this->authorize('edit', $directory);
|
||||
return view('bo.pages.directories.edit', ['directoryModel' => $directory]);
|
||||
}
|
||||
|
||||
|
|
@ -72,27 +75,26 @@ class DirectoriesController extends Controller
|
|||
*
|
||||
* @param \App\Http\Requests\Bo\Directories\UpdateDirectoryRequest $request
|
||||
* @param \App\Models\Directory $directory
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateDirectoryRequest $request, Directory $directory)
|
||||
public function update(UpdateDirectoryRequest $request, Directory $directory): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$this->authorize('edit', $directory);
|
||||
return DB::transaction(function () use ($request, $directory) {
|
||||
$directory->fill($request->validated());
|
||||
|
||||
if ($directory->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.directories.edit', $directory)
|
||||
->route('bo.directories.edit', ['tenant' => \tenant(), 'directory' => $directory])
|
||||
->with('success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.directories'))]
|
||||
['model' => trans('models.classes.directory')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.directories'))]
|
||||
['model' => trans('models.classes.directory')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -101,12 +103,12 @@ class DirectoriesController extends Controller
|
|||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Directory $directory
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function destroy(Directory $directory)
|
||||
public function destroy(Directory $directory): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
$this->authorize('delete', $directory);
|
||||
return DB::transaction(function () use ($directory) {
|
||||
/** @var \App\Models\Directory $directoryChild */
|
||||
foreach ($directory->children as $directoryChild) {
|
||||
$directoryChild->directory_id = null;
|
||||
$directoryChild->saveOrFail();
|
||||
|
|
@ -114,7 +116,8 @@ class DirectoriesController extends Controller
|
|||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Document> */
|
||||
$documents = $directory->documents()->get()->sortBy('lang', \SORT_REGULAR, true);
|
||||
if ($documents->count()) {
|
||||
$documents->each(function (Document $document) {
|
||||
$documents->each(function (\Illuminate\Database\Eloquent\Model $document) {
|
||||
/** @var \App\Models\Document $document */
|
||||
$document->deleteOrFail();
|
||||
});
|
||||
}
|
||||
|
|
@ -127,7 +130,7 @@ class DirectoriesController extends Controller
|
|||
':model :name n\'a pas été supprimé,
|
||||
un bouton est encore associé à ce dernier dans les paramètres :',
|
||||
[
|
||||
'model' => Str::singular(trans('models.classes.directories')),
|
||||
'model' => trans('models.classes.directory'),
|
||||
'name' => $directory->name['fr']
|
||||
]
|
||||
)
|
||||
|
|
@ -146,7 +149,7 @@ class DirectoriesController extends Controller
|
|||
* @param \Illuminate\Http\Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function saveOrder(Request $request)
|
||||
public function saveOrder(Request $request): void
|
||||
{
|
||||
$this->assignOrder($request->directories, null);
|
||||
}
|
||||
|
|
@ -154,11 +157,11 @@ class DirectoriesController extends Controller
|
|||
/**
|
||||
* Assign the new order and directory id to each directory.
|
||||
*
|
||||
* @param array $directories
|
||||
* @param integer $directoryId
|
||||
* @param array $directories
|
||||
* @param integer|null $directoryId
|
||||
* @return void
|
||||
*/
|
||||
public function assignOrder(array $directories, int $directoryId = null)
|
||||
public function assignOrder(array $directories, int|null $directoryId = null): void
|
||||
{
|
||||
foreach ($directories as $newDirectory) {
|
||||
$directory = Directory::where('id', $newDirectory['id'])->first();
|
||||
|
|
@ -175,27 +178,27 @@ class DirectoriesController extends Controller
|
|||
* Save the new order/structure of directories.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \App\Models\Directory
|
||||
*/
|
||||
public function needAuthorization(Request $request)
|
||||
public function needAuthorization(Request $request): \App\Models\Directory
|
||||
{
|
||||
$directory = Directory::where('id', $request->id)->firstOrFail();
|
||||
$directory = Directory::query()->where('id', $request->id)->firstOrFail();
|
||||
$directory->needAuthorization = $directory->needAuthorization ? false : true;
|
||||
|
||||
if ($directory->saveOrFail()) {
|
||||
return $directory;
|
||||
}
|
||||
$directory->saveOrFail();
|
||||
return $directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get directories for component
|
||||
* Get directories for component.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection<array-key,\App\Models\Directory>
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
private function getDirectoriesForComponent()
|
||||
private function getDirectoriesForComponent(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
return Directory::query()
|
||||
->where('tenant_id', \tenant()->getKey())
|
||||
->withCount('documents')
|
||||
->orderBy('order', 'ASC')->get();
|
||||
->orderBy('order', 'asc')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\Documents\LangEnum;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Documents\StoreDocumentRequest;
|
||||
use App\Http\Requests\Bo\Documents\UpdateDocumentRequest;
|
||||
|
|
@ -11,7 +12,6 @@ use App\Models\Document;
|
|||
use App\Models\Tag;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
|
@ -25,19 +25,26 @@ class DocumentController extends Controller
|
|||
{
|
||||
use ChangesModelOrder;
|
||||
|
||||
/**
|
||||
* Create the controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Document::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
public function index(Request $request): \Illuminate\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
||||
$query = Document::query();
|
||||
$query = Document::query()->with(['directory', 'parentDocument']);
|
||||
$tags = Tag::get();
|
||||
|
||||
/** @var string $search Search field */
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
|
|
@ -46,7 +53,7 @@ class DocumentController extends Controller
|
|||
'title',
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Titre');
|
||||
$searchFields = trans('validation.attributes.title');
|
||||
|
||||
/** Search by tags */
|
||||
$query->when($request->tag, function ($query) use ($request) {
|
||||
|
|
@ -58,37 +65,43 @@ class DocumentController extends Controller
|
|||
/** Sort columns with a query */
|
||||
$this->sortQuery($query);
|
||||
|
||||
$documents = $this->paginate($query);
|
||||
$documentModels = $this->paginate($query);
|
||||
|
||||
return view('bo.pages.documents.index', [
|
||||
'documents' => $documents,
|
||||
'searchFields' => $searchFields,
|
||||
'searchTag' => $request->tag,
|
||||
'tags' => $tags
|
||||
'documentModels' => $documentModels,
|
||||
'searchFields' => $searchFields,
|
||||
'searchTag' => $request->tag,
|
||||
'tags' => $tags
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\Document $document
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
public function create(Document $document): \Illuminate\View\View
|
||||
{
|
||||
$documents = Document::where('lang', \App\Enums\Documents\LangEnum::fr())->get();
|
||||
$directories = Directory::getChildrenDirectories();
|
||||
$tags = Tag::get();
|
||||
$documentsList = Document::query()->where('lang', LangEnum::fr)->get();
|
||||
$directories = Directory::getChildrenDirectories();
|
||||
$tags = Tag::get();
|
||||
|
||||
return view('bo.pages.documents.create', compact('documents', 'directories', 'tags'));
|
||||
return view('bo.pages.documents.create', [
|
||||
'documentModel' => $document,
|
||||
'documentsList' => $documentsList,
|
||||
'directories' => $directories,
|
||||
'tags' => $tags
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Documents\StoreDocumentRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\Documents\StoreDocumentRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreDocumentRequest $request)
|
||||
public function store(StoreDocumentRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$document = new Document();
|
||||
|
|
@ -96,17 +109,17 @@ class DocumentController extends Controller
|
|||
if ($document->saveOrFail()) {
|
||||
$document->tags()->sync(collect($request->tags)->pluck('id'));
|
||||
return redirect()
|
||||
->route('bo.documents.edit', $document)
|
||||
->route('bo.documents.edit', ['tenant' => \tenant(), 'document' => $document])
|
||||
->with('success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.documents'))]
|
||||
['model' => trans('models.classes.document')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été créé',
|
||||
['model' => Str::singular(trans('models.classes.documents'))]
|
||||
['model' => trans('models.classes.document')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -115,47 +128,47 @@ class DocumentController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Document $document
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(Document $document)
|
||||
public function edit(Document $document): \Illuminate\View\View
|
||||
{
|
||||
$documents = Document::where('lang', \App\Enums\Documents\LangEnum::fr())->get();
|
||||
$directories = Directory::getChildrenDirectories();
|
||||
$tags = Tag::get();
|
||||
$documentsList = Document::query()->where('lang', LangEnum::fr)->get();
|
||||
$directories = Directory::getChildrenDirectories();
|
||||
$tags = Tag::get();
|
||||
|
||||
return view('bo.pages.documents.edit', [
|
||||
'documents' => $documents,
|
||||
'documentModel' => $document,
|
||||
'directories' => $directories,
|
||||
'tags' => $tags
|
||||
'documentsList' => $documentsList,
|
||||
'directories' => $directories,
|
||||
'tags' => $tags
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Document\UpdateDocumentRequest $request
|
||||
* @param \App\Models\Document $document
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\Documents\UpdateDocumentRequest $request
|
||||
* @param \App\Models\Document $document
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateDocumentRequest $request, Document $document)
|
||||
public function update(UpdateDocumentRequest $request, Document $document): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $document) {
|
||||
$document->fill($request->validated());
|
||||
$document->tags()->sync(collect($request->tags)->pluck('id'));
|
||||
if ($document->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.documents.edit', $document)
|
||||
->route('bo.documents.edit', ['tenant' => \tenant(), 'document' => $document])
|
||||
->with('success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.documents'))]
|
||||
['model' => trans('models.classes.document')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.documents'))]
|
||||
['model' => trans('models.classes.document')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -163,42 +176,49 @@ class DocumentController extends Controller
|
|||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Document $document
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\Document $document
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Document $document)
|
||||
public function destroy(Document $document): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
/** @var array<string,string> */
|
||||
$previousQueries = [];
|
||||
\parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries);
|
||||
$document->tags()->sync([]);
|
||||
/** @var \App\Models\Document $documentChild */
|
||||
foreach ($document->children as $documentChild) {
|
||||
Document::removeDocument($documentChild);
|
||||
$documentChild->deleteOrFail();
|
||||
}
|
||||
if ($document->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.documents.index')
|
||||
->route('bo.documents.index', array_merge(['tenant' => \tenant()], $previousQueries))
|
||||
->with('warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.documents'))]
|
||||
['model' => trans('models.classes.document')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.documents'))]
|
||||
['model' => trans('models.classes.document')]
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the document
|
||||
*
|
||||
* @param string $tenant
|
||||
* @param string $uuid
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function download(string $uuid)
|
||||
public function download(string $tenant, string $uuid): \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
{
|
||||
$doc = Document::where('uuid', $uuid)->firstOrFail();
|
||||
$pathToFile = public_path() . Storage::url('docs/' . $doc->uuid . '.' . $doc->type);
|
||||
$pathToFile = public_path() . Storage::url(
|
||||
sprintf('docs/%s/%s.%s', $tenant, $doc->uuid, $doc->type)
|
||||
);
|
||||
return response()->download($pathToFile, $doc->path);
|
||||
}
|
||||
|
||||
|
|
@ -224,10 +244,9 @@ class DocumentController extends Controller
|
|||
return $this->saveFile($save->getFile(), $request->uuid);
|
||||
}
|
||||
// We are in chunk mode, lets send the current progress.
|
||||
/** @var AbstractHandler $handler */
|
||||
$handler = $save->handler();
|
||||
return response()->json([
|
||||
"done" => $handler->getPercentageDone(),
|
||||
"done" => $handler->getPercentageDone(),
|
||||
'status' => true
|
||||
]);
|
||||
}
|
||||
|
|
@ -237,14 +256,14 @@ class DocumentController extends Controller
|
|||
* @param string|null $uuid
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
protected function saveFile(UploadedFile $file, ?string $uuid): JsonResponse
|
||||
protected function saveFile(UploadedFile $file, ?string $uuid): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||
$disk = Storage::disk('docs');
|
||||
$uuid = $uuid ?: Str::uuid();
|
||||
|
||||
/** @var \Illuminate\Http\UploadedFile $file */
|
||||
$filename = $uuid . '.' . $file->guessExtension();
|
||||
$filename = sprintf('%s/%s.%s', \tenant()->getKey(), $uuid, $file->guessExtension());
|
||||
$disk->putFileAs('', $file, $filename);
|
||||
|
||||
return response()->json([
|
||||
|
|
|
|||
|
|
@ -2,33 +2,38 @@
|
|||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Enums\Formularies\InputStatusEnum;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Formularies\StoreFormularyRequest;
|
||||
use App\Http\Requests\Bo\Formularies\UpdateFormularyRequest;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Models\Contact;
|
||||
use App\Models\Formulary;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class FormularyController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
|
||||
/**
|
||||
* Create the controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Formulary::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
public function index(Request $request): \Illuminate\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
||||
$query = Formulary::query();
|
||||
|
||||
/** @var string $search Search field */
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
|
|
@ -37,33 +42,34 @@ class FormularyController extends Controller
|
|||
'name',
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Nom');
|
||||
$searchFields = trans('validation.attributes.name');
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($query);
|
||||
|
||||
$formulariesModel = $this->paginate($query);
|
||||
$formularyModels = $this->paginate($query);
|
||||
|
||||
return view('bo.pages.formularies.index', compact('formulariesModel', 'searchFields'));
|
||||
return view('bo.pages.formularies.index', compact('formularyModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\Formulary $formulary
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
public function create(Formulary $formulary): \Illuminate\View\View
|
||||
{
|
||||
return view('bo.pages.formularies.create');
|
||||
return view('bo.pages.formularies.create', ['formularyModel' => $formulary]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Formularies\StoreFormularyRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\Formularies\StoreFormularyRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreFormularyRequest $request)
|
||||
public function store(StoreFormularyRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$formulary = new Formulary();
|
||||
|
|
@ -71,17 +77,17 @@ class FormularyController extends Controller
|
|||
|
||||
if ($formulary->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.formularies.edit', $formulary)
|
||||
->route('bo.formularies.edit', ['tenant' => \tenant(), 'formulary' => $formulary])
|
||||
->with('success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.formularies'))]
|
||||
['model' => trans('models.classes.formulary')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été créé',
|
||||
['model' => Str::singular(trans('models.classes.formularies'))]
|
||||
['model' => trans('models.classes.formulary')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -90,48 +96,40 @@ class FormularyController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Formulary $formulary
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(Formulary $formulary)
|
||||
public function edit(Formulary $formulary): \Illuminate\Http\RedirectResponse|\Illuminate\Contracts\View\View
|
||||
{
|
||||
if ($formulary->status->value === InputStatusEnum::system()->value) {
|
||||
return redirect()->route('bo.formularies.index')
|
||||
->with('error', trans(
|
||||
'Administration du champs :name impossible car il est vérouillé !',
|
||||
['name' => $formulary->name]
|
||||
));
|
||||
} else {
|
||||
return view('bo.pages.formularies.edit', [
|
||||
'formularyModel' => $formulary
|
||||
]);
|
||||
}
|
||||
return view('bo.pages.formularies.edit', [
|
||||
'formularyModel' => $formulary
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Formulary\UpdateFormularyRequest $request
|
||||
* @param \App\Models\Formulary $formulary
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\Formularies\UpdateFormularyRequest $request
|
||||
* @param \App\Models\Formulary $formulary
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateFormularyRequest $request, Formulary $formulary)
|
||||
public function update(UpdateFormularyRequest $request, Formulary $formulary): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $formulary) {
|
||||
$formulary->fill($request->validated());
|
||||
|
||||
if ($formulary->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.formularies.edit', $formulary)
|
||||
->route('bo.formularies.edit', ['tenant' => \tenant(), 'formulary' => $formulary])
|
||||
->with('success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.formularies'))]
|
||||
['model' => trans('models.classes.formulary')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.formularies'))]
|
||||
['model' => trans('models.classes.formulary')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -139,29 +137,41 @@ class FormularyController extends Controller
|
|||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Formulary $formulary
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\Formulary $formulary
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Formulary $formulary)
|
||||
public function destroy(Formulary $formulary): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($formulary) {
|
||||
/** @var array<string,string> */
|
||||
$previousQueries = [];
|
||||
\parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries);
|
||||
return DB::transaction(function () use ($formulary, $previousQueries) {
|
||||
// * Remove the input on all contacts.
|
||||
ToolboxHelper::removeDataInputOnAllContacts($formulary);
|
||||
Contact::removeDataInputOnAllContacts($formulary);
|
||||
if ($formulary->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.formularies.index')
|
||||
->route('bo.formularies.index', array_merge(['tenant' => \tenant()], $previousQueries))
|
||||
->with('warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.formularies'))]
|
||||
['model' => trans('models.classes.formulary')]
|
||||
));
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.formularies'))]
|
||||
));
|
||||
return redirect()->back()->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => trans('models.classes.formulary')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate the specified resource.
|
||||
*
|
||||
* @param \App\Models\Formulary $formulary
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function duplicate(Formulary $formulary): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return $this->create($formulary->replicate());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,38 +6,62 @@ use App\Http\Controllers\Controller;
|
|||
use App\Http\Requests\Bo\Settings\UpdateSettingRequest;
|
||||
use App\Models\Directory;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create the controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Setting::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index()
|
||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$directories = Directory::renderDirectories(Directory::whereNull('directory_id')->get());
|
||||
$directories = Directory::renderDirectories(
|
||||
Directory::query()->whereNull('directory_id')->with('parent')->get(),
|
||||
);
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $settings */
|
||||
$settings = Setting::query();
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
||||
$query = Setting::query();
|
||||
|
||||
$this->sortQuery($settings);
|
||||
$settings = $settings->get();
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
$request->search,
|
||||
null,
|
||||
'key',
|
||||
);
|
||||
}
|
||||
$searchFields = trans('validation.custom.key');
|
||||
|
||||
return view('bo.pages.settings.index', compact('settings', 'directories'));
|
||||
$this->sortQuery($query);
|
||||
|
||||
$settingModels = $query->get();
|
||||
|
||||
return view('bo.pages.settings.index', compact('settingModels', 'searchFields', 'directories'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Setting $setting
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(Setting $setting)
|
||||
public function edit(Setting $setting): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$directories = Directory::renderDirectories(Directory::whereNull('directory_id')->get());
|
||||
$directories = Directory::renderDirectories(
|
||||
Directory::query()->whereNull('directory_id')->with('parent')->get(),
|
||||
);
|
||||
|
||||
return view('bo.pages.settings.edit', ['settingModel' => $setting, 'directories' => $directories]);
|
||||
}
|
||||
|
|
@ -45,27 +69,27 @@ class SettingController extends Controller
|
|||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Setting\UpdateSettingRequest $request
|
||||
* @param \App\Models\Setting $setting
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\Settings\UpdateSettingRequest $request
|
||||
* @param \App\Models\Setting $setting
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateSettingRequest $request, Setting $setting)
|
||||
public function update(UpdateSettingRequest $request, Setting $setting): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $setting) {
|
||||
$setting->fill($request->validated());
|
||||
if ($setting->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.settings.edit', $setting)
|
||||
->route('bo.settings.edit', ['tenant' => \tenant(), 'setting' => $setting])
|
||||
->with('success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.settings'))]
|
||||
['model' => trans('models.classes.setting')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.settings'))]
|
||||
['model' => trans('models.classes.setting')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -73,24 +97,26 @@ class SettingController extends Controller
|
|||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Setting $setting
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\Setting $setting
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Setting $setting)
|
||||
public function destroy(Setting $setting): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
if ($setting->deleteOrFail()) {
|
||||
return DB::transaction(function () use ($setting) {
|
||||
if ($setting->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.settings.index', ['tenant' => \tenant()])
|
||||
->with('warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => trans('models.classes.setting')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->route('bo.settings.index')
|
||||
->with('warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.settings'))]
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => trans('models.classes.setting')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.settings'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,24 +9,30 @@ use App\Models\Tag;
|
|||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
|
||||
/**
|
||||
* Create the controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Tag::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index(Request $request)
|
||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
||||
$query = Tag::query();
|
||||
|
||||
/** @var string $search Search field */
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
|
|
@ -35,50 +41,51 @@ class TagController extends Controller
|
|||
'name',
|
||||
);
|
||||
}
|
||||
$searchFields = trans('Nom');
|
||||
$searchFields = trans('validation.attributes.name');
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($query);
|
||||
|
||||
$tags = $this->paginate($query);
|
||||
$tagModels = $this->paginate($query);
|
||||
|
||||
return view('bo.pages.tags.index', compact('tags', 'searchFields'));
|
||||
return view('bo.pages.tags.index', compact('tagModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\Tag $tag
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function create()
|
||||
public function create(Tag $tag): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.tags.create');
|
||||
return view('bo.pages.tags.create', ['tagModel' => $tag]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Tag\StoreTagRequest $request
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\Tags\StoreTagRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreTagRequest $request)
|
||||
public function store(StoreTagRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$tag = new Tag();
|
||||
$tag->fill($request->validated());
|
||||
if ($tag->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.tags.edit', $tag)
|
||||
->route('bo.tags.edit', ['tenant' => \tenant(), 'tag' => $tag])
|
||||
->with('success', trans(
|
||||
':model a été créé',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
['model' => trans('models.classes.tag')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été créé',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
['model' => trans('models.classes.tag')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -87,9 +94,9 @@ class TagController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Tag $tag
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(Tag $tag)
|
||||
public function edit(Tag $tag): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.tags.edit', ['tagModel' => $tag]);
|
||||
}
|
||||
|
|
@ -97,28 +104,28 @@ class TagController extends Controller
|
|||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Tag\UpdateTagRequest $request
|
||||
* @param \App\Models\Tag $tag
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Http\Requests\Bo\Tags\UpdateTagRequest $request
|
||||
* @param \App\Models\Tag $tag
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateTagRequest $request, Tag $tag)
|
||||
public function update(UpdateTagRequest $request, Tag $tag): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $tag) {
|
||||
$tag->fill($request->validated());
|
||||
|
||||
if ($tag->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.tags.edit', $tag)
|
||||
->route('bo.tags.edit', ['tenant' => \tenant(), 'tag' => $tag])
|
||||
->with('success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
['model' => trans('models.classes.tag')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été mis à jour',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
['model' => trans('models.classes.tag')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
@ -126,24 +133,40 @@ class TagController extends Controller
|
|||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Tag $tag
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param \App\Models\Tag $tag
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Tag $tag)
|
||||
public function destroy(Tag $tag): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
if ($tag->deleteOrFail()) {
|
||||
/** @var array<string,string> */
|
||||
$previousQueries = [];
|
||||
\parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries);
|
||||
return DB::transaction(function () use ($tag, $previousQueries) {
|
||||
if ($tag->deleteOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.tags.index', array_merge(['tenant' => \tenant()], $previousQueries))
|
||||
->with('warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => trans('models.classes.tag')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->route('bo.tags.index')
|
||||
->with('warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => trans('models.classes.tag')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => Str::singular(trans('models.classes.tags'))]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate the specified resource.
|
||||
*
|
||||
* @param \App\Models\Tag $tag
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function duplicate(Tag $tag): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return $this->create($tag->replicate());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
174
app/Http/Controllers/Bo/TenantController.php
Normal file
174
app/Http/Controllers/Bo/TenantController.php
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Bo\Tenants\StoreTenantRequest;
|
||||
use App\Http\Requests\Bo\Tenants\UpdateTenantRequest;
|
||||
use App\Models\Tenant;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class TenantController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create the controller instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authorizeResource(Tenant::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
||||
$query = Tenant::query();
|
||||
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$query,
|
||||
$request->search,
|
||||
null,
|
||||
'name',
|
||||
);
|
||||
}
|
||||
$searchFields = trans('validation.attributes.name');
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($query);
|
||||
|
||||
$tenantModels = $this->paginate($query);
|
||||
|
||||
return view('bo.pages.tenants.index', compact('tenantModels', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param \App\Models\Tenant $tenant
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function create(Tenant $tenant): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.tenants.create', ['tenantModel' => $tenant]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Tenants\StoreTenantRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreTenantRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$tenant = new Tenant();
|
||||
$tenant->fill($request->validated());
|
||||
if ($tenant->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.tenants.edit', ['tenant' => $tenant])
|
||||
->with('success', trans(
|
||||
':model a été créé',
|
||||
['model' => trans('models.classes.tenant')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été créé',
|
||||
['model' => trans('models.classes.tenant')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\Tenant $tenant
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(Tenant $tenant): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return view('bo.pages.tenants.edit', ['tenantModel' => $tenant]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Tenants\UpdateTenantRequest $request
|
||||
* @param \App\Models\Tenant $tenant
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateTenantRequest $request, Tenant $tenant): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $tenant) {
|
||||
$tenant->fill($request->validated());
|
||||
|
||||
if ($tenant->saveOrFail()) {
|
||||
return redirect()
|
||||
->route('bo.tenants.edit', ['tenant' => $tenant])
|
||||
->with('success', trans(
|
||||
':model a été mis à jour',
|
||||
['model' => trans('models.classes.tenant')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été mis à jour',
|
||||
['model' => trans('models.classes.tenant')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Tenant $tenant
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(Tenant $tenant): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
/** @var array<string,string> */
|
||||
$previousQueries = [];
|
||||
\parse_str(\parse_url(url()->previous(), \PHP_URL_QUERY), $previousQueries);
|
||||
return DB::transaction(function () use ($tenant, $previousQueries) {
|
||||
if ($tenant->deleteOrFail()) {
|
||||
/** @var string $tenantKey */
|
||||
$tenantKey = $tenant->getKey();
|
||||
Storage::disk('public')->deleteDirectory("modelfiles/{$tenantKey}");
|
||||
Storage::disk('public')->deleteDirectory("docs/{$tenantKey}");
|
||||
return redirect()
|
||||
->route('bo.tenants.index', $previousQueries)
|
||||
->with('warning', trans(
|
||||
':model a bien été supprimé',
|
||||
['model' => trans('models.classes.tenant')]
|
||||
));
|
||||
}
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', trans(
|
||||
':model n\'a pas été supprimé',
|
||||
['model' => trans('models.classes.tenant')]
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate the specified resource.
|
||||
*
|
||||
* @param \App\Models\Tenant $tenant
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function duplicate(Tenant $tenant): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return $this->create($tenant->replicate());
|
||||
}
|
||||
}
|
||||
170
app/Http/Controllers/Bo/UserController.php
Normal file
170
app/Http/Controllers/Bo/UserController.php
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<?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\Tenant;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
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\View
|
||||
*/
|
||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $userModels */
|
||||
$userModels = User::query()->with('tenants');
|
||||
|
||||
/** @var string $search Search field */
|
||||
$search = $request->search;
|
||||
if ($search) {
|
||||
$this->searchQuery(
|
||||
$userModels,
|
||||
$search,
|
||||
null,
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'role',
|
||||
);
|
||||
}
|
||||
$searchFields = \implode(', ', [
|
||||
trans('validation.attributes.first_name'),
|
||||
trans('validation.attributes.last_name'),
|
||||
trans('validation.attributes.email'),
|
||||
trans('validation.attributes.role'),
|
||||
]);
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($userModels);
|
||||
|
||||
/** Custom pagination */
|
||||
$userModels = $this->paginate($userModels);
|
||||
|
||||
return view('bo.pages.users.index', compact('userModels', 'search', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function create(User $user): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$tenants = Tenant::query()->orderBy('name', 'asc')->get();
|
||||
return view('bo.pages.users.create', ['userModel' => $user, 'tenants' => $tenants]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\Users\StoreUserRequest $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(StoreUserRequest $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request) {
|
||||
$user = new User();
|
||||
$user->fill($request->validated());
|
||||
|
||||
if ($user->saveOrFail()) {
|
||||
$user->tenants()->sync(collect($request->validated('tenants'))->pluck('id'));
|
||||
return redirect()->route('bo.users.edit', ['tenant' => tenant(), 'user' => $user])
|
||||
->with('success', __('crud.messages.has_been_created', [
|
||||
'model' => Str::ucfirst(__('models.classes.user'))
|
||||
]));
|
||||
}
|
||||
return redirect()->back()
|
||||
->with('error', __('crud.messages.cannot_be_created', [
|
||||
'model' => Str::ucfirst(__('models.classes.user'))
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function edit(User $user): \Illuminate\Contracts\View\View
|
||||
{
|
||||
$tenants = Tenant::query()->orderBy('name', 'asc')->get();
|
||||
return view('bo.pages.users.edit', ['userModel' => $user, 'tenants' => $tenants]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
return DB::transaction(function () use ($request, $user) {
|
||||
$user->fill($request->validated());
|
||||
|
||||
if ($user->saveOrFail()) {
|
||||
$user->tenants()->sync(collect($request->validated('tenants'))->pluck('id'));
|
||||
return redirect()->route('bo.users.edit', ['tenant' => tenant(), 'user' => $user])
|
||||
->with('success', __('crud.messages.has_been_updated', [
|
||||
'model' => Str::ucfirst(__('models.classes.user'))
|
||||
]));
|
||||
}
|
||||
return redirect()->route('bo.users.edit', ['tenant' => tenant(), 'user' => $user])
|
||||
->with('error', __('crud.messages.cannot_be_updated', [
|
||||
'model' => Str::ucfirst(__('models.classes.user'))
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(User $user): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
if ($user->deleteOrFail()) {
|
||||
return redirect()->route('bo.users.index', ['tenant' => tenant()])
|
||||
->with('success', __('crud.messages.has_been_deleted', [
|
||||
'model' => Str::ucfirst(__('models.classes.user'))
|
||||
]));
|
||||
}
|
||||
return redirect()->back()
|
||||
->with('error', __('crud.messages.cannot_be_deleted', [
|
||||
'model' => Str::ucfirst(__('models.classes.user'))
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate the specified resource.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function duplicate(User $user): \Illuminate\Contracts\View\View
|
||||
{
|
||||
return $this->create($user->replicate());
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use App\Enums\ItemsPerPaginationEnum;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
|
|
@ -14,6 +12,7 @@ use Illuminate\Support\Facades\Cache;
|
|||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
use Uwil\LaravelCommon\Helpers\ToolboxHelper;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
|
|
@ -27,7 +26,7 @@ class Controller extends BaseController
|
|||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query The eloquent query builder.
|
||||
* @param string $search The query string.
|
||||
* @param callable $searchQuery The query string.
|
||||
* @param callable|null $searchQuery The query string.
|
||||
* @param string ...$fields Either a simple array or a string
|
||||
* in case of a string the two fields
|
||||
* would be concatenate to make the search.
|
||||
|
|
@ -36,7 +35,7 @@ class Controller extends BaseController
|
|||
protected function searchQuery(
|
||||
Builder $query,
|
||||
string $search,
|
||||
callable $searchQuery = null,
|
||||
callable|null $searchQuery = null,
|
||||
string ...$fields
|
||||
): Builder {
|
||||
if (count($fields)) {
|
||||
|
|
@ -96,16 +95,16 @@ class Controller extends BaseController
|
|||
* @param array $ignore
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
protected function sortQuery(Builder $query, array $ignore = []): Builder
|
||||
protected function sortQuery(Builder $query, array $ignore = []): \Illuminate\Database\Eloquent\Builder
|
||||
{
|
||||
$rName = request()->route()->getName();
|
||||
$table = $query->getModel()->getTable();
|
||||
if (request()->sort_col) {
|
||||
Session::put("$rName.sort_col", request()->sort_col);
|
||||
if (request()->input('sort_col')) {
|
||||
Session::put("$rName.sort_col", request()->input('sort_col'));
|
||||
Session::put("$rName.sorted", true);
|
||||
}
|
||||
if (request()->sort_way) {
|
||||
Session::put("$rName.sort_way", request()->sort_way);
|
||||
if (request()->input('sort_way')) {
|
||||
Session::put("$rName.sort_way", request()->input('sort_way'));
|
||||
Session::put("$rName.sorted", true);
|
||||
}
|
||||
if (request()->rst) {
|
||||
|
|
@ -113,17 +112,29 @@ class Controller extends BaseController
|
|||
Session::remove("$rName.sort_col");
|
||||
Session::remove("$rName.sort_way");
|
||||
}
|
||||
if (request()->sort_col and request()->sort_way and Schema::hasColumn($table, request()->sort_col)) {
|
||||
if (
|
||||
!isset($ignore) or
|
||||
(isset($ignore) and !in_array(request()->sort_col, $ignore))
|
||||
) {
|
||||
$query = $query->orderBy(\sprintf("$table.%s", request()->sort_col), request()->sort_way);
|
||||
if (
|
||||
request()->input('sort_col') and
|
||||
request()->input('sort_way') and
|
||||
Schema::hasColumn($table, request()->input('sort_col'))
|
||||
) {
|
||||
if (!in_array(request()->input('sort_col'), $ignore)) {
|
||||
$query = $query->orderBy(
|
||||
\sprintf("$table.%s", request()->input('sort_col')),
|
||||
request()->input('sort_way')
|
||||
);
|
||||
}
|
||||
} elseif (Schema::hasColumn($table, 'order')) {
|
||||
$query = $query->orderBy('order', 'ASC');
|
||||
$query = $query->orderBy('order', 'asc');
|
||||
Session::put("$rName.sort_col", 'order');
|
||||
Session::put("$rName.sort_way", 'asc');
|
||||
} elseif (Schema::hasColumn($table, 'updated_at')) {
|
||||
$query = $query->orderBy('updated_at', 'desc');
|
||||
Session::put("$rName.sort_col", 'updated_at');
|
||||
Session::put("$rName.sort_way", 'desc');
|
||||
} elseif (Schema::hasColumn($table, 'created_at')) {
|
||||
$query = $query->orderBy('created_at', 'desc');
|
||||
Session::put("$rName.sort_col", 'created_at');
|
||||
Session::put("$rName.sort_way", 'desc');
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
|
@ -131,17 +142,21 @@ class Controller extends BaseController
|
|||
/**
|
||||
* Customize pagination with cache or config (default).
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param \App\Enums\Pagination\ItemsPerPaginationEnum|null $pagination
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param \App\Enums\ItemsPerPaginationEnum|null $pagination
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
*/
|
||||
protected function paginate(Builder $query, ItemsPerPaginationEnum $pagination = null): LengthAwarePaginator
|
||||
{
|
||||
protected function paginate(
|
||||
Builder $query,
|
||||
ItemsPerPaginationEnum|null $pagination = null
|
||||
): \Illuminate\Contracts\Pagination\LengthAwarePaginator {
|
||||
$currentRoutePath = Str::slug(request()->route()->getName());
|
||||
$cacheKey = "pagination.{$currentRoutePath}";
|
||||
$pagination = $pagination ?? ItemsPerPaginationEnum::twelve();
|
||||
$pagination = ToolboxHelper::getValidatedPaginate(
|
||||
Cache::get($cacheKey, $pagination->value)
|
||||
$pagination = $pagination ?? ItemsPerPaginationEnum::twelve;
|
||||
$pagination = ToolboxHelper::getValidatedEnum(
|
||||
Cache::get($cacheKey, $pagination->value()),
|
||||
'pagination',
|
||||
'\App\Enums\ItemsPerPaginationEnum',
|
||||
);
|
||||
if (Cache::get($cacheKey) !== $pagination) {
|
||||
Cache::put($cacheKey, $pagination);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ class Kernel extends HttpKernel
|
|||
protected $middleware = [
|
||||
\App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Fruitcake\Cors\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
|
|
@ -37,7 +36,13 @@ class Kernel extends HttpKernel
|
|||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\SecureHeaders::class
|
||||
\App\Http\Middleware\SecureHeaders::class,
|
||||
],
|
||||
|
||||
'saml' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
|
|
@ -54,16 +59,17 @@ class Kernel extends HttpKernel
|
|||
* @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,
|
||||
'api.token' => \App\Http\Middleware\CheckApiToken::class,
|
||||
'api.token' => \App\Http\Middleware\CheckApiToken::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'htmlsanitize' => \App\Http\Middleware\HtmlSanitizer::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'restrict_tenant_access' => \App\Http\Middleware\RestrictTenantAccess::class,
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Authenticate extends Middleware
|
|||
* @param mixed $request
|
||||
* @return string|null
|
||||
*/
|
||||
protected function redirectTo($request)
|
||||
protected function redirectTo(mixed $request): string|null
|
||||
{
|
||||
$logins = [
|
||||
'backend' => route('bo.login')
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class CheckApiToken
|
|||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
public function handle(Request $request, Closure $next): mixed
|
||||
{
|
||||
if (isset($request->token) && $request->token == config('auth.API_TOKEN')) {
|
||||
return $next($request);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,5 @@ class EncryptCookies extends Middleware
|
|||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $except = [
|
||||
];
|
||||
protected $except = [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use Uwil\LaravelCommon\Helpers\ToolboxHelper;
|
||||
|
||||
class HtmlSanitizer
|
||||
{
|
||||
|
|
@ -15,7 +15,7 @@ class HtmlSanitizer
|
|||
* @param mixed ...$params
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, \Closure $next, ...$params)
|
||||
public function handle(Request $request, \Closure $next, mixed ...$params): mixed
|
||||
{
|
||||
$inputs = $request->all();
|
||||
/** @var callable|null */
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ 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
|
||||
|
|
@ -19,8 +20,11 @@ class RedirectIfAuthenticated
|
|||
* @throws \RuntimeException If guard is unhandled.
|
||||
* @phpcs:enable
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, ...$guards)
|
||||
{
|
||||
public function handle(
|
||||
Request $request,
|
||||
Closure $next,
|
||||
string|null ...$guards
|
||||
): \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse {
|
||||
$guards = empty($guards) ? [null] : $guards;
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
|
|
|
|||
48
app/Http/Middleware/RestrictTenantAccess.php
Normal file
48
app/Http/Middleware/RestrictTenantAccess.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\Tenant;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class RestrictTenantAccess
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): \Symfony\Component\HttpFoundation\Response
|
||||
{
|
||||
/** @var \App\Models\User|null $user */
|
||||
$user = \auth('backend')->user();
|
||||
if ($user) {
|
||||
if (
|
||||
!$request->routeIs(['bo.dashboard', 'bo.users.*', 'bo.tenants.*']) &&
|
||||
$request->tenant &&
|
||||
!\in_array($request->tenant, Tenant::get()->pluck('id')->toArray())
|
||||
) {
|
||||
// @phpstan-ignore argument.type
|
||||
abort('404');
|
||||
}
|
||||
if (Tenant::count() && $request->routeIs(['bo.tenants.*', 'bo.users.*']) && $user->can('isAdmin')) {
|
||||
$tenant = Tenant::first()->getKey();
|
||||
tenancy()->initialize($tenant);
|
||||
return $next($request);
|
||||
}
|
||||
if (
|
||||
Tenant::count() && ($request->routeIs('bo.dashboard')
|
||||
|| $request->routeIs('bo.users.edit', $user->getKey()))
|
||||
) {
|
||||
$tenant = ($user->tenants->count()) ? $user->tenants->first() : Tenant::first()->getKey();
|
||||
tenancy()->initialize($tenant);
|
||||
return $next($request);
|
||||
}
|
||||
} //end if
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ use Closure;
|
|||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\Vite;
|
||||
|
||||
class SecureHeaders
|
||||
{
|
||||
|
|
@ -26,14 +27,13 @@ class SecureHeaders
|
|||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
public function handle(Request $request, Closure $next): \Symfony\Component\HttpFoundation\Response
|
||||
{
|
||||
View::share('nonce', $nonce = \uniqid());
|
||||
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);
|
||||
|
|
@ -49,19 +49,18 @@ class SecureHeaders
|
|||
// * CKEDITOR Specific https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/csp.html
|
||||
"connect-src 'self' blob:;",
|
||||
"img-src * data: blob:;",
|
||||
"object-src 'self' " . implode(' ', []) . ';',
|
||||
'frame-src ' . implode(' ', []) . ';',
|
||||
"font-src 'self' data: ;",
|
||||
// ! 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'
|
||||
'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:',
|
||||
]) . ';'
|
||||
|
|
@ -76,12 +75,12 @@ class SecureHeaders
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove unwanted headers
|
||||
* Remove unwanted headers.
|
||||
*
|
||||
* @param array $headerList
|
||||
* @return void
|
||||
*/
|
||||
private function removeUnwantedHeaders(array $headerList)
|
||||
private function removeUnwantedHeaders(array $headerList): void
|
||||
{
|
||||
foreach ($headerList as $header) {
|
||||
header_remove($header);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class TrustHosts extends Middleware
|
|||
*
|
||||
* @return array<int, string|null>
|
||||
*/
|
||||
public function hosts()
|
||||
public function hosts(): array
|
||||
{
|
||||
return [
|
||||
$this->allSubdomainsOfApplicationUrl(),
|
||||
|
|
|
|||
|
|
@ -6,26 +6,15 @@ use Illuminate\Foundation\Http\FormRequest;
|
|||
|
||||
class DestroyContactsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// * Check is done with api.token middleware
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'contactUuidList' => \collect($this->contactUuidList)->filter()->all()
|
||||
'contactUuidList' => \collect($this->contactUuidList)->filter()->all(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -34,10 +23,10 @@ class DestroyContactsRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'contactUuidList' => 'present|array|min:0',
|
||||
'contactUuidList' => 'present|array|min:0',
|
||||
'contactUuidList.*' => 'uuid',
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,27 +6,16 @@ use App\Enums\Formularies\InputTypeEnum;
|
|||
use App\Lib\Inputs\Definition\InputData;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class UpsertContactsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// * Check is done with api.token middleware
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'contacts' => \collect($this->contacts)->filter()
|
||||
|
|
@ -61,35 +50,35 @@ class UpsertContactsRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'contacts' => 'present|array',
|
||||
'contacts.*' => 'array',
|
||||
'contacts.*.id' => 'uuid',
|
||||
'contacts.*.lastname' => 'nullable|string|max:255',
|
||||
'contacts.*.firstname' => 'nullable|string|max:255',
|
||||
'contacts' => 'present|array',
|
||||
'contacts.*' => 'array',
|
||||
'contacts.*.id' => 'uuid',
|
||||
'contacts.*.lastname' => 'nullable|string|between:1,255',
|
||||
'contacts.*.firstname' => 'nullable|string|between:1,255',
|
||||
// * Dot not validate email here (soft validate), if it does not pass, app will be blocked.
|
||||
'contacts.*.email' => 'required|string|max:255',
|
||||
'contacts.*.phone' => 'nullable|string|max:255',
|
||||
'contacts.*.email' => 'required|string|between:1,255',
|
||||
'contacts.*.phone' => 'nullable|string|between:1,255',
|
||||
'contacts.*.timestamp' => 'required|date',
|
||||
|
||||
// * DATA
|
||||
'contacts.*.data' => 'present|array',
|
||||
'contacts.*.dataParsed' => 'present',
|
||||
'contacts.*.data.*' => 'array',
|
||||
'contacts.*.data.*.title' => 'present|string|min:1|max:255',
|
||||
'contacts.*.data.*.formSlug' => 'present|string|min:1|max:255',
|
||||
'contacts.*.data.*.type' => ['present', new EnumIsValidRule(InputTypeEnum::class)],
|
||||
'contacts.*.data.*.value' => 'present',
|
||||
'contacts.*.data.*.required' => 'present|boolean',
|
||||
'contacts.*.data' => 'present|array',
|
||||
'contacts.*.dataParsed' => 'present',
|
||||
'contacts.*.data.*' => 'array',
|
||||
'contacts.*.data.*.title' => 'present|string|min:1|max:255',
|
||||
'contacts.*.data.*.formSlug' => 'present|string|min:1|max:255',
|
||||
'contacts.*.data.*.type' => ['present', new Enum(InputTypeEnum::class)],
|
||||
'contacts.*.data.*.value' => 'present',
|
||||
'contacts.*.data.*.required' => 'present|boolean',
|
||||
'contacts.*.data.*.send_to_app_user_id' => 'nullable|numeric',
|
||||
|
||||
'contacts.*.notes' => 'nullable|string',
|
||||
'contacts.*.visits' => 'present|array',
|
||||
'contacts.*.visits.*' => 'required|array',
|
||||
'contacts.*.notes' => 'nullable|string',
|
||||
'contacts.*.visits' => 'present|array',
|
||||
'contacts.*.visits.*' => 'required|array',
|
||||
'contacts.*.visits.*.title' => 'present|string',
|
||||
'contacts.*.visits.*.note' => 'present|string',
|
||||
'contacts.*.visits.*.note' => 'present|string',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +90,7 @@ class UpsertContactsRequest extends FormRequest
|
|||
* @return mixed
|
||||
* @throws \Illuminate\Validation\ValidationException In case of parse failure.
|
||||
*/
|
||||
private function filterDataLine(array $data, $index)
|
||||
private function filterDataLine(array $data, mixed $index): mixed
|
||||
{
|
||||
$data = \collect($data);
|
||||
try {
|
||||
|
|
@ -117,10 +106,15 @@ class UpsertContactsRequest extends FormRequest
|
|||
'error' => "wrong formSlug on data index '{$index}'"
|
||||
]);
|
||||
}
|
||||
$type = InputTypeEnum::make($data->get('type') ? $data->get('type') : null);
|
||||
$type = InputTypeEnum::make($data->get('type') ? $data->get('type') : null);
|
||||
if (\is_null($type)) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => "wrong inputType on data index '{$index}'"
|
||||
]);
|
||||
}
|
||||
$value = $data['value'] ?? null;
|
||||
$required = $data->get('required') ? true : false;
|
||||
$inputClass = $type->inputClass;
|
||||
$inputClass = $type->getInputClass();
|
||||
return $inputClass::from(InputData::make(
|
||||
$title,
|
||||
$formSlug,
|
||||
|
|
|
|||
56
app/Http/Requests/Api/SendFlyerRequest.php
Normal file
56
app/Http/Requests/Api/SendFlyerRequest.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Api;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/** FIXME: currently not used but will be in the future. */
|
||||
class SendFlyerRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'emails.email' => [
|
||||
'required',
|
||||
'email:rfc,strict,dns,spoof,filter',
|
||||
Rule::exists('contacts', 'email')->where(function ($query) {
|
||||
$query->whereIn('app_user_id', function ($subQuery) {
|
||||
$subQuery->select('id')->from('app_users')->where('tenant_id', $this->tenant);
|
||||
});
|
||||
}),
|
||||
],
|
||||
'emails.subject' => 'required|string|between:3,255',
|
||||
'emails.message' => 'required|string|min:3',
|
||||
'emails.app_user_id' => [
|
||||
'required',
|
||||
'integer',
|
||||
Rule::exists('app_users', 'id')->where('tenant_id', $this->tenant)
|
||||
],
|
||||
'emails.documents' => 'required|array|min:1',
|
||||
'emails.documents.*.title' => 'required|string|min:3',
|
||||
'emails.documents.*.uuid' => 'required|string|min:3',
|
||||
'emails.documents.*.type' => 'required|string|min:1',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'emails.email' => trans('validation.attributes.email'),
|
||||
'emails.subject' => trans('validation.attributes.subject'),
|
||||
'emails.message' => trans('validation.attributes.message'),
|
||||
'emails.app_user_id' => trans('models.classes.app_user'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,13 @@
|
|||
namespace App\Http\Requests\Bo\AppUser;
|
||||
|
||||
use App\Enums\AppUserRolesEnum;
|
||||
use App\Models\AppUser;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
|
||||
class StoreAppUserRequest extends FormRequest
|
||||
|
|
@ -14,9 +19,9 @@ class StoreAppUserRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
return Gate::check('create', AppUser::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -24,10 +29,10 @@ class StoreAppUserRequest extends FormRequest
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'status' => $this->status ? true : false,
|
||||
'status' => $this->status ? true : false,
|
||||
'authorizedFolders' => $this->authorizedFolders ? $this->authorizedFolders : [],
|
||||
]);
|
||||
}
|
||||
|
|
@ -37,14 +42,22 @@ class StoreAppUserRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'lastname' => 'required|min:3|max:255',
|
||||
'firstname' => 'required|min:3|max:255',
|
||||
'email' => 'required|min:3|max:255|email:rfc,dns|unique:app_users,email',
|
||||
'password' => [
|
||||
'required', 'required_with:password_confirmation', 'confirmed', 'max:255',
|
||||
'lastname' => 'required|min:3|max:255',
|
||||
'firstname' => 'required|min:3|max:255',
|
||||
'email' => [
|
||||
'required',
|
||||
'email:rfc,strict,dns,spoof,filter',
|
||||
Rule::unique('app_users', 'email')
|
||||
->where(fn(Builder $query) => $query->where('tenant_id', tenant('id')))
|
||||
],
|
||||
'password' => [
|
||||
'required',
|
||||
'required_with:password_confirmation',
|
||||
'confirmed',
|
||||
'max:255',
|
||||
Password::min(8)
|
||||
->letters()
|
||||
->mixedCase()
|
||||
|
|
@ -52,11 +65,11 @@ class StoreAppUserRequest extends FormRequest
|
|||
->symbols()
|
||||
],
|
||||
'authorizedFolders' => 'present|array',
|
||||
'role' => [
|
||||
'role' => [
|
||||
'required',
|
||||
new EnumIsValidRule(AppUserRolesEnum::class)
|
||||
new Enum(AppUserRolesEnum::class)
|
||||
],
|
||||
'status' => 'required|boolean'
|
||||
'status' => 'required|boolean'
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -65,16 +78,16 @@ class StoreAppUserRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'lastname' => \trans('nom'),
|
||||
'firstname' => \trans('prénom'),
|
||||
'email' => \trans('email'),
|
||||
'password' => \trans('mot de passe'),
|
||||
'authorizedFolders' => \trans('dossiers autorisés'),
|
||||
'role' => \trans('rôle'),
|
||||
'status' => \trans('statut')
|
||||
'lastname' => \trans('validation.attributes.last_name'),
|
||||
'firstname' => \trans('validation.attributes.first_name'),
|
||||
'email' => \trans('validation.attributes.email'),
|
||||
'password' => \trans('validation.attributes.password'),
|
||||
'authorizedFolders' => Str::of(\trans('models.classes.directory'))->plural(),
|
||||
'role' => \trans('validation.custom.role'),
|
||||
'status' => \trans('validation.custom.status')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,29 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\AppUser;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
|
||||
class UpdateAppUserRequest extends StoreAppUserRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::check('update', $this->route('app_user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'email' => [
|
||||
|
|
@ -20,7 +32,9 @@ class UpdateAppUserRequest extends StoreAppUserRequest
|
|||
'min:3',
|
||||
'max:255',
|
||||
'email:rfc,dns',
|
||||
Rule::unique('app_users', 'email')->ignore($this->route('app_user')->id),
|
||||
Rule::unique('app_users', 'email')
|
||||
->where(fn (Builder $query) => $query->where('tenant_id', tenant('id')))
|
||||
->ignore($this->route('app_user')->getKey())
|
||||
],
|
||||
'password' => [
|
||||
'sometimes', 'nullable', 'required_with:password_confirmation', 'confirmed', 'max:255',
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
namespace App\Http\Requests\Bo\Directories;
|
||||
|
||||
use App\Enums\Documents\LangEnum;
|
||||
use App\Models\Directory;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class StoreDirectoryRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -12,9 +14,9 @@ class StoreDirectoryRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
return Gate::check('create', Directory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -22,7 +24,7 @@ class StoreDirectoryRequest extends FormRequest
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'needAuthorization' => $this->needAuthorization ? true : false,
|
||||
|
|
@ -37,8 +39,8 @@ class StoreDirectoryRequest extends FormRequest
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required|array',
|
||||
'name.*' => 'required|string|min:3|max:255',
|
||||
'name' => 'required|array',
|
||||
'name.*' => 'required|string|min:3|max:255',
|
||||
'needAuthorization' => 'required|boolean'
|
||||
];
|
||||
}
|
||||
|
|
@ -48,17 +50,15 @@ class StoreDirectoryRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
public function attributes(): array
|
||||
{
|
||||
$rules = [
|
||||
'name' => \trans('nom du dossier'),
|
||||
'needAuthorization' => \trans('autorisation du dossier')
|
||||
'name' => \trans('validation.attributes.name'),
|
||||
'needAuthorization' => \trans('validation.custom.authorization')
|
||||
];
|
||||
/** @var Object $langEnum */
|
||||
foreach (LangEnum::toArray() as $langEnum) {
|
||||
$def = $langEnum->getDefinition();
|
||||
$rules["name.{$def}"] = \trans('nom du dossier :lang', [
|
||||
'lang' => $langEnum->label
|
||||
]);
|
||||
$rules["name.{$langEnum->name}"] = sprintf('%s %s', trans('validation.attributes.name'), $langEnum->label);
|
||||
}
|
||||
return $rules;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,17 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Directories;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class UpdateDirectoryRequest extends StoreDirectoryRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::check('update', $this->route('directory'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ namespace App\Http\Requests\Bo\Documents;
|
|||
|
||||
use App\Enums\Documents\LangEnum;
|
||||
use App\Enums\Documents\TypeEnum;
|
||||
use App\Lib\Helpers\FileStorageHelper;
|
||||
use App\Models\Document;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
use Uwil\LaravelCommon\Helpers\FileHelper;
|
||||
|
||||
class StoreDocumentRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -17,9 +19,9 @@ class StoreDocumentRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
return Gate::check('create', Document::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -27,21 +29,15 @@ class StoreDocumentRequest extends FormRequest
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'status' => $this->status ? true : false
|
||||
'status' => $this->status ? true : false,
|
||||
]);
|
||||
if (Document::query()->where('id', $this->document_id)->exists()) {
|
||||
$this->merge([
|
||||
'directory_id' => Document::query()->where('id', $this->document_id)
|
||||
->value('directory_id')
|
||||
]);
|
||||
}
|
||||
// * Sanitize Path
|
||||
if (!empty($this->path)) {
|
||||
$filename = $this->path;
|
||||
$refMethod = new \ReflectionMethod(FileStorageHelper::class, 'sanitizeFileName');
|
||||
$refMethod = new \ReflectionMethod(FileHelper::class, 'sanitizeFileName');
|
||||
$refMethod->setAccessible(true);
|
||||
$filename = \pathinfo(
|
||||
$refMethod->invoke(null, htmlspecialchars($filename), false),
|
||||
|
|
@ -51,6 +47,12 @@ class StoreDocumentRequest extends FormRequest
|
|||
'path' => $filename
|
||||
]);
|
||||
}
|
||||
if (Document::query()->where('id', $this->document_id)->exists() && $this->type) {
|
||||
$this->merge([
|
||||
'directory_id' => Document::query()->where('id', $this->document_id)->value('directory_id'),
|
||||
'type' => TypeEnum::make($this->type, 'name')->name(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -58,20 +60,23 @@ class StoreDocumentRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||
$disk = Storage::disk('docs');
|
||||
return [
|
||||
'directory_id' => 'required|integer',
|
||||
'document_id' => 'sometimes:directory_id|nullable|integer',
|
||||
'uuid' => [
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
'required', 'uuid', function ($attribute, $value, $fail) use ($disk) {
|
||||
if ($this->type and \in_array($this->type, TypeEnum::toValues())) {
|
||||
$value = "{$value}.{$this->type}";
|
||||
'document_id' => 'sometimes:directory_id|nullable|integer',
|
||||
'uuid' => [
|
||||
'required',
|
||||
'uuid',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, $value, $fail) use ($disk) {
|
||||
if ($this->type and \array_column(TypeEnum::toArray(), 'name')) {
|
||||
$extension = TypeEnum::make($this->type, 'name')->name();
|
||||
$value = "{$value}.{$extension}";
|
||||
}
|
||||
if (!$disk->has($value)) {
|
||||
if (!$disk->has(sprintf('%s/%s', \tenant()->getKey(), $value))) {
|
||||
$path = $this->path ?? $this->value ?? 'not found';
|
||||
$fail(\trans('Le fichier :filename n\'est pas présent dans le système de fichier', [
|
||||
'filename' => $path
|
||||
|
|
@ -79,17 +84,11 @@ class StoreDocumentRequest extends FormRequest
|
|||
}
|
||||
}
|
||||
],
|
||||
'title' => 'required|min:3|max:255',
|
||||
'type' => [
|
||||
'required',
|
||||
new EnumIsValidRule(TypeEnum::class)
|
||||
],
|
||||
'path' => 'required|min:3|max:255',
|
||||
'lang' => [
|
||||
'required',
|
||||
new EnumIsValidRule(LangEnum::class)
|
||||
],
|
||||
'status' => 'required|boolean'
|
||||
'title' => 'required|min:3|max:255',
|
||||
'type' => ['required', 'string', Rule::in(array_column(TypeEnum::toArray(), 'name'))],
|
||||
'path' => 'required|min:3|max:255',
|
||||
'lang' => ['required', new Enum(LangEnum::class)],
|
||||
'status' => 'required|boolean'
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -98,17 +97,17 @@ class StoreDocumentRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'directory_id' => \trans('dossier à associer'),
|
||||
'document_id' => \trans('document (FR) à associer'),
|
||||
'title' => \trans('titre'),
|
||||
'uuid' => \trans('document'),
|
||||
'type' => \trans('type du document'),
|
||||
'path' => \trans('chemin du document'),
|
||||
'lang' => \trans('langue du document'),
|
||||
'status' => \trans('état de publication du document'),
|
||||
'directory_id' => \trans('models.classes.directory'),
|
||||
'document_id' => \trans('models.classes.document'),
|
||||
'title' => \trans('validation.attributes.title'),
|
||||
'uuid' => \trans('models.classes.document'),
|
||||
'type' => \trans('validation.custom.type'),
|
||||
'path' => \trans('validation.custom.path'),
|
||||
'lang' => \trans('validation.custom.lang'),
|
||||
'status' => \trans('validation.custom.status'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,17 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Documents;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class UpdateDocumentRequest extends StoreDocumentRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::check('update', $this->route('document'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class FilterCustomerRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -11,9 +12,9 @@ class FilterCustomerRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return \auth()->check();
|
||||
return \auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -21,10 +22,15 @@ class FilterCustomerRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'customer' => 'sometimes|nullable|numeric|exists:app_users,id'
|
||||
'customer' => [
|
||||
'sometimes',
|
||||
'nullable',
|
||||
'numeric',
|
||||
Rule::unique('app_users', 'id')->where('tenant_id', tenant('id'))
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ namespace App\Http\Requests\Bo\Formularies;
|
|||
|
||||
use App\Enums\Formularies\InputStatusEnum;
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Models\Formulary;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class StoreFormularyRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -15,14 +17,15 @@ class StoreFormularyRequest extends FormRequest
|
|||
* @var string[]
|
||||
*/
|
||||
private $mobileAppLocales = ['fr', 'en', 'de', 'nl'];
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
return Gate::check('create', Formulary::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -30,10 +33,10 @@ class StoreFormularyRequest extends FormRequest
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'required' => $this->required ? true : false,
|
||||
'required' => $this->required ? true : false,
|
||||
'is_visible' => $this->is_visible ? true : false,
|
||||
]);
|
||||
}
|
||||
|
|
@ -43,21 +46,21 @@ class StoreFormularyRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'type' => ['required', new EnumIsValidRule(InputTypeEnum::class)],
|
||||
'type' => ['required', new Enum(InputTypeEnum::class)],
|
||||
'placeholder' => 'present|array',
|
||||
'details' => 'nullable|array',
|
||||
'details.*' => 'required|array',
|
||||
'required' => 'required|boolean',
|
||||
'is_visible' => 'required|boolean',
|
||||
'details' => 'nullable|array',
|
||||
'details.*' => 'required|array',
|
||||
'required' => 'required|boolean',
|
||||
'is_visible' => 'required|boolean',
|
||||
];
|
||||
foreach ($this->mobileAppLocales as $locale) {
|
||||
$rules["placeholder.{$locale}"] = 'required|string|min:3|max:100';
|
||||
$rules["details.*.{$locale}"] = 'required|string|min:3|max:100';
|
||||
}
|
||||
if (intval($this->status) !== InputStatusEnum::locked()->value) {
|
||||
if (intval($this->status) !== InputStatusEnum::locked->value()) {
|
||||
$rules = array_merge($rules, ['name' => 'required|string|min:3|max:70']);
|
||||
}
|
||||
return $rules;
|
||||
|
|
@ -71,17 +74,18 @@ class StoreFormularyRequest extends FormRequest
|
|||
public function attributes(): array
|
||||
{
|
||||
$attributes = [
|
||||
'type' => trans('type'),
|
||||
'name' => trans('nom'),
|
||||
'placeholder' => trans('placeholder'),
|
||||
'details' => trans('détail'),
|
||||
'details.*' => trans('détail 2'),
|
||||
'details.*.value' => trans('valeur d\'un élément dans la liste des détails du contenu'),
|
||||
'required' => trans('l\'état d\'obligation'),
|
||||
'is_visible' => trans('l\'état de visibilité'),
|
||||
'type' => trans('validation.custom.type'),
|
||||
'name' => trans('validation.attributes.name'),
|
||||
'placeholder' => trans('validation.custom.placeholder'),
|
||||
'details' => trans('validation.custom.detail'),
|
||||
'details.*' => trans('validation.custom.detail'),
|
||||
'details.*.value' => trans('validation.custom.valeur'),
|
||||
'required' => trans('validation.custom.required'),
|
||||
'is_visible' => trans('validation.custom.visibility'),
|
||||
];
|
||||
foreach ($this->mobileAppLocales as $locale) {
|
||||
$attributes["placeholder.{$locale}"] = trans('placeholder (:lang)', ['lang' => $locale]);
|
||||
$attributes["details.*.{$locale}"] = trans('details (:lang)', ['lang' => $locale]);
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,26 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Formularies;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class UpdateFormularyRequest extends StoreFormularyRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::check('update', $this->route('formulary'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'type' => 'nullable',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class ImportRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ class ImportRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'import' => [
|
||||
|
|
@ -30,7 +30,7 @@ class ImportRequest extends FormRequest
|
|||
'mimes:csv,txt',
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
'mimetypes:text/csv,text/plain,application/csv,text/comma-separated-values,text/anytext,application/octet-stream,application/txt',
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, $value, $fail) {
|
||||
if (
|
||||
$this->import->getClientMimeType() !== 'text/csv'
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Settings;
|
||||
|
||||
use App\Enums\UserRolesEnum;
|
||||
use App\Models\Setting;
|
||||
use App\Traits\Requests\HasPicture;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Uwil\LaravelCommon\Traits\Requests\HasPicture;
|
||||
|
||||
class UpdateSettingRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -17,17 +17,18 @@ class UpdateSettingRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
if (
|
||||
$this->key === "Button1" ||
|
||||
$this->key === "Button2" ||
|
||||
$this->key === "Button3" ||
|
||||
$this->key === "ShowIsActive"
|
||||
$this->key === "Button3"
|
||||
) {
|
||||
return auth('backend')->check();
|
||||
return Gate::check('update', $this->route('setting'));
|
||||
} else {
|
||||
return (auth('backend')->check() && Auth::user()->role === UserRolesEnum::admin()->value);
|
||||
/** @var \App\Models\User $user */
|
||||
$user = Auth::guard('backend')->user();
|
||||
return $user->can('isAdmin');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,11 +37,9 @@ class UpdateSettingRequest extends FormRequest
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
if ($this->key === "ShowIsActive") {
|
||||
$this->merge(['value' => intval($this->value) ? "true" : "false"]);
|
||||
} elseif (
|
||||
if (
|
||||
$this->key === "Button1" ||
|
||||
$this->key === "Button2" ||
|
||||
$this->key === "Button3"
|
||||
|
|
@ -61,7 +60,7 @@ class UpdateSettingRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
if (
|
||||
$this->key === "Button1" ||
|
||||
|
|
@ -69,10 +68,11 @@ class UpdateSettingRequest extends FormRequest
|
|||
$this->key === "Button3"
|
||||
) {
|
||||
$buttonsNullable = 0;
|
||||
$buttons = Setting::where('key', 'Button1')
|
||||
->orWhere('key', 'Button2')
|
||||
->orWhere('key', 'Button3')
|
||||
->get();
|
||||
$buttons = Setting::query()
|
||||
->where('key', 'Button1')
|
||||
->orWhere('key', 'Button2')
|
||||
->orWhere('key', 'Button3')
|
||||
->get();
|
||||
foreach ($buttons as $button) {
|
||||
if ($button->value === null) {
|
||||
if ($button->key !== $this->key) {
|
||||
|
|
@ -82,7 +82,7 @@ class UpdateSettingRequest extends FormRequest
|
|||
}
|
||||
return [
|
||||
'value' => [
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||
//phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
|
||||
function ($attribute, $value, $fail) use ($buttonsNullable) {
|
||||
if (!isset($value) && $buttonsNullable >= 2) {
|
||||
$fail(\trans('Au moins 1 bouton doît être défini.'));
|
||||
|
|
@ -96,7 +96,7 @@ class UpdateSettingRequest extends FormRequest
|
|||
$this->key === "BackgroundImage" ||
|
||||
$this->key === "HomeButtonImage"
|
||||
) {
|
||||
return $this->pictureRules('value', true, 100, 100, 1920, 1200);
|
||||
return $this->pictureRules('value', 100, 100, 1920, 1200, true);
|
||||
} else {
|
||||
return ['value' => 'required|string|min:1'];
|
||||
} //end if
|
||||
|
|
@ -107,12 +107,12 @@ class UpdateSettingRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes()
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'key' => \trans('clé'),
|
||||
'value' => \trans('valeur'),
|
||||
'type' => \trans('type'),
|
||||
'key' => \trans('validation.custom.key'),
|
||||
'value' => \trans('validation.custom.value'),
|
||||
'type' => \trans('validation.custom.type'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Tags;
|
||||
|
||||
use App\Models\Tag;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class StoreTagRequest extends FormRequest
|
||||
{
|
||||
|
|
@ -12,21 +13,9 @@ class StoreTagRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'slug' => Str::slug($this->name),
|
||||
]);
|
||||
return Gate::check('create', Tag::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -34,7 +23,7 @@ class StoreTagRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|min:2|max:25',
|
||||
|
|
@ -49,8 +38,7 @@ class StoreTagRequest extends FormRequest
|
|||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'name' => trans('name of the tag'),
|
||||
'slug' => trans('slug of the tag'),
|
||||
'name' => trans('models.classes.tag'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,17 @@
|
|||
|
||||
namespace App\Http\Requests\Bo\Tags;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class UpdateTagRequest extends StoreTagRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::check('update', $this->route('tag'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
44
app/Http/Requests/Bo/Tenants/StoreTenantRequest.php
Normal file
44
app/Http/Requests/Bo/Tenants/StoreTenantRequest.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Tenants;
|
||||
|
||||
use App\Models\Tenant;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class StoreTenantRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::allows('create', Tenant::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|min:2|max:25',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'name' => trans('validation.attributes.name'),
|
||||
];
|
||||
}
|
||||
}
|
||||
18
app/Http/Requests/Bo/Tenants/UpdateTenantRequest.php
Normal file
18
app/Http/Requests/Bo/Tenants/UpdateTenantRequest.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Tenants;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class UpdateTenantRequest extends StoreTenantRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::check('update', $this->route('tenant'));
|
||||
}
|
||||
}
|
||||
|
|
@ -4,14 +4,14 @@ namespace App\Http\Requests\Bo;
|
|||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ChangeOrderRequest extends FormRequest
|
||||
class UpdateChangeOrderRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth('backend')->check();
|
||||
}
|
||||
|
|
@ -21,10 +21,10 @@ class ChangeOrderRequest extends FormRequest
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'direction' => $this->action === 'up' ? true : false
|
||||
'direction' => $this->route('direction') === 'up' ? true : false
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -33,10 +33,9 @@ class ChangeOrderRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'action' => 'required|string|in:up,down',
|
||||
'direction' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
|
|
@ -11,9 +11,9 @@ class UploadRequest extends FormRequest
|
|||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
public function authorize(): bool
|
||||
{
|
||||
return \auth()->check();
|
||||
return \auth('backend')->check();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -21,7 +21,7 @@ class UploadRequest extends FormRequest
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'uuid' => 'nullable|uuid'
|
||||
|
|
|
|||
77
app/Http/Requests/Bo/Users/StoreUserRequest.php
Normal file
77
app/Http/Requests/Bo/Users/StoreUserRequest.php
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Users;
|
||||
|
||||
use App\Enums\UserRolesEnum;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class StoreUserRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::check('create', User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
if ($this->input('role') == UserRolesEnum::admin->value()) {
|
||||
$this->merge([
|
||||
'tenants' => null
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$isClient = $this->input('role') == UserRolesEnum::client->value();
|
||||
return [
|
||||
'first_name' => 'required|string|min:3|max:255',
|
||||
'last_name' => 'required|string|min:3|max:255',
|
||||
'email' => [
|
||||
'required',
|
||||
'email:rfc,strict,dns,spoof,filter',
|
||||
Rule::unique('users', 'email')
|
||||
],
|
||||
'role' => ['required', new Enum(UserRolesEnum::class)],
|
||||
'tenants' => $isClient ? 'required|array' : 'nullable|array',
|
||||
'tenants.*' => $isClient ? 'required|array' : 'nullable|array',
|
||||
'tenants.*.id' => $isClient ? 'required|exists:tenants,id' : 'nullable|exists:tenants,id',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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'),
|
||||
'tenants' => Str::of(trans('models.classes.tenant'))->plural(),
|
||||
];
|
||||
}
|
||||
}
|
||||
42
app/Http/Requests/Bo/Users/UpdateUserRequest.php
Normal file
42
app/Http/Requests/Bo/Users/UpdateUserRequest.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo\Users;
|
||||
|
||||
use App\Enums\UserRolesEnum;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
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'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
/** @var \App\Models\User $userModel */
|
||||
$userModel = request()->route()->parameter('user');
|
||||
$rules = [
|
||||
'email' => [
|
||||
'required',
|
||||
'string',
|
||||
'unique:users,email,' . $userModel->getKey(),
|
||||
'email:rfc,strict,dns,spoof,filter',
|
||||
'max:255'
|
||||
],
|
||||
'role' => ['sometimes', new Enum(UserRolesEnum::class)],
|
||||
];
|
||||
return \array_merge(parent::rules(), $rules);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,12 +8,14 @@ class ApiResponseResource extends JsonResource
|
|||
{
|
||||
/**
|
||||
* Status
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* Datas
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $datas;
|
||||
|
|
@ -38,11 +40,11 @@ class ApiResponseResource extends JsonResource
|
|||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function toArray($request)
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'status' => $this->status,
|
||||
'datas' => $this->datas
|
||||
'datas' => $this->datas
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Enums\AppUserRolesEnum;
|
||||
use App\Models\Directory;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
|
|
@ -11,26 +12,34 @@ class AppUserResource extends JsonResource
|
|||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
//phpcs:enable
|
||||
/**
|
||||
* @var \App\Models\AppUser
|
||||
* @phpstan-ignore varTag.nativeType
|
||||
*/
|
||||
$appUser = $this;
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'email' => $this->email,
|
||||
'surname' => $this->lastname,
|
||||
'firstname' => $this->firstname,
|
||||
'password' => $this->password,
|
||||
'activated' => $this->status,
|
||||
'role' => ($this->role === 1) ? "TOTAL" : "USER",
|
||||
'authorizedFolders' => json_encode($this->directories->each(function (Directory $directory) use ($request) {
|
||||
return (new DirectoryResource($directory))->toArray($request);
|
||||
})),
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
'id' => $appUser->id,
|
||||
'email' => $appUser->email,
|
||||
'surname' => $appUser->lastname,
|
||||
'firstname' => $appUser->firstname,
|
||||
'password' => $appUser->password,
|
||||
'activated' => $appUser->status,
|
||||
'role' => ($appUser->role->equals(AppUserRolesEnum::total)) ? "TOTAL" : "USER",
|
||||
'authorizedFolders' => json_encode(
|
||||
$appUser->directories->each(
|
||||
// @phpstan-ignore argument.type
|
||||
function (Directory $directory) use ($request) {
|
||||
return (new DirectoryResource($directory))->toArray($request);
|
||||
}
|
||||
)
|
||||
),
|
||||
'created_at' => $appUser->created_at,
|
||||
'updated_at' => $appUser->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,23 +16,25 @@ class ContactResource extends JsonResource
|
|||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
//phpcs:enable
|
||||
/** @var \App\Models\Contact */
|
||||
/**
|
||||
* @var \App\Models\Contact
|
||||
* @phpstan-ignore varTag.nativeType
|
||||
*/
|
||||
$contact = $this;
|
||||
return [
|
||||
'id' => $contact->id,
|
||||
'lastname' => $contact->lastname,
|
||||
'firstname' => $contact->firstname,
|
||||
'email' => $contact->email,
|
||||
'phone' => $contact->phone,
|
||||
'data' => $contact->data,
|
||||
'notes' => $contact->notes,
|
||||
'visits' => $contact->visits,
|
||||
'timestamp' => $contact->timestamp->toISOString(),
|
||||
'app_user_id' => $contact->app_user_id,
|
||||
'id' => $contact->id,
|
||||
'lastname' => $contact->lastname,
|
||||
'firstname' => $contact->firstname,
|
||||
'email' => $contact->email,
|
||||
'phone' => $contact->phone,
|
||||
'data' => $contact->data,
|
||||
'notes' => $contact->notes,
|
||||
'visits' => $contact->visits,
|
||||
'timestamp' => $contact->timestamp->toISOString(),
|
||||
'app_user_id' => $contact->app_user_id,
|
||||
'send_to_app_user_id' => null,
|
||||
'created_at' => $contact->created_at,
|
||||
'updated_at' => $contact->updated_at,
|
||||
'created_at' => $contact->created_at,
|
||||
'updated_at' => $contact->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,19 @@ class DirectoryResource extends JsonResource
|
|||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
//phpcs:enable
|
||||
/**
|
||||
* @var \App\Models\Directory
|
||||
* @phpstan-ignore varTag.nativeType
|
||||
*/
|
||||
$directory = $this;
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => json_encode($this->name),
|
||||
'parent' => $this->directory_id,
|
||||
'order' => $this->order,
|
||||
'needAuthorization' => $this->needAuthorization,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
'id' => $directory->id,
|
||||
'name' => json_encode($directory->name),
|
||||
'parent' => $directory->directory_id,
|
||||
'order' => $directory->order,
|
||||
'needAuthorization' => $directory->needAuthorization,
|
||||
'created_at' => $directory->created_at,
|
||||
'updated_at' => $directory->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,18 +16,23 @@ class DocumentResource extends JsonResource
|
|||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
/**
|
||||
* @var \App\Models\Document
|
||||
* @phpstan-ignore varTag.nativeType
|
||||
*/
|
||||
$document = $this;
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'uuid' => $this->uuid,
|
||||
'title' => $this->title,
|
||||
'type' => $this->type->value,
|
||||
'directory' => $this->directory_id,
|
||||
'path' => $this->path,
|
||||
'lang' => $this->lang->getDefinition(),
|
||||
'published' => ($this->status) ? 1 : 0,
|
||||
'parent' => $this->document_id,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
'id' => $document->id,
|
||||
'uuid' => $document->uuid,
|
||||
'title' => $document->title,
|
||||
'type' => $document->type,
|
||||
'directory' => $document->directory_id,
|
||||
'path' => $document->path,
|
||||
'lang' => $document->lang->name,
|
||||
'published' => ($document->status) ? 1 : 0,
|
||||
'parent' => $document->document_id,
|
||||
'created_at' => $document->created_at,
|
||||
'updated_at' => $document->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,27 +11,30 @@ class FormularyResource extends JsonResource
|
|||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
|
||||
* @phpcs:disable: Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable: Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
/** @var \App\Models\Formulary */
|
||||
/**
|
||||
* @var \App\Models\Formulary
|
||||
* @phpstan-ignore varTag.nativeType
|
||||
*/
|
||||
$formulary = $this;
|
||||
return [
|
||||
'id' => $formulary->id,
|
||||
'type' => $formulary->type->value,
|
||||
'name' => $formulary->name,
|
||||
'slug' => $formulary->slug,
|
||||
'id' => $formulary->id,
|
||||
'type' => $formulary->type->value,
|
||||
'name' => $formulary->name,
|
||||
'slug' => $formulary->slug,
|
||||
'placeholder' => $formulary->placeholder,
|
||||
'details' => \collect($formulary->details)->filter()->map(function (array $detail) {
|
||||
'details' => \collect($formulary->details)->filter()->map(function (array $detail) {
|
||||
// * Realm can't hold more deeper dans Map<mixed,primitive>
|
||||
return \json_encode($detail);
|
||||
})->all(),
|
||||
'is_visible' => $formulary->is_visible,
|
||||
'required' => $formulary->required,
|
||||
'status' => $formulary->status->value,
|
||||
'order' => $formulary->order,
|
||||
'is_visible' => $formulary->is_visible,
|
||||
'required' => $formulary->required,
|
||||
'status' => $formulary->status->value,
|
||||
'order' => $formulary->order,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class AppUserImport implements ToModel, WithUpserts, WithCustomCsvSettings
|
|||
/**
|
||||
* @return string|array
|
||||
*/
|
||||
public function uniqueBy()
|
||||
public function uniqueBy(): string|array
|
||||
{
|
||||
return 'email';
|
||||
}
|
||||
|
|
@ -37,29 +37,27 @@ class AppUserImport implements ToModel, WithUpserts, WithCustomCsvSettings
|
|||
*
|
||||
* @return \Illuminate\Database\Eloquent\Model|null
|
||||
*/
|
||||
public function model(array $row)
|
||||
public function model(array $row): \Illuminate\Database\Eloquent\Model|null
|
||||
{
|
||||
if (!isset($row[0]) || !isset($row[1]) || !isset($row[2]) || !isset($row[3])) {
|
||||
return null;
|
||||
}
|
||||
$user = new AppUser([
|
||||
'email' => $row[3],
|
||||
'lastname' => ucfirst(strtolower($row[1])),
|
||||
$password = Hash::make(Str::random(10));
|
||||
$user = new AppUser([
|
||||
'email' => $row[3],
|
||||
'lastname' => ucfirst(strtolower($row[1])),
|
||||
'firstname' => ucfirst(strtolower($row[2])),
|
||||
'password' => '',
|
||||
'status' => 1,
|
||||
'role' => AppUserRolesEnum::user(),
|
||||
'password' => $password,
|
||||
'status' => 1,
|
||||
'role' => AppUserRolesEnum::user,
|
||||
]);
|
||||
|
||||
if ($user) {
|
||||
$password = Str::random(10);
|
||||
$user->password = Hash::make($password);
|
||||
$user->save();
|
||||
|
||||
Mail::to($user->email)->send(new AccountCreated($user, $password));
|
||||
}
|
||||
|
||||
$user->saveOrFail();
|
||||
Mail::to($user->email)->send(new AccountCreated([
|
||||
'email' => $user->email,
|
||||
'lastname' => $user->lastname,
|
||||
'firstname' => $user->firstname,
|
||||
'password' => $user->password,
|
||||
]));
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
|
|
|||
46
app/Jobs/Mails/SendTenantDeletedMail.php
Normal file
46
app/Jobs/Mails/SendTenantDeletedMail.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs\Mails;
|
||||
|
||||
use App\Mail\TenantDeleted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class SendTenantDeletedMail implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
|
||||
/** @var string $author */
|
||||
private $author;
|
||||
|
||||
/** @var string $name */
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param string $author
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $author, string $name)
|
||||
{
|
||||
$this->author = $author;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
foreach (config('mail.admin.address') as $address) {
|
||||
Mail::to($address)->send(new TenantDeleted($this->author, $this->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Helpers;
|
||||
|
||||
class ExceptionsHelper
|
||||
{
|
||||
/**
|
||||
* Handle sentry event
|
||||
*
|
||||
* @param \Sentry\Event $event
|
||||
* @return null|\Sentry\Event
|
||||
*/
|
||||
public static function sentryEventHandler(\Sentry\Event $event): ?\Sentry\Event
|
||||
{
|
||||
// Remove unwanted reports.
|
||||
$event->setModules([]);
|
||||
$event->setOsContext(null);
|
||||
|
||||
/** @var \Sentry\ExceptionDataBag[] */
|
||||
$exceptionBag = [];
|
||||
foreach ($event->getExceptions() as $exceptionDataBag) {
|
||||
$exceptionBag[] = self::getAnonymizedSentryException($exceptionDataBag);
|
||||
}
|
||||
$event->setExceptions($exceptionBag);
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonimize Sentry Exception bag
|
||||
*
|
||||
* @param \Sentry\ExceptionDataBag $exceptionDataBag
|
||||
* @return \Sentry\ExceptionDataBag
|
||||
*/
|
||||
private static function getAnonymizedSentryException(
|
||||
\Sentry\ExceptionDataBag $exceptionDataBag
|
||||
): \Sentry\ExceptionDataBag {
|
||||
$exceptionDataBag->setValue(self::getAnonymizedMessage($exceptionDataBag->getValue()));
|
||||
if ($stackTrace = $exceptionDataBag->getStacktrace()) {
|
||||
$exceptionDataBag->setStacktrace(self::getAnonymizedSentryStackTrace($stackTrace));
|
||||
}
|
||||
return $exceptionDataBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymise sentry stacktrace
|
||||
*
|
||||
* @param \Sentry\Stacktrace $stackTrace
|
||||
* @return \Sentry\Stacktrace
|
||||
*/
|
||||
private static function getAnonymizedSentryStackTrace(\Sentry\Stacktrace $stackTrace): \Sentry\Stacktrace
|
||||
{
|
||||
/** @var \Sentry\Frame[] */
|
||||
$frames = \array_reverse($stackTrace->getFrames(), true);
|
||||
$i = \count($frames) - 1;
|
||||
// * Remove all but keep first (index.php).
|
||||
while ($i-- > 0) {
|
||||
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
||||
}
|
||||
foreach ($frames as $index => $frame) {
|
||||
$frame->setPostContext([]);
|
||||
$frame->setPreContext([]);
|
||||
$frame->setContextLine('');
|
||||
$frame->setVars(self::getAnonymizedSentryParams($frame->getVars()));
|
||||
$stackTrace->addFrame($frame);
|
||||
if ($index === 0) {
|
||||
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
||||
}
|
||||
}
|
||||
return $stackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get anonymized sentry params
|
||||
*
|
||||
* @param mixed[] $params
|
||||
* @return string[]
|
||||
*/
|
||||
private static function getAnonymizedSentryParams(array $params): array
|
||||
{
|
||||
foreach ($params as &$param) {
|
||||
$type = \strtolower(\gettype($param));
|
||||
if (\is_string($param)) {
|
||||
$type = \explode(' ', \trim($param))[0] ?? null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'Lambda':
|
||||
case 'Object':
|
||||
continue 2;
|
||||
case 'array':
|
||||
$param = sprintf('Array(%d)', \count($param));
|
||||
continue 2;
|
||||
default:
|
||||
if (\is_numeric($param)) {
|
||||
$param = \ucfirst($type);
|
||||
continue 2;
|
||||
}
|
||||
if (\is_string($param)) {
|
||||
$param = sprintf('String(%d)', \strlen($param));
|
||||
continue 2;
|
||||
}
|
||||
} //end switch
|
||||
} //end foreach
|
||||
return $params;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Anonymize at least Sql queries
|
||||
*
|
||||
* @param string $message
|
||||
* @return string
|
||||
*/
|
||||
public static function getAnonymizedMessage(string $message): string
|
||||
{
|
||||
$message = \preg_replace('/^(.*)( \(SQL:.*\))$/', '$1', $message) ?? $message;
|
||||
if ($sqlPos = \strpos($message, 'to use near')) {
|
||||
$message = \mb_strcut($message, 0, $sqlPos);
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anonymize stack trace
|
||||
*
|
||||
* @param \Throwable $e
|
||||
* @return string
|
||||
*/
|
||||
public static function getAnonymizedStackTrace(\Throwable $e): string
|
||||
{
|
||||
$projectPath = \realpath(\sprintf('%s/../', \app_path()));
|
||||
$traceStack = $e->getTrace();
|
||||
$traceStr = '';
|
||||
$maxStackStage = 0;
|
||||
foreach ($traceStack as $stackStage => $stack) {
|
||||
$maxStackStage = $stackStage;
|
||||
$traceStr .= \sprintf(
|
||||
'#%s %s(%d): ',
|
||||
$stackStage,
|
||||
str_replace($projectPath, '', $stack['file'] ?? ''),
|
||||
$stack['line'] ?? ''
|
||||
);
|
||||
if (isset($stack['class'])) {
|
||||
$traceStr .= "{$stack['class']}->{$stack['function']}(";
|
||||
if (isset($stack['args'])) {
|
||||
$traceStr .= self::handleArgs($stack);
|
||||
}
|
||||
$traceStr .= ")\n";
|
||||
} elseif (isset($stack['function'])) {
|
||||
$traceStr .= "{$stack['function']}(";
|
||||
if (isset($stack['args'])) {
|
||||
$traceStr .= self::handleArgs($stack);
|
||||
}
|
||||
$traceStr .= ")\n";
|
||||
}
|
||||
} //end foreach
|
||||
$maxStackStage++;
|
||||
$traceStr .= "#$maxStackStage {main}";
|
||||
return $traceStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Args
|
||||
*
|
||||
* @param array $stack
|
||||
* @return string
|
||||
*/
|
||||
public static function handleArgs(array $stack): string
|
||||
{
|
||||
$traceArgs = '';
|
||||
$argsCount = count($stack['args']);
|
||||
for ($i = 0; $i < $argsCount; $i++) {
|
||||
$type = \gettype($stack['args'][$i]);
|
||||
switch ($type) {
|
||||
case 'object':
|
||||
$traceArgs .= sprintf('Object(%s)', \get_class($stack['args'][$i]));
|
||||
break;
|
||||
case 'array':
|
||||
$traceArgs .= sprintf('Array(%d)', \count($stack['args'][$i]));
|
||||
break;
|
||||
case 'string':
|
||||
$traceArgs .= sprintf('String(%d)', \strlen($stack['args'][$i]));
|
||||
break;
|
||||
default:
|
||||
$traceArgs .= \gettype($stack['args'][$i]);
|
||||
}
|
||||
$traceArgs .= ($i !== ($argsCount - 1) ? ',' : '');
|
||||
}
|
||||
return $traceArgs;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,444 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Helpers;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* This class is used to handle files in LDC Laravel stack
|
||||
*
|
||||
* * The storage strategy will be using date.
|
||||
* The file name may contain sufix timestamp highresolution time (hrtime or microtime) if is duplicate.
|
||||
* (function() { return time() . ' ' . Str::slug(microtime(true)) . ' ' . hrtime(true); })();
|
||||
*
|
||||
* posts/ - The model table name
|
||||
* 10/ - Year
|
||||
* 04/ - Month
|
||||
* 19/ - Day
|
||||
* 5f/ - First two letters of md5 file
|
||||
* black-cat-under-red-car.png - Slugified file name
|
||||
* black-cat-under-red-car-286071690833400.png - Slugified file name that is duplicated
|
||||
*
|
||||
* The final path will be storage/modelfiles/posts/10/04/19/5f/black-cat-under-red-car-286071690833400.png
|
||||
*
|
||||
* ! No limits of file per folder will be handled.
|
||||
*
|
||||
* @author Munsch Jérémy <jeremy.munsch@ldc.fr>
|
||||
*/
|
||||
class FileStorageHelper
|
||||
{
|
||||
/**
|
||||
* Destroy the file associate with the attribute.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $attribute
|
||||
* @return void
|
||||
*/
|
||||
public static function removeFile(Model $model, string $attribute): void
|
||||
{
|
||||
$path = \ltrim(\urldecode($model->{$attribute}), '/');
|
||||
if (\strpos($path, 'storage') !== 0) {
|
||||
return;
|
||||
}
|
||||
$path = ToolboxHelper::mbReplace('storage/', '', $path);
|
||||
if (Storage::disk('public')->exists($path)) {
|
||||
Storage::disk('public')->delete($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the file associate with the attribute old value (before updated to DB).
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $attribute
|
||||
* @param boolean $onlyIfUpdated
|
||||
* @return void
|
||||
*/
|
||||
public static function removeOldFile(Model $model, string $attribute, bool $onlyIfUpdated = true): void
|
||||
{
|
||||
// * Ignore If removal has to be done only if the field has changed and it actually hasnt.
|
||||
if ($onlyIfUpdated and $model->{$attribute} === $model->getOriginal($attribute)) {
|
||||
return;
|
||||
}
|
||||
$originalPath = \ltrim(\urldecode($model->getOriginal($attribute)), '/');
|
||||
if (\strpos($originalPath, 'storage') !== 0) {
|
||||
return;
|
||||
}
|
||||
$originalPath = ToolboxHelper::mbReplace('storage/', '', $originalPath);
|
||||
if (Storage::disk('public')->exists($originalPath)) {
|
||||
Storage::disk('public')->delete($originalPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a file using optimized storage strategy
|
||||
*
|
||||
* You can use filename param to overload file name.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model The model that will hold the picture.
|
||||
* @param \Illuminate\Http\UploadedFile|\SplFileInfo|string $file The file, will just return itself is string.
|
||||
* @param boolean $slugify Force filename slugification.
|
||||
* @param string|null $filename This string may be used to store the file.
|
||||
* @param boolean $private To store the file in a private space.
|
||||
* @return string
|
||||
* @throws \RuntimeException If file copy fails.
|
||||
*/
|
||||
public static function storeFile(
|
||||
Model $model,
|
||||
$file,
|
||||
bool $slugify = false,
|
||||
string $filename = null,
|
||||
bool $private = false
|
||||
): string {
|
||||
$tableName = $model->getTable();
|
||||
if (\is_object($file) and $file instanceof \Illuminate\Http\UploadedFile) {
|
||||
if ($private) {
|
||||
throw new \RuntimeException('Private storage for uploaded files is unhandled');
|
||||
}
|
||||
/** @var \Illuminate\Http\UploadedFile $file */
|
||||
$filename = $filename ?: $file->getClientOriginalName();
|
||||
$filename = $slugify ? self::slugifyFileName($filename) : $filename;
|
||||
$newPath = self::prepareMoveFile($tableName, $filename);
|
||||
$newPath = str_replace(storage_path('app'), '', $newPath);
|
||||
$file->storePubliclyAs(
|
||||
pathinfo($newPath, \PATHINFO_DIRNAME),
|
||||
pathinfo($newPath, \PATHINFO_BASENAME)
|
||||
);
|
||||
return 'storage' . str_replace('/public', '', $newPath);
|
||||
}
|
||||
if (\is_object($file) and $file instanceof \SplFileInfo) {
|
||||
/** @var \SplFileInfo $file */
|
||||
$filename = $filename ?: $file->getBaseName();
|
||||
$filename = $slugify ? self::slugifyFileName($filename) : $filename;
|
||||
$newPath = self::prepareMoveFile($tableName, $filename, $private);
|
||||
if (!File::copy($file->getRealPath(), $newPath)) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Failed to copy file %s to %s',
|
||||
$file->getRealPath(),
|
||||
$newPath
|
||||
));
|
||||
}
|
||||
return $private ?
|
||||
\ltrim(str_replace(\storage_path('app/private'), '/storage/app/private', $newPath), '/') :
|
||||
\ltrim(str_replace(\storage_path('app/public'), '/storage', $newPath), '/');
|
||||
}
|
||||
return strval($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store all files from string attribute html
|
||||
* If oldHtmlString is passed, a diff is done with new and old files
|
||||
* to keep only files that are present in the new html string.
|
||||
*
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model The model that will hold the picture.
|
||||
* @param string $htmlString The html string to parse and modify files.
|
||||
* @param string|null $oldHtmlString The old html string with alreadyParsed
|
||||
* files using storeModelFilesFromHtml.
|
||||
* @return string Html with files pathes replaced using storage strategy.
|
||||
*/
|
||||
public static function storeModelFilesFromHtml(
|
||||
Model $model,
|
||||
string $htmlString,
|
||||
string $oldHtmlString = null
|
||||
): string {
|
||||
\collect(self::onlyUploadedFilesWithFileManager(self::findFilesInHtml($htmlString)))
|
||||
->each(function (string $path) use ($model, &$htmlString) {
|
||||
/** @var \Illuminate\Filesystem\FilesystemAdapter */
|
||||
$disk = Storage::disk('uploads');
|
||||
$fileInfo = new \SplFileInfo($disk->path(
|
||||
ToolboxHelper::mbReplace('/uploads/', '', \urldecode($path))
|
||||
));
|
||||
$htmlString = ToolboxHelper::mbReplace(
|
||||
$path,
|
||||
'/' . self::storeFile($model, $fileInfo, true),
|
||||
$htmlString
|
||||
);
|
||||
});
|
||||
|
||||
if ($oldHtmlString) {
|
||||
self::removeOldModelFilesFromHtml($htmlString, $oldHtmlString);
|
||||
}
|
||||
|
||||
return $htmlString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all old files from string attribute html that are stored in public that
|
||||
* are nove present anymore on new html string
|
||||
*
|
||||
* @param string $newHtmlString The html string with alreadyParsed files using storeModelFilesFromHtml.
|
||||
* @param string $oldHtmlString The old html string with alreadyParsed files using storeModelFilesFromHtml.
|
||||
* @return void
|
||||
*/
|
||||
public static function removeOldModelFilesFromHtml(string $newHtmlString, string $oldHtmlString): void
|
||||
{
|
||||
self::removeOldFiles(self::findFilesInHtml($oldHtmlString), self::findFilesInHtml($newHtmlString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all old files that are stored in public that
|
||||
* are not present anymore on new array files
|
||||
*
|
||||
* @param string[] $oldFiles The old array files.
|
||||
* @param string[] $newFiles The new array files.
|
||||
* @return void
|
||||
*/
|
||||
public static function removeOldFiles(array $oldFiles, array $newFiles): void
|
||||
{
|
||||
$oldFiles = \collect(self::onlyUploadedFilesWithFileStorageHelper($oldFiles));
|
||||
$filesToKeep = \collect(self::onlyUploadedFilesWithFileStorageHelper($newFiles));
|
||||
$filesToRemove = $oldFiles->diff($filesToKeep);
|
||||
$filesToRemove->each(function (string $publicStorageFilePath) {
|
||||
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
|
||||
if (Storage::disk('public')->exists($path)) {
|
||||
Storage::disk('public')->delete($path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all files from string attribute html that are stored in public
|
||||
*
|
||||
* @param string $htmlString The html string with alreadyParsed files using storeModelFilesFromHtml.
|
||||
* @return void
|
||||
*/
|
||||
public static function removeModelFilesOfHtml(string $htmlString): void
|
||||
{
|
||||
$filesToRemove = \collect(self::onlyUploadedFilesWithFileStorageHelper(self::findFilesInHtml($htmlString)));
|
||||
$filesToRemove->each(function (string $publicStorageFilePath) {
|
||||
$path = ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($publicStorageFilePath), '/'));
|
||||
if (Storage::disk('public')->exists($path)) {
|
||||
Storage::disk('public')->delete($path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all occurence of files in html
|
||||
* @param string $html
|
||||
* @return array
|
||||
*/
|
||||
public static function findFilesInHtml(string $html): array
|
||||
{
|
||||
preg_match_all('/href="(?P<href>.*)"|src="(?P<src>.*)"|url="(?P<url>.*)"/Um', $html, $m, PREG_SET_ORDER, 0);
|
||||
return collect($m)->pluck('href')->filter()
|
||||
->concat(collect($m)->pluck('url')->filter())
|
||||
->concat(collect($m)->pluck('src')->filter())
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter array to get only uploaded files that exists
|
||||
* on disk 'public' (using helper storage strategy)
|
||||
*
|
||||
* @param array $urls
|
||||
* @return array
|
||||
*/
|
||||
public static function onlyUploadedFilesWithFileStorageHelper(array $urls): array
|
||||
{
|
||||
return \collect($urls)->unique()
|
||||
// * Filter to get only /uploads and using app url or empty
|
||||
->filter(function (string $url) {
|
||||
$path = \parse_url($url, \PHP_URL_PATH);
|
||||
return \strpos(\ltrim($path, '/'), 'storage/modelfiles') === 0;
|
||||
})->filter(function (string $url) {
|
||||
$path = \parse_url($url, \PHP_URL_PATH);
|
||||
return Storage::disk('public')
|
||||
->exists(ToolboxHelper::mbReplace('storage/', '', \ltrim(\urldecode($path), '/')));
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter array to get only uploaded files that exists
|
||||
* on disk 'uploads'
|
||||
*
|
||||
* @param array $urls
|
||||
* @return array
|
||||
*/
|
||||
private static function onlyUploadedFilesWithFileManager(array $urls): array
|
||||
{
|
||||
return \collect($urls)->unique()
|
||||
// * Filter to get only /uploads and using app url or empty
|
||||
->filter(function (string $url) {
|
||||
$host = \parse_url($url, \PHP_URL_HOST);
|
||||
$path = \parse_url($url, \PHP_URL_PATH);
|
||||
return ($host === \parse_url(config('app.url'), PHP_URL_HOST) or \is_null($host)) and
|
||||
\strpos(\ltrim($path, '/'), 'uploads') === 0;
|
||||
})->filter(function (string $url) {
|
||||
$path = \parse_url($url, \PHP_URL_PATH);
|
||||
return Storage::disk('uploads')
|
||||
->exists(ToolboxHelper::mbReplace('uploads/', '', \ltrim(\urldecode($path), '/')));
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare storage path and return
|
||||
* the file full path
|
||||
*
|
||||
* @param string $tableName Model table name.
|
||||
* @param string $filename The basename for the file.
|
||||
* @param boolean $private May the file be stored in a private dir.
|
||||
* @return string
|
||||
*/
|
||||
private static function prepareMoveFile(string $tableName, string $filename, bool $private = false): string
|
||||
{
|
||||
// * Security filter + beautifier
|
||||
$filename = self::sanitizeFileName($filename);
|
||||
// * Security filter
|
||||
$filename = \filter_var($filename, \FILTER_SANITIZE_STRING);
|
||||
// * Slugify filename
|
||||
$ext = \pathinfo($filename, \PATHINFO_EXTENSION);
|
||||
$filename = Str::slug(\pathinfo($filename, \PATHINFO_FILENAME)) .
|
||||
(\strlen($ext) ? ".{$ext}" : '');
|
||||
|
||||
$folderPath = self::getStoragePath(
|
||||
$private ? 'app/private/modelfiles' : 'app/public/modelfiles',
|
||||
$tableName,
|
||||
$filename,
|
||||
$private
|
||||
);
|
||||
$filename = self::getFileUniqueName($folderPath, $filename);
|
||||
return "{$folderPath}/{$filename}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create sub folders to store files using pattern
|
||||
* storage/modelfiles/posts/10/04/19/5f
|
||||
* year/month/day/md5 first 2 letters
|
||||
*
|
||||
* @param string $storage_dir
|
||||
* @param string $table
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
private static function getStoragePath(string $storage_dir, string $table, string $filename): string
|
||||
{
|
||||
$filenameHash = \md5($filename);
|
||||
$pathFolder = \storage_path(sprintf(
|
||||
'%s/%s/%s/%s/%s/%s',
|
||||
$storage_dir,
|
||||
$table,
|
||||
gmdate('y'),
|
||||
gmdate('m'),
|
||||
gmdate('d'),
|
||||
substr($filenameHash, 0, 2)
|
||||
));
|
||||
if (!File::exists($pathFolder)) {
|
||||
File::makeDirectory($pathFolder, 0755, true);
|
||||
}
|
||||
return $pathFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unique filename if the path is already occupied
|
||||
*
|
||||
* @param string $folderPath
|
||||
* @param string $filename
|
||||
* @return string
|
||||
* @throws \RuntimeException If a unique filename cannot be obtained.
|
||||
*/
|
||||
private static function getFileUniqueName(string $folderPath, string $filename): string
|
||||
{
|
||||
$attempts = 0;
|
||||
$maxAttempts = 20;
|
||||
while (File::exists("{$folderPath}/{$filename}")) {
|
||||
if ($attempts++ >= $maxAttempts) {
|
||||
throw new \RuntimeException("Failed to has a unique filename for {$folderPath}/{$filename}");
|
||||
}
|
||||
$filename = pathinfo($filename, \PATHINFO_FILENAME) .
|
||||
\uniqid('-') . '.' .
|
||||
pathinfo($filename, \PATHINFO_EXTENSION);
|
||||
}
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slugify the filename
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
public static function slugifyFileName(string $filename): string
|
||||
{
|
||||
return Str::slug(pathinfo($filename, \PATHINFO_FILENAME)) . '.' . pathinfo($filename, \PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize File name for uploaded files
|
||||
*
|
||||
* @param string $filename The original uploaded client file name.
|
||||
* @param boolean $beautify Beautify the filename.
|
||||
* @return string The sanitized file name.
|
||||
*/
|
||||
public static function sanitizeFileName(string $filename, bool $beautify = true): string
|
||||
{
|
||||
// * Sanitize filename
|
||||
// phpcs:disable Generic.Files.LineLength.TooLong
|
||||
$filename = preg_replace(
|
||||
'~
|
||||
[<>:"/\\\|?*]| # file system reserved https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
|
||||
[\x00-\x1F]| # control characters http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
|
||||
[\x7F\xA0\xAD]| # non-printing characters DEL, NO-BREAK SPACE, SOFT HYPHEN
|
||||
[#\[\]@!$&\'()+,;=]| # URI reserved https://tools.ietf.org/html/rfc3986#section-2.2
|
||||
[{}^\~`] # URL unsafe characters https://www.ietf.org/rfc/rfc1738.txt
|
||||
~x',
|
||||
'-',
|
||||
$filename
|
||||
);
|
||||
// phpcs:enable
|
||||
// * Avoids '.' '..' or '.hiddenFiles' .
|
||||
$filename = Str::of($filename)->ltrim('.-');
|
||||
// * Optional beautification
|
||||
if ($beautify) {
|
||||
$filename = static::beautifyFilename($filename);
|
||||
}
|
||||
// * Maximize filename length to 255 bytes http://serverfault.com/a/9548/44086
|
||||
/** @var string */
|
||||
$extension = pathinfo($filename, \PATHINFO_EXTENSION);
|
||||
/** @var string */
|
||||
$filename = pathinfo($filename, \PATHINFO_FILENAME);
|
||||
|
||||
$encoding = mb_detect_encoding($filename);
|
||||
$encoding = $encoding ? $encoding : null;
|
||||
return \mb_strcut(
|
||||
$filename,
|
||||
0,
|
||||
255 - (!empty($extension) ? strlen($extension) + 1 : 0),
|
||||
$encoding
|
||||
) . (!empty($extension) ? ".$extension" : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Beautify a filename
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
private static function beautifyFilename(string $filename): string
|
||||
{
|
||||
// Reduce consecutive characters.
|
||||
$filename = preg_replace([
|
||||
// * "file name.zip" becomes 'file-name.zip'
|
||||
'/ +/',
|
||||
// * "file___name.zip" becomes 'file-name.zip'
|
||||
'/_+/',
|
||||
// * "file---name.zip" becomes 'file-name.zip'
|
||||
'/-+/'
|
||||
], '-', $filename);
|
||||
$filename = preg_replace([
|
||||
// * "file--.--.-.--name.zip" becomes "file.name.zip"
|
||||
'/-*\.-*/',
|
||||
// * "file...name..zip" becomes "file.name.zip"
|
||||
'/\.{2,}/'
|
||||
], '.', $filename);
|
||||
// Lowercase for windows/unix interoperability http://support.microsoft.com/kb/100625 .
|
||||
$filename = mb_strtolower($filename, mb_detect_encoding($filename));
|
||||
// * ".file-name.-" becomes "file-name"
|
||||
$filename = trim($filename, '.-');
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,298 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Helpers;
|
||||
|
||||
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use App\Models\Contact;
|
||||
use App\Models\Formulary;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class ToolboxHelper
|
||||
{
|
||||
/**
|
||||
* Strip scheme (https) on oembed urls
|
||||
* Only embed allowed are for MP4 self hosted videos right now
|
||||
*
|
||||
* https is force by ckeditor MediaElements which natively supports
|
||||
* only cloud hosted medias (youtube, spotify etc..)
|
||||
*
|
||||
* @param string $input
|
||||
* @return string
|
||||
*/
|
||||
public static function stripCkEditorSchemesOnMediaInputs(string $input): string
|
||||
{
|
||||
$input = \preg_replace('/(?<=<oembed url=")(https:\/\/)(?=.*?">)/m', '', $input);
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert That no Back Office url is present on txt
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $text
|
||||
* @return string
|
||||
* @throws \Illuminate\Validation\ValidationException If url is a bo url.
|
||||
*/
|
||||
public static function assertNoInternalBoUrls(string $field, string $text): string
|
||||
{
|
||||
$routes = Route::getRoutes();
|
||||
// * Url replace and email replace.
|
||||
$text = preg_replace_callback(
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
'/(?P<url>(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/',
|
||||
function ($matches) use ($routes, $field) {
|
||||
$match = collect($matches)->first() ?? '';
|
||||
$url = $match;
|
||||
try {
|
||||
$request = Request::create($url);
|
||||
// If a route is match then it do not throws exception.
|
||||
if (
|
||||
\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) &&
|
||||
trim($routes->match($request)->getPrefix() ?? '', '/') === 'bo'
|
||||
) {
|
||||
// Removes the matched url.
|
||||
throw ValidationException::withMessages([
|
||||
$field => ':attribute : Il est interdit de coller une url du back office dans ce champ'
|
||||
]);
|
||||
}
|
||||
return $match;
|
||||
} catch (NotFoundHttpException $e) {
|
||||
return $match;
|
||||
}
|
||||
},
|
||||
$text
|
||||
);
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert That only external url is present on txt
|
||||
*
|
||||
* @param string $field
|
||||
* @param string $text
|
||||
* @return string
|
||||
* @throws \Illuminate\Validation\ValidationException If url is a bo url.
|
||||
*/
|
||||
public static function assertNoInternalUrls(string $field, string $text): string
|
||||
{
|
||||
self::assertNoInternalBoUrls($field, $text);
|
||||
$routes = Route::getRoutes();
|
||||
// * Url replace and email replace.
|
||||
$text = preg_replace_callback(
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
'/(?P<url>(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*))/',
|
||||
function ($matches) use ($routes, $field) {
|
||||
$match = collect($matches)->first() ?? '';
|
||||
$url = $match;
|
||||
try {
|
||||
$request = Request::create($url);
|
||||
// If a route is match then it do not throws exception.
|
||||
if (
|
||||
\parse_url(config('app.url'), \PHP_URL_HOST) === \parse_url($url, \PHP_URL_HOST) &&
|
||||
$routes->match($request)
|
||||
) {
|
||||
// Removes the matched url.
|
||||
throw ValidationException::withMessages([
|
||||
$field => sprintf(
|
||||
':attribute : Il est interdit de coller une url de %s dans ce champ',
|
||||
config('app.name')
|
||||
)
|
||||
]);
|
||||
}
|
||||
return $match;
|
||||
} catch (NotFoundHttpException $e) {
|
||||
return $match;
|
||||
}
|
||||
},
|
||||
$text
|
||||
);
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutltibyte string replace
|
||||
* @param mixed $search
|
||||
* @param mixed $replace
|
||||
* @param mixed $subject
|
||||
* @param integer $count
|
||||
* @return mixed
|
||||
*/
|
||||
public static function mbReplace($search, $replace, $subject, int &$count = 0)
|
||||
{
|
||||
if (!is_array($search) && is_array($replace)) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($subject)) {
|
||||
// Call mb_replace for each single string in $subject .
|
||||
foreach ($subject as &$string) {
|
||||
$string = &self::mbReplace($search, $replace, $string, $count);
|
||||
}
|
||||
} elseif (is_array($search)) {
|
||||
if (!is_array($replace)) {
|
||||
foreach ($search as &$string) {
|
||||
$subject = self::mbReplace($string, $replace, $subject, $count);
|
||||
}
|
||||
} else {
|
||||
$n = max(count($search), count($replace));
|
||||
while ($n--) {
|
||||
$subject = self::mbReplace(current($search), current($replace), $subject, $count);
|
||||
next($search);
|
||||
next($replace);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$parts = mb_split(preg_quote($search), $subject);
|
||||
$count = count($parts) - 1;
|
||||
$subject = implode($replace, $parts);
|
||||
} //end if
|
||||
return $subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the field is unique
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $field
|
||||
* @param mixed $value
|
||||
* @param integer|null $id
|
||||
* @param callable|null $query
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException If the field is not unique.
|
||||
*/
|
||||
public static function assertFieldIsUnique(
|
||||
string $table,
|
||||
string $field,
|
||||
$value,
|
||||
?int $id = null,
|
||||
?callable $query = null
|
||||
) {
|
||||
if (!$query) {
|
||||
Validator::make([$field => $value], [
|
||||
self::mbReplace('.', '\.', $field) => Rule::unique($table, $field)->ignore($id),
|
||||
], [
|
||||
self::mbReplace('.', '\.', "{$field}.unique")
|
||||
=> trans('La valeur :value pour le champ :attribute est déjà utilisé', [
|
||||
'attribute' => $field,
|
||||
'value' => $value
|
||||
])
|
||||
])->validate();
|
||||
return;
|
||||
}
|
||||
Validator::make([$field => $value], [
|
||||
$field => Rule::unique($table)->where($query)->ignore($id),
|
||||
], [
|
||||
$field . '.unique' => trans('La valeur pour le champ :attribute est déjà utilisé', [
|
||||
'attribute' => $field
|
||||
])
|
||||
])->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert deeply an object to array
|
||||
*
|
||||
* @param array|object $input
|
||||
* @return array
|
||||
* @throws \RuntimeException If $input var is a scalar value.
|
||||
*/
|
||||
public static function objectToArray($input): array
|
||||
{
|
||||
// Only process if it's an object or array being passed to the function.
|
||||
if (is_object($input) or is_array($input)) {
|
||||
$ret = (array)$input;
|
||||
foreach ($ret as &$item) {
|
||||
// Recursively process EACH element only if not scalar.
|
||||
$item = (is_object($item) or is_array($item)) ?
|
||||
self::objectToArray($item) : $item;
|
||||
}
|
||||
return $ret;
|
||||
} else {
|
||||
throw new \RuntimeException('cannot handle $input of type ' . \gettype($input));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert deeply an array to object
|
||||
*
|
||||
* @param array|object $input
|
||||
* @return object
|
||||
* @throws \RuntimeException If $input var is a scalar value.
|
||||
*/
|
||||
public static function arrayToObject($input): object
|
||||
{
|
||||
// Only process if it's an object or array being passed to the function.
|
||||
if (is_object($input) or is_array($input)) {
|
||||
$ret = (object)$input;
|
||||
foreach ($ret as &$item) {
|
||||
// Recursively process EACH element only if not scalar.
|
||||
$item = (is_object($item) or is_array($item)) ?
|
||||
self::arrayToObject($item) : $item;
|
||||
}
|
||||
return $ret;
|
||||
} else {
|
||||
throw new \RuntimeException('cannot handle $input of type ' . \gettype($input));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get validated pagination from request
|
||||
*
|
||||
* @param integer $default
|
||||
* @return integer
|
||||
*/
|
||||
public static function getValidatedPaginate(int $default): int
|
||||
{
|
||||
try {
|
||||
return \intval(Validator::make(
|
||||
['pagination' => \request()->get('pagination')],
|
||||
['pagination' => new EnumIsValidRule(ItemsPerPaginationEnum::class)]
|
||||
)->validated()['pagination']);
|
||||
} catch (ValidationException $e) {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert contact data is matching actual Formularies
|
||||
*
|
||||
* @param \App\Models\Contact $contact
|
||||
* @return void
|
||||
*/
|
||||
public static function assertContactDataIsMatchingFormulary(Contact $contact)
|
||||
{
|
||||
/** @var \Illuminate\Support\Collection<string,integer> */
|
||||
$formularies = Formulary::query()->pluck('slug')->flip();
|
||||
\collect($contact->data)->each(function (Input $input) use ($formularies) {
|
||||
if (!$formularies->has($input->data->formSlug)) {
|
||||
throw new \ErrorException(
|
||||
"Formulary {$input->data->formSlug} does not exist, do not store this contact data prop"
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Data Input on All contacts
|
||||
*
|
||||
* @param \App\Models\Formulary $formulary
|
||||
* @return void
|
||||
*/
|
||||
public static function removeDataInputOnAllContacts(Formulary $formulary): void
|
||||
{
|
||||
DB::transaction(function () use ($formulary) {
|
||||
Contact::query()->select(['id', 'data'])->each(function (Contact $contact) use ($formulary) {
|
||||
$contact->data = \collect($contact->data)->filter(function (Input $input) use ($formulary) {
|
||||
return $input->data->formSlug !== $formulary->slug;
|
||||
});
|
||||
$contact->saveOrFail();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Lib\Inputs\Definition;
|
||||
|
||||
use App\Models\Formulary;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
/**
|
||||
* To manipulate Input
|
||||
|
|
@ -63,10 +62,11 @@ abstract class Input implements InputInterface
|
|||
/**
|
||||
* Get the matching formulary for this object
|
||||
*
|
||||
* @return \App\Models/Formulary|null
|
||||
* @return \App\Models\Formulary|null
|
||||
*/
|
||||
public function getFormulary(): ?Formulary
|
||||
public function getFormulary(): \App\Models\Formulary|null
|
||||
{
|
||||
// @phpstan-ignore return.type
|
||||
return $this->formularyQuery()->first();
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ abstract class Input implements InputInterface
|
|||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
private function formularyQuery(): Builder
|
||||
private function formularyQuery(): \Illuminate\Database\Eloquent\Builder
|
||||
{
|
||||
return Formulary::query()
|
||||
->where('slug', $this->data->formSlug)
|
||||
|
|
@ -102,10 +102,12 @@ abstract class Input implements InputInterface
|
|||
* @return static
|
||||
* @throws \RuntimeException If the input type is not recognized, or data is invalid.
|
||||
*/
|
||||
public static function from(InputData $data, bool $required = true)
|
||||
public static function from(InputData $data, bool $required = true): static
|
||||
{
|
||||
$inputTypeDataClass = static::class;
|
||||
$type = "";
|
||||
try {
|
||||
// @phpstan-ignore function.alreadyNarrowedType
|
||||
$type = \is_numeric($data->type) ? intval($data->type) : strval($data->type);
|
||||
return new static(
|
||||
InputData::make($data->title, $data->formSlug, $type, $data->value, $required),
|
||||
|
|
@ -131,7 +133,7 @@ abstract class Input implements InputInterface
|
|||
* @return static
|
||||
* @throws \RuntimeException If the input type is not recognized, or data is invalid.
|
||||
*/
|
||||
public static function make(string $title, string $formSlug, $data, bool $required = true)
|
||||
public static function make(string $title, string $formSlug, $data, bool $required = true): static
|
||||
{
|
||||
return static::from(
|
||||
InputData::make(
|
||||
|
|
@ -165,9 +167,9 @@ abstract class Input implements InputInterface
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
public function toArray(): array
|
||||
{
|
||||
return (array)$this->data;
|
||||
return (array) $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -177,7 +179,7 @@ abstract class Input implements InputInterface
|
|||
* @return string
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
|
||||
*/
|
||||
public function toJson($options = 0)
|
||||
public function toJson($options = 0): string
|
||||
{
|
||||
// phpcs:enable
|
||||
return \json_encode($this->jsonSerialize(), $options);
|
||||
|
|
@ -188,8 +190,7 @@ abstract class Input implements InputInterface
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ namespace App\Lib\Inputs\Definition;
|
|||
use App\Enums\Formularies\InputTypeEnum;
|
||||
|
||||
/**
|
||||
* @property-read string $title The input type placeholder
|
||||
* @property-read string $formSlug The original Formulary slug.
|
||||
* @property-read integer $type The input type value
|
||||
* @property-read string|array<integer,string> $value The input value, either a string or an array
|
||||
* @property string $title The input type placeholder
|
||||
* @property string $formSlug The original Formulary slug.
|
||||
* @property integer $type The input type value
|
||||
* @property string|array<integer,string> $value The input value, either a string or an array
|
||||
* with the value index and label
|
||||
* (for Multiselect and checkboxes)
|
||||
* @property-read boolean $required The input is required ?
|
||||
* @property boolean $required The input is required ?
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputData extends \stdClass
|
||||
|
|
@ -62,7 +62,7 @@ class InputData extends \stdClass
|
|||
* @return void
|
||||
* @throws \RuntimeException If $data is wrong.
|
||||
*/
|
||||
public static function assertIsInputTypeData(InputData $data)
|
||||
public static function assertIsInputTypeData(InputData $data): void
|
||||
{
|
||||
$title = $data->title;
|
||||
$type = $data->type;
|
||||
|
|
@ -70,15 +70,19 @@ class InputData extends \stdClass
|
|||
$value = $data->value;
|
||||
$required = $data->required;
|
||||
|
||||
// @phpstan-ignore function.alreadyNarrowedType
|
||||
if (!\is_string($title)) {
|
||||
throw new \RuntimeException("InputTypeData 'title' should be a string");
|
||||
}
|
||||
// @phpstan-ignore function.alreadyNarrowedType
|
||||
if (!\is_string($formSlug)) {
|
||||
throw new \RuntimeException("InputTypeData 'formSlug' should be a string");
|
||||
}
|
||||
// @phpstan-ignore function.alreadyNarrowedType
|
||||
if (!\is_integer($type)) {
|
||||
throw new \RuntimeException("InputTypeData 'type' should be an integer");
|
||||
}
|
||||
// @phpstan-ignore function.alreadyNarrowedType
|
||||
if (!\is_bool($required)) {
|
||||
throw new \RuntimeException("InputTypeData 'required' should be a boolean");
|
||||
}
|
||||
|
|
@ -89,6 +93,7 @@ class InputData extends \stdClass
|
|||
throw new \RuntimeException($e->getMessage());
|
||||
}
|
||||
|
||||
// @phpstan-ignore function.impossibleType, function.alreadyNarrowedType, booleanAnd.alwaysFalse
|
||||
if (!\is_null($value) && !\is_string($value) && !\is_array($value)) {
|
||||
$type = \gettype($value);
|
||||
$value = \json_encode($value);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ interface InputInterface extends Jsonable, Arrayable, \JsonSerializable
|
|||
* @return static
|
||||
* @throws \RuntimeException If the input type is not recognized, or data is invalid.
|
||||
*/
|
||||
public static function from(InputData $data, bool $required = true);
|
||||
public static function from(InputData $data, bool $required = true): static;
|
||||
|
||||
/**
|
||||
* Parse DB line to Object
|
||||
|
|
@ -45,7 +45,7 @@ interface InputInterface extends Jsonable, Arrayable, \JsonSerializable
|
|||
* @return static
|
||||
* @throws \RuntimeException If the input type is not recognized, or data is invalid.
|
||||
*/
|
||||
public static function make(string $title, string $formSlug, $data, bool $required = true);
|
||||
public static function make(string $title, string $formSlug, $data, bool $required = true): static;
|
||||
|
||||
// * --- CHILDS Should implement ---
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ interface InputInterface extends Jsonable, Arrayable, \JsonSerializable
|
|||
/**
|
||||
* Get the matching formulary for this object
|
||||
*
|
||||
* @return \App\Models/Formulary|null
|
||||
* @return \App\Models\Formulary|null
|
||||
*/
|
||||
public function getFormulary(): ?Formulary;
|
||||
|
||||
|
|
@ -91,8 +91,8 @@ interface InputInterface extends Jsonable, Arrayable, \JsonSerializable
|
|||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return string|array<integer,string>
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException If the data is invalid.
|
||||
*/
|
||||
public static function validateData($data, bool $required);
|
||||
public static function validateData($data, bool $required): void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Lib\Inputs;
|
|||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
|
|
@ -18,9 +17,9 @@ class InputCheckbox extends Input
|
|||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
public static function getType(): \App\Enums\Formularies\InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::checkbox();
|
||||
return InputTypeEnum::checkbox;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -31,12 +30,12 @@ class InputCheckbox extends Input
|
|||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
public static function getValidator($data, bool $required): \Illuminate\Contracts\Validation\Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
[
|
||||
'value' => 'array' . ($required ? '|min:1' : ''),
|
||||
'value' => 'array' . ($required ? '|min:1' : ''),
|
||||
'value.*' => 'required|string|max:255'
|
||||
]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Lib\Inputs;
|
|||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
|
|
@ -18,9 +17,9 @@ class InputEmail extends Input
|
|||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
public static function getType(): \App\Enums\Formularies\InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::email();
|
||||
return InputTypeEnum::email;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -31,7 +30,7 @@ class InputEmail extends Input
|
|||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
public static function getValidator($data, bool $required): \Illuminate\Contracts\Validation\Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Lib\Inputs;
|
|||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
|
|
@ -18,9 +17,9 @@ class InputPhone extends Input
|
|||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
public static function getType(): \App\Enums\Formularies\InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::phone();
|
||||
return InputTypeEnum::phone;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -31,7 +30,7 @@ class InputPhone extends Input
|
|||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
public static function getValidator($data, bool $required): \Illuminate\Contracts\Validation\Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Lib\Inputs;
|
|||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
|
|
@ -18,9 +17,9 @@ class InputRadio extends Input
|
|||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
public static function getType(): \App\Enums\Formularies\InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::radio();
|
||||
return InputTypeEnum::radio;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -31,7 +30,7 @@ class InputRadio extends Input
|
|||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
public static function getValidator($data, bool $required): \Illuminate\Contracts\Validation\Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Lib\Inputs;
|
|||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
|
|
@ -18,9 +17,9 @@ class InputSelect extends Input
|
|||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
public static function getType(): \App\Enums\Formularies\InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::select();
|
||||
return InputTypeEnum::select;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -31,7 +30,7 @@ class InputSelect extends Input
|
|||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
public static function getValidator($data, bool $required): \Illuminate\Contracts\Validation\Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ class InputSelectMultiple extends InputCheckbox
|
|||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
public static function getType(): \App\Enums\Formularies\InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::selectMultiple();
|
||||
return InputTypeEnum::selectMultiple;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Lib\Inputs;
|
|||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
|
|
@ -17,9 +16,9 @@ class InputText extends Input
|
|||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
public static function getType(): \App\Enums\Formularies\InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::text();
|
||||
return InputTypeEnum::text;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -30,7 +29,7 @@ class InputText extends Input
|
|||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
public static function getValidator($data, bool $required): \Illuminate\Contracts\Validation\Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\AppUser;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
|
@ -12,36 +11,30 @@ class AccountCreated extends Mailable
|
|||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The app user instance
|
||||
*
|
||||
* @var \App\Models\AppUser;
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/** @var string */
|
||||
public $password;
|
||||
/** @var object */
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param \App\Models\AppUser $user
|
||||
* @param string $password
|
||||
* @param mixed $data
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(AppUser $user, string $password)
|
||||
public function __construct(mixed $data)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->password = $password;
|
||||
$this->data = (object) $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
* @return mixed
|
||||
*/
|
||||
public function build()
|
||||
public function build(): mixed
|
||||
{
|
||||
return $this->subject(__("Votre compte a été créé"))->view('emails.account-created');
|
||||
return $this
|
||||
->from($this->data->email, sprintf('%s %s', $this->data->lastname, $this->data->firstname))
|
||||
->subject(__("Votre compte a été créé"))
|
||||
->markdown('bo.mails.account-created');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class SendFlyer extends Mailable
|
||||
class SendFlyer extends Mailable implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
|
@ -20,20 +21,20 @@ class SendFlyer extends Mailable
|
|||
* @param mixed $data
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($data)
|
||||
public function __construct(mixed $data)
|
||||
{
|
||||
$this->data = (object)$data;
|
||||
$this->data = (object) $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
* @return mixed
|
||||
*/
|
||||
public function build()
|
||||
public function build(): mixed
|
||||
{
|
||||
return $this
|
||||
->from($this->data->from, $this->data->fromName)
|
||||
->from(config('mail.from.address'), $this->data->fromName)
|
||||
->subject($this->data->subject)
|
||||
->markdown('bo.mails.sendflyer');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class SendFlyerFailed extends Mailable
|
||||
class SendFlyerFailed extends Mailable implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
|
@ -20,20 +21,19 @@ class SendFlyerFailed extends Mailable
|
|||
* @param mixed $data
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($data)
|
||||
public function __construct(mixed $data)
|
||||
{
|
||||
$this->data = (object)$data;
|
||||
$this->data = (object) $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
* @return mixed
|
||||
*/
|
||||
public function build()
|
||||
public function build(): mixed
|
||||
{
|
||||
return $this
|
||||
->from('noreply@ldc.fr', '[APP] ' . config('app.name'))
|
||||
->subject('[MAIL] Une erreur est survenue')
|
||||
->view('bo.mails.sendflyerfailed', ['data' => $this->data]);
|
||||
}
|
||||
|
|
|
|||
48
app/Mail/TenantDeleted.php
Normal file
48
app/Mail/TenantDeleted.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TenantDeleted extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/** @var string $author */
|
||||
private $author;
|
||||
|
||||
/** @var string $name */
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param string $author
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $author, string $name)
|
||||
{
|
||||
$this->author = $author;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function build(): mixed
|
||||
{
|
||||
return $this
|
||||
->from(config('mail.from.address'), config('mail.from.name'))
|
||||
->subject(sprintf('Suppression du tenant %s', $this->name))
|
||||
->markdown('bo.mails.tenant-deleted', [
|
||||
'author' => $this->author,
|
||||
'name' => $this->name,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,30 +3,35 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Enums\AppUserRolesEnum;
|
||||
use App\Lib\Helpers\ToolboxHelper;
|
||||
use App\Traits\Models\IsRelatedToTenant;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Kwaadpepper\Enum\Traits\CastsEnums;
|
||||
use Stancl\Tenancy\Database\Concerns\BelongsToTenant;
|
||||
|
||||
/**
|
||||
* @property integer $id
|
||||
* @property string $lastname
|
||||
* @property string $firstname
|
||||
* @property string $email
|
||||
* @property string $password
|
||||
* @property \App\Enums\AppUserRolesEnum $role
|
||||
* @property boolean $status
|
||||
* @property integer $order
|
||||
* @property integer $id App user id.
|
||||
* @property string $lastname App user last name.
|
||||
* @property string $firstname App user first name.
|
||||
* @property string $email App user email.
|
||||
* @property string $password App user password.
|
||||
* @property string|null $tenant_id Associated tenant.
|
||||
* @property boolean $status App user status.
|
||||
* @property \App\Enums\AppUserRolesEnum $role App user role.
|
||||
* @property integer $order App user order.
|
||||
* @property-read \Carbon\Carbon $created_at Created date.
|
||||
* @property-read \Carbon\Carbon $updated_at Updated date.
|
||||
*/
|
||||
class AppUser extends Model
|
||||
{
|
||||
use BelongsToTenant;
|
||||
use IsRelatedToTenant;
|
||||
use HasFactory;
|
||||
use CastsEnums;
|
||||
|
||||
/**
|
||||
* fillable
|
||||
* @var string[]
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'lastname',
|
||||
|
|
@ -41,17 +46,18 @@ class AppUser extends Model
|
|||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
];
|
||||
|
||||
/**
|
||||
* cast enum
|
||||
* @var string[]
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $enumCasts = [
|
||||
protected $casts = [
|
||||
'role' => AppUserRolesEnum::class
|
||||
];
|
||||
|
||||
|
|
@ -62,15 +68,14 @@ class AppUser extends Model
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
self::assertFieldIsUnique('email', $model->email);
|
||||
self::setOrder($model);
|
||||
static::updatePassword($model);
|
||||
self::updatePassword($model);
|
||||
});
|
||||
static::updating(function (self $model) {
|
||||
static::updatePassword($model);
|
||||
self::updatePassword($model);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -89,29 +94,17 @@ class AppUser extends Model
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param self $model
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(Model $model): void
|
||||
private static function setOrder(self $model): void
|
||||
{
|
||||
$model->order = \intval(self::query()->max('order')) + 1;
|
||||
$model->order = \intval(
|
||||
self::query()->where(self::whereTenantQuery())->max('order')
|
||||
) + 1;
|
||||
}
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
|
@ -121,7 +114,7 @@ class AppUser extends Model
|
|||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||
*/
|
||||
public function directories()
|
||||
public function directories(): \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||
{
|
||||
return $this->morphToMany(Directory::class, 'directorable');
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue