Compare commits
No commits in common. "master" and "stats" have entirely different histories.
744 changed files with 15345 additions and 189969 deletions
|
|
@ -1,5 +0,0 @@
|
||||||
# Browsers that we support
|
|
||||||
|
|
||||||
last 3 version
|
|
||||||
> 0.3%
|
|
||||||
not dead # no browsers without security updates
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
.git
|
|
||||||
*.md
|
|
||||||
|
|
@ -3,9 +3,9 @@ root = true
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
indent_size = 4
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
|
|
@ -13,9 +13,3 @@ trim_trailing_whitespace = false
|
||||||
|
|
||||||
[*.{yml,yaml}]
|
[*.{yml,yaml}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[docker-compose.yml]
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
[*.vue]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
|
||||||
39
.env.example
39
.env.example
|
|
@ -14,9 +14,18 @@ DB_DATABASE=laravel
|
||||||
DB_USERNAME=root
|
DB_USERNAME=root
|
||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
|
|
||||||
|
DB_CONNECTION_OLD=mysql
|
||||||
|
DB_HOST_OLD=127.0.0.1
|
||||||
|
DB_PORT_OLD=3306
|
||||||
|
DB_DATABASE_OLD=ldccrm_12_2020
|
||||||
|
DB_USERNAME_OLD=root
|
||||||
|
DB_PASSWORD_OLD=
|
||||||
|
|
||||||
|
MIGRATIONPAGINATION=20000
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
BROADCAST_DRIVER=log
|
||||||
CACHE_DRIVER=file
|
CACHE_DRIVER=file
|
||||||
QUEUE_CONNECTION=database
|
QUEUE_CONNECTION=sync
|
||||||
SESSION_DRIVER=file
|
SESSION_DRIVER=file
|
||||||
SESSION_LIFETIME=120
|
SESSION_LIFETIME=120
|
||||||
|
|
||||||
|
|
@ -25,27 +34,23 @@ REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=dev-mailpit
|
MAIL_HOST=smtp.mailtrap.io
|
||||||
MAIL_PORT=1025
|
MAIL_PORT=2525
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
MAIL_FROM_ADDRESS=null
|
MAIL_FROM_ADDRESS=null
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
MAIL_DIGITAL_SERVICE=""
|
|
||||||
|
|
||||||
# Sentry
|
AWS_ACCESS_KEY_ID=
|
||||||
SENTRY_LARAVEL_DSN=
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
|
||||||
# UWIL ADMIN SECURE
|
PUSHER_APP_ID=
|
||||||
# - LIST SEPARATED WITH ',' (Required)
|
PUSHER_APP_KEY=
|
||||||
UWIL_ADMIN_SECURE_CIDR_LIST=""
|
PUSHER_APP_SECRET=
|
||||||
# - LIST SEPARATED WITH ',' (Optional)
|
PUSHER_APP_CLUSTER=mt1
|
||||||
UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST=""
|
|
||||||
|
|
||||||
# SAML
|
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
SAML2_DEFAULT_TENANT_UUID=
|
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
SAML2_SP_CERT_x509=
|
|
||||||
SAML2_SP_CERT_PRIVATEKEY=
|
|
||||||
SAML2_CONTACT_TECHNICAL_EMAIL=
|
|
||||||
SAML2_CONTACT_SUPPORT_EMAIL=
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,15 @@ DB_DATABASE=testing_ldccrm_12_2020
|
||||||
DB_USERNAME=root
|
DB_USERNAME=root
|
||||||
DB_PASSWORD=DBPASSWORD
|
DB_PASSWORD=DBPASSWORD
|
||||||
|
|
||||||
|
DB_CONNECTION_OLD=mysql
|
||||||
|
DB_HOST_OLD=127.0.0.1
|
||||||
|
DB_PORT_OLD=3306
|
||||||
|
DB_DATABASE_OLD="ldc-crm"
|
||||||
|
DB_USERNAME_OLD=root
|
||||||
|
DB_PASSWORD_OLD=
|
||||||
|
|
||||||
|
MIGRATIONPAGINATION=20000
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
BROADCAST_DRIVER=log
|
||||||
CACHE_DRIVER=file
|
CACHE_DRIVER=file
|
||||||
QUEUE_CONNECTION=database
|
QUEUE_CONNECTION=database
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2021": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:vue/vue3-strongly-recommended",
|
|
||||||
"@vue/eslint-config-typescript"
|
|
||||||
],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.vue"],
|
|
||||||
"rules": {
|
|
||||||
"no-undef": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"files": ["*.vue"],
|
|
||||||
"rules": {
|
|
||||||
"indent": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parser": "vue-eslint-parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"ecmaVersion": "latest",
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": ["vue", "@typescript-eslint"],
|
|
||||||
"ignorePatterns": ["webpack.mix.js", "**/vendor/*.js", "**/vendor/**/*.js"],
|
|
||||||
"rules": {
|
|
||||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
|
||||||
"linebreak-style": ["error", "unix"],
|
|
||||||
"quotes": ["error", "double"],
|
|
||||||
"semi": ["error", "always"],
|
|
||||||
"vue/script-indent": ["error", 2, { "baseIndent": 0, "switchCase": 1 }],
|
|
||||||
"vue/one-component-per-file": "off"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"import/resolver": {
|
|
||||||
"node": {
|
|
||||||
"extensions": [".js", ".vue", ".ts", ".d.ts"]
|
|
||||||
},
|
|
||||||
"alias": {
|
|
||||||
"extensions": [".vue", ".js", ".ts", ".scss", ".d.ts"],
|
|
||||||
"map": [
|
|
||||||
["~", "./resources/assets"],
|
|
||||||
["@", "./node_modules"]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
.gitattributes
vendored
14
.gitattributes
vendored
|
|
@ -1,11 +1,5 @@
|
||||||
* text=auto eol=lf
|
* text=auto
|
||||||
|
*.css linguist-vendored
|
||||||
*.blade.php diff=html
|
*.scss linguist-vendored
|
||||||
*.css diff=css
|
*.js linguist-vendored
|
||||||
*.html diff=html
|
|
||||||
*.md diff=markdown
|
|
||||||
*.php diff=php
|
|
||||||
|
|
||||||
/.github export-ignore
|
|
||||||
CHANGELOG.md export-ignore
|
CHANGELOG.md export-ignore
|
||||||
.styleci.yml export-ignore
|
|
||||||
|
|
|
||||||
35
.gitignore
vendored
35
.gitignore
vendored
|
|
@ -1,31 +1,22 @@
|
||||||
.env
|
|
||||||
.env.testing
|
|
||||||
.env.backup
|
|
||||||
.env.production
|
|
||||||
.phpunit.result.cache
|
|
||||||
.stylelintcache
|
|
||||||
/.fleet
|
|
||||||
/.idea
|
|
||||||
/.phpunit.cache
|
|
||||||
/.vscode
|
|
||||||
/node_modules
|
/node_modules
|
||||||
/bootstrap
|
|
||||||
/public/build
|
|
||||||
/public/cache
|
|
||||||
/public/hot
|
/public/hot
|
||||||
/public/sitemap.xml
|
|
||||||
/public/storage
|
/public/storage
|
||||||
/storage/*.key
|
/storage/*.key
|
||||||
/vendor
|
/vendor
|
||||||
auth.json
|
.vscode/
|
||||||
docker-compose.override.yml
|
.idea/
|
||||||
|
package-lock.json
|
||||||
|
composer.lock
|
||||||
|
.env
|
||||||
|
.env.testing
|
||||||
|
.env.backup
|
||||||
|
.phpunit.result.cache
|
||||||
Homestead.json
|
Homestead.json
|
||||||
Homestead.yaml
|
Homestead.yaml
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
.npmrc
|
storage/crm_migration.csv
|
||||||
.phpdoc
|
MIG/errors_sql.txt
|
||||||
.zshrc
|
public/js
|
||||||
.npm/
|
public/css
|
||||||
.composer/
|
public/assets
|
||||||
tests/coverage
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
include:
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "lint/lint.yml"
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "security/security.yml"
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "build/docker-multistage.yml"
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "test/test.yml"
|
|
||||||
- project: "ldc-web/shared-ci"
|
|
||||||
ref: "main"
|
|
||||||
file: "deploy/deploy.yml"
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- lint
|
|
||||||
- security
|
|
||||||
- build
|
|
||||||
- test
|
|
||||||
- deploy
|
|
||||||
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -1,3 +1,3 @@
|
||||||
[submodule "client"]
|
[submodule "clients/V2"]
|
||||||
path = client
|
path = clients/V2
|
||||||
url = git@lab.s-web.fr:ldc-web/projets/crm-client.git
|
url = https://ldc-web:phaeZ6ej@voight001.lesidc.com/crm-client
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
npx --no -- commitlint --config node_modules/@uwil/husky-config/commitlint.config.cjs --edit $1
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
{
|
|
||||||
"extends": [
|
|
||||||
"stylelint-config-standard-scss",
|
|
||||||
"stylelint-config-sass-guidelines",
|
|
||||||
"stylelint-config-idiomatic-order"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"stylelint-scss"
|
|
||||||
],
|
|
||||||
"files": [
|
|
||||||
"**/*.css",
|
|
||||||
"**/*.scss"
|
|
||||||
],
|
|
||||||
"ignoreFiles": [
|
|
||||||
"**/vendor/*.css",
|
|
||||||
"**/vendor/**/*.css",
|
|
||||||
"**/vendor/*.scss",
|
|
||||||
"**/vendor/**/*.scss",
|
|
||||||
"**/vendor/*.sass",
|
|
||||||
"**/vendor/**/*.sass",
|
|
||||||
"**/vendor/*.less",
|
|
||||||
"**/vendor/**/*.less"
|
|
||||||
],
|
|
||||||
"customSyntax": "postcss-scss",
|
|
||||||
"rules": {
|
|
||||||
"declaration-property-value-no-unknown": true,
|
|
||||||
"selector-max-id": null,
|
|
||||||
"color-no-invalid-hex": true,
|
|
||||||
"order/properties-alphabetical-order": null,
|
|
||||||
"max-nesting-depth": 5,
|
|
||||||
"selector-max-compound-selectors": 5,
|
|
||||||
"declaration-colon-newline-after": null,
|
|
||||||
"value-list-comma-newline-after": null,
|
|
||||||
"scss/double-slash-comment-empty-line-before": [
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
"ignore": [
|
|
||||||
"between-comments",
|
|
||||||
"stylelint-commands",
|
|
||||||
"inside-block"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
.vscode/extensions.json
vendored
20
.vscode/extensions.json
vendored
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"recommendations": [
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"rvest.vs-code-prettier-eslint",
|
|
||||||
"onecentlin.laravel-extension-pack",
|
|
||||||
"johnpapa.vscode-peacock",
|
|
||||||
"xdebug.php-debug",
|
|
||||||
"neilbrayfield.php-docblocker",
|
|
||||||
"bmewburn.vscode-intelephense-client",
|
|
||||||
"valeryanm.vscode-phpsab",
|
|
||||||
"syler.sass-indented",
|
|
||||||
"sibiraj-s.vscode-scss-formatter",
|
|
||||||
"mrmlnc.vscode-scss",
|
|
||||||
"stylelint.vscode-stylelint",
|
|
||||||
"vue.vscode-typescript-vue-plugin",
|
|
||||||
"wscats.vue",
|
|
||||||
"vue.volar",
|
|
||||||
"misterj.vue-volar-extention-pack"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
25
.vscode/settings.json
vendored
25
.vscode/settings.json
vendored
|
|
@ -1,25 +0,0 @@
|
||||||
|
|
||||||
{
|
|
||||||
"workbench.colorCustomizations": {
|
|
||||||
"activityBar.activeBackground": "#8dc952",
|
|
||||||
"activityBar.activeBorder": "#3d7fc2",
|
|
||||||
"activityBar.background": "#8dc952",
|
|
||||||
"activityBar.foreground": "#15202b",
|
|
||||||
"activityBar.inactiveForeground": "#15202b99",
|
|
||||||
"activityBarBadge.background": "#3d7fc2",
|
|
||||||
"activityBarBadge.foreground": "#e7e7e7",
|
|
||||||
"sash.hoverBorder": "#8dc952",
|
|
||||||
"statusBar.background": "#73b137",
|
|
||||||
"statusBar.foreground": "#15202b",
|
|
||||||
"statusBarItem.hoverBackground": "#5a8a2b",
|
|
||||||
"statusBarItem.remoteBackground": "#73b137",
|
|
||||||
"statusBarItem.remoteForeground": "#15202b",
|
|
||||||
"titleBar.activeBackground": "#73b137",
|
|
||||||
"titleBar.activeForeground": "#15202b",
|
|
||||||
"titleBar.inactiveBackground": "#73b13799",
|
|
||||||
"titleBar.inactiveForeground": "#15202b99",
|
|
||||||
"commandCenter.border": "#15202b99"
|
|
||||||
},
|
|
||||||
"peacock.remoteColor": "#73b137",
|
|
||||||
"intelephense.environment.phpVersion": "8.5"
|
|
||||||
}
|
|
||||||
7
CRM V2.code-workspace
Normal file
7
CRM V2.code-workspace
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
50
Dockerfile
50
Dockerfile
|
|
@ -1,50 +0,0 @@
|
||||||
ARG PHP_8_5_TAG=latest
|
|
||||||
|
|
||||||
FROM composer:2.8 AS vendor
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
ARG GITLAB_USER
|
|
||||||
ARG GITLAB_PASSWORD
|
|
||||||
|
|
||||||
COPY database/ database/
|
|
||||||
|
|
||||||
COPY composer.json composer.json
|
|
||||||
COPY composer.lock composer.lock
|
|
||||||
|
|
||||||
RUN composer config gitlab-token.lab.s-web.fr "${GITLAB_USER}" "${GITLAB_PASSWORD}"
|
|
||||||
RUN composer install \
|
|
||||||
--ignore-platform-reqs \
|
|
||||||
--no-interaction \
|
|
||||||
--no-plugins \
|
|
||||||
--no-scripts \
|
|
||||||
--no-dev \
|
|
||||||
--prefer-dist
|
|
||||||
|
|
||||||
FROM node:20.18 AS frontend
|
|
||||||
|
|
||||||
ARG GITLAB_PASSWORD
|
|
||||||
|
|
||||||
RUN mkdir -p /app/public/build
|
|
||||||
|
|
||||||
COPY package*.json tsconfig.json vite.config.ts .eslintrc.json .stylelintrc.json /app/
|
|
||||||
COPY resources/ /app/resources/
|
|
||||||
WORKDIR /app
|
|
||||||
RUN npm config set @ldc-web:registry https://lab.s-web.fr/api/v4/packages/npm/
|
|
||||||
RUN npm config set -- '//lab.s-web.fr/api/v4/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
|
|
||||||
RUN npm config set @uwil:registry https://lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/
|
|
||||||
RUN npm config set -- '//lab.s-web.fr/api/v4/groups/ldc-web/-/packages/npm/:_authToken' "${GITLAB_PASSWORD}"
|
|
||||||
RUN npm ci --no-audit --no-fund --loglevel=error && npm run prod
|
|
||||||
|
|
||||||
ARG PHP_8_5_TAG
|
|
||||||
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 --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}
|
|
||||||
69
MIG/CPlatosChiffrement.class.php
Normal file
69
MIG/CPlatosChiffrement.class.php
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use phpseclib3\Crypt\Rijndael;
|
||||||
|
|
||||||
|
class CPlatosChiffrement
|
||||||
|
{
|
||||||
|
private static $cipher = MCRYPT_RIJNDAEL_128; // Algorithme utilisé pour le cryptage des blocs
|
||||||
|
//private static $key = "yY75y2kLQ"; // Clé de cryptage PROD
|
||||||
|
private static $key = "123456789"; // Clé de cryptage DEV
|
||||||
|
private static $mode = 'cbc'; // Mode opératoire (traitement des blocs)
|
||||||
|
|
||||||
|
public static function crypt($data)
|
||||||
|
{
|
||||||
|
$keyHash = md5(self::$key);
|
||||||
|
$data = mcrypt_encrypt(self::$cipher, self::getKey($keyHash), $data, self::$mode, self::getIv($keyHash));
|
||||||
|
return base64_encode($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function decrypt($data)
|
||||||
|
{
|
||||||
|
$keyHash = md5(self::$key);
|
||||||
|
$data = base64_decode($data);
|
||||||
|
$data = mcrypt_decrypt(self::$cipher, self::getKey($keyHash), $data, self::$mode, self::getIv($keyHash));
|
||||||
|
return rtrim($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getIv($keyHash)
|
||||||
|
{
|
||||||
|
$iv = substr($keyHash, 0, mcrypt_get_block_size(self::$cipher, self::$mode));
|
||||||
|
return $iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getKey($keyHash)
|
||||||
|
{
|
||||||
|
$key = substr($keyHash, 0, mcrypt_get_key_size(self::$cipher, self::$mode));
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function encryptRJ256($key, $iv, $text)
|
||||||
|
{
|
||||||
|
$cipher = new Rijndael('cbc');
|
||||||
|
$cipher->setBlockLength(128);
|
||||||
|
// keys are null-padded to the closest valid size
|
||||||
|
// longer than the longest key and it's truncated
|
||||||
|
$cipher->setKeyLength(128);
|
||||||
|
$cipher->setKey($key);
|
||||||
|
// the IV defaults to all-NULLs if not explicitly defined
|
||||||
|
$cipher->setIV($iv);
|
||||||
|
$cipher->disablePadding();
|
||||||
|
$length = strlen($text);
|
||||||
|
$pad = 32 - ($length % 32);
|
||||||
|
$text = str_pad($text, $length + $pad, chr(0));
|
||||||
|
return base64_encode($cipher->encrypt($text));
|
||||||
|
}
|
||||||
|
private function decryptRJ256($key, $iv, $text)
|
||||||
|
{
|
||||||
|
$cipher = new Rijndael('cbc'); // could use CRYPT_RIJNDAEL_MODE_CBC
|
||||||
|
$cipher->setBlockLength(128);
|
||||||
|
// keys are null-padded to the closest valid size
|
||||||
|
// longer than the longest key and it's truncated
|
||||||
|
$cipher->setKeyLength(128);
|
||||||
|
$cipher->setKey($key);
|
||||||
|
// the IV defaults to all-NULLs if not explicitly defined
|
||||||
|
$cipher->setIV($iv);
|
||||||
|
$cipher->disablePadding();
|
||||||
|
return $cipher->decrypt(base64_decode($text));
|
||||||
|
}
|
||||||
|
}
|
||||||
96
MIG/Db.php
Normal file
96
MIG/Db.php
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Database
|
||||||
|
{
|
||||||
|
|
||||||
|
static $instance;
|
||||||
|
private static $host;
|
||||||
|
private static $database;
|
||||||
|
private static $user;
|
||||||
|
private static $password;
|
||||||
|
|
||||||
|
public function __construct($host, $database, $user, $password)
|
||||||
|
{
|
||||||
|
self::$host = $host;
|
||||||
|
self::$database = $database;
|
||||||
|
self::$user = $user;
|
||||||
|
self::$password = $password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function Instance()
|
||||||
|
{
|
||||||
|
if (!self::$instance) {
|
||||||
|
try {
|
||||||
|
self::$instance = new \PDO('mysql:host=' . self::$host . ';dbname=' . self::$database . ';charset=UTF8', self::$user, self::$password, array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
die($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function request($statement, $params = false)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = self::Instance();
|
||||||
|
$query = $db->prepare($statement);
|
||||||
|
if ($params) {
|
||||||
|
$query->execute($params);
|
||||||
|
} else {
|
||||||
|
$query->execute();
|
||||||
|
}
|
||||||
|
} catch (\PDOException $e) {
|
||||||
|
die($e->getMessage());
|
||||||
|
}
|
||||||
|
$query->setFetchMode(\PDO::FETCH_ASSOC);
|
||||||
|
$result = $query->fetch();
|
||||||
|
$query->closeCursor();
|
||||||
|
return ($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requestAll($statement, $params = false)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = self::Instance();
|
||||||
|
$query = $db->prepare($statement);
|
||||||
|
if ($params) {
|
||||||
|
$query->execute($params);
|
||||||
|
} else {
|
||||||
|
$query->execute();
|
||||||
|
}
|
||||||
|
} catch (\PDOException $e) {
|
||||||
|
die($e->getMessage());
|
||||||
|
}
|
||||||
|
$query->setFetchMode(\PDO::FETCH_ASSOC);
|
||||||
|
$result = $query->fetchAll();
|
||||||
|
$query->closeCursor();
|
||||||
|
return ($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requestPush($statement, $params = false)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = self::Instance();
|
||||||
|
$query = $db->prepare($statement);
|
||||||
|
if ($params)
|
||||||
|
$query->execute($params);
|
||||||
|
else
|
||||||
|
$query->execute();
|
||||||
|
return true;
|
||||||
|
} catch (\PDOException $e) {
|
||||||
|
die($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requestPushInsert($statement, $params)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = self::Instance();
|
||||||
|
$query = $db->prepare($statement);
|
||||||
|
$query->execute($params);
|
||||||
|
return $db->lastInsertId();
|
||||||
|
} catch (\PDOException $e) {
|
||||||
|
file_put_contents("errors_sql.txt", implode(',', $params) . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
MIG/export.php
Normal file
90
MIG/export.php
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?php
|
||||||
|
ini_set("memory_limit", "-1");
|
||||||
|
set_time_limit(0);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
require_once 'Db.php';
|
||||||
|
require_once 'CPlatosChiffrement.class.php';
|
||||||
|
require_once 'LDCCRM_V1.php';
|
||||||
|
|
||||||
|
$db = new Database('localhost', 'ldc-crm', 'ldc-crmadm', 'wai6dahB');
|
||||||
|
//$db = new Database('192.168.30.3', 'ldc-crm', 'ldc-crmadm', 'wai6dahB');
|
||||||
|
$apiCrm = new \LDCCRM\ApiV1('http://crm.test', 'giu6OCyG6FuJvM56zFntDcrtDI23GU7WNnkvOk9rPPTOzKArI8IV9nqgEAnsA8wEQUDnKheQ9FDfKUwG');
|
||||||
|
|
||||||
|
$siteId = 17;
|
||||||
|
$siteName = "REGHALAL";
|
||||||
|
|
||||||
|
$accounts = $db->requestAll("SELECT *
|
||||||
|
FROM useraccount
|
||||||
|
INNER JOIN siteuser su ON useraccount.user_id = su.siteuser_useraccountId
|
||||||
|
WHERE su.siteuser_siteId = :siteid
|
||||||
|
AND user_status = 1
|
||||||
|
AND user_lastUpdateDate >= '2018-03-01'
|
||||||
|
AND (user_emailCheckStatus <> 0 OR user_emailCheckStatus IS NULL)
|
||||||
|
AND (user_lastCnxDateHeure IS NOT NULL AND user_lastCnxDateHeure <> '0000-00-00 00:00:00')", ['siteid' => $siteId]);
|
||||||
|
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$isSingleOptin = false;
|
||||||
|
|
||||||
|
$oldCRMid = $account['user_id'];
|
||||||
|
|
||||||
|
$civility = $account['user_civilite'];
|
||||||
|
$firstname = $account['user_prenom'];
|
||||||
|
$lastname = $account['user_nom'];
|
||||||
|
|
||||||
|
$birthdate = $account['user_dateNaissance'];
|
||||||
|
|
||||||
|
$address1 = !empty($account['user_adresse1']) ? $account['user_adresse1'] : null;
|
||||||
|
$address2 = !empty($account['user_adresse2']) ? $account['user_adresse2'] : null;
|
||||||
|
$postcode = (!empty($account['user_codePostal']) && $account['user_codePostal'] !== 0 ? $account['user_codePostal'] : null);
|
||||||
|
$city = !empty($account['user_ville']) ? $account['user_ville'] : null;
|
||||||
|
|
||||||
|
$optin = $account['user_inscritNewsletter'];
|
||||||
|
$haschcode = $account['user_hashcode'];
|
||||||
|
$status = $account['user_status'];
|
||||||
|
|
||||||
|
$created_at = $account['user_creationDate'];
|
||||||
|
$updated_at = $account['user_lastUpdateDate'];
|
||||||
|
|
||||||
|
$email = $account['user_email'];
|
||||||
|
$password = CPlatosChiffrement::decrypt($account['user_pwd']);
|
||||||
|
|
||||||
|
$last_cnx = $account['user_lastCnxDateHeure'];
|
||||||
|
|
||||||
|
if (empty($firstname) && empty($lastname))
|
||||||
|
$isSingleOptin = true;
|
||||||
|
|
||||||
|
// Récupération des champs complémentaires
|
||||||
|
$fields = [['fieldkey' => 'created_at', 'fieldvalue' => $created_at], ['fieldkey' => 'updated_at', 'fieldvalue' => $updated_at], ['fieldkey' => 'last_cnx', 'fieldvalue' => $last_cnx]];
|
||||||
|
|
||||||
|
if (!$isSingleOptin) {
|
||||||
|
$crmUser = $apiCrm->createCustomer($email, $password, $firstname, $lastname, $optin, $birthdate, null, $address1, $address2, $city, $postcode, "France");
|
||||||
|
if ($crmUser->status === 'OK') {
|
||||||
|
$newCRMId = $crmUser->user->crm_id;
|
||||||
|
$activate = $apiCrm->activateCustomer($newCRMId);
|
||||||
|
if ($activate->status === 'NOK') {
|
||||||
|
file_put_contents("Export_errors.txt", "OLD CRM ID : $oldCRMid - NEW CRM ID : $newCRMId - ACTIVATE API ERROR : " . $activate->code . " - " . $activate->message . PHP_EOL, FILE_APPEND);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file_put_contents("Export_errors.txt", "OLD CRM ID : $oldCRMid - API ERROR : " . $crmUser->code . " - " . $crmUser->message . PHP_EOL, FILE_APPEND);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result = $apiCrm->createSingleOptin($email);
|
||||||
|
|
||||||
|
if ($result->status === 'OK') {
|
||||||
|
$newCRMId = "SINGLEOPTIN";
|
||||||
|
} else {
|
||||||
|
file_put_contents("Export_errors.txt", "OLD CRM ID : $oldCRMid - API ERROR : " . $crmUser->code . " - " . $crmUser->message . PHP_EOL, FILE_APPEND);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write("$oldCRMid;$newCRMId;$email;" . json_encode($fields) . PHP_EOL, $siteName);
|
||||||
|
}
|
||||||
|
|
||||||
|
function write($text, $siteName)
|
||||||
|
{
|
||||||
|
if (!file_exists("Export_$siteName.csv"))
|
||||||
|
file_put_contents("Export_$siteName.csv", "\xEF\xBB\xBF", FILE_APPEND); // BOM UTF-8
|
||||||
|
file_put_contents("Export_$siteName.csv", $text, FILE_APPEND);
|
||||||
|
}
|
||||||
9
MIG/make_tmp_table.sql
Normal file
9
MIG/make_tmp_table.sql
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
CREATE TABLE `legaulois_migration` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` BIGINT(20) NOT NULL DEFAULT '0',
|
||||||
|
`pwd` VARCHAR(255) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
)
|
||||||
|
COLLATE='utf8_unicode_ci'
|
||||||
|
ENGINE=InnoDB
|
||||||
|
AUTO_INCREMENT=0;
|
||||||
80
MIG/migrate.php
Normal file
80
MIG/migrate.php
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
ini_set("memory_limit", "-1");
|
||||||
|
set_time_limit(0);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
require_once 'Db.php';
|
||||||
|
|
||||||
|
$db = new Database('192.168.31.102', 'ldccrm_12_2020', 'ldccrmadm', 'wai6dahB'); // INFOS NOUVELLE CRM
|
||||||
|
|
||||||
|
$newBrandId = 2; // BRAND ID de la migration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Generator
|
||||||
|
*/
|
||||||
|
$fileData = function() {
|
||||||
|
$file = fopen(__DIR__ . '/Export_REGHALAL.csv', 'r');
|
||||||
|
|
||||||
|
if (!$file)
|
||||||
|
die('file does not exist or cannot be opened');
|
||||||
|
|
||||||
|
while (($line = fgets($file)) !== false) {
|
||||||
|
yield $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($file);
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach ($fileData() as $line) {
|
||||||
|
$isSingleOptin = false;
|
||||||
|
|
||||||
|
$datas = explode(";", $line);
|
||||||
|
$oldCrmId = $datas[0];
|
||||||
|
$newCrmId = $datas[1];
|
||||||
|
$email = $datas[2];
|
||||||
|
$otherFields = json_decode($datas[3]);
|
||||||
|
|
||||||
|
if ($newCrmId === 'SINGLEOPTIN')
|
||||||
|
$isSingleOptin = true;
|
||||||
|
|
||||||
|
foreach ($otherFields as $otherField){
|
||||||
|
// created_at - updated_at - last_cnx ne bougent pas car génériques et db sur nouvelle CRM sinon DB sur nouveau site.
|
||||||
|
switch($otherField->fieldkey){
|
||||||
|
case 'created_at':
|
||||||
|
if (!$isSingleOptin) {
|
||||||
|
$query = "UPDATE customers SET created_at = :nvalue WHERE id = :newid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId]);
|
||||||
|
$query = "UPDATE customer_infos SET created_at = :nvalue WHERE customer_id = :newid AND brand_id = :brandid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId, 'brandid' => $newBrandId]);
|
||||||
|
$query = "UPDATE customer_login SET created_at = :nvalue WHERE customer_id = :newid AND brand_id = :brandid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId, 'brandid' => $newBrandId]);
|
||||||
|
$query = "UPDATE customer_opt_in_history SET created_at = :nvalue WHERE customer_id = :newid AND brand_id = :brandid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId, 'brandid' => $newBrandId]);
|
||||||
|
}else{
|
||||||
|
$query = "UPDATE single_optin SET created_at = :nvalue, updated_at = :nvalue WHERE email = :email AND brand_id = :brandid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'email' => $email, 'brandid' => $newBrandId]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'updated_at':
|
||||||
|
if (!$isSingleOptin) {
|
||||||
|
$query = "UPDATE customers SET updated_at = :nvalue WHERE id = :newid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId]);
|
||||||
|
$query = "UPDATE customer_infos SET updated_at = :nvalue WHERE customer_id = :newid AND brand_id = :brandid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId, 'brandid' => $newBrandId]);
|
||||||
|
$query = "UPDATE customer_login SET updated_at = :nvalue WHERE customer_id = :newid AND brand_id = :brandid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId, 'brandid' => $newBrandId]);
|
||||||
|
$query = "UPDATE customer_opt_in_history SET updated_at = :nvalue WHERE customer_id = :newid AND brand_id = :brandid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId, 'brandid' => $newBrandId]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'last_cnx':
|
||||||
|
if (!$isSingleOptin) {
|
||||||
|
$query = "UPDATE customer_login SET last_connection = :nvalue WHERE customer_id = :newid AND brand_id = :brandid";
|
||||||
|
$db->requestPush($query, ['nvalue' => $otherField->fieldvalue, 'newid' => $newCrmId, 'brandid' => $newBrandId]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
//var_dump($otherField);
|
||||||
|
}
|
||||||
|
}
|
||||||
89
MIG/pwd.php
Normal file
89
MIG/pwd.php
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
ini_set("memory_limit", "-1");
|
||||||
|
set_time_limit(0);
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
require_once 'Db.php';
|
||||||
|
require_once 'CPlatosChiffrement.class.php';
|
||||||
|
$db = new Database('localhost', 'ldc-crm', 'root', '');
|
||||||
|
//$db = new Database('192.168.34.2', 'ldc-crm', 'ldc-crmadm', 'wai6dahB');
|
||||||
|
if (!isset($argv[1]) || !isset($argv[2]))
|
||||||
|
die('params missing');
|
||||||
|
$name = $argv[1];
|
||||||
|
$siteId = $argv[2];
|
||||||
|
$table = $name."_migration";
|
||||||
|
$maxdate = date("Y-m-d", strtotime("-36 month", time()));
|
||||||
|
$db->requestPush("CREATE TABLE IF NOT EXISTS $table (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` BIGINT(20) NOT NULL DEFAULT '0',
|
||||||
|
`firstname` VARCHAR(255) NOT NULL DEFAULT '0',
|
||||||
|
`lastname` VARCHAR(255) NOT NULL DEFAULT '0',
|
||||||
|
`birthdate` VARCHAR(255) NULL DEFAULT '0',
|
||||||
|
`address` VARCHAR(255) NULL DEFAULT '0',
|
||||||
|
`address2` VARCHAR(255) NULL DEFAULT '0',
|
||||||
|
`city` VARCHAR(255) NULL DEFAULT '0',
|
||||||
|
`postcode` VARCHAR(255) NULL DEFAULT '0',
|
||||||
|
`optin` INT(11) NOT NULL DEFAULT '0',
|
||||||
|
`email` VARCHAR(255) NOT NULL DEFAULT '0',
|
||||||
|
`pwd` VARCHAR(255) NOT NULL DEFAULT '0',
|
||||||
|
`created_at` TIMESTAMP NOT NULL,
|
||||||
|
`updated_at` TIMESTAMP NOT NULL,
|
||||||
|
`last_cnx` TIMESTAMP NOT NULL,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) COLLATE='utf8_unicode_ci' ENGINE=InnoDB AUTO_INCREMENT=0;");
|
||||||
|
|
||||||
|
$getAccounts = function ($skip) use ($db, $siteId, $maxdate){
|
||||||
|
return $db->requestAll("SELECT *
|
||||||
|
FROM useraccount
|
||||||
|
INNER JOIN siteuser su ON useraccount.user_id = su.siteuser_useraccountId
|
||||||
|
WHERE su.siteuser_siteId = :siteid
|
||||||
|
AND user_id >= 701697
|
||||||
|
AND user_status = 1
|
||||||
|
AND user_lastUpdateDate >= :maxdate
|
||||||
|
AND (user_emailCheckStatus <> 0 OR user_emailCheckStatus IS NULL)
|
||||||
|
AND (user_lastCnxDateHeure IS NOT NULL AND user_lastCnxDateHeure <> '0000-00-00 00:00:00')
|
||||||
|
AND user_lastCnxDateHeure >= :maxdate
|
||||||
|
AND user_email IS NOT NULL LIMIT 4600 OFFSET ". ($skip * 4600), ['siteid' => $siteId, 'maxdate' => $maxdate]);
|
||||||
|
};
|
||||||
|
$k = 0;
|
||||||
|
while (count($accounts = $getAccounts($k++))) {
|
||||||
|
$sql = [];
|
||||||
|
$toto = "";
|
||||||
|
foreach ($accounts as $account){
|
||||||
|
$crm_id = $account['user_id'];
|
||||||
|
$civility = $account['user_civilite'];
|
||||||
|
$firstname = ucfirst($account['user_prenom']);
|
||||||
|
$lastname = ucfirst($account['user_nom']);
|
||||||
|
$birthdate = $account['user_dateNaissance'];
|
||||||
|
$address1 = !empty($account['user_adresse1']) ? $account['user_adresse1'] : null;
|
||||||
|
$address2 = !empty($account['user_adresse2']) ? $account['user_adresse2'] : null;
|
||||||
|
$postcode = (!empty($account['user_codePostal']) && $account['user_codePostal'] !== 0 ? $account['user_codePostal'] : null);
|
||||||
|
$city = !empty($account['user_ville']) ? $account['user_ville'] : null;
|
||||||
|
$optin = $account['user_inscritNewsletter'];
|
||||||
|
$haschcode = $account['user_hashcode'];
|
||||||
|
$status = $account['user_status'];
|
||||||
|
$created_at = $account['user_creationDate'];
|
||||||
|
$updated_at = $account['user_lastUpdateDate'];
|
||||||
|
$email = strtolower($account['user_email']);
|
||||||
|
//$password = CPlatosChiffrement::decrypt($account['user_pwd']);
|
||||||
|
$password = "toto";
|
||||||
|
$last_cnx = $account['user_lastCnxDateHeure'];
|
||||||
|
$datas = [
|
||||||
|
$crm_id,
|
||||||
|
$firstname,
|
||||||
|
$lastname,
|
||||||
|
$birthdate,
|
||||||
|
$address1,
|
||||||
|
$address2,
|
||||||
|
$city,
|
||||||
|
$postcode,
|
||||||
|
$optin,
|
||||||
|
$email,
|
||||||
|
$password,
|
||||||
|
$created_at,
|
||||||
|
$updated_at,
|
||||||
|
$last_cnx
|
||||||
|
];
|
||||||
|
$toto = "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
$db->requestPushInsert("INSERT INTO $table (user_id, firstname, lastname, birthdate, address, address2, city, postcode, optin, email, pwd, created_at, updated_at, last_cnx) VALUES $toto", $datas);
|
||||||
|
}
|
||||||
|
}
|
||||||
63
README.md
63
README.md
|
|
@ -1,10 +1,61 @@
|
||||||
# CRM
|
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p>
|
||||||
|
|
||||||
## Documentation
|
<p align="center">
|
||||||
https://cdlfr.sharepoint.com/:b:/r/sites/LDCWEB/Documents%20partages/Documentations/Projets/CRM/FICHE%20FONCTIONNELLE%20OUTIL%20R%C3%89CLAMATIONS%20CONSO.pdf?csf=1&web=1&e=qktL4V
|
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
## Tests unitaire
|
## About Laravel
|
||||||
|
|
||||||
### Comment lancer les tests unitaires ?
|
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||||
|
|
||||||
[Suivre le wiki dédié au tests unitaires](https://lab.s-web.fr/ldc-web/projets/crm/-/wikis/Tests-unitaires)
|
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||||
|
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||||
|
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||||
|
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||||
|
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||||
|
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||||
|
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||||
|
|
||||||
|
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||||
|
|
||||||
|
## Learning Laravel
|
||||||
|
|
||||||
|
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
|
||||||
|
|
||||||
|
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 1500 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||||
|
|
||||||
|
## Laravel Sponsors
|
||||||
|
|
||||||
|
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).
|
||||||
|
|
||||||
|
### Premium Partners
|
||||||
|
|
||||||
|
- **[Vehikl](https://vehikl.com/)**
|
||||||
|
- **[Tighten Co.](https://tighten.co)**
|
||||||
|
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||||
|
- **[64 Robots](https://64robots.com)**
|
||||||
|
- **[Cubet Techno Labs](https://cubettech.com)**
|
||||||
|
- **[Cyber-Duck](https://cyber-duck.co.uk)**
|
||||||
|
- **[Many](https://www.many.co.uk)**
|
||||||
|
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
|
||||||
|
- **[DevSquad](https://devsquad.com)**
|
||||||
|
- **[OP.GG](https://op.gg)**
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||||
|
|
||||||
|
## Security Vulnerabilities
|
||||||
|
|
||||||
|
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,12 @@ namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Customer;
|
use App\Models\Customer;
|
||||||
use App\Models\CustomerLogin;
|
use App\Models\CustomerLogin;
|
||||||
use App\Models\CustomerOptInHistory;
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
class DeleteUnconfirmedCustomers extends Command
|
class DeleteUnconfirmedCustomers extends Command
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
*
|
*
|
||||||
|
|
@ -33,40 +28,25 @@ class DeleteUnconfirmedCustomers extends Command
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
* @return integer
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle()
|
||||||
{
|
{
|
||||||
/** @var \Illuminate\Database\Eloquent\Collection $customersLogins */
|
$customersLogins = CustomerLogin::where([['status', 0], ['created_at', '<', Carbon::now()->subDay(1)]])->get();
|
||||||
$customersLogins = CustomerLogin::query()
|
foreach ($customersLogins as $customerLogin) {
|
||||||
->where('status', false)
|
// Si non activé et créer il y a plus d'un jour : Suppression
|
||||||
->where('created_at', '<', Carbon::now()->subDay(1))
|
$customerLogin->customer->infos()->where('brand_id', $customerLogin->brand_id)->first()->delete();
|
||||||
->with(['brand', 'customer'])
|
// On récupère son id pour le cas ou on doit le supprimer complètement après
|
||||||
->get();
|
$customerId = $customerLogin->customer->id;
|
||||||
$customersLogins->map(function (CustomerLogin $customerLogin) {
|
// Suppression de ses infos de login pour la marque
|
||||||
Log::info($customerLogin->customer_id);
|
$customerLogin->delete();
|
||||||
DB::transaction(function () use ($customerLogin) {
|
// Si le customer n'a plus d'info il n'a donc plus besoin de compte en crm
|
||||||
/** @var \App\Models\Customer $customer */
|
if (count($customerLogin->customer->infos) === 0) {
|
||||||
$customer = $customerLogin->customer;
|
// Suppression du customer une fois tout le reste supprimé
|
||||||
|
$customer = Customer::find($customerId);
|
||||||
/** @var \App\Models\Brand */
|
$customer->optInHistory()->delete();
|
||||||
$brand = $customerLogin->brand;
|
$customer->delete();
|
||||||
|
}
|
||||||
// * Suppression de ses infos de login pour la marque.
|
}
|
||||||
$customer->info($brand, Customer::FIRST_OR_FAIL)->deleteOrFail();
|
|
||||||
$customer->login($brand, Customer::FIRST_OR_FAIL)->deleteOrFail();
|
|
||||||
|
|
||||||
// * Si le customer n'a plus d'info il n'a donc plus besoin de compte en crm.
|
|
||||||
if (!$customer->infos()->count()) {
|
|
||||||
// * Suppression du customer une fois tout le reste supprimé.
|
|
||||||
$customer->optInHistory()->get()
|
|
||||||
->map(function (CustomerOptInHistory $customerOptInHistory) {
|
|
||||||
$customerOptInHistory->deleteOrFail();
|
|
||||||
});
|
|
||||||
$customer->deleteOrFail();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,20 @@ namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Enums\ApiError;
|
use App\Enums\ApiError;
|
||||||
use App\Enums\ApiStatus;
|
use App\Enums\ApiStatus;
|
||||||
|
use App\Enums\ArcadiaMailType;
|
||||||
use App\Enums\ArcadiaOrderType;
|
use App\Enums\ArcadiaOrderType;
|
||||||
use App\Enums\Country;
|
use App\Enums\Country;
|
||||||
use App\Enums\QuestionType;
|
use App\Enums\QuestionType;
|
||||||
use App\Exceptions\Api\V4\ApiErrorException;
|
use App\Exceptions\Api\V2\ApiErrorException;
|
||||||
use App\Exceptions\Api\V4\CrmException;
|
use App\Exceptions\Api\V2\CrmException;
|
||||||
use App\Traits\Enums\BaseEnum;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
/**
|
class GenerateCrmClient extends Command
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
class GenerateClient extends Command
|
|
||||||
{
|
{
|
||||||
private const TARGET = 'client/src';
|
|
||||||
|
private const TARGET = 'clients/V2/src';
|
||||||
private const CLIENTNAMESPACE = 'LDC\\LDCCRM';
|
private const CLIENTNAMESPACE = 'LDC\\LDCCRM';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -35,29 +32,22 @@ class GenerateClient extends Command
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $description = 'Generate the crm V4 client in client folder';
|
protected $description = 'Generate the crm v2 client in clients/V2 folder';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
* @return integer
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle()
|
||||||
{
|
{
|
||||||
$this->copyTraits();
|
|
||||||
$this->copyEnums();
|
$this->copyEnums();
|
||||||
$this->copyExceptions();
|
$this->copyExceptions();
|
||||||
$this->copyRoutesList();
|
$this->copyRoutesList();
|
||||||
$this->copyApiConfigInfo();
|
$this->copyApiConfigInfo();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function copyApiConfigInfo()
|
||||||
* Copy config files
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function copyApiConfigInfo(): void
|
|
||||||
{
|
{
|
||||||
$this->info('Copy Api Config');
|
$this->info('Copy Api Config');
|
||||||
$rootTarget = app_path('../' . self::TARGET);
|
$rootTarget = app_path('../' . self::TARGET);
|
||||||
|
|
@ -70,18 +60,13 @@ class GenerateClient extends Command
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function copyRoutesList()
|
||||||
* Copy routes into a json file
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function copyRoutesList(): void
|
|
||||||
{
|
{
|
||||||
$this->info('Copy Routes');
|
$this->info('Copy Routes');
|
||||||
$routes = [];
|
$routes = [];
|
||||||
/** @var \Illuminate\Routing\Route */
|
/** @var \Illuminate\Routing\Route */
|
||||||
foreach (Route::getRoutes() as $route) {
|
foreach (Route::getRoutes() as $route) {
|
||||||
if (\strpos($route->getPrefix(), 'v4') !== false) {
|
if (\strpos($route->getPrefix(), 'v2') !== false) {
|
||||||
$routes[$route->getName()] = [
|
$routes[$route->getName()] = [
|
||||||
'uri' => $route->uri(),
|
'uri' => $route->uri(),
|
||||||
'methods' => $route->methods()
|
'methods' => $route->methods()
|
||||||
|
|
@ -98,84 +83,53 @@ class GenerateClient extends Command
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy Exeption classes
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function copyExceptions(): void
|
private function copyExceptions(): void
|
||||||
{
|
{
|
||||||
$this->info('Copy Exceptions');
|
$this->info('Copy Exceptions');
|
||||||
$rootTarget = app_path('../' . self::TARGET);
|
$rootTarget = app_path('../' . self::TARGET);
|
||||||
$classes = [
|
$this->copyToFolder([
|
||||||
CrmException::class,
|
CrmException::class,
|
||||||
ApiErrorException::class
|
ApiErrorException::class
|
||||||
];
|
], 'Exceptions');
|
||||||
$this->copyToFolder($classes, 'Exceptions');
|
$this->replaceInPhpFile(
|
||||||
foreach ($classes as $class) {
|
"$rootTarget/Exceptions/ApiErrorException.php",
|
||||||
$classBasename = class_basename($class);
|
'App\Enums\ApiError',
|
||||||
$dest = "$rootTarget/Exceptions/$classBasename.php";
|
'LDC\LDCCRM\Enums\ApiError'
|
||||||
$this->replaceInPhpFile($dest, 'App\\', self::CLIENTNAMESPACE . '\\');
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy base enums classes
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function copyTraits(): void
|
|
||||||
{
|
|
||||||
$this->info('Copy Traits');
|
|
||||||
$rootTarget = app_path('../' . self::TARGET);
|
|
||||||
$classes = [
|
|
||||||
BaseEnum::class
|
|
||||||
];
|
|
||||||
$this->copyToFolder($classes, 'Traits');
|
|
||||||
foreach ($classes as $class) {
|
|
||||||
$classBasename = class_basename($class);
|
|
||||||
$dest = "$rootTarget/Traits/$classBasename.php";
|
|
||||||
$this->replaceInPhpFile($dest, 'App\\', self::CLIENTNAMESPACE . '\\');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy enums classes
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function copyEnums(): void
|
private function copyEnums(): void
|
||||||
{
|
{
|
||||||
$this->info('Copy Enums');
|
$this->info('Copy Enums');
|
||||||
$rootTarget = app_path('../' . self::TARGET);
|
$classes = [
|
||||||
$classes = [
|
|
||||||
ApiError::class,
|
ApiError::class,
|
||||||
ApiStatus::class,
|
ApiStatus::class,
|
||||||
|
ArcadiaMailType::class,
|
||||||
ArcadiaOrderType::class,
|
ArcadiaOrderType::class,
|
||||||
Country::class,
|
Country::class,
|
||||||
QuestionType::class
|
QuestionType::class
|
||||||
];
|
];
|
||||||
$this->copyToFolder($classes, 'Enums');
|
$this->copyToFolder($classes, 'Enums');
|
||||||
|
$rootTarget = app_path('../' . self::TARGET);
|
||||||
foreach ($classes as $class) {
|
foreach ($classes as $class) {
|
||||||
$classBasename = class_basename($class);
|
$classBasename = class_basename($class);
|
||||||
$dest = "$rootTarget/Enums/$classBasename.php";
|
$dest = "$rootTarget/Enums/$classBasename.php";
|
||||||
$this->replaceInPhpFile($dest, 'App\\', self::CLIENTNAMESPACE . '\\');
|
$this->replaceInPhpFile($dest, 'BaseEnumRoutable', 'BaseEnum');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy Classes to specified folder
|
* Copy Classes to specified folder
|
||||||
*
|
*
|
||||||
* @param array $classes
|
* @param array $classes
|
||||||
* @param string $folder
|
* @param string $folder
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function copyToFolder(array $classes, string $folder): void
|
private function copyToFolder(array $classes, string $folder): void
|
||||||
{
|
{
|
||||||
$rootTarget = app_path('../' . self::TARGET);
|
$rootTarget = app_path('../' . self::TARGET);
|
||||||
$folderNamespace = \str_replace('/', '\\', $folder);
|
|
||||||
foreach ($classes as $class) {
|
foreach ($classes as $class) {
|
||||||
$classFileName = \str_replace("App\\$folderNamespace\\", '', sprintf('%s.php', $class));
|
$classFileName = \str_replace("App\\$folder\\", '', sprintf('%s.php', $class));
|
||||||
$classFileName = \str_replace('\\', '/', $classFileName);
|
$classFileName = \str_replace('\\', '/', $classFileName);
|
||||||
$classBasename = class_basename($class);
|
$classBasename = class_basename($class);
|
||||||
$source = \app_path("$folder/$classFileName");
|
$source = \app_path("$folder/$classFileName");
|
||||||
|
|
@ -188,28 +142,16 @@ class GenerateClient extends Command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces a specific string with another on a file
|
|
||||||
*
|
|
||||||
* @param string $source
|
|
||||||
* @param string $search
|
|
||||||
* @param string $replace
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function replaceInPhpFile(string $source, string $search, string $replace): void
|
private function replaceInPhpFile(string $source, string $search, string $replace): void
|
||||||
{
|
{
|
||||||
$fContent = File::get($source);
|
$fContent = File::get($source);
|
||||||
|
|
||||||
// Remove trailing \Api\V4 .
|
// remove trailing \Api\V2
|
||||||
if ($pos = strpos($fContent, '\Api\V4')) {
|
if ($pos = strpos($fContent, '\Api\V2')) {
|
||||||
$fContent = substr_replace($fContent, '', $pos, strlen('\Api\V4'));
|
$fContent = substr_replace($fContent, '', $pos, strlen('\Api\V2'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove trailing \Api .
|
// replace namespace top level
|
||||||
$fContent = Str::of($fContent)->replaceMatches("/\\\(Api)([\s;\\\])/", '$2');
|
|
||||||
$fContent = Str::of($fContent)->replaceMatches("/\\\Traits\\\Enums/", '\Traits');
|
|
||||||
|
|
||||||
// Replace namespace top level.
|
|
||||||
$pos = strpos($fContent, $search);
|
$pos = strpos($fContent, $search);
|
||||||
if ($pos !== false) {
|
if ($pos !== false) {
|
||||||
File::put($source, \str_replace($search, $replace, $fContent));
|
File::put($source, \str_replace($search, $replace, $fContent));
|
||||||
71
app/Console/Commands/MigrateCrmUsers.php
Normal file
71
app/Console/Commands/MigrateCrmUsers.php
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Lib\MigrateOldData;
|
||||||
|
use App\Models\Brand;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class MigrateCrmUsers extends Command
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'migrate:crm';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Migrate crm users';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$table = $this->ask('What is the tmp table name with users data ?');
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB::connection(config('database.oldDB'))->table($table)->exists();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->error(sprintf('%s table not found on old crm database', $table));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$brandname = $this->ask('What is the brand name ?');
|
||||||
|
$brand = Brand::where('name', 'LIKE', "%$brandname%")->first();
|
||||||
|
if (!$brand) {
|
||||||
|
if (!$this->confirm(sprintf('Would you like to use %s ? ', $brandname))) {
|
||||||
|
$this->info('Command cancelled');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ($this->confirm('Would you like to create a new one ?')) {
|
||||||
|
$brand = new Brand();
|
||||||
|
$brand->name = $brandname;
|
||||||
|
$brand->save();
|
||||||
|
} else {
|
||||||
|
$this->info('Command cancelled');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$mgOldData = new MigrateOldData();
|
||||||
|
$mgOldData->runMigration($brand, $table);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->error(sprintf('Failed %s', $e));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,11 +5,9 @@ namespace App\Console\Commands;
|
||||||
use App\Jobs\StartStatJobs as JobsStartStatJobs;
|
use App\Jobs\StartStatJobs as JobsStartStatJobs;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
/**
|
|
||||||
* @codeCoverageIgnore
|
|
||||||
*/
|
|
||||||
class StartStatJobs extends Command
|
class StartStatJobs extends Command
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
*
|
*
|
||||||
|
|
@ -27,9 +25,9 @@ class StartStatJobs extends Command
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
* @return integer
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle()
|
||||||
{
|
{
|
||||||
\dispatch(new JobsStartStatJobs())->afterResponse();
|
\dispatch(new JobsStartStatJobs())->afterResponse();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
|
|
||||||
class TestMail extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'uwil:mail:test';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Send test email to equipe.web@ldc.fr';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
Mail::raw(sprintf('UWIL mail-test from %s %s', \config('app.name'), \config('app.url')), function ($msg) {
|
|
||||||
$msg->to('equipe.web@ldc.fr')->subject('Test Email');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,204 +2,48 @@
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Validation\ValidationException;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class UserCreate extends Command
|
class UserCreate extends Command
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name and signature of the console command.
|
* The name and signature of the console command.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'uwil:user:create';
|
protected $signature = 'user:create';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $description = 'Create a backend admin user';
|
protected $description = 'Command description';
|
||||||
|
|
||||||
/**
|
|
||||||
* The first name of the new user.
|
|
||||||
*
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $firstName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last name of the new user.
|
|
||||||
*
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $lastName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The email of the new user.
|
|
||||||
*
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $email;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The role of the new user.
|
|
||||||
*
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $role;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle()
|
||||||
{
|
{
|
||||||
$this->firstName = null;
|
$admin = false;
|
||||||
$this->addFirstName();
|
|
||||||
|
|
||||||
$this->lastName = null;
|
$firstname = $this->ask('What is the firstname?');
|
||||||
$this->addLastName();
|
$lastname = $this->ask('What is the lastname?');
|
||||||
|
$email = $this->ask('What is the email?');
|
||||||
|
$pwd = $this->secret('What is the password?');
|
||||||
|
|
||||||
$this->email = null;
|
$user = new User();
|
||||||
$this->addEmail();
|
$user->firstname = $firstname;
|
||||||
|
$user->lastname = $lastname;
|
||||||
|
$user->email = $email;
|
||||||
|
$user->password = Hash::make($pwd);
|
||||||
|
$user->save();
|
||||||
|
|
||||||
$this->role = null;
|
$this->info('User created.');
|
||||||
$this->addRole();
|
|
||||||
|
|
||||||
$user = new User([
|
|
||||||
'first_name' => $this->firstName,
|
|
||||||
'last_name' => $this->lastName,
|
|
||||||
'email' => $this->email,
|
|
||||||
'role' => $this->role,
|
|
||||||
'published' => true,
|
|
||||||
'published_at' => Carbon::now(),
|
|
||||||
]);
|
|
||||||
$user->saveOrFail();
|
|
||||||
|
|
||||||
$this->info('User created 👌');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a first name to the user.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function addFirstName(): void
|
|
||||||
{
|
|
||||||
while (is_null($this->firstName)) {
|
|
||||||
try {
|
|
||||||
$tmp = $this->ask('Type the wanted user first name', 'Admin');
|
|
||||||
$validator = Validator::make(['first_name' => $tmp], [
|
|
||||||
'first_name' => 'required|min:3|max:255'
|
|
||||||
]);
|
|
||||||
$validator->validate();
|
|
||||||
$this->firstName = $tmp;
|
|
||||||
} catch (ValidationException $e) {
|
|
||||||
$this->error(sprintf(
|
|
||||||
'Please provide a valid first name %s',
|
|
||||||
\implode(',', collect($e->errors())->flatten()->all())
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a last name to the user.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function addLastName(): void
|
|
||||||
{
|
|
||||||
while (is_null($this->lastName)) {
|
|
||||||
try {
|
|
||||||
$tmp = $this->ask('Type the wanted user last name', 'Saïtama');
|
|
||||||
$validator = Validator::make(['last_name' => $tmp], [
|
|
||||||
'last_name' => 'required|min:3|max:255'
|
|
||||||
]);
|
|
||||||
$validator->validate();
|
|
||||||
$this->lastName = $tmp;
|
|
||||||
} catch (ValidationException $e) {
|
|
||||||
$this->error(sprintf(
|
|
||||||
'Please provide a valid last_name %s',
|
|
||||||
\implode(',', collect($e->errors())->flatten()->all())
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an email to the user.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function addEmail(): void
|
|
||||||
{
|
|
||||||
while (is_null($this->email)) {
|
|
||||||
try {
|
|
||||||
$tmp = $this->ask('Type the wanted user email', 'equipe.web@ldc.fr');
|
|
||||||
$validator = Validator::make(['email' => $tmp], [
|
|
||||||
'email' => 'required|unique:users,email|email:rfc,dns'
|
|
||||||
]);
|
|
||||||
$validator->validate();
|
|
||||||
$this->email = $tmp;
|
|
||||||
} catch (ValidationException $e) {
|
|
||||||
$this->error(sprintf(
|
|
||||||
'Please provide a valid email %s',
|
|
||||||
\implode(',', collect($e->errors())->flatten()->all())
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a role to the user.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function addRole(): void
|
|
||||||
{
|
|
||||||
while (is_null($this->role)) {
|
|
||||||
try {
|
|
||||||
$tmp = $this->choice(
|
|
||||||
'Select his role',
|
|
||||||
[
|
|
||||||
Str::ucFirst(RoleEnum::conceptor->label()),
|
|
||||||
Str::ucFirst(RoleEnum::admin->label()),
|
|
||||||
Str::ucFirst(RoleEnum::marketing->label())
|
|
||||||
],
|
|
||||||
Str::ucFirst(RoleEnum::marketing->label()),
|
|
||||||
);
|
|
||||||
if ($tmp === Str::ucFirst(RoleEnum::conceptor->label())) {
|
|
||||||
$tmp = RoleEnum::conceptor;
|
|
||||||
}
|
|
||||||
if ($tmp === Str::ucFirst(RoleEnum::admin->label())) {
|
|
||||||
$tmp = RoleEnum::admin;
|
|
||||||
}
|
|
||||||
if ($tmp === Str::ucFirst(RoleEnum::marketing->label())) {
|
|
||||||
$tmp = RoleEnum::marketing;
|
|
||||||
}
|
|
||||||
$validator = Validator::make(['role' => $tmp], [
|
|
||||||
'role' => 'required'
|
|
||||||
]);
|
|
||||||
$validator->validate();
|
|
||||||
$this->role = $tmp;
|
|
||||||
} catch (ValidationException $e) {
|
|
||||||
$this->error(sprintf(
|
|
||||||
'Please choose from the selection %s',
|
|
||||||
\implode(',', collect($e->errors())->flatten()->all())
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,13 @@
|
||||||
|
|
||||||
namespace App\Console;
|
namespace App\Console;
|
||||||
|
|
||||||
use App\Console\Commands\DeleteUnconfirmedCustomers;
|
|
||||||
use App\Jobs\SendTransferredToDigitalCountMail;
|
|
||||||
use App\Jobs\StartStatJobs;
|
use App\Jobs\StartStatJobs;
|
||||||
use Illuminate\Console\Scheduling\Schedule;
|
use Illuminate\Console\Scheduling\Schedule;
|
||||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||||
|
|
||||||
class Kernel extends ConsoleKernel
|
class Kernel extends ConsoleKernel
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Artisan commands provided by your application.
|
* The Artisan commands provided by your application.
|
||||||
*
|
*
|
||||||
|
|
@ -20,16 +19,13 @@ class Kernel extends ConsoleKernel
|
||||||
/**
|
/**
|
||||||
* Define the application's command schedule.
|
* Define the application's command schedule.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function schedule(Schedule $schedule): void
|
protected function schedule(Schedule $schedule)
|
||||||
{
|
{
|
||||||
// @codeCoverageIgnoreStart
|
// stats job on night
|
||||||
$schedule->job(StartStatJobs::class)->dailyAt('03:30');
|
$schedule->job(StartStatJobs::class)->dailyAt('03:30');
|
||||||
$schedule->job(SendTransferredToDigitalCountMail::class)->weekdays()->at('07:00');
|
|
||||||
$schedule->command(DeleteUnconfirmedCustomers::class)->dailyAt('05:30');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,7 +33,7 @@ class Kernel extends ConsoleKernel
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function commands(): void
|
protected function commands()
|
||||||
{
|
{
|
||||||
$this->load(__DIR__ . '/Commands');
|
$this->load(__DIR__ . '/Commands');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\ActivityLogs;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ActivityLogsEventEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case created = 1;
|
|
||||||
case updated = 2;
|
|
||||||
case duplicated = 3;
|
|
||||||
case deleted = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::created->name => 'Création',
|
|
||||||
self::updated->name => 'Mise à jour',
|
|
||||||
self::duplicated->name => 'Duplication',
|
|
||||||
self::deleted->name => 'Suppression',
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom added classes definition
|
|
||||||
*/
|
|
||||||
private const BOOTSTRAPCLASS = [
|
|
||||||
self::created->name => 'success',
|
|
||||||
self::updated->name => 'warning',
|
|
||||||
self::duplicated->name => 'secondary',
|
|
||||||
self::deleted->name => 'danger',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Class
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function bootstrapClass(): string
|
|
||||||
{
|
|
||||||
return self::BOOTSTRAPCLASS[$this->name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,43 +2,108 @@
|
||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||||
|
|
||||||
enum ApiError: int
|
/**
|
||||||
|
* This describes an API error.
|
||||||
|
*
|
||||||
|
* @method static self modelNotFound()
|
||||||
|
* The request model was not found (typically the customer)
|
||||||
|
*
|
||||||
|
* @method static self validationFailed()
|
||||||
|
* This means some data could not be validated,
|
||||||
|
* you may have to look into message to get the details
|
||||||
|
*
|
||||||
|
* @method static self customerExists()
|
||||||
|
* The customer already exists
|
||||||
|
*
|
||||||
|
* @method static self customerNotActivated()
|
||||||
|
* The customer account is not activated and cannot perform
|
||||||
|
* this action
|
||||||
|
*
|
||||||
|
* @method static self customerAlreadyActive()
|
||||||
|
* You have requested to activate a customer account,
|
||||||
|
* but it is already active
|
||||||
|
*
|
||||||
|
* @method static self singleOptinCustomerExists()
|
||||||
|
* You have requested to create a single optin for an email,
|
||||||
|
* but it already exists
|
||||||
|
*
|
||||||
|
* @method static self apiAuthFailed()
|
||||||
|
* The authentification to the api failed. You may have to
|
||||||
|
* check into config or .env file for your brand credentials
|
||||||
|
*
|
||||||
|
* @method static self authFailed()
|
||||||
|
* The authentification for this customer failed because of wrong credentials
|
||||||
|
*
|
||||||
|
* @method static self needAuth()
|
||||||
|
* This action requires to be authenticated
|
||||||
|
*
|
||||||
|
* @method static self methodNotAllowed()
|
||||||
|
* This http method is not allowed
|
||||||
|
*
|
||||||
|
* @method static self wrongTimeStamp()
|
||||||
|
* The timestamp given is wrong. This would happen in case if
|
||||||
|
* a replay attack scenario. Timestamps are provided in headers
|
||||||
|
* and in the http body
|
||||||
|
*
|
||||||
|
* @method static self missingParameter()
|
||||||
|
* The request is missing some parameters
|
||||||
|
*
|
||||||
|
* @method static self throttleRequestsException()
|
||||||
|
* Too many requests have been attempted. The is a throttle security.
|
||||||
|
* Normally you should not trigger this.
|
||||||
|
* If this happens fill a ticket on https://supportweb.ldc.fr
|
||||||
|
* with some technical details
|
||||||
|
*
|
||||||
|
* @method static self authorizationException()
|
||||||
|
* You are maybe trying to access data that is out of your range.
|
||||||
|
* This should not happen normally, it is here to allow you to handle this case.
|
||||||
|
* If this happens fill a ticket on https://supportweb.ldc.fr
|
||||||
|
* with some technical details
|
||||||
|
*
|
||||||
|
* @package LDCCrmClient
|
||||||
|
* @subpackage enums
|
||||||
|
*/
|
||||||
|
class ApiError extends BaseEnumRoutable
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
public static function values(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'modelNotFound' => 101,
|
||||||
|
'validationFailed' => 102,
|
||||||
|
'customerExists' => 103,
|
||||||
|
'customerAlreadyActive' => 110,
|
||||||
|
'customerNotActivated' => 116,
|
||||||
|
'authFailed' => 117,
|
||||||
|
'needAuth' => 118,
|
||||||
|
'apiAuthFailed' => 119,
|
||||||
|
'singleOptinCustomerExists' => 120,
|
||||||
|
'methodNotAllowed' => 150,
|
||||||
|
'wrongTimeStamp' => 151,
|
||||||
|
'missingParameter' => 400,
|
||||||
|
'authorizationException' => 403,
|
||||||
|
'throttleRequestsException' => 429
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
case modelNotFound = 101;
|
public static function labels(): array
|
||||||
case validationFailed = 102;
|
{
|
||||||
case customerExists = 103;
|
return [
|
||||||
case customerAlreadyActive = 110;
|
'modelNotFound' => '%s introuvable.',
|
||||||
case customerNotActivated = 116;
|
'validationFailed' => 'Impossible de valider les données',
|
||||||
case authFailed = 117;
|
'customerExists' => 'L\'utilisateur est déjà enregistré sur ce site',
|
||||||
case apiAuthFailed = 119;
|
'customerNotActivated' => 'Le compte n\'est pas activé',
|
||||||
case singleOptinCustomerExists = 120;
|
'customerAlreadyActive' => 'Le compte est déjà activé',
|
||||||
case methodNotAllowed = 150;
|
'singleOptinCustomerExists' => 'Le single optin ne peut être ajouté car un compte existe.',
|
||||||
case wrongTimeStamp = 151;
|
'authFailed' => 'Echec de l\'authentification du compte',
|
||||||
case missingParameter = 400;
|
'needAuth' => 'Vous devez être authentifié',
|
||||||
case authorizationException = 403;
|
'apiAuthFailed' => 'Echec de l\'authentification client à l\'Api LDC-CRM pour ce service',
|
||||||
case throttleRequestsException = 429;
|
'methodNotAllowed' => 'This method is not allowed for this request',
|
||||||
|
'wrongTimeStamp' => 'Your request is malformed, please check timestamp header and parameter',
|
||||||
/**
|
'missingParameter' => 'The request is missing some parameters',
|
||||||
* Optionnal labels definition
|
'authorizationException' => 'You are not autorized to access this',
|
||||||
*/
|
'throttleRequestsException' => 'Throttle: too many request have been attempted, please retry later'
|
||||||
private const LABELS = [
|
];
|
||||||
self::modelNotFound->name => '%s introuvable.',
|
}
|
||||||
self::validationFailed->name => 'Impossible de valider les données',
|
|
||||||
self::customerExists->name => 'L\'utilisateur est déjà enregistré sur ce site',
|
|
||||||
self::customerNotActivated->name => 'Le compte n\'est pas activé',
|
|
||||||
self::customerAlreadyActive->name => 'Le compte est déjà activé',
|
|
||||||
self::singleOptinCustomerExists->name => 'Le single optin ne peut être ajouté car un compte existe.',
|
|
||||||
self::authFailed->name => 'Echec de l\'authentification du compte',
|
|
||||||
self::apiAuthFailed->name => 'Echec de l\'authentification client à l\'Api LDC-CRM pour ce service',
|
|
||||||
self::methodNotAllowed->name => 'This method is not allowed for this request',
|
|
||||||
self::wrongTimeStamp->name => 'Your request is malformed, please check timestamp header and
|
|
||||||
parameter',
|
|
||||||
self::missingParameter->name => 'The request is missing some parameters',
|
|
||||||
self::authorizationException->name => 'You are not autorized to access this',
|
|
||||||
self::throttleRequestsException->name => 'Throttle: too many request have been attempted, please retry later'
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,15 @@
|
||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||||
|
|
||||||
enum ApiStatus: int
|
/**
|
||||||
|
* @method static self OK()
|
||||||
|
* @method static self KO()
|
||||||
|
*
|
||||||
|
* @package LDCCrmClient
|
||||||
|
* @subpackage enums
|
||||||
|
*/
|
||||||
|
class ApiStatus extends BaseEnumRoutable
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case OK = 1;
|
|
||||||
case KO = 2;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,22 @@
|
||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||||
|
|
||||||
enum ArcadiaMailType: int
|
/**
|
||||||
|
* @method static self default()
|
||||||
|
* @method static self game()
|
||||||
|
*
|
||||||
|
* @package LDCCrmClient
|
||||||
|
* @subpackage enums
|
||||||
|
*/
|
||||||
|
class ArcadiaMailType extends BaseEnumRoutable
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
public static function values(): array
|
||||||
|
{
|
||||||
case default = 1;
|
return [
|
||||||
case game = 2;
|
'default' => 1,
|
||||||
|
'game' => 2
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,22 @@
|
||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||||
|
|
||||||
enum ArcadiaOrderType: int
|
/**
|
||||||
|
* @method static self cb()
|
||||||
|
* @method static self check()
|
||||||
|
*
|
||||||
|
* @package LDCCrmClient
|
||||||
|
* @subpackage enums
|
||||||
|
*/
|
||||||
|
class ArcadiaOrderType extends BaseEnumRoutable
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
public static function values(): array
|
||||||
|
{
|
||||||
case cb = 0;
|
return [
|
||||||
case check = 1;
|
'cb' => 0,
|
||||||
|
'check' => 1
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Claims;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ClaimMessageType: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case system = 1;
|
|
||||||
case human = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::system->name => 'Système',
|
|
||||||
self::human->name => 'Humain',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Claims;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ClaimResponseType: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case none = 1;
|
|
||||||
case manual = 2;
|
|
||||||
case mail = 3;
|
|
||||||
case email = 4;
|
|
||||||
case phone = 5;
|
|
||||||
case other = 99;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::none->name => 'Non défini',
|
|
||||||
self::manual->name => 'Manuelle',
|
|
||||||
self::mail->name => 'Courrier',
|
|
||||||
self::email->name => 'E-mail',
|
|
||||||
self::phone->name => 'Téléphone',
|
|
||||||
self::other->name => 'Autre',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition.
|
|
||||||
*/
|
|
||||||
private const COLORS = [
|
|
||||||
self::none->name => '#b8b8b8',
|
|
||||||
self::manual->name => '#a7a7a7',
|
|
||||||
self::mail->name => '#757575',
|
|
||||||
self::email->name => '#5e5e5e',
|
|
||||||
self::phone->name => '#414141',
|
|
||||||
self::other->name => '#2b2b2b',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Class.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function color(): string
|
|
||||||
{
|
|
||||||
return self::COLORS[$this->name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Claims;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ClaimStatus: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case untreated = 1;
|
|
||||||
case sentDigital = 2;
|
|
||||||
case sentMarketing = 3;
|
|
||||||
case treated = 4;
|
|
||||||
case refused = 5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::untreated->name => 'Non traitée',
|
|
||||||
self::sentDigital->name => 'Transférée au service Digital',
|
|
||||||
self::sentMarketing->name => 'Retournée au Marketing',
|
|
||||||
self::treated->name => 'Traitée',
|
|
||||||
self::refused->name => 'Refusé de répondre',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition.
|
|
||||||
*/
|
|
||||||
private const COLORS = [
|
|
||||||
self::untreated->name => '#5a5a5a',
|
|
||||||
self::sentDigital->name => '#0033c0',
|
|
||||||
self::sentMarketing->name => '#69077c',
|
|
||||||
self::treated->name => '#188618',
|
|
||||||
self::refused->name => '#dc143c',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Class.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function color(): string
|
|
||||||
{
|
|
||||||
return self::COLORS[$this->name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Claims;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ClaimType: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case classic = 1;
|
|
||||||
case br = 2;
|
|
||||||
case rgpd = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::classic->name => 'Classique',
|
|
||||||
self::br->name => 'BR',
|
|
||||||
self::rgpd->name => 'RGPD',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition.
|
|
||||||
*/
|
|
||||||
private const COLORS = [
|
|
||||||
self::classic->name => '#08818a',
|
|
||||||
self::br->name => '#9021f8',
|
|
||||||
self::rgpd->name => '#c2237a',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Class.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function color(): string
|
|
||||||
{
|
|
||||||
return self::COLORS[$this->name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -2,23 +2,32 @@
|
||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||||
|
|
||||||
enum CustomerExportType: int
|
/**
|
||||||
|
* @method static self singleOptin()
|
||||||
|
* @method static self customer()
|
||||||
|
* @method static self both()
|
||||||
|
*
|
||||||
|
* @package LDCCrmClient
|
||||||
|
* @subpackage enums
|
||||||
|
*/
|
||||||
|
class CustomerExportType extends BaseEnumRoutable
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
public static function values(): array
|
||||||
|
{
|
||||||
case singleOptin = 1;
|
return [
|
||||||
case customer = 2;
|
'singleOptin' => 1,
|
||||||
case both = 3;
|
'customer' => 2,
|
||||||
|
'both' => 3
|
||||||
/**
|
];
|
||||||
* Optionnal labels definition
|
}
|
||||||
*/
|
public static function labels(): array
|
||||||
private const LABELS = [
|
{
|
||||||
self::singleOptin->name => 'Les single-optins uniquement',
|
return [
|
||||||
self::customer->name => 'Les clients uniquement acceptant de recevoir les newsletters',
|
'singleOptin' => trans('Les single optins uniquement'),
|
||||||
self::both->name => 'La totalité des single-optins ainsi que des clients acceptant
|
'customer' => trans('Les clients uniquement acceptant de recevoir les newsletters'),
|
||||||
de recevoir les newsletters',
|
'both' => trans('La totalité des client acceptant de recevoir les newsletters')
|
||||||
];
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ExportFormat: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case csv = 1;
|
|
||||||
case csvWithoutAttachment = 2;
|
|
||||||
case pdf = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::csv->name => 'csv',
|
|
||||||
self::csvWithoutAttachment->name => 'csv sans pièces jointes',
|
|
||||||
self::pdf->name => 'pdf',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bootstrap color class to use for the export buttons.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function class(): string
|
|
||||||
{
|
|
||||||
return match ($this) {
|
|
||||||
self::csv,
|
|
||||||
self::csvWithoutAttachment => 'success',
|
|
||||||
self::pdf => 'danger',
|
|
||||||
default => 'primary',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Font Awesome picto to use for the export buttons.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function picto(): string
|
|
||||||
{
|
|
||||||
return match ($this) {
|
|
||||||
self::csv,
|
|
||||||
self::csvWithoutAttachment => 'fa-solid fa-file-csv',
|
|
||||||
self::pdf => 'fa-solid fa-file-pdf',
|
|
||||||
default => 'fa-solid fa-file',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File headers to use when the exported file is return with StreamedResponse.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function fileHeaders(): array
|
|
||||||
{
|
|
||||||
return match ($this) {
|
|
||||||
self::csv,
|
|
||||||
self::csvWithoutAttachment => [
|
|
||||||
'Content-Type' => 'text/csv',
|
|
||||||
'Content-Disposition' => 'attachment; filename="export.csv"',
|
|
||||||
],
|
|
||||||
default => [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export file name.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function fileName(): string
|
|
||||||
{
|
|
||||||
return match ($this) {
|
|
||||||
self::csv,
|
|
||||||
self::csvWithoutAttachment => 'export.csv',
|
|
||||||
self::pdf => 'export.pdf',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Pagination;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum ItemsPerPaginationEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case five = 5;
|
|
||||||
case twelve = 12;
|
|
||||||
case twentyfive = 25;
|
|
||||||
case fifty = 50;
|
|
||||||
case onehundred = 100;
|
|
||||||
}
|
|
||||||
|
|
@ -2,13 +2,24 @@
|
||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||||
|
|
||||||
enum QuestionType: int
|
/**
|
||||||
|
* @method static self select()
|
||||||
|
* @method static self radio()
|
||||||
|
* @method static self checkbox()
|
||||||
|
*
|
||||||
|
* @package LDCCrmClient
|
||||||
|
* @subpackage enums
|
||||||
|
*/
|
||||||
|
class QuestionType extends BaseEnumRoutable
|
||||||
{
|
{
|
||||||
use BaseEnum;
|
public static function values(): array
|
||||||
|
{
|
||||||
case select = 1;
|
return [
|
||||||
case radio = 2;
|
'select' => 1,
|
||||||
case checkbox = 3;
|
'radio' => 2,
|
||||||
|
'checkbox' => 3
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Theme;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum BootstrapThemeEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case light = 1;
|
|
||||||
case dark = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::light->name => 'Light',
|
|
||||||
self::dark->name => 'Dark',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums\Users;
|
|
||||||
|
|
||||||
use Uwil\LaravelCommon\Traits\Enums\BaseEnum;
|
|
||||||
|
|
||||||
enum RoleEnum: int
|
|
||||||
{
|
|
||||||
use BaseEnum;
|
|
||||||
|
|
||||||
case conceptor = 1;
|
|
||||||
case admin = 2;
|
|
||||||
case marketing = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionnal labels definition.
|
|
||||||
*/
|
|
||||||
private const LABELS = [
|
|
||||||
self::conceptor->name => 'Concepteur',
|
|
||||||
self::admin->name => 'Administrateur',
|
|
||||||
self::marketing->name => 'Marketing',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Events;
|
|
||||||
|
|
||||||
use App\Models\Claim;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class ClaimModelChanged
|
|
||||||
{
|
|
||||||
use Dispatchable;
|
|
||||||
use InteractsWithSockets;
|
|
||||||
use SerializesModels;
|
|
||||||
|
|
||||||
/** @var \App\Models\Claim $claim Current claim modified. */
|
|
||||||
public $claim;
|
|
||||||
|
|
||||||
/** @var string $field Modified field. */
|
|
||||||
public $field;
|
|
||||||
|
|
||||||
/** @var string $label Label of the modified field. */
|
|
||||||
public $label;
|
|
||||||
|
|
||||||
/** @var \App\Models\User|null $user Current authenticated user. */
|
|
||||||
public $user;
|
|
||||||
|
|
||||||
/** @var string|null $content Custom content message. */
|
|
||||||
public $content;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new event instance.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Claim $claim
|
|
||||||
* @param string $field
|
|
||||||
* @param string $label
|
|
||||||
* @param \App\Models\User|null $user
|
|
||||||
* @param string|null $content
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(
|
|
||||||
Claim $claim,
|
|
||||||
string $field,
|
|
||||||
string $label,
|
|
||||||
User|null $user = null,
|
|
||||||
string|null $content = null,
|
|
||||||
) {
|
|
||||||
$this->claim = $claim;
|
|
||||||
$this->field = $field;
|
|
||||||
$this->label = $label;
|
|
||||||
$this->user = $user;
|
|
||||||
$this->content = $content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
app/Exceptions/AbortRowImportException.php
Normal file
14
app/Exceptions/AbortRowImportException.php
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class Exception is used to skip a row import from
|
||||||
|
* database migration (2016 -> 2020)
|
||||||
|
* @author Jérémy Munsch <jeremy.munsch@ldc.fr>
|
||||||
|
*/
|
||||||
|
class AbortRowImportException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -10,17 +10,18 @@ use Throwable;
|
||||||
/**
|
/**
|
||||||
* This would be thrown if any of the case
|
* This would be thrown if any of the case
|
||||||
* referenced in \App\Enums\ApiError would
|
* referenced in \App\Enums\ApiError would
|
||||||
* occur within the crm.
|
* occur within the crm
|
||||||
*
|
*
|
||||||
* On the client an ApiErrorException would
|
* On the client an ApiErrorException would
|
||||||
* also be throw with the ApiError corresponding to
|
* also be throw with the ApiError corresponding to
|
||||||
* the situation.
|
* the situation
|
||||||
*
|
*
|
||||||
* @package LDCCrmClient
|
* @package LDCCrmClient
|
||||||
* @subpackage exceptions
|
* @subpackage exceptions
|
||||||
*/
|
*/
|
||||||
class ApiErrorException extends Exception
|
class ApiErrorException extends Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Api Error
|
* Api Error
|
||||||
* This value makes the error more explicit.
|
* This value makes the error more explicit.
|
||||||
|
|
@ -34,7 +35,7 @@ class ApiErrorException extends Exception
|
||||||
/**
|
/**
|
||||||
* This is an explicit error message,
|
* This is an explicit error message,
|
||||||
* ou may print this to the front or not depending
|
* ou may print this to the front or not depending
|
||||||
* on $error value.
|
* on $error value
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
|
|
@ -45,34 +46,26 @@ class ApiErrorException extends Exception
|
||||||
* This value could be used to handle errors.
|
* This value could be used to handle errors.
|
||||||
* But please take in consideration $error first
|
* But please take in consideration $error first
|
||||||
*
|
*
|
||||||
* @var integer
|
* @var int
|
||||||
*/
|
*/
|
||||||
protected $httpCode;
|
protected $httpCode;
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new exception base on ApiError enum.
|
|
||||||
*
|
|
||||||
* @param \App\Enums\ApiError $error
|
|
||||||
* @param integer $httpCode
|
|
||||||
* @param string $message
|
|
||||||
* @param Throwable|null $previous
|
|
||||||
*/
|
|
||||||
public function __construct(ApiError $error, int $httpCode = 400, string $message = '', Throwable $previous = null)
|
public function __construct(ApiError $error, int $httpCode = 400, string $message = '', Throwable $previous = null)
|
||||||
{
|
{
|
||||||
$this->error = $error;
|
$this->error = $error;
|
||||||
$this->message = $message;
|
$this->message = $message;
|
||||||
$this->httpCode = $httpCode;
|
$this->httpCode = $httpCode;
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
strlen($this->message) ? $this->message : $error->label(),
|
strlen($this->message) ? $this->message : $error->label,
|
||||||
$error->value(),
|
$error->value,
|
||||||
$previous
|
$previous
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Api Error.
|
* Get the Api Error
|
||||||
*
|
*
|
||||||
* @return \App\Enums\ApiError
|
* @return ApiError
|
||||||
*/
|
*/
|
||||||
public function getApiError(): ApiError
|
public function getApiError(): ApiError
|
||||||
{
|
{
|
||||||
|
|
@ -80,25 +73,17 @@ class ApiErrorException extends Exception
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the http code.
|
* Get the http code
|
||||||
*
|
*
|
||||||
* @return integer
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getStatusCode(): int
|
public function getStatusCode(): int
|
||||||
{
|
{
|
||||||
return $this->httpCode;
|
return $this->httpCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function report()
|
||||||
* This is used by laravel only.
|
|
||||||
* It uses Log class to print the error.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function report(): void
|
|
||||||
{
|
{
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
Log::debug(sprintf('CRM API: %s', $this->getMessage()));
|
Log::debug(sprintf('CRM API: %s', $this->getMessage()));
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,7 @@ use Illuminate\Support\Facades\Log;
|
||||||
*/
|
*/
|
||||||
class CrmException extends Exception
|
class CrmException extends Exception
|
||||||
{
|
{
|
||||||
/**
|
public function report()
|
||||||
* This is used by laravel only.
|
|
||||||
* It uses Log class to print the error.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function report(): void
|
|
||||||
{
|
{
|
||||||
Log::critical(sprintf('CRM API: %s', $this->getMessage()));
|
Log::critical(sprintf('CRM API: %s', $this->getMessage()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Exceptions\Api\V4;
|
|
||||||
|
|
||||||
use App\Enums\ApiError;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This would be thrown if any of the case
|
|
||||||
* referenced in \App\Enums\ApiError would
|
|
||||||
* occur within the crm.
|
|
||||||
*
|
|
||||||
* On the client an ApiErrorException would
|
|
||||||
* also be throw with the ApiError corresponding to
|
|
||||||
* the situation.
|
|
||||||
*
|
|
||||||
* @package LDCCrmClient
|
|
||||||
* @subpackage exceptions
|
|
||||||
*/
|
|
||||||
class ApiErrorException extends \RuntimeException
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Api Error
|
|
||||||
* This value makes the error more explicit.
|
|
||||||
* Handling these errors are normal as inputs or
|
|
||||||
* request may be undesired or refused by the crm.
|
|
||||||
*
|
|
||||||
* @var \App\Enums\ApiError
|
|
||||||
*/
|
|
||||||
protected $error;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an explicit error message,
|
|
||||||
* ou may print this to the front or not depending
|
|
||||||
* on $error value.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the http code returned by the crm.
|
|
||||||
* This value could be used to handle errors.
|
|
||||||
* But please take in consideration $error first.
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
protected $httpCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new exception base on ApiError enum.
|
|
||||||
*
|
|
||||||
* @param \App\Enums\ApiError $error
|
|
||||||
* @param integer $httpCode
|
|
||||||
* @param string $message
|
|
||||||
* @param \Throwable|null $previous
|
|
||||||
*/
|
|
||||||
public function __construct(ApiError $error, int $httpCode = 400, string $message = '', \Throwable $previous = null)
|
|
||||||
{
|
|
||||||
$this->error = $error;
|
|
||||||
$this->message = $message;
|
|
||||||
$this->httpCode = $httpCode;
|
|
||||||
parent::__construct(
|
|
||||||
strlen($this->message) ? $this->message : $error->label(),
|
|
||||||
$error->value(),
|
|
||||||
$previous
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Api Error.
|
|
||||||
*
|
|
||||||
* @return \App\Enums\ApiError
|
|
||||||
*/
|
|
||||||
public function getApiError(): ApiError
|
|
||||||
{
|
|
||||||
return $this->error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the http code.
|
|
||||||
*
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
public function getStatusCode(): int
|
|
||||||
{
|
|
||||||
return $this->httpCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is used by laravel only.
|
|
||||||
* It uses Log class to print the error.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function report(): void
|
|
||||||
{
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
Log::debug(sprintf('CRM API: %s', $this->getMessage()));
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Exceptions\Api\V4;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a critical error.
|
|
||||||
* The request could not be handled. You may dump any value you can
|
|
||||||
* get before submitting a ticker to https://support.uwil.fr/
|
|
||||||
*
|
|
||||||
* @package LDCCrmClient
|
|
||||||
* @subpackage exceptions
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class CrmException extends \RuntimeException
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This is used by laravel only.
|
|
||||||
* It uses Log class to print the error.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function report(): void
|
|
||||||
{
|
|
||||||
Log::critical(sprintf('CRM API: %s', $this->getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,10 +4,9 @@ namespace App\Exceptions;
|
||||||
|
|
||||||
use App\Enums\ApiError;
|
use App\Enums\ApiError;
|
||||||
use App\Enums\ApiStatus;
|
use App\Enums\ApiStatus;
|
||||||
use App\Exceptions\Api\V2\ApiErrorException as V2ApiErrorException;
|
use App\Exceptions\Api\V2\ApiErrorException;
|
||||||
use App\Exceptions\Api\V4\ApiErrorException as V4ApiErrorException;
|
use App\Exceptions\Api\V2\CrmException;
|
||||||
use App\Http\Resources\Api\V2\ApiResponse as V2ApiResponse;
|
use App\Http\Resources\Api\V2\ApiResponse as V2ApiResponse;
|
||||||
use App\Http\Resources\Api\V4\ApiResponse as V4ApiResponse;
|
|
||||||
use App\Lib\Helper;
|
use App\Lib\Helper;
|
||||||
use Illuminate\Auth\Access\AuthorizationException;
|
use Illuminate\Auth\Access\AuthorizationException;
|
||||||
use Illuminate\Auth\AuthenticationException;
|
use Illuminate\Auth\AuthenticationException;
|
||||||
|
|
@ -16,12 +15,13 @@ use Illuminate\Http\Exceptions\ThrottleRequestsException;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
use Kwaadpepper\ExceptionHandler\Exceptions\ExceptionHandler;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
class Handler extends ExceptionHandler
|
class Handler extends ExceptionHandler
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of the exception types that are not reported.
|
* A list of the exception types that are not reported.
|
||||||
*
|
*
|
||||||
|
|
@ -47,129 +47,105 @@ class Handler extends ExceptionHandler
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function register(): void
|
public function register()
|
||||||
{
|
{
|
||||||
$this->reportable(function (\Throwable $e) {
|
//
|
||||||
if (app()->bound('sentry')) {
|
|
||||||
app('sentry')->captureException($e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render an exception into an HTTP response.
|
* Render an exception into an HTTP response.
|
||||||
*
|
*
|
||||||
* @param mixed $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param \Throwable $e
|
* @param \Throwable $e
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
*/
|
|
||||||
public function render(mixed $request, \Throwable $e): Response
|
|
||||||
{
|
|
||||||
if ((Helper::isRequestForApiV2($request) || Helper::isRequestForApiV4($request)) and $request->isJson()) {
|
|
||||||
return $this->handleApiException($request, $e);
|
|
||||||
} //end if
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
return parent::render($request, $e);
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a json response for any apiV4 error case.
|
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @throws \Throwable
|
||||||
* @param \Throwable $e
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
private function handleApiException(Request $request, \Throwable $e): JsonResponse
|
// phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||||
|
public function render($request, Throwable $e)
|
||||||
{
|
{
|
||||||
switch (get_class($e)) {
|
if (Helper::isRequestForApiV2($request) and $request->isJson()) {
|
||||||
case AuthenticationException::class:
|
switch (get_class($e)) {
|
||||||
/** @var AuthenticationException $e */
|
case AuthenticationException::class:
|
||||||
return $this->getReponse(
|
/** @var AuthenticationException $e */
|
||||||
$request,
|
return $this->getReponse(
|
||||||
401,
|
$request,
|
||||||
ApiError::apiAuthFailed->value(),
|
401,
|
||||||
sprintf('%s, %s', ApiError::apiAuthFailed->label(), $e->getMessage())
|
ApiError::needAuth()->value,
|
||||||
);
|
sprintf('%s, %s', ApiError::needAuth()->label, $e->getMessage())
|
||||||
case MethodNotAllowedHttpException::class:
|
);
|
||||||
/** @var MethodNotAllowedHttpException $e */
|
case MethodNotAllowedHttpException::class:
|
||||||
return $this->getReponse(
|
/** @var MethodNotAllowedHttpException $e */
|
||||||
$request,
|
return $this->getReponse(
|
||||||
$e->getStatusCode(),
|
$request,
|
||||||
ApiError::methodNotAllowed->value(),
|
$e->getStatusCode(),
|
||||||
sprintf('%s, %s', ApiError::methodNotAllowed->label(), $e->getMessage())
|
ApiError::methodNotAllowed()->value,
|
||||||
);
|
sprintf('%s, %s', ApiError::methodNotAllowed()->label, $e->getMessage())
|
||||||
case ValidationException::class:
|
);
|
||||||
/** @var ValidationException $e */
|
case ValidationException::class:
|
||||||
return $this->getReponse(
|
/** @var ValidationException $e */
|
||||||
$request,
|
return $this->getReponse(
|
||||||
$e->status,
|
$request,
|
||||||
ApiError::validationFailed->value(),
|
$e->status,
|
||||||
sprintf(ApiError::validationFailed->label(), $e->getMessage()),
|
ApiError::validationFailed()->value,
|
||||||
['errors' => $e->errors()]
|
sprintf(ApiError::validationFailed()->label, $e->getMessage()),
|
||||||
);
|
['errors' => $e->errors()]
|
||||||
case ModelNotFoundException::class:
|
);
|
||||||
/** @var ModelNotFoundException $e */
|
case ModelNotFoundException::class:
|
||||||
return $this->getReponse(
|
/** @var ModelNotFoundException $e */
|
||||||
$request,
|
return $this->getReponse(
|
||||||
404,
|
$request,
|
||||||
ApiError::modelNotFound->value(),
|
404,
|
||||||
sprintf(
|
ApiError::modelNotFound()->value,
|
||||||
ApiError::modelNotFound->label(),
|
sprintf(
|
||||||
\array_slice(explode('\\', $e->getModel()), -1)[0]
|
ApiError::modelNotFound()->label,
|
||||||
)
|
\array_slice(explode('\\', $e->getModel()), -1)[0]
|
||||||
);
|
)
|
||||||
case V4ApiErrorException::class:
|
);
|
||||||
/** @var \App\Exceptions\Api\V4\ApiErrorException $e */
|
case ApiErrorException::class:
|
||||||
return $this->getReponse(
|
/** @var ApiErrorException $e */
|
||||||
$request,
|
return $this->getReponse(
|
||||||
$e->getStatusCode(),
|
$request,
|
||||||
$e->getCode(),
|
$e->getStatusCode(),
|
||||||
$e->getMessage()
|
$e->getCode(),
|
||||||
);
|
$e->getMessage()
|
||||||
case V2ApiErrorException::class:
|
);
|
||||||
/** @var \App\Exceptions\Api\V2\ApiErrorException $e */
|
case ThrottleRequestsException::class:
|
||||||
return $this->getReponse(
|
/** @var ThrottleRequestsException $e */
|
||||||
$request,
|
return $this->getReponse(
|
||||||
$e->getStatusCode(),
|
$request,
|
||||||
$e->getCode(),
|
429,
|
||||||
$e->getMessage()
|
ApiError::throttleRequestsException()->value,
|
||||||
);
|
ApiError::throttleRequestsException()->label
|
||||||
case ThrottleRequestsException::class:
|
);
|
||||||
/** @var ThrottleRequestsException $e */
|
case AuthorizationException::class:
|
||||||
return $this->getReponse(
|
/** @var AuthorizationException $e */
|
||||||
$request,
|
return $this->getReponse(
|
||||||
429,
|
$request,
|
||||||
ApiError::throttleRequestsException->value(),
|
403,
|
||||||
ApiError::throttleRequestsException->label()
|
ApiError::authorizationException()->value,
|
||||||
);
|
ApiError::authorizationException()->label
|
||||||
case AuthorizationException::class:
|
);
|
||||||
/** @var AuthorizationException $e */
|
case CrmException::class:
|
||||||
return $this->getReponse(
|
default:
|
||||||
$request,
|
if (config('app.env') === 'testing') {
|
||||||
403,
|
// phpcs:ignore Squiz.PHP.DiscouragedFunctions.Found
|
||||||
ApiError::authorizationException->value(),
|
print_r((string)$e);
|
||||||
ApiError::authorizationException->label()
|
}
|
||||||
);
|
return $this->getReponse($request, 500, $e->getCode(), $e->getMessage());
|
||||||
} //end switch
|
}
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
if (config('app.env') === 'testing') {
|
|
||||||
// phpcs:ignore Squiz.PHP.DiscouragedFunctions.Found
|
|
||||||
print_r((string) $e);
|
|
||||||
}
|
}
|
||||||
return $this->getReponse($request, 500, \intval($e->getCode()), $e->getMessage());
|
return parent::render($request, $e);
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an ApiV4 json response.
|
* Generate an ApiV2 json response
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param Request $request
|
||||||
* @param integer $httpCode
|
* @param integer $httpCode
|
||||||
* @param integer $apiCode
|
* @param integer $apiCode
|
||||||
* @param string $message
|
* @param string $message
|
||||||
* @param array $data
|
* @return JsonResponse
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
*/
|
||||||
private static function getReponse(
|
private static function getReponse(
|
||||||
Request $request,
|
Request $request,
|
||||||
|
|
@ -178,15 +154,15 @@ class Handler extends ExceptionHandler
|
||||||
string $message,
|
string $message,
|
||||||
array $data = []
|
array $data = []
|
||||||
): JsonResponse {
|
): JsonResponse {
|
||||||
if (Helper::isRequestForApiV2($request)) {
|
return (new V2ApiResponse(
|
||||||
return (new V2ApiResponse(
|
(object)array_merge(
|
||||||
ApiStatus::KO,
|
$data,
|
||||||
(object) array_merge($data, ['message' => $message, 'code' => $apiCode]),
|
[
|
||||||
))->toResponse($request)->setStatusCode($httpCode);
|
'message' => $message,
|
||||||
}
|
'code' => $apiCode
|
||||||
return (new V4ApiResponse(
|
]
|
||||||
ApiStatus::KO,
|
),
|
||||||
(object) array_merge($data, ['message' => $message, 'code' => $apiCode]),
|
ApiStatus::KO()
|
||||||
))->toResponse($request)->setStatusCode($httpCode);
|
))->toResponse($request)->setStatusCode($httpCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
42
app/Http/Controllers/AnswerController.php
Normal file
42
app/Http/Controllers/AnswerController.php
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Answer;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
|
||||||
|
use Kwaadpepper\CrudPolicies\Traits\CrudController;
|
||||||
|
|
||||||
|
class AnswerController extends Controller
|
||||||
|
{
|
||||||
|
use CrudController {
|
||||||
|
index as crudIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Log */
|
||||||
|
public static $modelClass = Answer::class;
|
||||||
|
|
||||||
|
public static $layout = 'layouts.app';
|
||||||
|
|
||||||
|
public function indexQuery(Builder $query): Builder
|
||||||
|
{
|
||||||
|
$parent = request()->question;
|
||||||
|
if ($parent) {
|
||||||
|
$query->whereHas('question', function ($q) use ($parent) {
|
||||||
|
return $q->whereId($parent->id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(CrudIndexRequest $request)
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\View\View */
|
||||||
|
$view = $this->crudIndex($request);
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
return view('answer.index', $view->getData());
|
||||||
|
}
|
||||||
|
}
|
||||||
331
app/Http/Controllers/Api/V1/ArcadiaController.php
Normal file
331
app/Http/Controllers/Api/V1/ArcadiaController.php
Normal file
|
|
@ -0,0 +1,331 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\V1;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Resources\StatusResource;
|
||||||
|
use App\Mail\CourrierArcadiaError;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use DOMDocument;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
class ArcadiaController extends Controller
|
||||||
|
{
|
||||||
|
public function outgoingMail(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'crm_id' => 'required',
|
||||||
|
'fields' => 'required|json',
|
||||||
|
'type' => 'required',
|
||||||
|
'shipping' => 'required_if:type,default|json'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return new StatusResource([
|
||||||
|
'status' => 'KO',
|
||||||
|
'code' => 201,
|
||||||
|
'message' => 'Error on required fields.',
|
||||||
|
'errors' => $validator->errors()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
$crmId = $request->crm_id;
|
||||||
|
$fields = json_decode($request->fields);
|
||||||
|
$type = $request->type;
|
||||||
|
$shipping = $type === 'default' ? json_decode($request->shipping) : false;
|
||||||
|
|
||||||
|
$customer = Customer::where('id', $crmId)->first();
|
||||||
|
if (!$customer) {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 202, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$CustomerInfo = $customer->infos()->where('brand_id', $brandId)->first();
|
||||||
|
|
||||||
|
if (!$CustomerInfo) {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 202, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$check = $this->checkRequiredFields($fields, $type);
|
||||||
|
if ($check['status'] !== 'OK') {
|
||||||
|
return new StatusResource($check);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type === 'default') {
|
||||||
|
$check = $this->checkShippingRequiredFields($shipping);
|
||||||
|
if ($check['status'] !== 'OK') {
|
||||||
|
return new StatusResource($check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$xml = $this->makeXml($fields, $type, $customer, $CustomerInfo, $shipping);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Storage::disk('arcadia')->put(date("Ymd_His") . microtime(true) . ".xml", $xml);
|
||||||
|
return new StatusResource(['status' => 'OK']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::critical("ARCADIA XML CREATION FAILED : " . $e->getMessage());
|
||||||
|
Mail::to(config('mail.MAIL_ADMIN'))->send(new CourrierArcadiaError(
|
||||||
|
"ARCADIA XML CREATION FAILED",
|
||||||
|
"Une erreur est survenue lors de la création du fichier XML : " . $e->getMessage(),
|
||||||
|
$xml
|
||||||
|
));
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 204, 'message' => 'Arcadia XML Creation failed.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkShippingRequiredFields($fields)
|
||||||
|
{
|
||||||
|
$test = [
|
||||||
|
'firstname',
|
||||||
|
'lastname',
|
||||||
|
'address',
|
||||||
|
'city',
|
||||||
|
'postcode'
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($test as $t) {
|
||||||
|
if (!array_key_exists($t, $fields)) {
|
||||||
|
$errors[] = ['field' => $t, 'error' => 'required'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($errors)) {
|
||||||
|
return ['status' => 'KO', 'code' => 203, 'message' => $errors];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['status' => 'OK'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||||
|
private function checkRequiredFields($fields, $type)
|
||||||
|
{
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
$key = array_search('operation', array_column($fields->root, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'operation', 'error' => 'required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = array_search('support_code', array_column($fields->orderLine, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'support_code', 'error' => 'required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = array_search('label_type_support', array_column($fields->orderLine, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'label_type_support', 'error' => 'required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = array_search('order_date', array_column($fields->root, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'order_date', 'error' => 'required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = join('', [
|
||||||
|
'/^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|',
|
||||||
|
'((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))',
|
||||||
|
'|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]',
|
||||||
|
'|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/'
|
||||||
|
]);
|
||||||
|
if (!preg_match($regex, $fields->root[$key]->fieldValue)) {
|
||||||
|
$errors[] = ['field' => 'order_date', 'error' => 'format must be DD/MM/YYYY'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type === 'default') {
|
||||||
|
$key = array_search('order_num', array_column($fields->root, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'order_num', 'error' => 'required for default type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_numeric($fields->root[$key]->fieldValue) || strlen($fields->root[$key]->fieldValue) !== 9) {
|
||||||
|
$errors[] = ['field' => 'order_num', 'error' => 'format must be 9 numeric characters'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = array_search('state_order_cb', array_column($fields->root, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'state_order_cb', 'error' => 'required for default type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fields->root[$key]->fieldValue !== 1 && $fields->root[$key]->fieldValue !== 'Null') {
|
||||||
|
$errors[] = ['field' => 'state_order_cb', 'error' => 'value must be 1 or Null (Yes Null not NULL)'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$orderCB = $fields->root[$key]->fieldValue;
|
||||||
|
|
||||||
|
$key = array_search('state_order_check', array_column($fields->root, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'state_order_check', 'error' => 'required for default type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fields->root[$key]->fieldValue !== 1 && $fields->root[$key]->fieldValue !== 'Null') {
|
||||||
|
$errors[] = ['field' => 'state_order_check', 'error' => 'value must be 1 or Null (Yes Null not NULL)'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$orderCheck = $fields->root[$key]->fieldValue;
|
||||||
|
|
||||||
|
if ($orderCB === $orderCheck) {
|
||||||
|
$errors[] = [
|
||||||
|
'field' => 'state_order',
|
||||||
|
'error' => 'state_order_cb and state_order_check values must be different'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = array_search('package_unit_weight', array_column($fields->orderLine, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'package_unit_weight', 'error' => 'required for default type'];
|
||||||
|
}
|
||||||
|
} elseif ($type === 'game') {
|
||||||
|
$key = array_search('code_unique', array_column($fields->orderLine, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$errors[] = ['field' => 'code_unique', 'error' => 'required for game type'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($errors)) {
|
||||||
|
return ['status' => 'KO', 'code' => 203, 'message' => $errors];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['status' => 'OK'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
|
||||||
|
private function makeXml($fields, $type, $customer, $customerInfos, $shipping)
|
||||||
|
{
|
||||||
|
$pivot = [
|
||||||
|
'order_num' => 'Num_Commande', // required if type = default - format 9 numeric characters
|
||||||
|
'order_date' => 'Date_Commande', // required - format : DD/MM/YYYY
|
||||||
|
'operation' => 'Operation', // required
|
||||||
|
'support_code' => 'Code_Support', // required
|
||||||
|
'label_type_support' => 'Libelle_Type_Support', // required
|
||||||
|
'package_unit_weight' => 'Poids_Unitaire_Colis', // required if type = default
|
||||||
|
'qty' => 'Quantite',
|
||||||
|
'code_on_pack' => 'Code_on_Pack',
|
||||||
|
'code_unique' => 'Code_Unique', // required if type = game
|
||||||
|
// required if type = default - format 1 ou Null (oui Null et pas NULL)
|
||||||
|
'state_order_cb' => 'Etat_Commande_CB',
|
||||||
|
// required if type = default - format 1 ou Null (oui Null et pas NULL)
|
||||||
|
'state_order_check' => 'Etat_Commande_Cheque',
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||||
|
$dom->formatOutput = true;
|
||||||
|
|
||||||
|
$root = $dom->createElement('export_arcadia');
|
||||||
|
$dom->appendChild($root);
|
||||||
|
$order = $root->appendChild($dom->createElement('Commande'));
|
||||||
|
|
||||||
|
$key = array_search('order_num', array_column($fields->root, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$order->appendChild($dom->createElement('Num_Commande'));
|
||||||
|
} else {
|
||||||
|
$order->appendChild($dom->createElement('Num_Commande', $fields->root[$key]->fieldValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($fields->root as $value) {
|
||||||
|
// phpcs:ignore PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
|
||||||
|
if (
|
||||||
|
isset($pivot[$value->fieldName]) && $value->fieldName !== 'state_order_cb' &&
|
||||||
|
$value->fieldName !== 'state_order_check' && $value->fieldName !== 'order_num'
|
||||||
|
) {
|
||||||
|
$order->appendChild($dom->createElement($pivot[$value->fieldName], $value->fieldValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type === 'default') {
|
||||||
|
$key = array_search('state_order_cb', array_column($fields->root, 'fieldName'));
|
||||||
|
if ($key) {
|
||||||
|
$order->appendChild($dom->createElement('Etat_Commande_CB', $fields->root[$key]->fieldValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = array_search('state_order_check', array_column($fields->root, 'fieldName'));
|
||||||
|
if ($key) {
|
||||||
|
$order->appendChild($dom->createElement('Etat_Commande_Cheque', $fields->root[$key]->fieldValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$order->appendChild($dom->createElement('Email_conso'))
|
||||||
|
->appendChild($dom->createCDATASection("$customer->email"));
|
||||||
|
$order->appendChild($dom->createElement('Civilite'));
|
||||||
|
|
||||||
|
if ($type === 'default') {
|
||||||
|
$order->appendChild($dom->createElement('Nom'))
|
||||||
|
->appendChild($dom->createCDATASection("$shipping->lastname"));
|
||||||
|
$order->appendChild($dom->createElement('Prenom'))
|
||||||
|
->appendChild($dom->createCDATASection("$shipping->firstname"));
|
||||||
|
$order->appendChild($dom->createElement('Adresse'))
|
||||||
|
->appendChild($dom->createCDATASection("$shipping->address"));
|
||||||
|
$order->appendChild($dom->createElement('Adresse_Complementaire'));
|
||||||
|
$order->appendChild($dom->createElement('CP'))
|
||||||
|
->appendChild($dom->createCDATASection("$shipping->postcode"));
|
||||||
|
$order->appendChild($dom->createElement('Ville'))->appendChild($dom->createCDATASection("$shipping->city"));
|
||||||
|
if (isset($shipping->phone) && !empty($shipping->phone)) {
|
||||||
|
$order->appendChild($dom->createElement('Telephone'))
|
||||||
|
->appendChild($dom->createCDATASection("$shipping->phone"));
|
||||||
|
} else {
|
||||||
|
$order->appendChild($dom->createElement('Telephone'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$order->appendChild($dom->createElement('Nom'))
|
||||||
|
->appendChild($dom->createCDATASection("$customerInfos->lastname"));
|
||||||
|
$order->appendChild($dom->createElement('Prenom'))
|
||||||
|
->appendChild($dom->createCDATASection("$customerInfos->firstname"));
|
||||||
|
$order->appendChild($dom->createElement('Adresse'))
|
||||||
|
->appendChild($dom->createCDATASection("$customerInfos->address"));
|
||||||
|
$order->appendChild($dom->createElement('Adresse_Complementaire'))
|
||||||
|
->appendChild($dom->createCDATASection("$customerInfos->address2"));
|
||||||
|
$order->appendChild($dom->createElement('CP'))
|
||||||
|
->appendChild($dom->createCDATASection("$customerInfos->postcode"));
|
||||||
|
$order->appendChild($dom->createElement('Ville'))
|
||||||
|
->appendChild($dom->createCDATASection("$customerInfos->city"));
|
||||||
|
$order->appendChild($dom->createElement('Telephone'))
|
||||||
|
->appendChild($dom->createCDATASection("$customerInfos->phone"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$orderLine = $order->appendChild($dom->createElement('Ligne_de_Commande'));
|
||||||
|
|
||||||
|
$key = array_search('qty', array_column($fields->orderLine, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$orderLine->appendChild($dom->createElement('Quantite', '1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = array_search('package_unit_weight', array_column($fields->orderLine, 'fieldName'));
|
||||||
|
if ($key === false) {
|
||||||
|
$orderLine->appendChild($dom->createElement('Poids_Unitaire_Colis'));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($fields->orderLine as $value) {
|
||||||
|
// phpcs:ignore PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
|
||||||
|
if (
|
||||||
|
isset($pivot[$value->fieldName]) &&
|
||||||
|
$value->fieldName !== 'code_on_pack' &&
|
||||||
|
$value->fieldName !== 'code_unique'
|
||||||
|
) {
|
||||||
|
$orderLine->appendChild($dom->createElement($pivot[$value->fieldName], $value->fieldValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type === 'game') {
|
||||||
|
$key = array_search('code_on_pack', array_column($fields->orderLine, 'fieldName'));
|
||||||
|
if ($key) {
|
||||||
|
$orderLine->appendChild(
|
||||||
|
$dom->createElement('Code_on_Pack')
|
||||||
|
)->appendChild($dom->createCDATASection($fields->orderLine[$key]->fieldValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = array_search('code_unique', array_column($fields->orderLine, 'fieldName'));
|
||||||
|
if ($key) {
|
||||||
|
$orderLine->appendChild(
|
||||||
|
$dom->createElement('Code_Unique')
|
||||||
|
)->appendChild($dom->createCDATASection($fields->orderLine[$key]->fieldValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dom->saveXML();
|
||||||
|
}
|
||||||
|
}
|
||||||
556
app/Http/Controllers/Api/V1/CustomerController.php
Normal file
556
app/Http/Controllers/Api/V1/CustomerController.php
Normal file
|
|
@ -0,0 +1,556 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\V1;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Resources\CustomerResource;
|
||||||
|
use App\Http\Resources\StatusResource;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use App\Models\CustomerInfo;
|
||||||
|
use App\Models\CustomerLogin;
|
||||||
|
use App\Models\CustomerOptInHistory;
|
||||||
|
use App\Models\SingleOptin;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class CustomerController extends Controller
|
||||||
|
{
|
||||||
|
// TODO : Voir pour les contraintes de mot de passe
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage
|
||||||
|
* @param Request $request
|
||||||
|
* @return CustomerResource|StatusResource
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'email' => 'required|email',
|
||||||
|
'password' => 'required',
|
||||||
|
'firstname' => 'required',
|
||||||
|
'lastname' => 'required',
|
||||||
|
'opt_in' => 'required',
|
||||||
|
'birth_date' => 'date_format:Y-m-d'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return new StatusResource([
|
||||||
|
'status' => 'KO', 'code' => 102,
|
||||||
|
'message' => 'Error on required fields.', 'errors' => $validator->errors()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
$email = strtolower(filter_var($request->email, FILTER_SANITIZE_EMAIL));
|
||||||
|
$firstname = filter_var($request->firstname, FILTER_SANITIZE_STRING);
|
||||||
|
$lastname = filter_var($request->lastname, FILTER_SANITIZE_STRING);
|
||||||
|
$optIn = filter_var($request->opt_in, FILTER_SANITIZE_STRING);
|
||||||
|
$hashcode = Str::uuid();
|
||||||
|
|
||||||
|
// Récupère le customer s'il existe déjà
|
||||||
|
$customer = Customer::where('email', $email)->first();
|
||||||
|
|
||||||
|
// Si le customer n'existe pas déjà
|
||||||
|
if (!$customer) {
|
||||||
|
$customer = new Customer();
|
||||||
|
$customer->email = $email;
|
||||||
|
$customer->save();
|
||||||
|
$singleOptin = SingleOptin::where([['email', $email], ['brand_id', $brandId]])->first();
|
||||||
|
if ($singleOptin) {
|
||||||
|
$singleOptin->delete();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Récupère les infos s'ils existent déjà
|
||||||
|
$CustomerInfo = CustomerInfo::where([['customer_id', $customer->id], ['brand_id', $brandId]])->first();
|
||||||
|
if ($CustomerInfo) {
|
||||||
|
return new StatusResource([
|
||||||
|
'status' => 'KO', 'code' => 103,
|
||||||
|
'message' => 'User already registered on this site.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$customerInfos = new CustomerInfo();
|
||||||
|
$customerInfos->firstname = ucfirst(strtolower($firstname));
|
||||||
|
$customerInfos->lastname = ucfirst(strtolower($lastname));
|
||||||
|
$customerInfos->birth_date = !empty($request->birth_date) ?
|
||||||
|
filter_var($request->birth_date, FILTER_SANITIZE_STRING) : null;
|
||||||
|
$customerInfos->address = !empty($request->address) ?
|
||||||
|
filter_var($request->address, FILTER_SANITIZE_STRING) : null;
|
||||||
|
$customerInfos->address2 = !empty($request->address2) ?
|
||||||
|
filter_var($request->address2, FILTER_SANITIZE_STRING) : null;
|
||||||
|
$customerInfos->phone = !empty($request->phone) ?
|
||||||
|
filter_var($request->phone, FILTER_SANITIZE_STRING) : null;
|
||||||
|
$customerInfos->country = !empty($request->country) ?
|
||||||
|
filter_var($request->country, FILTER_SANITIZE_STRING) : null;
|
||||||
|
$customerInfos->city = !empty($request->city) ?
|
||||||
|
filter_var($request->city, FILTER_SANITIZE_STRING) : null;
|
||||||
|
$customerInfos->postcode = !empty($request->postcode) ?
|
||||||
|
filter_var($request->postcode, FILTER_SANITIZE_STRING) : null;
|
||||||
|
$customerInfos->opt_in = $optIn;
|
||||||
|
$customerInfos->hashcode = $hashcode;
|
||||||
|
$customerInfos->brand_id = $brandId;
|
||||||
|
$customerInfos->customer_id = $customer->id;
|
||||||
|
|
||||||
|
$customer->infos()->save($customerInfos);
|
||||||
|
|
||||||
|
// Création du login pour cet utilisateur sur ce service
|
||||||
|
$customerLogin = new CustomerLogin();
|
||||||
|
$customerLogin->customer_id = $customer->id;
|
||||||
|
$customerLogin->password = Hash::make(trim($request->password));
|
||||||
|
$customerLogin->last_connection = now();
|
||||||
|
$customerLogin->brand_id = $brandId;
|
||||||
|
$customerLogin->status = 0;
|
||||||
|
|
||||||
|
$customer->logins()->save($customerLogin);
|
||||||
|
|
||||||
|
// Ajout dans la table d'historique des opt-in de la nouvelle valeur
|
||||||
|
$optInHistory = new CustomerOptInHistory();
|
||||||
|
$optInHistory->customer_id = $customer->id;
|
||||||
|
$optInHistory->brand_id = $brandId;
|
||||||
|
$optInHistory->new_value = $optIn;
|
||||||
|
$optInHistory->save();
|
||||||
|
|
||||||
|
return new CustomerResource($customer, $brandId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return CustomerResource | StatusResource
|
||||||
|
*/
|
||||||
|
public function show(Request $request, $type, $value)
|
||||||
|
{
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
|
||||||
|
if ($type === 'id') {
|
||||||
|
$customer = Customer::find($value);
|
||||||
|
if (!$customer) {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 101, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
} elseif ($type === 'email') {
|
||||||
|
$customer = Customer::where('email', $value)->first();
|
||||||
|
if (!$customer) {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 101, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$CustomerInfo = $customer->infos()->where('brand_id', $brandId)->first();
|
||||||
|
|
||||||
|
if (!$CustomerInfo) {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 101, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 101, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CustomerResource($customer, $brandId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param int $id
|
||||||
|
* @return CustomerResource|StatusResource
|
||||||
|
*/
|
||||||
|
// phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'birth_date' => 'date_format:Y-m-d'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return new StatusResource([
|
||||||
|
'status' => 'KO', 'code' => 104,
|
||||||
|
'message' => 'Error on required fields.', 'errors' => $validator->errors()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
$customer = Customer::find($id);
|
||||||
|
|
||||||
|
if (!$customer) {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 105, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$CustomerInfo = $customer->infos()->where('brand_id', $brandId)->first();
|
||||||
|
if (!$CustomerInfo) {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 105, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('firstname')) {
|
||||||
|
$CustomerInfo->firstname = filter_var($request->firstname, FILTER_SANITIZE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('lastname')) {
|
||||||
|
$CustomerInfo->lastname = filter_var($request->lastname, FILTER_SANITIZE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('birth_date')) {
|
||||||
|
if (!empty($request->birth_date)) {
|
||||||
|
$CustomerInfo->birth_date = filter_var($request->birth_date, FILTER_SANITIZE_STRING);
|
||||||
|
} else {
|
||||||
|
$CustomerInfo->birth_date = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('address')) {
|
||||||
|
if (!empty($request->address)) {
|
||||||
|
$CustomerInfo->address = filter_var($request->address, FILTER_SANITIZE_STRING);
|
||||||
|
} else {
|
||||||
|
$CustomerInfo->address = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('address2')) {
|
||||||
|
if (!empty($request->address2)) {
|
||||||
|
$CustomerInfo->address2 = filter_var($request->address2, FILTER_SANITIZE_STRING);
|
||||||
|
} else {
|
||||||
|
$CustomerInfo->address2 = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('phone')) {
|
||||||
|
if (!empty($request->phone)) {
|
||||||
|
$CustomerInfo->phone = filter_var($request->phone, FILTER_SANITIZE_STRING);
|
||||||
|
} else {
|
||||||
|
$CustomerInfo->phone = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('country')) {
|
||||||
|
if (!empty($request->country)) {
|
||||||
|
$CustomerInfo->country = filter_var($request->country, FILTER_SANITIZE_STRING);
|
||||||
|
} else {
|
||||||
|
$CustomerInfo->country = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('city')) {
|
||||||
|
if (!empty($request->city)) {
|
||||||
|
$CustomerInfo->city = filter_var($request->city, FILTER_SANITIZE_STRING);
|
||||||
|
} else {
|
||||||
|
$CustomerInfo->city = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('postcode')) {
|
||||||
|
if (!empty($request->postcode)) {
|
||||||
|
$CustomerInfo->postcode = filter_var($request->postcode, FILTER_SANITIZE_STRING);
|
||||||
|
} else {
|
||||||
|
$CustomerInfo->postcode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('opt_in')) {
|
||||||
|
$optIn = filter_var($request->opt_in, FILTER_SANITIZE_STRING);
|
||||||
|
|
||||||
|
if ($CustomerInfo->opt_in != $optIn) {
|
||||||
|
// Ajout dans la table d'historique des opt-in de la nouvelle valeur
|
||||||
|
$optInHistory = new CustomerOptInHistory();
|
||||||
|
$optInHistory->customer_id = $customer->id;
|
||||||
|
$optInHistory->brand_id = $brandId;
|
||||||
|
$optInHistory->new_value = $optIn;
|
||||||
|
$optInHistory->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$CustomerInfo->opt_in = $optIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
$CustomerInfo->save();
|
||||||
|
|
||||||
|
return new CustomerResource($customer, $brandId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate the user
|
||||||
|
* @param Request $request
|
||||||
|
* @return CustomerResource|StatusResource
|
||||||
|
*/
|
||||||
|
public function authenticate(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'email' => 'required|email',
|
||||||
|
'password' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return new StatusResource([
|
||||||
|
'status' => 'KO', 'code' => 115,
|
||||||
|
'message' => 'Error on required fields.', 'errors' => $validator->errors()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
$email = filter_var($request->email, FILTER_SANITIZE_EMAIL);
|
||||||
|
$password = trim($request->password);
|
||||||
|
$customer = Customer::where('email', $email)->first();
|
||||||
|
if ($customer) {
|
||||||
|
$login = $customer->logins()->where('brand_id', $brandId)->first();
|
||||||
|
if ($login) {
|
||||||
|
if (Hash::check($password, $login->password)) {
|
||||||
|
if ($login->status === false) {
|
||||||
|
$infos = $customer->infos()->where('brand_id', $brandId)->first();
|
||||||
|
// "Le compte de l'utilisateur n'est pas activé"
|
||||||
|
return new StatusResource(
|
||||||
|
[
|
||||||
|
'status' => 'KO',
|
||||||
|
'code' => 116,
|
||||||
|
'message' => 'Account not activated.',
|
||||||
|
'user' => [
|
||||||
|
'crm_id' => $customer->id,
|
||||||
|
'firstname' => $infos->firstname,
|
||||||
|
'lastname' => $infos->lastname,
|
||||||
|
'email' => $customer->email,
|
||||||
|
'birth_date' => $infos->birth_date,
|
||||||
|
'address' => $infos->address,
|
||||||
|
'address2' => $infos->address2,
|
||||||
|
'phone' => $infos->phone,
|
||||||
|
'country' => $infos->country,
|
||||||
|
'city' => $infos->city,
|
||||||
|
'postcode' => $infos->postcode,
|
||||||
|
'opt_in' => $infos->opt_in,
|
||||||
|
'hashcode' => $infos->hashcode,
|
||||||
|
'status' => $login->status,
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$login->last_connection = now();
|
||||||
|
$customer->logins()->save($login);
|
||||||
|
return new CustomerResource($customer, $brandId);
|
||||||
|
}
|
||||||
|
// "Mot de passe incorrect"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 117, 'message' => 'Authentication failed.']);
|
||||||
|
} else {
|
||||||
|
// "Ce compte n'est pas enregistré pour cette marque"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 118, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// "Ce compte n'existe pas dans la CRM"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 119, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the password of the user for the brand
|
||||||
|
* @param Request $request
|
||||||
|
* @param $id
|
||||||
|
*/
|
||||||
|
public function changePassword(Request $request, $id)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'password' => 'required',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return new StatusResource([
|
||||||
|
'status' => 'KO', 'code' => 107,
|
||||||
|
'message' => 'Error on required fields.', 'errors' => $validator->errors()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
$customer = Customer::find($id);
|
||||||
|
$password = trim($request->password);
|
||||||
|
|
||||||
|
if ($customer) {
|
||||||
|
$customerLogin = $customer->logins()->where('brand_id', $brandId)->first();
|
||||||
|
if ($customerLogin) {
|
||||||
|
// Check if same password
|
||||||
|
if (Hash::check($password, $customerLogin->password)) {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 123, 'message' => 'Same password.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$customerLogin->password = Hash::make($password);
|
||||||
|
$customerLogin->save();
|
||||||
|
} else {
|
||||||
|
// "Ce compte n'est pas enregistré pour cette marque"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 108, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// "Ce compte n'existe pas"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 109, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
return new StatusResource(['status' => 'OK', 'message' => 'Update complete.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate the account of the user
|
||||||
|
* @param Request $request
|
||||||
|
* @param $id
|
||||||
|
*/
|
||||||
|
public function activateAccount(
|
||||||
|
Request $request,
|
||||||
|
$id
|
||||||
|
) {
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
|
||||||
|
$customer = Customer::find($id);
|
||||||
|
if ($customer) {
|
||||||
|
$login = $customer->logins()->where('brand_id', $brandId)->first();
|
||||||
|
if ($login) {
|
||||||
|
if ($login->status === false) {
|
||||||
|
$login->status = true;
|
||||||
|
$login->save();
|
||||||
|
// "Le compte a bien été activé"
|
||||||
|
return new StatusResource(['status' => 'OK', 'message' => 'Update complete.']);
|
||||||
|
} else {
|
||||||
|
// "Ce compte est déjà activé"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 110, 'message' => 'User already active.']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// "Ce compte n'est pas enregistré pour cette marque"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 111, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// "Cet utilisateur n'existe pas dans la CRM"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 112, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the user account for the brand
|
||||||
|
* @param Request $request
|
||||||
|
* @param $id
|
||||||
|
*/
|
||||||
|
// phpcs:disable Squiz.PHP.NonExecutableCode.Unreachable
|
||||||
|
public function delete(Request $request, $id)
|
||||||
|
{
|
||||||
|
die("Not implemented yet");
|
||||||
|
// TODO : A voir pour les stats, obuton dans le bo qui permet de faire les stats sur les customer puis supprimer
|
||||||
|
// TODO : Gestion avec mesBR
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
|
||||||
|
$customer = Customer::find($id);
|
||||||
|
if ($customer) {
|
||||||
|
$customer->infos()->where('brand_id', $brandId)->first()->delete();
|
||||||
|
$customer->logins()->where('brand_id', $brandId)->first()->delete();
|
||||||
|
|
||||||
|
if (count($customer->infos) === 0 && count($customer->logins) === 0) {
|
||||||
|
$customer->optInHistory()->delete();
|
||||||
|
$customer->delete();
|
||||||
|
// Suppression du compte de la CRM terminée
|
||||||
|
return new StatusResource(['status' => 'OK', 'message' => 'Deletion complete.']);
|
||||||
|
} else {
|
||||||
|
// Suppression des informations du compte pour la marque terminée
|
||||||
|
return new StatusResource(['status' => 'OK', 'message' => 'Deletion complete.']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 106, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the status of the opt-in for the customer on this brand
|
||||||
|
* @param Request $request
|
||||||
|
* @param $id
|
||||||
|
*/
|
||||||
|
public function toggleOptin(Request $request, $id)
|
||||||
|
{
|
||||||
|
// TODO : Liaison des opt-in avec MailJet
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
|
||||||
|
$customer = Customer::find($id);
|
||||||
|
if ($customer) {
|
||||||
|
$infos = $customer->infos()->where('brand_id', $brandId)->first();
|
||||||
|
if ($infos) {
|
||||||
|
$infos->opt_in = $infos->opt_in === 0 ? 1 : 0;
|
||||||
|
|
||||||
|
// On enregistre l'historique du changement d'optin
|
||||||
|
$optinHistory = new CustomerOptInHistory();
|
||||||
|
$optinHistory->customer_id = $customer->id;
|
||||||
|
$optinHistory->new_value = $infos->opt_in;
|
||||||
|
$optinHistory->brand_id = $brandId;
|
||||||
|
$optinHistory->save();
|
||||||
|
|
||||||
|
$infos->save();
|
||||||
|
// "Changement effectué"
|
||||||
|
return new StatusResource(['status' => 'OK', 'message' => 'Update complete.']);
|
||||||
|
} else {
|
||||||
|
// "Ce compte n'a pas d'information liés à cette marque"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 113, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// "Cet utilisateur n'existe pas dans la CRM"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 114, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove opt-in for the customer on this brand
|
||||||
|
* @param Request $request
|
||||||
|
* @param $hashcode
|
||||||
|
*/
|
||||||
|
public function removeOptin(Request $request, $hashcode)
|
||||||
|
{
|
||||||
|
// TODO : Liaison des opt-in avec MailJet
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
|
||||||
|
$infos = CustomerInfo::where([
|
||||||
|
['brand_id', $brandId],
|
||||||
|
['hashcode', $hashcode]
|
||||||
|
])->first();
|
||||||
|
|
||||||
|
if ($infos) {
|
||||||
|
$infos->opt_in = 0;
|
||||||
|
|
||||||
|
// On enregistre l'historique du changement d'optin
|
||||||
|
$optinHistory = new CustomerOptInHistory();
|
||||||
|
$optinHistory->customer_id = $infos->customer_id;
|
||||||
|
$optinHistory->new_value = 0;
|
||||||
|
$optinHistory->brand_id = $brandId;
|
||||||
|
$optinHistory->save();
|
||||||
|
|
||||||
|
$infos->save();
|
||||||
|
// "Changement effectué"
|
||||||
|
return new StatusResource(['status' => 'OK', 'message' => 'Update complete.']);
|
||||||
|
} else {
|
||||||
|
// "Ce compte n'a pas d'information liés à cette marque"
|
||||||
|
return new StatusResource(['status' => 'KO', 'code' => 122, 'message' => 'User not found.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addSingleOptin(Request $request)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'email' => 'required|email',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return new StatusResource([
|
||||||
|
'status' => 'KO', 'code' => 120,
|
||||||
|
'message' => 'Error on required fields.', 'errors' => $validator->errors()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$brandId = $request->brand_id;
|
||||||
|
$email = filter_var($request->email, FILTER_SANITIZE_EMAIL);
|
||||||
|
|
||||||
|
// Check si le customer ou l'optin simple existe avant de l'ajouter en optin simple
|
||||||
|
// phpcs:ignore PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
|
||||||
|
if (
|
||||||
|
!SingleOptin::where([['email', $email], ['brand_id', $brandId]])->exists() &&
|
||||||
|
!CustomerInfo::join("customers", "customer_infos.customer_id", "=", "customers.id")->where([
|
||||||
|
['brand_id', $brandId], ['email', $email]
|
||||||
|
])->exists()
|
||||||
|
) {
|
||||||
|
$singleOptin = new SingleOptin();
|
||||||
|
$singleOptin->email = $email;
|
||||||
|
$singleOptin->brand_id = $brandId;
|
||||||
|
$singleOptin->save();
|
||||||
|
} else {
|
||||||
|
// "Cet utilisateur est déjà inscrit à la newsletter pour cette marque"
|
||||||
|
return new StatusResource([
|
||||||
|
'status' => 'KO', 'code' => 121,
|
||||||
|
'message' => 'This user is already subscribed to the newsletter for this brand.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return new StatusResource(['status' => 'OK', 'message' => 'Optin added.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,43 +4,31 @@ namespace App\Http\Controllers\Api\V2;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Api\V2\StoreCustomerAnswers;
|
use App\Http\Requests\Api\V2\StoreCustomerAnswers;
|
||||||
|
use App\Models\Answer;
|
||||||
use App\Models\Customer;
|
use App\Models\Customer;
|
||||||
use App\Models\ModelAnswer;
|
use App\Models\Service;
|
||||||
use App\Models\Question;
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
class AnswerController extends Controller
|
class AnswerController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Store the customer answers.
|
* Store the customer answers
|
||||||
*
|
*
|
||||||
* @param \App\Http\Requests\Api\V2\StoreCustomerAnswers $request
|
* @param \App\Http\Requests\Api\V2\StoreCustomerAnswers $request
|
||||||
* @param \App\Models\Customer $customer
|
* @param \App\Models\Service $service
|
||||||
|
* @param \App\Models\Customer $customer
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
*/
|
*/
|
||||||
|
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||||
public function storeCustomerAnswers(
|
public function storeCustomerAnswers(
|
||||||
StoreCustomerAnswers $request,
|
StoreCustomerAnswers $request,
|
||||||
|
Service $service,
|
||||||
Customer $customer
|
Customer $customer
|
||||||
): \Illuminate\Http\JsonResponse {
|
): JsonResponse {
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
$this->authorize('customerBelongsToService', $customer);
|
||||||
|
$existingAnswerIds = $customer->getAnswers($service)->pluck('id');
|
||||||
$question = Question::find($request->validated('question'));
|
$answersID = Answer::whereIn('id', $request->answers)->pluck('id');
|
||||||
|
$customer->answers()->sync($answersID->merge($existingAnswerIds));
|
||||||
// Column model_id is varchar because of singleoptin uuid, so force cast in string.
|
return \response()->json();
|
||||||
ModelAnswer::query()
|
|
||||||
->where('model_type', Customer::class)
|
|
||||||
->where('model_id', (string) $customer->getKey())
|
|
||||||
->whereIn('answer_id', $question->answers->modelKeys())
|
|
||||||
->delete();
|
|
||||||
|
|
||||||
foreach ($request->validated('answers') as $answerId) {
|
|
||||||
ModelAnswer::create([
|
|
||||||
'model_type' => Customer::class,
|
|
||||||
'model_id' => (string) $customer->getKey(),
|
|
||||||
'answer_id' => $answerId,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,40 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V2;
|
namespace App\Http\Controllers\Api\V2;
|
||||||
|
|
||||||
|
use App\Enums\ApiError;
|
||||||
|
use App\Exceptions\Api\V2\ApiErrorException;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\JsonResponse;
|
use App\Lib\Helper;
|
||||||
|
use App\Models\Service;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
class ApiController extends Controller
|
class ApiController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
public function ping()
|
||||||
* Just returns HTTP 200 response.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function ping(): JsonResponse
|
|
||||||
{
|
{
|
||||||
return response()->json();
|
return response()->json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function authenticate(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$bearerToken = Helper::getBearerTokenFromRequest($request);
|
||||||
|
if (!$bearerToken) {
|
||||||
|
throw new ApiErrorException(ApiError::missingParameter());
|
||||||
|
}
|
||||||
|
/** @var \App\Models\Service */
|
||||||
|
$service = Service::getFromBearerToken($bearerToken);
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
throw new ApiErrorException(ApiError::apiAuthFailed());
|
||||||
|
}
|
||||||
|
if (!Hash::check($request->bearer_pwd, $service->bearer_pwd)) {
|
||||||
|
throw new ApiErrorException(ApiError::apiAuthFailed());
|
||||||
|
}
|
||||||
|
|
||||||
|
$apiToken = $service->generateApiToken();
|
||||||
|
$service->saveOrFail();
|
||||||
|
return response()->json(['api_token' => $apiToken]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,82 +4,64 @@ namespace App\Http\Controllers\Api\V2;
|
||||||
|
|
||||||
use App\Enums\ArcadiaMailType;
|
use App\Enums\ArcadiaMailType;
|
||||||
use App\Enums\ArcadiaOrderType;
|
use App\Enums\ArcadiaOrderType;
|
||||||
|
use App\Exceptions\Api\V2\CrmException;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Api\V2\BaseApiRequest;
|
use App\Http\Requests\Api\V2\BaseApiRequest;
|
||||||
use App\Http\Requests\Api\V2\SendArchadiaDefaultMailRequest;
|
use App\Http\Requests\Api\V2\SendArchadiaDefaultMailRequest;
|
||||||
use App\Http\Requests\Api\V2\SendArchadiaGameMailRequest;
|
use App\Http\Requests\Api\V2\SendArchadiaGameMailRequest;
|
||||||
use App\Mail\CourrierArcadiaError;
|
use App\Mail\CourrierArcadiaError;
|
||||||
|
use App\Models\Service;
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use Illuminate\Http\JsonResponse;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Facades\Mail;
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ! Ici c'est du sale à cause d'arcadia
|
* TODO: séparer ça quand coté arcadia ils auront branché le cerveau
|
||||||
|
* Ici c'est du sale à cause d'arcadia
|
||||||
* Ils ont fait le choix de rajouter une fonctionnalité
|
* Ils ont fait le choix de rajouter une fonctionnalité
|
||||||
* sur une methode existante en rajoutant des conditions
|
* sur un methode existant en rajoutant des conditions
|
||||||
* sales. Ils ont donc une seule méthode pour envoyer plusieurs
|
* sales
|
||||||
* types de réclas avec des champs différents...
|
|
||||||
*
|
*
|
||||||
* Donc une séparation est faite sur les endpoints CRM et dans le client
|
* Donc un séparation est faite sur les endpoints CRM et dans le client
|
||||||
* pour éviter une confusion de nos utilisateurs
|
* pour éviter une confusion de noes utilisateurs
|
||||||
*/
|
*/
|
||||||
class ArcadiaController extends Controller
|
class ArcadiaController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
public function outgoingMailDefault(SendArchadiaDefaultMailRequest $request, Service $service)
|
||||||
* Send arcadia default mail (reclamations).
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V2\SendArchadiaDefaultMailRequest $request
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function outgoingMailDefault(SendArchadiaDefaultMailRequest $request): JsonResponse
|
|
||||||
{
|
{
|
||||||
return $this->handleArcadiaMail($request, ArcadiaMailType::default);
|
return $this->handleArcadiaMail($request, ArcadiaMailType::default(), $service);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function outgoingMailGame(SendArchadiaGameMailRequest $request, Service $service)
|
||||||
* Send arcadia game mail (games).
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V2\SendArchadiaGameMailRequest $request
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function outgoingMailGame(SendArchadiaGameMailRequest $request): JsonResponse
|
|
||||||
{
|
{
|
||||||
return $this->handleArcadiaMail($request, ArcadiaMailType::game);
|
return $this->handleArcadiaMail($request, ArcadiaMailType::game(), $service);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function handleArcadiaMail(
|
||||||
* Form xml message and save it in the apropriate storage location
|
BaseApiRequest $request,
|
||||||
* to be picked up by the arcadia job.
|
ArcadiaMailType $type
|
||||||
*
|
) {
|
||||||
* @param \App\Http\Requests\Api\V2\BaseApiRequest $request
|
|
||||||
* @param \App\Enums\ArcadiaMailType $type
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \Exception If an error occurs while generating and saving the xml file.
|
|
||||||
*/
|
|
||||||
private function handleArcadiaMail(BaseApiRequest $request, ArcadiaMailType $type): JsonResponse
|
|
||||||
{
|
|
||||||
$request = $request->merge([
|
$request = $request->merge([
|
||||||
'order_num' => str_pad(\intval($request->order_num), 9, '0', STR_PAD_LEFT)
|
'order_num' => str_pad(\intval($request->order_num), 9, '0', STR_PAD_LEFT)
|
||||||
]);
|
]);
|
||||||
$xml = 'none';
|
$xml = 'none';
|
||||||
try {
|
try {
|
||||||
$customerInfo = \array_intersect_key($request->all()['deliver'], [
|
$customerInfo = \array_intersect_key($request->all()['deliver'], [
|
||||||
'email' => '',
|
'email' => '',
|
||||||
'firstname' => '',
|
'firstname' => '',
|
||||||
'lastname' => '',
|
'lastname' => '',
|
||||||
'address' => '',
|
'address' => '',
|
||||||
'address2' => '',
|
'address2' => '',
|
||||||
'city' => '',
|
'city' => '',
|
||||||
'postcode' => '',
|
'postcode' => '',
|
||||||
'phone' => ''
|
'phone' => ''
|
||||||
]);
|
]);
|
||||||
$orderType = ArcadiaOrderType::make(intval($request->state_order));
|
$orderType = ArcadiaOrderType::make(intval($request->state_order));
|
||||||
$xml = $this->makeXml($request, $type, $orderType, $customerInfo);
|
$xml = $this->makeXml($request, $type, $orderType, $customerInfo);
|
||||||
|
|
||||||
// * Format xml.
|
// Format xml
|
||||||
$doc = new DOMDocument('1.0', 'utf-8');
|
$doc = new DOMDocument('1.0', 'utf-8');
|
||||||
$doc->xmlStandalone = true;
|
$doc->xmlStandalone = true;
|
||||||
$doc->preserveWhiteSpace = false;
|
$doc->preserveWhiteSpace = false;
|
||||||
|
|
@ -88,37 +70,36 @@ class ArcadiaController extends Controller
|
||||||
$xml = $doc->saveXML();
|
$xml = $doc->saveXML();
|
||||||
|
|
||||||
Storage::disk('arcadia')->put(Str::slug(sprintf(
|
Storage::disk('arcadia')->put(Str::slug(sprintf(
|
||||||
'v2_order_%s_%s_%s%s',
|
'v2_%s_%s%s.xml',
|
||||||
$request->order_num,
|
$type->label,
|
||||||
$type->label(),
|
|
||||||
date('Ymd_His'),
|
date('Ymd_His'),
|
||||||
\microtime(true)
|
\microtime(true)
|
||||||
)) . '.xml', $xml);
|
)), $xml);
|
||||||
return response()->json();
|
return response()->json();
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::critical("ARCADIA XML CREATION FAILED FOR $request->order_num : " . $e->getMessage());
|
Log::critical("ARCADIA XML CREATION FAILED : " . $e->getMessage());
|
||||||
if (!config('app.debug')) {
|
if (!config('app.debug')) {
|
||||||
dispatch(function () use ($xml, $e, $request) {
|
dispatch(function () use ($xml, $e) {
|
||||||
Mail::to(config('mail.MAIL_ADMIN'))->send(new CourrierArcadiaError(
|
Mail::to(config('mail.MAIL_ADMIN'))->send(new CourrierArcadiaError(
|
||||||
"ARCADIA XML CREATION FAILED FOR $request->order_num",
|
"ARCADIA XML CREATION FAILED",
|
||||||
"Une erreur est survenue lors de la création du fichier XML : " . $e->getMessage(),
|
"Une erreur est survenue lors de la création du fichier XML : " . $e->getMessage(),
|
||||||
$xml ?: ''
|
$xml
|
||||||
));
|
));
|
||||||
})->afterResponse();
|
})->afterResponse();
|
||||||
|
} else {
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
throw $e;
|
throw new CrmException('Failed to create the arcadia xml file', 0, $e);
|
||||||
// @codeCoverageIgnoreEnd
|
}
|
||||||
} //end try
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render Arcadia xml for order.
|
* render Arcadia xml for order
|
||||||
*
|
*
|
||||||
* @param \App\Http\Requests\Api\V2\BaseApiRequest $request
|
* @param SendArchadiaMailRequest $request
|
||||||
* @param \App\Enums\ArcadiaMailType $type
|
* @param ArcadiaMailType $type
|
||||||
* @param \App\Enums\ArcadiaOrderType $orderType
|
* @param ArcadiaOrderType $orderType
|
||||||
* @param array $customerInfo
|
* @param array $customerInfo
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function makeXml(
|
private function makeXml(
|
||||||
|
|
@ -127,13 +108,15 @@ class ArcadiaController extends Controller
|
||||||
ArcadiaOrderType $orderType,
|
ArcadiaOrderType $orderType,
|
||||||
array $customerInfo
|
array $customerInfo
|
||||||
): string {
|
): string {
|
||||||
$arcadiaMailType = $type->equals(ArcadiaMailType::default) ?
|
return view(
|
||||||
'mail.arcadiaOrders.default' : 'mail.arcadiaOrders.game';
|
$type->equals(ArcadiaMailType::default()) ?
|
||||||
return view($arcadiaMailType, [
|
'mail.arcadiaOrders.default' : 'mail.arcadiaOrders.game',
|
||||||
'request' => $request,
|
[
|
||||||
'type' => $type,
|
'request' => $request,
|
||||||
'orderType' => $orderType,
|
'type' => $type,
|
||||||
'customerInfo' => $customerInfo
|
'orderType' => $orderType,
|
||||||
])->render();
|
'customerInfo' => $customerInfo
|
||||||
|
]
|
||||||
|
)->render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,247 +14,199 @@ use App\Jobs\UpdateCustomerLastConnection;
|
||||||
use App\Models\Customer;
|
use App\Models\Customer;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use App\Models\SingleOptin;
|
use App\Models\SingleOptin;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class CustomerController extends Controller
|
class CustomerController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Creates a new customer for the specified service.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
* @param \App\Http\Requests\Api\V2\StoreCustomerRequest $request
|
* @param \App\Request\StoreCustomerRequest $request
|
||||||
* @param \App\Models\Service $service
|
* @param \App\Models\Service $service
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||||
* @throws \App\Exceptions\Api\V2\ApiErrorException With ApiError::customerExists if
|
|
||||||
* the customer with this email already exists.
|
|
||||||
* @throws \App\Exceptions\Api\V2\CrmException If saving the customer to DB failed.
|
|
||||||
*/
|
*/
|
||||||
public function store(StoreCustomerRequest $request, Service $service): JsonResource
|
public function store(StoreCustomerRequest $request, Service $service): JsonResource
|
||||||
{
|
{
|
||||||
$data = (object) $request->validated();
|
$data = (object)$request->validated();
|
||||||
|
|
||||||
/** @var \App\Models\Customer */
|
/** @var \App\Models\Customer */
|
||||||
$customer = Customer::query()->where('email', $data->email)->firstOrCreate([
|
$customer = Customer::where('email', $data->email)->firstOrCreate([
|
||||||
'email' => $data->email
|
'email' => $data->email
|
||||||
]);
|
]);
|
||||||
|
$customer->saveOrFail();
|
||||||
|
$customer->setOptIn($service->brand, $data->opt_in);
|
||||||
|
|
||||||
DB::transaction(function () use (&$customer, $data, $request, $service) {
|
// Delete Single optin if exists
|
||||||
|
if (
|
||||||
|
$singleOptin = SingleOptin::where('email', $data->email)
|
||||||
|
->where('brand_id', $service->brand->id)->first()
|
||||||
|
) {
|
||||||
|
$singleOptin->delete();
|
||||||
|
}
|
||||||
|
|
||||||
$saved = $customer->save();
|
/** @var \App\Models\CustomerInfo */
|
||||||
$customer->setOptIn($service->brand, $data->opt_in);
|
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_NEW);
|
||||||
|
if ($customerInfo->exists) {
|
||||||
|
throw new ApiErrorException(ApiError::customerExists());
|
||||||
|
}
|
||||||
|
$customerInfo->fill($request->validated());
|
||||||
|
$customerInfo->brand()->associate($service->brand);
|
||||||
|
$customerInfo->customer()->associate($customer);
|
||||||
|
$customerInfo->saveOrFail();
|
||||||
|
|
||||||
// * Delete Single optin if exists.
|
/** @var \App\Models\CustomerLogin */
|
||||||
/** @var \App\Models\SingleOptin|null $singleOptin */
|
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_NEW);
|
||||||
$singleOptin = SingleOptin::query()->where('email', $data->email)
|
$customerLogin->fill($request->validated());
|
||||||
->whereHas('brand', function (Builder $q) use ($service) {
|
$customerLogin->brand()->associate($service->brand);
|
||||||
$q->where('id', $service->brand->id);
|
$customerLogin->customer()->associate($customer);
|
||||||
})->first();
|
$customerLogin->saveOrFail();
|
||||||
if ($singleOptin) {
|
|
||||||
$saved = $singleOptin->delete() && $saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerInfo */
|
|
||||||
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_NEW);
|
|
||||||
if ($customerInfo->exists) {
|
|
||||||
throw new ApiErrorException(ApiError::customerExists);
|
|
||||||
}
|
|
||||||
$customerInfo->fill($request->validated());
|
|
||||||
$customerInfo->brand()->associate($service->brand);
|
|
||||||
$customerInfo->customer()->associate($customer);
|
|
||||||
$saved = $customerInfo->save() && $saved;
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerLogin */
|
|
||||||
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_NEW);
|
|
||||||
$customerLogin->fill($request->validated());
|
|
||||||
$customerLogin->brand()->associate($service->brand);
|
|
||||||
$customerLogin->customer()->associate($customer);
|
|
||||||
$saved = $customerLogin->save() && $saved;
|
|
||||||
|
|
||||||
if (!$saved) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to store customer.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return new CustomerResource($service->brand, $customer);
|
return new CustomerResource($service->brand, $customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the specific customer infos.
|
* Display the specified resource.
|
||||||
*
|
*
|
||||||
* @param \App\Models\Service $service
|
* @param \App\Models\Service $service
|
||||||
* @param \App\Models\Customer $customer
|
* @param \App\Models\Customer $customer
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||||
*/
|
*/
|
||||||
public function show(Service $service, Customer $customer): JsonResource
|
public function show(Customer $customer, Service $service): JsonResource
|
||||||
{
|
{
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
$this->authorize('customerBelongsToService', $customer);
|
||||||
|
return new CustomerResource($service->brand, $customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param \App\Request\UpdateCustomerRequest $request
|
||||||
|
* @param \App\Models\Service $service
|
||||||
|
* @param \App\Models\Customer $customer
|
||||||
|
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||||
|
*/
|
||||||
|
public function update(UpdateCustomerRequest $request, Customer $customer, Service $service): JsonResource
|
||||||
|
{
|
||||||
|
$this->authorize('customerBelongsToService', $customer);
|
||||||
|
// To correct with create
|
||||||
|
$customer->fill($request->all());
|
||||||
|
if ($customer->saveOrFail() === false) {
|
||||||
|
throw new CrmException(sprintf('Could not update customer %d', $customer));
|
||||||
|
}
|
||||||
|
if ($request->has('opt_in')) {
|
||||||
|
$customer->setOptIn($service->brand, $request->opt_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \App\Models\CustomerInfo */
|
||||||
|
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_FAIL);
|
||||||
|
$customerInfo->fill($request->validated());
|
||||||
|
$customerInfo->saveOrFail();
|
||||||
|
|
||||||
|
/** @var \App\Models\CustomerLogin */
|
||||||
|
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
||||||
|
$customerLogin->fill($request->validated());
|
||||||
|
$customerLogin->saveOrFail();
|
||||||
|
|
||||||
return new CustomerResource($service->brand, $customer);
|
return new CustomerResource($service->brand, $customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates information for a specific customer.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
* @param \App\Http\Requests\Api\V2\UpdateCustomerRequest $request
|
* @param \App\Models\Service $service
|
||||||
* @param \App\Models\Service $service
|
* @param \App\Models\Customer $customer
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
|
||||||
* @throws \App\Exceptions\Api\V2\CrmException If saving the customer to DB failed.
|
|
||||||
*/
|
|
||||||
public function update(UpdateCustomerRequest $request, Service $service, Customer $customer): JsonResource
|
|
||||||
{
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
|
||||||
|
|
||||||
DB::transaction(function () use ($request, $customer, $service) {
|
|
||||||
// To correct with create.
|
|
||||||
$customer->fill($request->validated());
|
|
||||||
$saved = $customer->save();
|
|
||||||
if ($request->has('opt_in')) {
|
|
||||||
$customer->setOptIn($service->brand, $request->opt_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerInfo */
|
|
||||||
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
$customerInfo->fill($request->validated());
|
|
||||||
$saved = $customerInfo->save() && $saved;
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerLogin */
|
|
||||||
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
$customerLogin->fill($request->validated());
|
|
||||||
$saved = $customerLogin->save() && $saved;
|
|
||||||
|
|
||||||
if (!$saved) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update customer.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return new CustomerResource($service->brand, $customer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes customer information for a specific service.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
* @throws \App\Exceptions\Api\V2\CrmException If removing the customer off the DB failed.
|
|
||||||
*/
|
*/
|
||||||
public function destroy(Service $service, Customer $customer): JsonResponse
|
public function destroy(Customer $customer, Service $service): JsonResponse
|
||||||
{
|
{
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
$this->authorize('customerBelongsToService', $customer);
|
||||||
|
// TODO : A voir pour les stats, obuton dans le bo qui permet de faire les stats sur les customer puis supprimer
|
||||||
|
// TODO : Gestion avec mesBR
|
||||||
/** @var \App\Models\CustomerInfo */
|
/** @var \App\Models\CustomerInfo */
|
||||||
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_FAIL);
|
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_FAIL);
|
||||||
/** @var \App\Models\CustomerLogin */
|
/** @var \App\Models\CustomerLogin */
|
||||||
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
||||||
|
|
||||||
DB::transaction(function () use ($service, $customer, $customerLogin, $customerInfo) {
|
if (
|
||||||
if (
|
!$customerInfo->delete() ||
|
||||||
$customerInfo->delete() === false ||
|
!$customerLogin->delete() ||
|
||||||
$customerLogin->delete() === false
|
|
||||||
) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to delete customer.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
};
|
|
||||||
|
|
||||||
$customer->optInHistory()->whereHas('brand', function ($q) use ($service) {
|
$customer->optInHistory()->whereHas('brand', function ($q) use ($service) {
|
||||||
$q->where('id', $service->brand_id);
|
$q->where('id', $service->brand_id);
|
||||||
})->delete();
|
})->delete() === false
|
||||||
|
) {
|
||||||
|
throw new CrmException(sprintf(
|
||||||
|
'Could not delete customer %d for brand %d',
|
||||||
|
$customer->id,
|
||||||
|
$service->brand->id
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
// * Force loading real relation counts.
|
$logins = $customer->logins()->count();
|
||||||
$customer->unsetRelation('logins');
|
$infos = $customer->infos()->count();
|
||||||
$customer->unsetRelation('infos');
|
$history = $customer->optInHistory()->count();
|
||||||
$logins = $customer->logins()->count();
|
|
||||||
$infos = $customer->infos()->count();
|
|
||||||
|
|
||||||
// If customer is not associated with any brand then delete.
|
// If customer is not associated with any brand then delete
|
||||||
if (!$logins and !$infos) {
|
if (!$logins and !$infos and !$history) {
|
||||||
if ($customer->delete() === false) {
|
if ($customer->delete() === false) {
|
||||||
// @codeCoverageIgnoreStart
|
throw new CrmException(sprintf(
|
||||||
throw new CrmException('Api failed to update customer.');
|
'Could not delete customer %d',
|
||||||
// @codeCoverageIgnoreEnd
|
$customer->id
|
||||||
}
|
));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return response()->json();
|
return response()->json();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate the user.
|
* Authenticate the user
|
||||||
*
|
* @param \App\Models\Service $service
|
||||||
* @param \App\Http\Requests\Api\V2\AuthenticateRequest $request
|
* @param \App\Request\AuthenticateRequest $request
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||||
* @throws \App\Exceptions\Api\V2\ApiErrorException With ApiError::authFailed in case
|
|
||||||
* of wrong credentials.
|
|
||||||
* @throws \App\Exceptions\Api\V2\ApiErrorException With ApiError::customerNotActivated if
|
|
||||||
* customer account is not activated.
|
|
||||||
*/
|
*/
|
||||||
public function authenticate(AuthenticateRequest $request, Service $service): JsonResource
|
public function authenticate(AuthenticateRequest $request, Service $service): JsonResource
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
/** @var \App\Models\Customer */
|
/** @var \App\Models\Customer */
|
||||||
$customer = Customer::query()->where('email', $request->email)->firstOrFail();
|
$customer = Customer::where('email', $request->email)->firstOrFail();
|
||||||
|
$customer->loadBrandData($service->brand, true);
|
||||||
/** @var \App\Models\CustomerLogin $customerLogin */
|
$customerLogin = $customer->logins->first();
|
||||||
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
if (!$customerLogin->passwordMatch($request->password)) {
|
|
||||||
throw new ApiErrorException(ApiError::authFailed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$customerLogin->status) {
|
|
||||||
throw new ApiErrorException(ApiError::customerNotActivated);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateCustomerLastConnection::dispatch($customer, $customerLogin, now())
|
|
||||||
->onConnection('database')->afterResponse();
|
|
||||||
|
|
||||||
return new CustomerResource($service->brand, $customer);
|
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
throw new ApiErrorException(ApiError::authFailed);
|
throw new ApiErrorException(ApiError::authFailed());
|
||||||
} //end try
|
}
|
||||||
|
|
||||||
|
if (!$customerLogin->passwordMatch($request->password)) {
|
||||||
|
throw new ApiErrorException(ApiError::authFailed());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$customerLogin->status) {
|
||||||
|
throw new ApiErrorException(ApiError::customerNotActivated());
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateCustomerLastConnection::dispatch($customer, $customerLogin, now())
|
||||||
|
->onConnection('database');
|
||||||
|
|
||||||
|
return new CustomerResource($service->brand, $customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate the account of the user.
|
* Activate the account of the user
|
||||||
*
|
* @param Customer $customer
|
||||||
* @param \App\Models\Customer $customer
|
* @param Service $service
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
* @throws \App\Exceptions\Api\V2\ApiErrorException With ApiError::customerAlreadyActive
|
|
||||||
* if customer account is already active.
|
|
||||||
* @throws \App\Exceptions\Api\V2\CrmException If saving the customer to DB failed.
|
|
||||||
*/
|
*/
|
||||||
public function activateAccount(Customer $customer, Service $service): JsonResponse
|
public function activateAccount(Customer $customer, Service $service)
|
||||||
{
|
{
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
$this->authorize('customerBelongsToService', $customer);
|
||||||
|
|
||||||
/** @var \App\Models\CustomerLogin $login */
|
|
||||||
$login = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
$login = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
||||||
|
|
||||||
if ($login->status) {
|
if (!$login->status) {
|
||||||
throw new ApiErrorException(ApiError::customerAlreadyActive);
|
$login->status = true;
|
||||||
|
$login->save();
|
||||||
|
return response()->json();
|
||||||
|
} else {
|
||||||
|
throw new ApiErrorException(ApiError::customerAlreadyActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
$login->status = true;
|
|
||||||
if (!$login->save()) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Failed to save login');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
return response()->json();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,8 @@ namespace App\Http\Controllers\Api\V2;
|
||||||
|
|
||||||
use App\Enums\ApiError;
|
use App\Enums\ApiError;
|
||||||
use App\Exceptions\Api\V2\ApiErrorException;
|
use App\Exceptions\Api\V2\ApiErrorException;
|
||||||
use App\Exceptions\Api\V2\CrmException;
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Api\V2\BaseApiRequest;
|
|
||||||
use App\Http\Requests\Api\V2\SingleOptinRequest;
|
use App\Http\Requests\Api\V2\SingleOptinRequest;
|
||||||
use App\Http\Requests\Api\V2\SingleOptinRemoveWithHashcodeRequest;
|
|
||||||
use App\Models\CustomerInfo;
|
use App\Models\CustomerInfo;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use App\Models\SingleOptin;
|
use App\Models\SingleOptin;
|
||||||
|
|
@ -16,88 +13,28 @@ use App\Models\SingleOptin;
|
||||||
class OptinController extends Controller
|
class OptinController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Creates a new Single optin or destroys it if exists.
|
* Store a newly created resource in storage.
|
||||||
*
|
*
|
||||||
* @param \App\Http\Requests\Api\V2\SingleOptinRequest $request
|
* @param \App\Request\SingleOptinRequest $request
|
||||||
* @param \App\Models\Service $service
|
* @param \App\Models\Service $service
|
||||||
* @return \Illuminate\Http\JsonResponse
|
* @return \Illuminate\Http\JsonResponse
|
||||||
* @throws \App\Exceptions\Api\V2\ApiErrorException With ApiError::singleOptinCustomerExists
|
|
||||||
* if this email already has a full account.
|
|
||||||
* @throws \App\Exceptions\Api\V2\CrmException If the single optin could not be added or removed.
|
|
||||||
*/
|
*/
|
||||||
public function optin(SingleOptinRequest $request, Service $service): \Illuminate\Http\JsonResponse
|
public function optin(SingleOptinRequest $request, Service $service)
|
||||||
{
|
{
|
||||||
$validatedData = $request->validated();
|
if (CustomerInfo::getFromEmail($service->brand, $request->email)->exists()) {
|
||||||
if (CustomerInfo::getFromEmail($service->brand, $validatedData['email'])->exists()) {
|
throw new ApiErrorException(ApiError::singleOptinCustomerExists());
|
||||||
throw new ApiErrorException(ApiError::singleOptinCustomerExists);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \App\Models\SingleOptin */
|
/** @var \App\Models\SingleOptin */
|
||||||
$singleOptin = SingleOptin::query()
|
$singleOptin = SingleOptin::where('email', $request->email)->firstOrNew();
|
||||||
->where('email', $validatedData['email'])
|
|
||||||
->whereHas('brand', function ($q) use ($service) {
|
|
||||||
$q->where('id', $service->brand->id);
|
|
||||||
})
|
|
||||||
->firstOrNew();
|
|
||||||
|
|
||||||
if (!$this->changeOptin($service, $request, \boolval($validatedData['opt_in']), $singleOptin)) {
|
if ($request->opt_in) {
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update single optin.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($validatedData['answer_id'])) {
|
|
||||||
$singleOptin->answers()->attach($validatedData['answer_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Single optin or destroys it if exists using hashcode.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V2\SingleOptinRemoveWithHashcodeRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \App\Exceptions\Api\V2\CrmException If the single optin could not be removed.
|
|
||||||
*/
|
|
||||||
public function optoutWithHashcode(
|
|
||||||
SingleOptinRemoveWithHashcodeRequest $request,
|
|
||||||
Service $service
|
|
||||||
): \Illuminate\Http\JsonResponse {
|
|
||||||
/** @var \App\Models\SingleOptin */
|
|
||||||
$singleOptin = SingleOptin::query()
|
|
||||||
->where('hashcode', $request->hashcode)
|
|
||||||
->whereHas('brand', function ($q) use ($service) {
|
|
||||||
$q->whereId($service->brand->id);
|
|
||||||
})
|
|
||||||
->firstOrFail();
|
|
||||||
|
|
||||||
if ($singleOptin and !$this->changeOptin($service, $request, \boolval($request->opt_in), $singleOptin)) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update single optin.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the optin state.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @param \App\Http\Requests\Api\V2\BaseApiRequest $request
|
|
||||||
* @param boolean $optin
|
|
||||||
* @param \App\Models\SingleOptin $singleOptin
|
|
||||||
* @return boolean Returns false in case of failure.
|
|
||||||
*/
|
|
||||||
private function changeOptin(Service $service, BaseApiRequest $request, bool $optin, SingleOptin $singleOptin): bool
|
|
||||||
{
|
|
||||||
if ($optin) {
|
|
||||||
$singleOptin->fill($request->validated());
|
$singleOptin->fill($request->validated());
|
||||||
$singleOptin->brand()->associate($service->brand);
|
$singleOptin->brand()->associate($service->brand);
|
||||||
return $singleOptin->save();
|
$singleOptin->saveOrFail();
|
||||||
|
} else {
|
||||||
|
$singleOptin->delete();
|
||||||
}
|
}
|
||||||
return $singleOptin->delete() !== false;
|
return response()->json();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,48 +14,46 @@ use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
class QuestionController extends Controller
|
class QuestionController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Returns all service questions.
|
* Display all specified resources.
|
||||||
*
|
*
|
||||||
* @param \App\Models\Service $service
|
* @param \App\Models\Service $service
|
||||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||||
*/
|
*/
|
||||||
|
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
|
||||||
public function index(Service $service): ResourceCollection
|
public function index(Service $service): ResourceCollection
|
||||||
{
|
{
|
||||||
return new QuestionsResource($service->brand->questions);
|
return new QuestionsResource($service->brand->questions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all service questions with user answers for all of them.
|
* Display all specified resources.
|
||||||
*
|
*
|
||||||
* @param \App\Models\Service $service
|
* @param \App\Models\Service $service
|
||||||
* @param \App\Models\Customer $customer
|
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
|
||||||
*/
|
*/
|
||||||
|
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
|
||||||
public function indexWithResponse(Service $service, Customer $customer): ResourceCollection
|
public function indexWithResponse(Service $service, Customer $customer): ResourceCollection
|
||||||
{
|
{
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
$this->authorize('customerBelongsToService', $customer);
|
||||||
|
|
||||||
$customerAnswers = $customer->getAnswers($service);
|
$customerAnswers = $customer->getAnswers($service);
|
||||||
return new QuestionsResource($service->brand->questions, $customerAnswers);
|
return new QuestionsResource($service->brand->questions, $customerAnswers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all service questions that was not answered by a user.
|
* Display all specified resource by customer.
|
||||||
*
|
*
|
||||||
* @param \App\Models\Service $service
|
* @param \App\Models\Service $service
|
||||||
* @param \App\Models\Customer $customer
|
* @param \App\Models\Customer $customer
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
* @return \Illuminate\Http\Resources\Json\JsonResource
|
||||||
*/
|
*/
|
||||||
|
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed
|
||||||
public function unAnsweredBy(Service $service, Customer $customer): JsonResource
|
public function unAnsweredBy(Service $service, Customer $customer): JsonResource
|
||||||
{
|
{
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
$this->authorize('customerBelongsToService', $customer);
|
||||||
|
$questions = Question::whereHas('brand', function ($q) use ($service) {
|
||||||
$questions = Question::query()->whereHas('brand', function ($q) use ($service) {
|
|
||||||
$q->where('id', $service->brand->id);
|
$q->where('id', $service->brand->id);
|
||||||
})->whereDoesntHave('answers', function ($q) use ($customer) {
|
})->whereDoesntHave('answers', function ($q) use ($customer) {
|
||||||
$q->whereIn('id', Answer::query()->whereHas('customers', function ($q) use ($customer) {
|
$q->whereIn('id', Answer::whereHas('customers', function ($q) use ($customer) {
|
||||||
$q->where('id', $customer->id);
|
$q->where('id', $customer->id);
|
||||||
})->pluck('id'));
|
})->pluck('id'));
|
||||||
})->with('answers')->get();
|
})->with('answers')->get();
|
||||||
|
|
|
||||||
|
|
@ -8,43 +8,28 @@ use App\Http\Requests\Api\V2\GetQuestionStatsRequest;
|
||||||
use App\Http\Resources\Api\V2\BrandStatsResource;
|
use App\Http\Resources\Api\V2\BrandStatsResource;
|
||||||
use App\Http\Resources\Api\V2\QuestionStatsResource;
|
use App\Http\Resources\Api\V2\QuestionStatsResource;
|
||||||
use App\Models\BrandStat;
|
use App\Models\BrandStat;
|
||||||
use App\Models\ModelAnswer;
|
use App\Models\CustomerAnswer;
|
||||||
use App\Models\Question;
|
use App\Models\Question;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class StatsController extends Controller
|
class StatsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Get specific brand statistics.
|
public function brandStats(Service $service, GetBrandStatsRequest $request): ResourceCollection
|
||||||
*
|
{
|
||||||
* @param \App\Http\Requests\Api\V2\GetBrandStatsRequest $request
|
$stats = BrandStat::whereDate('created_at', '>=', $request->start)
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
|
||||||
*/
|
|
||||||
public function brandStats(
|
|
||||||
GetBrandStatsRequest $request,
|
|
||||||
Service $service
|
|
||||||
): \Illuminate\Http\Resources\Json\ResourceCollection {
|
|
||||||
$stats = BrandStat::query()->whereDate('created_at', '>=', $request->start)
|
|
||||||
->whereDate('created_at', '<=', $request->end)
|
->whereDate('created_at', '<=', $request->end)
|
||||||
->whereBrandId($service->brand->id)->get();
|
->whereBrandId($service->brand->id)->get();
|
||||||
return new BrandStatsResource($stats);
|
return new BrandStatsResource($stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||||
* Get statistics for a specific question.
|
public function questionStats(Service $service, GetQuestionStatsRequest $request)
|
||||||
*
|
{
|
||||||
* @param \App\Http\Requests\Api\V2\GetQuestionStatsRequest $request
|
$question = Question::findOrFail($request->question);
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @return \App\Http\Resources\Api\V2\QuestionStatsResource
|
|
||||||
*/
|
|
||||||
public function questionStats(
|
|
||||||
GetQuestionStatsRequest $request,
|
|
||||||
Question $question
|
|
||||||
): \App\Http\Resources\Api\V2\QuestionStatsResource {
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('questionBelongsToService', $question);
|
$this->authorize('questionBelongsToService', $question);
|
||||||
|
|
||||||
$answers = $question->answers;
|
$answers = $question->answers;
|
||||||
|
|
@ -58,36 +43,32 @@ class StatsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total réponses par dates.
|
* Total réponses par dates
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Support\Collection $answers
|
* @param Collection $answers
|
||||||
* @param \Illuminate\Support\Carbon $start
|
* @param Carbon $start
|
||||||
* @param \Illuminate\Support\Carbon $end
|
* @param Carbon $end
|
||||||
* @return \Illuminate\Support\Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
private function answersByDays(Collection $answers, Carbon $start, Carbon $end): \Illuminate\Support\Collection
|
private function answersByDays(Collection $answers, Carbon $start, Carbon $end): Collection
|
||||||
{
|
{
|
||||||
// * Totalize by date all answers.
|
// Totalize by date all answers
|
||||||
$answersByDays = ModelAnswer::query()
|
$answersByDays = CustomerAnswer::whereDate('created_at', '>=', $start)
|
||||||
->whereDate('created_at', '>=', $start)
|
|
||||||
->whereDate('created_at', '<=', $end)
|
->whereDate('created_at', '<=', $end)
|
||||||
->whereIn('answer_id', $answers->pluck('id'))
|
->whereIn('answer_id', $answers->pluck('id'))
|
||||||
->get()
|
->get()->map(function ($custAnswer) {
|
||||||
->map(function ($custAnswer) {
|
|
||||||
return [
|
return [
|
||||||
'answer_id' => $custAnswer->answer_id,
|
'answer_id' => $custAnswer->answer_id,
|
||||||
'created_at' => $custAnswer->created_at->isoFormat('YYYY-MM-DD'),
|
'created_at' => $custAnswer->created_at->format('Y-m-d'),
|
||||||
];
|
];
|
||||||
})
|
})->groupBy(['created_at', 'answer_id'])->map(function ($day) {
|
||||||
->groupBy(['created_at', 'answer_id'])
|
|
||||||
->map(function ($day) {
|
|
||||||
return $day->map(function ($custAnswers) {
|
return $day->map(function ($custAnswers) {
|
||||||
return $custAnswers->count();
|
return $custAnswers->count();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$currentDate = $start->isoFormat('YYYY-MM-DD');
|
$currentDate = $start->format('Y-m-d');
|
||||||
/** @var \Illuminate\Support\Collection $answersByDays */
|
/** @var \Illuminate\Support\Collection $answersByDays */
|
||||||
if (!$answersByDays->has($currentDate)) {
|
if (!$answersByDays->has($currentDate)) {
|
||||||
$answersByDays->put(
|
$answersByDays->put(
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V4;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Api\V4\StoreCustomerAnswers;
|
|
||||||
use App\Models\Customer;
|
|
||||||
use App\Models\ModelAnswer;
|
|
||||||
use App\Models\Question;
|
|
||||||
|
|
||||||
class AnswerController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Store the customer answers.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\StoreCustomerAnswers $request
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function storeCustomerAnswers(
|
|
||||||
StoreCustomerAnswers $request,
|
|
||||||
Customer $customer
|
|
||||||
): \Illuminate\Http\JsonResponse {
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
|
||||||
|
|
||||||
$question = Question::find($request->validated('question'));
|
|
||||||
|
|
||||||
// Column model_id is varchar because of singleoptin uuid, so force cast in string.
|
|
||||||
ModelAnswer::query()
|
|
||||||
->where('model_type', Customer::class)
|
|
||||||
->where('model_id', (string) $customer->getKey())
|
|
||||||
->whereIn('answer_id', $question->answers->modelKeys())
|
|
||||||
->delete();
|
|
||||||
|
|
||||||
foreach ($request->validated('answers') as $answerId) {
|
|
||||||
ModelAnswer::create([
|
|
||||||
'model_type' => Customer::class,
|
|
||||||
'model_id' => (string) $customer->getKey(),
|
|
||||||
'answer_id' => $answerId,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V4;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
|
||||||
|
|
||||||
class ApiController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Just returns HTTP 200 response.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function ping(): JsonResponse
|
|
||||||
{
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V4;
|
|
||||||
|
|
||||||
use App\Enums\ArcadiaMailType;
|
|
||||||
use App\Enums\ArcadiaOrderType;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Api\V4\BaseApiRequest;
|
|
||||||
use App\Http\Requests\Api\V4\SendArchadiaDefaultMailRequest;
|
|
||||||
use App\Http\Requests\Api\V4\SendArchadiaGameMailRequest;
|
|
||||||
use App\Mail\CourrierArcadiaError;
|
|
||||||
use DOMDocument;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ! Ici c'est du sale à cause d'arcadia
|
|
||||||
* Ils ont fait le choix de rajouter une fonctionnalité
|
|
||||||
* sur une methode existante en rajoutant des conditions
|
|
||||||
* sales. Ils ont donc une seule méthode pour envoyer plusieurs
|
|
||||||
* types de réclas avec des champs différents...
|
|
||||||
*
|
|
||||||
* Donc une séparation est faite sur les endpoints CRM et dans le client
|
|
||||||
* pour éviter une confusion de nos utilisateurs
|
|
||||||
*/
|
|
||||||
class ArcadiaController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Send arcadia default mail (reclamations).
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\SendArchadiaDefaultMailRequest $request
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function outgoingMailDefault(SendArchadiaDefaultMailRequest $request): JsonResponse
|
|
||||||
{
|
|
||||||
return $this->handleArcadiaMail($request, ArcadiaMailType::default);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send arcadia game mail (games).
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\SendArchadiaGameMailRequest $request
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function outgoingMailGame(SendArchadiaGameMailRequest $request): JsonResponse
|
|
||||||
{
|
|
||||||
return $this->handleArcadiaMail($request, ArcadiaMailType::game);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Form xml message and save it in the apropriate storage location
|
|
||||||
* to be picked up by the arcadia job.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\BaseApiRequest $request
|
|
||||||
* @param \App\Enums\ArcadiaMailType $type
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \Exception If an error occurs while generating and saving the xml file.
|
|
||||||
*/
|
|
||||||
private function handleArcadiaMail(BaseApiRequest $request, ArcadiaMailType $type): JsonResponse
|
|
||||||
{
|
|
||||||
$request = $request->merge([
|
|
||||||
'order_num' => str_pad(\intval($request->order_num), 9, '0', STR_PAD_LEFT)
|
|
||||||
]);
|
|
||||||
$xml = 'none';
|
|
||||||
try {
|
|
||||||
$customerInfo = \array_intersect_key($request->all()['deliver'], [
|
|
||||||
'email' => '',
|
|
||||||
'firstname' => '',
|
|
||||||
'lastname' => '',
|
|
||||||
'address' => '',
|
|
||||||
'address2' => '',
|
|
||||||
'city' => '',
|
|
||||||
'postcode' => '',
|
|
||||||
'phone' => ''
|
|
||||||
]);
|
|
||||||
$orderType = ArcadiaOrderType::make(intval($request->state_order));
|
|
||||||
$xml = $this->makeXml($request, $type, $orderType, $customerInfo);
|
|
||||||
|
|
||||||
// * Format xml.
|
|
||||||
$doc = new DOMDocument('1.0', 'utf-8');
|
|
||||||
$doc->xmlStandalone = true;
|
|
||||||
$doc->preserveWhiteSpace = false;
|
|
||||||
$doc->formatOutput = true;
|
|
||||||
$doc->loadXML($xml);
|
|
||||||
$xml = $doc->saveXML();
|
|
||||||
|
|
||||||
Storage::disk('arcadia')->put(Str::slug(sprintf(
|
|
||||||
'v4_order_%s_%s_%s%s',
|
|
||||||
$request->order_num,
|
|
||||||
$type->label(),
|
|
||||||
date('Ymd_His'),
|
|
||||||
\microtime(true)
|
|
||||||
)) . '.xml', $xml);
|
|
||||||
return response()->json();
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
Log::critical("ARCADIA XML CREATION FAILED FOR $request->order_num : " . $e->getMessage());
|
|
||||||
if (!config('app.debug')) {
|
|
||||||
dispatch(function () use ($xml, $e, $request) {
|
|
||||||
Mail::to(config('mail.MAIL_ADMIN'))->send(new CourrierArcadiaError(
|
|
||||||
"ARCADIA XML CREATION FAILED FOR $request->order_num",
|
|
||||||
"Une erreur est survenue lors de la création du fichier XML : " . $e->getMessage(),
|
|
||||||
$xml ?: ''
|
|
||||||
));
|
|
||||||
})->afterResponse();
|
|
||||||
}
|
|
||||||
throw $e;
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
} //end try
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render Arcadia xml for order.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\BaseApiRequest $request
|
|
||||||
* @param \App\Enums\ArcadiaMailType $type
|
|
||||||
* @param \App\Enums\ArcadiaOrderType $orderType
|
|
||||||
* @param array $customerInfo
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function makeXml(
|
|
||||||
BaseApiRequest $request,
|
|
||||||
ArcadiaMailType $type,
|
|
||||||
ArcadiaOrderType $orderType,
|
|
||||||
array $customerInfo
|
|
||||||
): string {
|
|
||||||
$arcadiaMailType = $type->equals(ArcadiaMailType::default) ?
|
|
||||||
'mail.arcadiaOrders.default' : 'mail.arcadiaOrders.game';
|
|
||||||
return view($arcadiaMailType, [
|
|
||||||
'request' => $request,
|
|
||||||
'type' => $type,
|
|
||||||
'orderType' => $orderType,
|
|
||||||
'customerInfo' => $customerInfo
|
|
||||||
])->render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V4;
|
|
||||||
|
|
||||||
use App\Exceptions\Api\V4\CrmException;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Api\V4\SendClaimRequest;
|
|
||||||
use App\Models\Claim;
|
|
||||||
use App\Models\CustomerInfo;
|
|
||||||
use App\Models\Service;
|
|
||||||
use Illuminate\Support\Arr;
|
|
||||||
use Uwil\LaravelCommon\Helpers\FileHelper;
|
|
||||||
|
|
||||||
class ClaimController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Just returns HTTP 200 response.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\SendClaimRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \App\Exceptions\Api\V4\CrmException If the single optin could not be added or removed.
|
|
||||||
*/
|
|
||||||
public function store(SendClaimRequest $request, Service $service): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
$claimModel = (new Claim())->fill(Arr::except($request->validated(), 'file'));
|
|
||||||
if ($request->filled('file')) {
|
|
||||||
$claimModel->file = FileHelper::storeBase64File(
|
|
||||||
tableName: 'claim',
|
|
||||||
fileBase64: $request->file,
|
|
||||||
private: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add brand id from service.
|
|
||||||
$claimModel->brand_id = $service->brand->getKey();
|
|
||||||
|
|
||||||
// Add customer relation if exist.
|
|
||||||
$crmCustomer = CustomerInfo::getFromEmail($claimModel->brand, $claimModel->email)->first();
|
|
||||||
if (!is_null($crmCustomer)) {
|
|
||||||
$claimModel->hashcode = $crmCustomer->hashcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$claimModel->saveOrFail()) {
|
|
||||||
throw new CrmException('Api failed to store claim.');
|
|
||||||
}
|
|
||||||
$claimModel->brand()->associate($service->brand);
|
|
||||||
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,260 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V4;
|
|
||||||
|
|
||||||
use App\Enums\ApiError;
|
|
||||||
use App\Exceptions\Api\V4\ApiErrorException;
|
|
||||||
use App\Exceptions\Api\V4\CrmException;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Api\V4\AuthenticateRequest;
|
|
||||||
use App\Http\Requests\Api\V4\StoreCustomerRequest;
|
|
||||||
use App\Http\Requests\Api\V4\UpdateCustomerRequest;
|
|
||||||
use App\Http\Resources\Api\V4\CustomerResource;
|
|
||||||
use App\Jobs\UpdateCustomerLastConnection;
|
|
||||||
use App\Models\Customer;
|
|
||||||
use App\Models\Service;
|
|
||||||
use App\Models\SingleOptin;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class CustomerController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Creates a new customer for the specified service.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\StoreCustomerRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
|
||||||
* @throws \App\Exceptions\Api\V4\ApiErrorException With ApiError::customerExists if
|
|
||||||
* the customer with this email already exists.
|
|
||||||
* @throws \App\Exceptions\Api\V4\CrmException If saving the customer to DB failed.
|
|
||||||
*/
|
|
||||||
public function store(StoreCustomerRequest $request, Service $service): JsonResource
|
|
||||||
{
|
|
||||||
$data = (object) $request->validated();
|
|
||||||
|
|
||||||
/** @var \App\Models\Customer */
|
|
||||||
$customer = Customer::query()->where('email', $data->email)->firstOrCreate([
|
|
||||||
'email' => $data->email
|
|
||||||
]);
|
|
||||||
|
|
||||||
DB::transaction(function () use (&$customer, $data, $request, $service) {
|
|
||||||
|
|
||||||
$saved = $customer->save();
|
|
||||||
$customer->setOptIn($service->brand, $data->opt_in);
|
|
||||||
|
|
||||||
// * Delete Single optin if exists.
|
|
||||||
/** @var \App\Models\SingleOptin|null $singleOptin */
|
|
||||||
$singleOptin = SingleOptin::query()->where('email', $data->email)
|
|
||||||
->whereHas('brand', function (Builder $q) use ($service) {
|
|
||||||
$q->where('id', $service->brand->id);
|
|
||||||
})->first();
|
|
||||||
if ($singleOptin) {
|
|
||||||
$saved = $singleOptin->delete() && $saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerInfo */
|
|
||||||
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_NEW);
|
|
||||||
if ($customerInfo->exists) {
|
|
||||||
throw new ApiErrorException(ApiError::customerExists);
|
|
||||||
}
|
|
||||||
$customerInfo->fill($request->validated());
|
|
||||||
$customerInfo->brand()->associate($service->brand);
|
|
||||||
$customerInfo->customer()->associate($customer);
|
|
||||||
$saved = $customerInfo->save() && $saved;
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerLogin */
|
|
||||||
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_NEW);
|
|
||||||
$customerLogin->fill($request->validated());
|
|
||||||
$customerLogin->brand()->associate($service->brand);
|
|
||||||
$customerLogin->customer()->associate($customer);
|
|
||||||
$saved = $customerLogin->save() && $saved;
|
|
||||||
|
|
||||||
if (!$saved) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to store customer.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return new CustomerResource($service->brand, $customer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the specific customer infos.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
|
||||||
*/
|
|
||||||
public function show(Service $service, Customer $customer): JsonResource
|
|
||||||
{
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
|
||||||
|
|
||||||
return new CustomerResource($service->brand, $customer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates information for a specific customer.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\UpdateCustomerRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
|
||||||
* @throws \App\Exceptions\Api\V4\CrmException If saving the customer to DB failed.
|
|
||||||
*/
|
|
||||||
public function update(UpdateCustomerRequest $request, Service $service, Customer $customer): JsonResource
|
|
||||||
{
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
|
||||||
|
|
||||||
DB::transaction(function () use ($request, $customer, $service) {
|
|
||||||
// To correct with create.
|
|
||||||
$customer->fill($request->validated());
|
|
||||||
$saved = $customer->save();
|
|
||||||
if ($request->has('opt_in')) {
|
|
||||||
$customer->setOptIn($service->brand, $request->opt_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerInfo */
|
|
||||||
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
$customerInfo->fill($request->validated());
|
|
||||||
$saved = $customerInfo->save() && $saved;
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerLogin */
|
|
||||||
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
$customerLogin->fill($request->validated());
|
|
||||||
$saved = $customerLogin->save() && $saved;
|
|
||||||
|
|
||||||
if (!$saved) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update customer.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return new CustomerResource($service->brand, $customer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes customer information for a specific service.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \App\Exceptions\Api\V4\CrmException If removing the customer off the DB failed.
|
|
||||||
*/
|
|
||||||
public function destroy(Service $service, Customer $customer): JsonResponse
|
|
||||||
{
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerInfo */
|
|
||||||
$customerInfo = $customer->info($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
/** @var \App\Models\CustomerLogin */
|
|
||||||
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
|
|
||||||
DB::transaction(function () use ($service, $customer, $customerLogin, $customerInfo) {
|
|
||||||
if (
|
|
||||||
$customerInfo->delete() === false ||
|
|
||||||
$customerLogin->delete() === false
|
|
||||||
) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to delete customer.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
};
|
|
||||||
|
|
||||||
$customer->optInHistory()->whereHas('brand', function ($q) use ($service) {
|
|
||||||
$q->where('id', $service->brand_id);
|
|
||||||
})->delete();
|
|
||||||
|
|
||||||
// * Force loading real relation counts.
|
|
||||||
$customer->unsetRelation('logins');
|
|
||||||
$customer->unsetRelation('infos');
|
|
||||||
$logins = $customer->logins()->count();
|
|
||||||
$infos = $customer->infos()->count();
|
|
||||||
|
|
||||||
// If customer is not associated with any brand then delete.
|
|
||||||
if (!$logins and !$infos) {
|
|
||||||
if ($customer->delete() === false) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update customer.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticate the user.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\AuthenticateRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
|
||||||
* @throws \App\Exceptions\Api\V4\ApiErrorException With ApiError::authFailed in case
|
|
||||||
* of wrong credentials.
|
|
||||||
* @throws \App\Exceptions\Api\V4\ApiErrorException With ApiError::customerNotActivated if
|
|
||||||
* customer account is not activated.
|
|
||||||
*/
|
|
||||||
public function authenticate(AuthenticateRequest $request, Service $service): JsonResource
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
/** @var \App\Models\Customer */
|
|
||||||
$customer = Customer::query()->where('email', $request->email)->firstOrFail();
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerLogin $customerLogin */
|
|
||||||
$customerLogin = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
if (!$customerLogin->passwordMatch($request->password)) {
|
|
||||||
throw new ApiErrorException(ApiError::authFailed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$customerLogin->status) {
|
|
||||||
throw new ApiErrorException(ApiError::customerNotActivated);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateCustomerLastConnection::dispatch($customer, $customerLogin, now())
|
|
||||||
->onConnection('database')->afterResponse();
|
|
||||||
|
|
||||||
return new CustomerResource($service->brand, $customer);
|
|
||||||
} catch (ModelNotFoundException $e) {
|
|
||||||
throw new ApiErrorException(ApiError::authFailed);
|
|
||||||
} //end try
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activate the account of the user.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \App\Exceptions\Api\V4\ApiErrorException With ApiError::customerAlreadyActive
|
|
||||||
* if customer account is already active.
|
|
||||||
* @throws \App\Exceptions\Api\V4\CrmException If saving the customer to DB failed.
|
|
||||||
*/
|
|
||||||
public function activateAccount(Customer $customer, Service $service): JsonResponse
|
|
||||||
{
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
|
||||||
|
|
||||||
/** @var \App\Models\CustomerLogin $login */
|
|
||||||
$login = $customer->login($service->brand, Customer::FIRST_OR_FAIL);
|
|
||||||
|
|
||||||
if ($login->status) {
|
|
||||||
throw new ApiErrorException(ApiError::customerAlreadyActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
$login->status = true;
|
|
||||||
if (!$login->save()) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Failed to save login');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V4;
|
|
||||||
|
|
||||||
use App\Exceptions\Api\V4\CrmException;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Api\V4\BaseApiRequest;
|
|
||||||
use App\Http\Requests\Api\V4\SingleOptinRequest;
|
|
||||||
use App\Http\Requests\Api\V4\SingleOptinRemoveWithHashcodeRequest;
|
|
||||||
use App\Models\CustomerInfo;
|
|
||||||
use App\Models\Service;
|
|
||||||
use App\Models\SingleOptin;
|
|
||||||
|
|
||||||
class OptinController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Creates a new Single optin or destroys it if exists.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\SingleOptinRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \App\Exceptions\Api\V4\CrmException If the single optin could not be added or removed.
|
|
||||||
*/
|
|
||||||
public function optin(SingleOptinRequest $request, Service $service): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
$validatedData = $request->validated();
|
|
||||||
$crmCustomer = CustomerInfo::getFromEmail($service->brand, $validatedData['email'])->first();
|
|
||||||
if ($crmCustomer) {
|
|
||||||
// Update the optin field.
|
|
||||||
$crmCustomer->opt_in = \boolval($validatedData['opt_in']);
|
|
||||||
|
|
||||||
// Check the saving.
|
|
||||||
if (!$crmCustomer->saveOrFail()) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update customer optin.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Associate answers if presents.
|
|
||||||
if (isset($validatedData['answer_id'])) {
|
|
||||||
$crmCustomer->answers()->attach($validatedData['answer_id']);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Get the single optin if exist or create it.
|
|
||||||
/** @var \App\Models\SingleOptin */
|
|
||||||
$singleOptin = SingleOptin::query()
|
|
||||||
->where('email', $validatedData['email'])
|
|
||||||
->whereHas('brand', function ($q) use ($service) {
|
|
||||||
$q->whereKey($service->brand->getKey());
|
|
||||||
})
|
|
||||||
->firstOrNew();
|
|
||||||
|
|
||||||
// Update the optin field and check the saving.
|
|
||||||
if (!$this->changeOptin($service, $request, \boolval($validatedData['opt_in']), $singleOptin)) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update single optin.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Associate answers if presents.
|
|
||||||
if (isset($validatedData['answer_id'])) {
|
|
||||||
$singleOptin->answers()->attach($validatedData['answer_id']);
|
|
||||||
}
|
|
||||||
} //end if
|
|
||||||
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Single optin or destroys it if exists using hashcode.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\SingleOptinRemoveWithHashcodeRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
* @throws \App\Exceptions\Api\V4\CrmException If the single optin could not be removed.
|
|
||||||
*/
|
|
||||||
public function optoutWithHashcode(
|
|
||||||
SingleOptinRemoveWithHashcodeRequest $request,
|
|
||||||
Service $service
|
|
||||||
): \Illuminate\Http\JsonResponse {
|
|
||||||
$validatedData = $request->validated();
|
|
||||||
$crmCustomer = CustomerInfo::getFromHashcode($service->brand, $validatedData['hashcode'])->first();
|
|
||||||
if ($crmCustomer) {
|
|
||||||
// Update the optin field.
|
|
||||||
$crmCustomer->opt_in = false;
|
|
||||||
|
|
||||||
// Check the saving.
|
|
||||||
if (!$crmCustomer->saveOrFail()) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update customer optin.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Get the single optin if exist or create it.
|
|
||||||
/** @var \App\Models\SingleOptin */
|
|
||||||
$singleOptin = SingleOptin::query()->where('hashcode', $validatedData['hashcode'])
|
|
||||||
->whereHas('brand', function ($q) use ($service) {
|
|
||||||
$q->whereId($service->brand->getKey());
|
|
||||||
})->firstOrFail();
|
|
||||||
|
|
||||||
// Update the optin field and check the saving.
|
|
||||||
if ($singleOptin and !$this->changeOptin($service, $request, false, $singleOptin)) {
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new CrmException('Api failed to update single optin.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
} //end if
|
|
||||||
|
|
||||||
return response()->json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the optin state.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @param \App\Http\Requests\Api\V4\BaseApiRequest $request
|
|
||||||
* @param boolean $optin
|
|
||||||
* @param \App\Models\SingleOptin $singleOptin
|
|
||||||
* @return boolean Returns false in case of failure.
|
|
||||||
*/
|
|
||||||
private function changeOptin(Service $service, BaseApiRequest $request, bool $optin, SingleOptin $singleOptin): bool
|
|
||||||
{
|
|
||||||
if ($optin) {
|
|
||||||
$singleOptin->fill($request->validated());
|
|
||||||
$singleOptin->brand()->associate($service->brand);
|
|
||||||
return $singleOptin->save();
|
|
||||||
}
|
|
||||||
return $singleOptin->delete() !== false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V4;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Resources\Api\V4\QuestionsResource;
|
|
||||||
use App\Models\Answer;
|
|
||||||
use App\Models\Customer;
|
|
||||||
use App\Models\Question;
|
|
||||||
use App\Models\Service;
|
|
||||||
|
|
||||||
class QuestionController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns all service questions.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
|
||||||
*/
|
|
||||||
public function index(Service $service): \Illuminate\Http\Resources\Json\ResourceCollection
|
|
||||||
{
|
|
||||||
return new QuestionsResource($service->brand->questions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all service questions with user answers for all of them.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
|
||||||
*/
|
|
||||||
public function indexWithResponse(
|
|
||||||
Service $service,
|
|
||||||
Customer $customer
|
|
||||||
): \Illuminate\Http\Resources\Json\ResourceCollection {
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
|
||||||
|
|
||||||
$customerAnswers = $customer->getAnswers($service);
|
|
||||||
return new QuestionsResource($service->brand->questions, $customerAnswers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all service questions that was not answered by a user.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @return \Illuminate\Http\Resources\Json\JsonResource
|
|
||||||
*/
|
|
||||||
public function unAnsweredBy(Service $service, Customer $customer): \Illuminate\Http\Resources\Json\JsonResource
|
|
||||||
{
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('customerBelongsToService', $customer);
|
|
||||||
|
|
||||||
$questions = Question::query()
|
|
||||||
->whereHas('brand', function ($q) use ($service) {
|
|
||||||
$q->where('id', $service->brand->id);
|
|
||||||
})
|
|
||||||
->whereDoesntHave('answers', function ($q) use ($customer) {
|
|
||||||
$q->whereIn('id', Answer::query()->whereHas('customers', function ($q) use ($customer) {
|
|
||||||
$q->where('id', $customer->id);
|
|
||||||
})->pluck('id'));
|
|
||||||
})
|
|
||||||
->with('answers')
|
|
||||||
->get();
|
|
||||||
return new QuestionsResource($questions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\V4;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Api\V4\GetBrandStatsRequest;
|
|
||||||
use App\Http\Requests\Api\V4\GetQuestionStatsRequest;
|
|
||||||
use App\Http\Resources\Api\V4\BrandStatsResource;
|
|
||||||
use App\Http\Resources\Api\V4\QuestionStatsResource;
|
|
||||||
use App\Models\BrandStat;
|
|
||||||
use App\Models\ModelAnswer;
|
|
||||||
use App\Models\Question;
|
|
||||||
use App\Models\Service;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
class StatsController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Get specific brand statistics.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\GetBrandStatsRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\Resources\Json\ResourceCollection
|
|
||||||
*/
|
|
||||||
public function brandStats(
|
|
||||||
GetBrandStatsRequest $request,
|
|
||||||
Service $service
|
|
||||||
): \Illuminate\Http\Resources\Json\ResourceCollection {
|
|
||||||
$stats = BrandStat::query()->whereDate('created_at', '>=', $request->start)
|
|
||||||
->whereDate('created_at', '<=', $request->end)
|
|
||||||
->whereBrandId($service->brand->id)->get();
|
|
||||||
return new BrandStatsResource($stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get statistics for a specific question.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Api\V4\GetQuestionStatsRequest $request
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @return \App\Http\Resources\Api\V4\QuestionStatsResource
|
|
||||||
*/
|
|
||||||
public function questionStats(
|
|
||||||
GetQuestionStatsRequest $request,
|
|
||||||
Question $question
|
|
||||||
): \App\Http\Resources\Api\V4\QuestionStatsResource {
|
|
||||||
// * Make sure we are accessing a customer that belongs to our service.
|
|
||||||
$this->authorize('questionBelongsToService', $question);
|
|
||||||
|
|
||||||
$answers = $question->answers;
|
|
||||||
$start = Carbon::parse($request->start);
|
|
||||||
$end = Carbon::parse($request->end);
|
|
||||||
|
|
||||||
return new QuestionStatsResource(
|
|
||||||
$this->answersByDays($answers, $start, $end),
|
|
||||||
$question
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total réponses par dates.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Support\Collection $answers
|
|
||||||
* @param \Illuminate\Support\Carbon $start
|
|
||||||
* @param \Illuminate\Support\Carbon $end
|
|
||||||
* @return \Illuminate\Support\Collection
|
|
||||||
*/
|
|
||||||
private function answersByDays(Collection $answers, Carbon $start, Carbon $end): \Illuminate\Support\Collection
|
|
||||||
{
|
|
||||||
// * Totalize by date all answers.
|
|
||||||
$answersByDays = ModelAnswer::query()
|
|
||||||
->whereDate('created_at', '>=', $start)
|
|
||||||
->whereDate('created_at', '<=', $end)
|
|
||||||
->whereIn('answer_id', $answers->pluck('id'))
|
|
||||||
->get()
|
|
||||||
->map(function ($custAnswer) {
|
|
||||||
return [
|
|
||||||
'answer_id' => $custAnswer->answer_id,
|
|
||||||
'created_at' => $custAnswer->created_at->isoFormat('YYYY-MM-DD'),
|
|
||||||
];
|
|
||||||
})
|
|
||||||
->groupBy(['created_at', 'answer_id'])
|
|
||||||
->map(function ($day) {
|
|
||||||
return $day->map(function ($custAnswers) {
|
|
||||||
return $custAnswers->count();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
do {
|
|
||||||
$currentDate = $start->isoFormat('YYYY-MM-DD');
|
|
||||||
/** @var \Illuminate\Support\Collection $answersByDays */
|
|
||||||
if (!$answersByDays->has($currentDate)) {
|
|
||||||
$answersByDays->put(
|
|
||||||
$currentDate,
|
|
||||||
$answers->mapWithKeys(function ($answer) {
|
|
||||||
return [$answer->id => 0];
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$curentAnswers = $answersByDays->pull($currentDate);
|
|
||||||
$answersByDays->put(
|
|
||||||
$currentDate,
|
|
||||||
$answers->mapWithKeys(function ($answer) use ($curentAnswers) {
|
|
||||||
return [$answer->id =>
|
|
||||||
$curentAnswers->has($answer->id) ?
|
|
||||||
$curentAnswers->get($answer->id) : 0];
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$start = $start->addDay();
|
|
||||||
} while ($start->lessThanOrEqualTo($end));
|
|
||||||
|
|
||||||
return $answersByDays;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\ActivityLog;
|
|
||||||
use App\Traits\Controllers\ChangesModelOrder;
|
|
||||||
use App\Traits\Controllers\UpdateModelPublished;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class ActivityLogsController extends Controller
|
|
||||||
{
|
|
||||||
use ChangesModelOrder;
|
|
||||||
use UpdateModelPublished;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(ActivityLog::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
|
|
||||||
{
|
|
||||||
$this->authorize('isConceptor');
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
|
||||||
$query = ActivityLog::query()->with('user');
|
|
||||||
|
|
||||||
/** @var string $search Search field */
|
|
||||||
$search = $request->search;
|
|
||||||
if ($search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$search,
|
|
||||||
null,
|
|
||||||
'model_class',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$searchFields = \implode(', ', [
|
|
||||||
trans('validation.custom.target'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
/** Sort columns with a query */
|
|
||||||
$this->sortQuery($query);
|
|
||||||
|
|
||||||
/** Custom pagination */
|
|
||||||
$activitylogModels = $query->paginate($this->getPagination());
|
|
||||||
|
|
||||||
return view('bo.pages.activity_logs.index', compact('activitylogModels', 'search', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param App\Models\ActivityLog $activity_log
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function show(ActivityLog $activity_log): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$this->authorize('isConceptor');
|
|
||||||
$targetModelClass = $activity_log->model_class;
|
|
||||||
$targetModel = $activity_log->model_class::where(
|
|
||||||
(new $targetModelClass())->getRouteKeyName(),
|
|
||||||
$activity_log->model_id
|
|
||||||
)->first();
|
|
||||||
|
|
||||||
return view('bo.pages.activity_logs.show', [
|
|
||||||
'activitylogModel' => $activity_log,
|
|
||||||
'targetModel' => $targetModel,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\Answers\StoreAnswerRequest;
|
|
||||||
use App\Http\Requests\Bo\Answers\UpdateAnswerRequest;
|
|
||||||
use App\Models\Answer;
|
|
||||||
use App\Models\Question;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class AnswerController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Answer::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 \App\Models\Question $questionModel */
|
|
||||||
$questionModel = $request->question;
|
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
|
||||||
$query = Answer::query()->where('question_id', $questionModel->id);
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'answer',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($query);
|
|
||||||
$searchFields = trans('Réponse');
|
|
||||||
|
|
||||||
$answerModels = $query->paginate($this->getPagination());
|
|
||||||
|
|
||||||
return view('bo.pages.answers.index', compact('answerModels', 'questionModel', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \App\Models\Answer $answer
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create(Request $request, Answer $answer): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
/** @var \App\Models\Question $questionModel */
|
|
||||||
$questionModel = $request->question;
|
|
||||||
|
|
||||||
return view('bo.pages.answers.create', [
|
|
||||||
'answerModel' => $answer,
|
|
||||||
'questionModel' => $questionModel,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Answers\StoreAnswerRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreAnswerRequest $request): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$answer = new Answer();
|
|
||||||
$answer->fill($request->validated());
|
|
||||||
$questionModel = $request->route()->parameter('question');
|
|
||||||
$answer->question()->associate($questionModel->getKey());
|
|
||||||
if ($answer->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.questions.answers.edit', ['question' => $questionModel, 'answer' => $answer])
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.answers'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.answers'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @param \App\Models\Answer $answers
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(Question $question, Answer $answers): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
return view('bo.pages.answers.edit', [
|
|
||||||
'answerModel' => $answers,
|
|
||||||
'questionModel' => $question,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a spacific resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Answers\UpdateAnswerRequest $request
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @param \App\Models\Answer $answer
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(
|
|
||||||
UpdateAnswerRequest $request,
|
|
||||||
Question $question,
|
|
||||||
Answer $answer
|
|
||||||
): \Illuminate\Http\RedirectResponse {
|
|
||||||
return DB::transaction(function () use ($request, $question, $answer) {
|
|
||||||
$answer->fill($request->validated());
|
|
||||||
if ($answer->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.questions.answers.edit', ['question' => $question, 'answer' => $answer])
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.answers'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.answers'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @param \App\Models\Answer $answer
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(Question $question, Answer $answer): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
$answer->singleOptins()->detach();
|
|
||||||
if ($answer->deleteOrFail()) {
|
|
||||||
return redirect()->route('bo.questions.answers.index', $question)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été supprimé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.answers'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas pu être supprimé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.answers'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
|
||||||
use Illuminate\Contracts\View\View;
|
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class LoginController extends Controller
|
|
||||||
{
|
|
||||||
use AuthenticatesUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new controller instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->middleware('guest:backend')->except('logout');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the guard to be used during authentication.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
|
||||||
*/
|
|
||||||
protected function guard(): StatefulGuard
|
|
||||||
{
|
|
||||||
return Auth::guard('backend');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the application's login form.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function showLoginForm(): View
|
|
||||||
{
|
|
||||||
return view('bo.auth.login');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after login.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function redirectTo(): string
|
|
||||||
{
|
|
||||||
return response()->redirectToIntended()->getTargetUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to log the user into the application.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
protected function attemptLogin(Request $request)
|
|
||||||
{
|
|
||||||
$credentials = $this->credentials($request);
|
|
||||||
// * Attempt login only using published users.
|
|
||||||
$credentials['published'] = true;
|
|
||||||
return $this->guard()->attempt(
|
|
||||||
$credentials,
|
|
||||||
$request->boolean('remember')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo\Auth;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
|
||||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
|
|
||||||
class ResetPasswordController extends Controller
|
|
||||||
{
|
|
||||||
use ResetsPasswords;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the guard to be used during authentication.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\Auth\StatefulGuard
|
|
||||||
*/
|
|
||||||
protected function guard(): StatefulGuard
|
|
||||||
{
|
|
||||||
return Auth::guard('backend');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to redirect users after login.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function redirectTo(): string
|
|
||||||
{
|
|
||||||
return \route('bo.login');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\Brands\StoreBrandRequest;
|
|
||||||
use App\Http\Requests\Bo\Brands\UpdateBrandRequest;
|
|
||||||
use App\Http\Requests\Bo\PaginateModelsRequest;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Uwil\LaravelCommon\Helpers\CollectionHelper;
|
|
||||||
|
|
||||||
class BrandController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Brand::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
|
||||||
$query = Brand::query();
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'name',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($query);
|
|
||||||
$searchFields = trans('Nom');
|
|
||||||
|
|
||||||
$query->withCount(['customerInfos', 'customerInfos as customer_infos_optin_count' => function (Builder $q) {
|
|
||||||
$q->where('opt_in', true);
|
|
||||||
}]);
|
|
||||||
|
|
||||||
$brandModels = $query->paginate($this->getPagination());
|
|
||||||
|
|
||||||
return view('bo.pages.brands.index', compact('brandModels', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Brand $brands
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create(Brand $brands): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
return view('bo.pages.brands.create', [
|
|
||||||
'brandModel' => $brands
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Brands\Bo\StoreBrandRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreBrandRequest $request): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$brand = new Brand();
|
|
||||||
$brand->fill($request->validated());
|
|
||||||
if ($brand->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.brands.edit', $brand)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Brand $brands
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(Brand $brands): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
return view('bo.pages.brands.edit', [
|
|
||||||
'brandModel' => $brands
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a spacific resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Brands\Bo\UpdateBrandRequest $request
|
|
||||||
* @param \App\Models\Brand $brand
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateBrandRequest $request, Brand $brand): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $brand) {
|
|
||||||
$brand->fill($request->validated());
|
|
||||||
if ($brand->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.brands.edit', $brand)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.brands'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a paginate resource.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\PaginateModelsRequest $request
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function jsonPaginateModels(PaginateModelsRequest $request): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
$models = CollectionHelper::paginateManually(
|
|
||||||
Brand::getUserAssociatedBrands(),
|
|
||||||
$this->jsonItemPerPagination,
|
|
||||||
(int) $request->validated('page'),
|
|
||||||
);
|
|
||||||
return \response()->json($models);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,298 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Enums\Claims\ClaimResponseType;
|
|
||||||
use App\Enums\Claims\ClaimStatus;
|
|
||||||
use App\Enums\ExportFormat;
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Events\ClaimModelChanged;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\Claims\ExportClaimRequest;
|
|
||||||
use App\Http\Requests\Bo\Claims\SendClaimAnswerRequest;
|
|
||||||
use App\Http\Requests\Bo\Claims\UpdateClaimRequest;
|
|
||||||
use App\Http\Requests\Bo\Claims\ViewClaimAttachmentRequest;
|
|
||||||
use App\Http\Requests\Bo\PaginateModelsRequest;
|
|
||||||
use App\Lib\Helpers\FileHelper;
|
|
||||||
use App\Mail\ClaimAnswerMail;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\Claim;
|
|
||||||
use App\Models\ClaimMailTemplate;
|
|
||||||
use App\Models\ClaimMessage;
|
|
||||||
use App\Models\ClaimSubject;
|
|
||||||
use App\Traits\Controllers\ExportDatas;
|
|
||||||
use App\Traits\Controllers\UpdateModelPublished;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
use Uwil\LaravelCommon\Helpers\CollectionHelper;
|
|
||||||
|
|
||||||
class ClaimController extends Controller
|
|
||||||
{
|
|
||||||
use UpdateModelPublished;
|
|
||||||
use ExportDatas;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Claim::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 \App\Models\User $userModel */
|
|
||||||
$userModel = auth('backend')->user();
|
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
|
||||||
$query = Claim::query()
|
|
||||||
->when(
|
|
||||||
$request->filled('brand'),
|
|
||||||
fn($q) => $q->whereHas('brand', fn($q) => $q->where('id', $request->brand))
|
|
||||||
)->when(
|
|
||||||
$userModel->role->equals(RoleEnum::marketing),
|
|
||||||
fn($q) => $q->whereHas('brand', fn($q) => $q->whereIn('id', $userModel->brands->modelKeys()))
|
|
||||||
)
|
|
||||||
->when(
|
|
||||||
$request->filled('subject'),
|
|
||||||
fn($q) => $q->whereHas('claimSubject', fn($q) => $q->where('id', $request->subject))
|
|
||||||
)
|
|
||||||
->when(
|
|
||||||
$request->filled('status'),
|
|
||||||
fn($q) => $q->whereIn('status', $request->status),
|
|
||||||
fn($q) => $q->whereNotIn('status', [ClaimStatus::treated, ClaimStatus::refused])
|
|
||||||
);
|
|
||||||
|
|
||||||
/** @var string $search Search field */
|
|
||||||
$search = $request->search;
|
|
||||||
if ($search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$search,
|
|
||||||
null,
|
|
||||||
'reference',
|
|
||||||
'first_name',
|
|
||||||
'last_name',
|
|
||||||
'email',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$searchFields = \implode(', ', [
|
|
||||||
trans('validation.custom.reference'),
|
|
||||||
trans('validation.attributes.first_name'),
|
|
||||||
trans('validation.attributes.last_name'),
|
|
||||||
trans('validation.attributes.email'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
/** Sort columns with a query */
|
|
||||||
$this->sortQuery($query);
|
|
||||||
|
|
||||||
/** Custom pagination */
|
|
||||||
$claimModels = $query->simplePaginate($this->getPagination());
|
|
||||||
|
|
||||||
/** Define request brand filter if user only has 1 brand */
|
|
||||||
if (auth('backend')->user()->brands()->count() === 1) {
|
|
||||||
$request->merge(['brand' => auth('backend')->user()->brands()->value('id')]);
|
|
||||||
};
|
|
||||||
|
|
||||||
$claimSubjectModels = ClaimSubject::query()
|
|
||||||
->when(
|
|
||||||
$request->filled('brand'),
|
|
||||||
fn($q) => $q->whereHas('brand', fn($q) => $q->where('id', $request->brand)),
|
|
||||||
)
|
|
||||||
->when(
|
|
||||||
auth('backend')->user()->brands()->count() === 1,
|
|
||||||
fn($q) => $q->whereHas(
|
|
||||||
'brand',
|
|
||||||
fn($q) => $q->where('id', auth('backend')->user()->brands()->pluck('id'))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$claimSubjectModels = $request->filled('brand') || (auth('backend')->user()->brands()->count() === 1) ?
|
|
||||||
$claimSubjectModels->orderBy('label', 'ASC')->get() :
|
|
||||||
null;
|
|
||||||
|
|
||||||
return view('bo.pages.claims.index', compact('claimModels', 'search', 'searchFields', 'claimSubjectModels'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param App\Models\Claim $claim
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(Claim $claim): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$customerClaimModels = !is_null($claim->customerInfos) ? Claim::query()
|
|
||||||
->where('hashcode', $claim->customerInfos->hashcode)
|
|
||||||
->whereHas('brand', fn($q) => $q->whereKey($claim->brand->getKey()))
|
|
||||||
->whereNot('id', $claim->getKey())
|
|
||||||
->paginate($this->jsonItemPerPagination) : collect();
|
|
||||||
|
|
||||||
$brandModels = CollectionHelper::paginate(
|
|
||||||
Brand::getUserAssociatedBrands(),
|
|
||||||
$this->jsonItemPerPagination,
|
|
||||||
);
|
|
||||||
$claimMessageModels = ClaimMessage::getAllModelsFromClaim($claim->getKey());
|
|
||||||
$claimSubjectModels = CollectionHelper::paginate(
|
|
||||||
ClaimSubject::getAllModelsFromBrand($claim->brand->getKey()),
|
|
||||||
$this->jsonItemPerPagination,
|
|
||||||
);
|
|
||||||
$claimTemplateModels = CollectionHelper::paginate(
|
|
||||||
ClaimMailTemplate::getAllModelsFromBrand($claim->brand->getKey()),
|
|
||||||
$this->jsonItemPerPagination,
|
|
||||||
);
|
|
||||||
|
|
||||||
return view('bo.pages.claims.edit', [
|
|
||||||
'claimModel' => $claim->load(['brand', 'claimSubject']),
|
|
||||||
'customerClaimModels' => $customerClaimModels,
|
|
||||||
'brandModels' => $brandModels,
|
|
||||||
'claimMessageModels' => $claimMessageModels,
|
|
||||||
'claimSubjectModels' => $claimSubjectModels,
|
|
||||||
'claimTemplateModels' => $claimTemplateModels,
|
|
||||||
'customerInfoModel' => $claim->customerInfos,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Claims\UpdateClaimRequest $request
|
|
||||||
* @param \App\Models\Claim $claim
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateClaimRequest $request, Claim $claim): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $claim) {
|
|
||||||
$claim->fill($request->validated());
|
|
||||||
|
|
||||||
if ($claim->saveOrFail()) {
|
|
||||||
$claimMessageModels = ClaimMessage::getAllModelsFromClaim($claim->getKey());
|
|
||||||
return response()->json($claimMessageModels);
|
|
||||||
}
|
|
||||||
return response()->json([], 500);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the claim answer.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Claims\SendClaimAnswerRequest $request
|
|
||||||
* @param \App\Models\Claim $claim
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function answer(SendClaimAnswerRequest $request, Claim $claim): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $claim) {
|
|
||||||
/** @var \App\Models\User $userModel */
|
|
||||||
$userModel = auth()->user();
|
|
||||||
$enum = ClaimResponseType::manual;
|
|
||||||
$claim->response_type = $enum;
|
|
||||||
$claim->status = ClaimStatus::treated;
|
|
||||||
|
|
||||||
if ($claim->saveOrFail()) {
|
|
||||||
// Get only the content of the response.
|
|
||||||
$content = $request->validated()['content'];
|
|
||||||
|
|
||||||
// Send the response to the claim author.
|
|
||||||
Mail::to($claim->email)->send(new ClaimAnswerMail($claim, $content));
|
|
||||||
|
|
||||||
// Create custom event with content message.
|
|
||||||
// @phpcs:disable Generic.Files.LineLength.TooLong
|
|
||||||
$content = sprintf(
|
|
||||||
"<b>%s %s</b> %s <i class='badge' style='background-color:{$enum->color()}'>%s</i><hr class='my-2'>%s",
|
|
||||||
$userModel->first_name,
|
|
||||||
$userModel->last_name,
|
|
||||||
trans('a modifié :field en', ['field' => trans('validation.custom.response_type')]),
|
|
||||||
$claim->response_type->label(),
|
|
||||||
clean($content),
|
|
||||||
);
|
|
||||||
event(new ClaimModelChanged($claim, '', '', null, $content));
|
|
||||||
// @phpcs:enable
|
|
||||||
|
|
||||||
// Return conversation.
|
|
||||||
$claimMessageModels = ClaimMessage::getAllModelsFromClaim($claim->getKey());
|
|
||||||
return response()->json($claimMessageModels);
|
|
||||||
}
|
|
||||||
return response()->json([], 500);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Undocumented function
|
|
||||||
*
|
|
||||||
* @param ViewClaimAttachmentRequest $request
|
|
||||||
* @param Claim $claim
|
|
||||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
|
||||||
*
|
|
||||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter
|
|
||||||
*/
|
|
||||||
public function viewAttachment(
|
|
||||||
ViewClaimAttachmentRequest $request,
|
|
||||||
Claim $claim
|
|
||||||
): \Symfony\Component\HttpFoundation\BinaryFileResponse {
|
|
||||||
// phpcs:enable
|
|
||||||
return response()->file(Storage::disk('private')->path(FileHelper::getPrivateFilePath($claim->file)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a paginate resource.
|
|
||||||
* Needed to overheight the controller method and add a brand condition.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\PaginateModelsRequest $request
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function jsonClaimPaginateModels(PaginateModelsRequest $request): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
$data = $request->validated();
|
|
||||||
$brandModelKey = $request->route()->parameter('brand')->getKey();
|
|
||||||
$models = CollectionHelper::paginateManually(
|
|
||||||
$data['targetModel']::getAllModelsFromBrand($brandModelKey),
|
|
||||||
$this->jsonItemPerPagination,
|
|
||||||
$request->validated('page'),
|
|
||||||
);
|
|
||||||
return \response()->json($models);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// * EXPORT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export claim datas to a given format
|
|
||||||
*
|
|
||||||
* @param ExportClaimRequest $request
|
|
||||||
* @return \Illuminate\Http\Response|Symfony\Component\HttpFoundation\StreamedResponse|\Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function export(ExportClaimRequest $request)
|
|
||||||
{
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Collection<int, \App\Models\Claim> $claims*/
|
|
||||||
$claims = Claim::query()->whereIn('id', $request->validated('claimList'))->get();
|
|
||||||
$format = ExportFormat::from($request->validated('format'));
|
|
||||||
|
|
||||||
// * CSV
|
|
||||||
if ($format->equals(ExportFormat::csvWithoutAttachment, ExportFormat::csv)) {
|
|
||||||
$csv = $this->generateCsv($claims);
|
|
||||||
if (!$this->needsZip($format, $claims)) {
|
|
||||||
return new StreamedResponse(function () use ($format, $csv) {
|
|
||||||
echo $csv;
|
|
||||||
}, 200, $this->getFileHeaders($format));
|
|
||||||
}
|
|
||||||
return $this->returnExportZip($format, $claims, $csv);
|
|
||||||
// * PDF
|
|
||||||
} elseif ($format->equals(ExportFormat::pdf)) {
|
|
||||||
$pdf = $this->generatePdf($claims);
|
|
||||||
|
|
||||||
if (!$this->needsZip(ExportFormat::pdf, $claims)) {
|
|
||||||
return $pdf->download('export.pdf');
|
|
||||||
}
|
|
||||||
return $this->returnExportZip($format, $claims, $pdf->output());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,183 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Enums\Users\RoleEnum;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\ClaimMailTemplates\ClaimMailTemplateRequest;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\ClaimMailTemplate;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Uwil\LaravelCommon\Helpers\CollectionHelper;
|
|
||||||
|
|
||||||
class ClaimMailTemplateController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(ClaimMailTemplate::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 \App\Models\User $userModel */
|
|
||||||
$userModel = auth('backend')->user();
|
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
|
||||||
$query = ClaimMailTemplate::query()
|
|
||||||
->when(
|
|
||||||
$request->filled('brand'),
|
|
||||||
fn($q) => $q->whereHas('brand', fn($q) => $q->where('id', $request->brand))
|
|
||||||
)->when(
|
|
||||||
$userModel->role->equals(RoleEnum::marketing),
|
|
||||||
fn($q) => $q->whereHas('brand', fn($q) => $q->whereIn('id', $userModel->brands->modelKeys()))
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'label',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($query);
|
|
||||||
$searchFields = trans('validation.custom.label');
|
|
||||||
|
|
||||||
$claimMailTemplateModels = $query->paginate($this->getPagination());
|
|
||||||
|
|
||||||
return view('bo.pages.claim_mail_templates.index', compact('claimMailTemplateModels', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ClaimMailTemplate $claim_mail_template
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function show(ClaimMailTemplate $claim_mail_template): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
return view('bo.pages.claim_mail_templates.show', [
|
|
||||||
'claimMailTemplateModel' => $claim_mail_template,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ClaimMailTemplate $claim_mail_template
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create(ClaimMailTemplate $claim_mail_template): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$brandModels = CollectionHelper::paginate(Brand::getUserAssociatedBrands(), $this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.claim_mail_templates.create', [
|
|
||||||
'claimMailTemplateModel' => $claim_mail_template,
|
|
||||||
'brandModels' => $brandModels,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\ClaimMailTemplates\ClaimMailTemplateRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(ClaimMailTemplateRequest $request): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$claimMailTemplateModel = new ClaimMailTemplate();
|
|
||||||
$claimMailTemplateModel->fill($request->validated());
|
|
||||||
if ($claimMailTemplateModel->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.claim_mail_templates.edit', $claimMailTemplateModel)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.claimmailtemplates'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.claimmailtemplates'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ClaimMailTemplate $claim_mail_template
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(ClaimMailTemplate $claim_mail_template): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$brandModels = CollectionHelper::paginate(Brand::getUserAssociatedBrands(), $this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.claim_mail_templates.edit', [
|
|
||||||
'claimMailTemplateModel' => $claim_mail_template,
|
|
||||||
'brandModels' => $brandModels,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a spacific resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\ClaimSubjects\ClaimMailTemplateRequest $request
|
|
||||||
* @param \App\Models\ClaimMailTemplate $claim_mail_template
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(
|
|
||||||
ClaimMailTemplateRequest $request,
|
|
||||||
ClaimMailTemplate $claim_mail_template
|
|
||||||
): \Illuminate\Http\RedirectResponse {
|
|
||||||
return DB::transaction(function () use ($request, $claim_mail_template) {
|
|
||||||
$claim_mail_template->fill($request->validated());
|
|
||||||
if ($claim_mail_template->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.claim_mail_templates.edit', $claim_mail_template)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.claimmailtemplates'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.claimmailtemplates'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ClaimMailTemplate $claim_mail_template
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(ClaimMailTemplate $claim_mail_template): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
if ($claim_mail_template->deleteOrFail()) {
|
|
||||||
return redirect()->route('bo.claim_mail_templates.index')
|
|
||||||
->with('success', __('crud.messages.has_been_deleted', [
|
|
||||||
'model' => Str::of(__('models.classes.claimmailtemplates'))->singular()
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
return redirect()->back()
|
|
||||||
->with('error', __('crud.messages.cannot_be_deleted', [
|
|
||||||
'model' => Str::of(__('models.classes.claimmailtemplates'))->singular()
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\ClaimMessages\StoreMessageRequest;
|
|
||||||
use App\Http\Requests\Bo\ClaimMessages\UpdateMessageRequest;
|
|
||||||
use App\Models\ClaimMessage;
|
|
||||||
use App\Traits\Controllers\UpdateModelPublished;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
|
|
||||||
class ClaimMessageController extends Controller
|
|
||||||
{
|
|
||||||
use UpdateModelPublished;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a new specific resource.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\ClaimMessages\StoreMessageRequest $request
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreMessageRequest $request): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
$this->authorize('store', ClaimMessage::class);
|
|
||||||
|
|
||||||
$validatedData = $request->validated();
|
|
||||||
return DB::transaction(function () use ($validatedData) {
|
|
||||||
$claimMessage = (new ClaimMessage())->fill($validatedData);
|
|
||||||
if ($claimMessage->saveOrFail()) {
|
|
||||||
$claimMessageModels = ClaimMessage::getAllModelsFromClaim($claimMessage->claim->getKey());
|
|
||||||
return response()->json($claimMessageModels);
|
|
||||||
}
|
|
||||||
return response()->json([], 500);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\ClaimMessages\UpdateMessageRequest $request
|
|
||||||
* @param \App\Models\ClaimMessage $claim_message
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateMessageRequest $request, ClaimMessage $claim_message): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
$this->authorize('update', ClaimMessage::class);
|
|
||||||
|
|
||||||
$claim_message->content = $request->validated()['content'];
|
|
||||||
$claim_message->saveOrFail();
|
|
||||||
|
|
||||||
return response()->json($claim_message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\ClaimSubjects\ClaimSubjectRequest;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\ClaimSubject;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Uwil\LaravelCommon\Helpers\CollectionHelper;
|
|
||||||
|
|
||||||
class ClaimSubjectController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(ClaimSubject::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 = ClaimSubject::query()->when(
|
|
||||||
$request->filled('brand'),
|
|
||||||
fn($q) => $q->whereHas('brand', fn($q) => $q->where('id', $request->brand))
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'label',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($query);
|
|
||||||
$searchFields = trans('validation.custom.label');
|
|
||||||
|
|
||||||
$claimSubjectModels = $query->paginate($this->getPagination());
|
|
||||||
|
|
||||||
return view('bo.pages.claim_subjects.index', compact('claimSubjectModels', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ClaimSubject $claim_subject
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function show(ClaimSubject $claim_subject): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
return view('bo.pages.claim_subjects.show', [
|
|
||||||
'claimSubjectModel' => $claim_subject
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ClaimSubject $claim_subject
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create(ClaimSubject $claim_subject): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$brandModels = CollectionHelper::paginate(Brand::getUserAssociatedBrands(), $this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.claim_subjects.create', [
|
|
||||||
'claimSubjectModel' => $claim_subject,
|
|
||||||
'brandModels' => $brandModels,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\ClaimSubjects\ClaimSubjectRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(ClaimSubjectRequest $request): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$claimSubjectModel = new ClaimSubject();
|
|
||||||
$claimSubjectModel->fill($request->validated());
|
|
||||||
if ($claimSubjectModel->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.claim_subjects.edit', $claimSubjectModel)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.claimsubjects'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.claimsubjects'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ClaimSubject $claim_subject
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(ClaimSubject $claim_subject): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$brandModels = CollectionHelper::paginate(Brand::getUserAssociatedBrands(), $this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.claim_subjects.edit', [
|
|
||||||
'claimSubjectModel' => $claim_subject,
|
|
||||||
'brandModels' => $brandModels,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a spacific resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\ClaimSubjects\ClaimSubjectRequest $request
|
|
||||||
* @param \App\Models\ClaimSubject $claim_subject
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(ClaimSubjectRequest $request, ClaimSubject $claim_subject): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $claim_subject) {
|
|
||||||
$claim_subject->fill($request->validated());
|
|
||||||
if ($claim_subject->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.claim_subjects.edit', $claim_subject)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.claimsubjects'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.claimsubjects'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\ClaimSubject $claim_subject
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(ClaimSubject $claim_subject): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
if ($claim_subject->deleteOrFail()) {
|
|
||||||
return redirect()->route('bo.claim_subjects.index')
|
|
||||||
->with('success', __('crud.messages.has_been_deleted', [
|
|
||||||
'model' => Str::of(__('models.classes.claimsubjects'))->singular()
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
return redirect()->back()
|
|
||||||
->with('error', __('crud.messages.cannot_be_deleted', [
|
|
||||||
'model' => Str::of(__('models.classes.claimsubjects'))->singular()
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,422 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Enums\CustomerExportType;
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\CustomerExport;
|
|
||||||
use App\Models\Answer;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\Customer;
|
|
||||||
use App\Models\CustomerInfo;
|
|
||||||
use App\Models\CustomerLogin;
|
|
||||||
use App\Models\Question;
|
|
||||||
use App\Models\SingleOptin;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Database\Query\JoinClause;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use League\Csv\Writer;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class CustomerController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Customer::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* View all customers.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$modelClass = Customer::class;
|
|
||||||
$modelTable = (new Customer())->getTable();
|
|
||||||
$questionModels = null;
|
|
||||||
$answerModels = null;
|
|
||||||
$searchFields = trans('Email, Prénom, Nom');
|
|
||||||
|
|
||||||
// Reset session sorts.
|
|
||||||
if ($request->rstSrts) {
|
|
||||||
$this->resetSessionSorts($modelTable);
|
|
||||||
}
|
|
||||||
// Reset session filters.
|
|
||||||
if ($request->rstFltrs) {
|
|
||||||
$this->resetSessionFilters($modelTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->filled('search') || Session::get("crud.$modelTable.search")) {
|
|
||||||
$columns = ['customer_infos.lastname', 'customer_infos.firstname'];
|
|
||||||
$query = $this->buildCustomerQuery();
|
|
||||||
|
|
||||||
// Apply filters.
|
|
||||||
$this->applyBrandFilter($request, $query, $modelTable, $questionModels, $answerModels);
|
|
||||||
$this->applySearchFilter($request, $query, $modelTable, $columns);
|
|
||||||
$this->applySort($request, $query, $modelTable);
|
|
||||||
|
|
||||||
$customerModels = $query->with(['customer', 'brand'])->simplePaginate($this->getPagination());
|
|
||||||
} //end if
|
|
||||||
|
|
||||||
return view('bo.pages.customers.index', [
|
|
||||||
'modelClass' => $modelClass,
|
|
||||||
'modelTable' => $modelTable,
|
|
||||||
'customerModels' => $customerModels ?? collect(),
|
|
||||||
'searchFields' => $searchFields,
|
|
||||||
'questionModels' => $questionModels,
|
|
||||||
'answerModels' => $answerModels,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show a specific custmer.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @param \App\Models\Brand $brand
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function show(Customer $customer, Brand $brand): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$customerInfos = CustomerInfo::query()->where('customer_id', $customer->id)
|
|
||||||
->where('brand_id', $brand->id)->firstOrFail();
|
|
||||||
$customerLogin = CustomerLogin::query()->where('customer_id', $customer->id)
|
|
||||||
->where('brand_id', $brand->id)->first();
|
|
||||||
|
|
||||||
return view('bo.pages.customers.show', compact(
|
|
||||||
'customerInfos',
|
|
||||||
'customerLogin'
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a specific customer info.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Customer $customer
|
|
||||||
* @param \App\Models\Brand $brand
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function delete(Customer $customer, Brand $brand): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
/** @var \App\Models\CustomerInfo */
|
|
||||||
$customerInfo = $customer->info($brand, Customer::FIRST_OR_FAIL);
|
|
||||||
/** @var \App\Models\CustomerLogin */
|
|
||||||
$customerLogin = $customer->login($brand, Customer::FIRST_OR_FAIL);
|
|
||||||
|
|
||||||
DB::transaction(function () use (
|
|
||||||
$brand,
|
|
||||||
$customer,
|
|
||||||
$customerLogin,
|
|
||||||
$customerInfo
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
$customerInfo->delete() === false ||
|
|
||||||
$customerLogin->delete() === false
|
|
||||||
) {
|
|
||||||
throw new \ErrorException('Api failed to delete customer.');
|
|
||||||
};
|
|
||||||
|
|
||||||
$customer->optInHistory()->whereHas('brand', function ($q) use ($brand) {
|
|
||||||
$q->where('id', $brand->id);
|
|
||||||
})->delete();
|
|
||||||
|
|
||||||
$logins = $customer->logins()->count();
|
|
||||||
$infos = $customer->infos()->count();
|
|
||||||
$history = $customer->optInHistory()->count();
|
|
||||||
|
|
||||||
// If customer is not associated with any brand then delete.
|
|
||||||
if (!$logins and !$infos and !$history) {
|
|
||||||
if ($customer->delete() === false) {
|
|
||||||
throw new \ErrorException('Api failed to update customer.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (\ErrorException $e) {
|
|
||||||
return redirect()->route('bo.customers.index')
|
|
||||||
->with('error', trans('Le compte n\'a pas pu être supprimé.'));
|
|
||||||
} //end try
|
|
||||||
|
|
||||||
return redirect()->route('bo.customers.index')->with('warning', trans('Compte supprimé.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show export the customers form.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function export(): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$this->authorize('export', Customer::class);
|
|
||||||
$brands = Brand::all();
|
|
||||||
return view('bo.pages.customers.export', compact(
|
|
||||||
'brands'
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exports customers following the requested export type.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\CustomerExport $request
|
|
||||||
* @return \Symfony\Component\HttpFoundation\StreamedResponse
|
|
||||||
* @throws \Exception If the request export type in not handled.
|
|
||||||
*/
|
|
||||||
public function exportSubmit(CustomerExport $request): \Symfony\Component\HttpFoundation\StreamedResponse
|
|
||||||
{
|
|
||||||
$pagination = 2000;
|
|
||||||
$header = '"lastname";"firstname";"email";"hashcode"';
|
|
||||||
|
|
||||||
$w = Writer::createFromString($header . PHP_EOL);
|
|
||||||
$w->setDelimiter(';');
|
|
||||||
$w->setEnclosure('"');
|
|
||||||
$w->setOutputBOM(Writer::BOM_UTF8);
|
|
||||||
|
|
||||||
$exportType = CustomerExportType::make(\intval($request->export_type));
|
|
||||||
|
|
||||||
// * We send the CSV using Symfony StreamedResponse.
|
|
||||||
$response = new StreamedResponse();
|
|
||||||
$response->headers->set('Content-Encoding', 'none');
|
|
||||||
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
|
|
||||||
$response->headers->set('Description', 'File Transfer');
|
|
||||||
$response->headers->set(
|
|
||||||
'Content-Disposition',
|
|
||||||
sprintf(
|
|
||||||
'attachment; filename="Export pour newsletter %s %s.csv"',
|
|
||||||
Carbon::now()->isoFormat('DD-MM-YYYY_HH-mm'),
|
|
||||||
Str::slug($exportType->label())
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
switch ($exportType) {
|
|
||||||
case CustomerExportType::both:
|
|
||||||
$continue = true;
|
|
||||||
// ! Continue
|
|
||||||
case CustomerExportType::customer:
|
|
||||||
$page = 1;
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $req */
|
|
||||||
$req = CustomerInfo::query()->where('brand_id', $request->brand)
|
|
||||||
->where('opt_in', true);
|
|
||||||
$total = $req->count();
|
|
||||||
$pages = \ceil($total / $pagination);
|
|
||||||
do {
|
|
||||||
/** @var \Illuminate\Pagination\LengthAwarePaginator $items */
|
|
||||||
$items = $req->with('customer', function ($q) {
|
|
||||||
$q->select(['id', 'email']);
|
|
||||||
})->paginate(
|
|
||||||
$pagination,
|
|
||||||
['lastname', 'firstname', 'hashcode', 'customer_id'],
|
|
||||||
'page',
|
|
||||||
$page
|
|
||||||
);
|
|
||||||
$items->map(function (CustomerInfo $customerInfo) use ($w) {
|
|
||||||
$w->insertOne([
|
|
||||||
'lastname' => $customerInfo->lastname,
|
|
||||||
'firstname' => $customerInfo->firstname,
|
|
||||||
'email' => $customerInfo->customer->email,
|
|
||||||
'hashcode' => $customerInfo->hashcode
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
} while ($page++ <= $pages);
|
|
||||||
if (!isset($continue)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// ! Continue
|
|
||||||
case CustomerExportType::singleOptin:
|
|
||||||
SingleOptin::query()->whereHas('brand', function (Builder $q) use ($request) {
|
|
||||||
$q->where('id', $request->brand);
|
|
||||||
})->get()->map(function (SingleOptin $singleOptin) use ($w) {
|
|
||||||
$w->insertOne([
|
|
||||||
'lastname' => '',
|
|
||||||
'firstname' => '',
|
|
||||||
'email' => $singleOptin->email,
|
|
||||||
'hashcode' => $singleOptin->hashcode
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new \Exception(sprintf('Unhandled CustomerExportType %s', $exportType->label()));
|
|
||||||
} //end switch
|
|
||||||
|
|
||||||
/*
|
|
||||||
We create a callable to output the CSV in chunk
|
|
||||||
with Symfony StreamResponse you can flush the body content if necessary
|
|
||||||
see Symfony documentation for more information
|
|
||||||
*/
|
|
||||||
|
|
||||||
// * The flush value should depend on your CSV size.
|
|
||||||
$flush_threshold = 1000;
|
|
||||||
|
|
||||||
$response->setCallback(function () use ($w, $flush_threshold) {
|
|
||||||
foreach ($w->chunk(1024) as $offset => $chunk) {
|
|
||||||
echo $chunk;
|
|
||||||
if ($offset % $flush_threshold === 0) {
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset all session sorts.
|
|
||||||
*
|
|
||||||
* @param string $table
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function resetSessionSorts(string $table): void
|
|
||||||
{
|
|
||||||
Session::forget([
|
|
||||||
"crud.$table.sort_col",
|
|
||||||
"crud.$table.sort_way",
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset all session filters.
|
|
||||||
*
|
|
||||||
* @param string $table
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function resetSessionFilters(string $table): void
|
|
||||||
{
|
|
||||||
Session::forget([
|
|
||||||
"crud.$table.brand",
|
|
||||||
"crud.$table.question",
|
|
||||||
"crud.$table.answer",
|
|
||||||
"crud.$table.search",
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the customer query.
|
|
||||||
*
|
|
||||||
* @return Builder
|
|
||||||
*/
|
|
||||||
private function buildCustomerQuery(): Builder
|
|
||||||
{
|
|
||||||
return CustomerInfo::query()
|
|
||||||
->join('customer_logins', function (JoinClause $join) {
|
|
||||||
$join->on('customer_logins.brand_id', '=', 'customer_infos.brand_id')
|
|
||||||
->on('customer_logins.customer_id', '=', 'customer_infos.customer_id');
|
|
||||||
})
|
|
||||||
->join('customers', fn($join) => $join->on('customers.id', '=', 'customer_infos.customer_id'))
|
|
||||||
->join('brands', fn($join) => $join->on('brands.id', '=', 'customer_infos.brand_id'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply all filters (brand, question, answer).
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @param string $table
|
|
||||||
* @param \Illuminate\Support\Collection|null $questionModels
|
|
||||||
* @param \Illuminate\Support\Collection|null $answerModels
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function applyBrandFilter(
|
|
||||||
Request $request,
|
|
||||||
Builder &$query,
|
|
||||||
string $table,
|
|
||||||
?Collection &$questionModels,
|
|
||||||
?Collection &$answerModels
|
|
||||||
): void {
|
|
||||||
$brand = $request->brand ?? Session::get("crud.$table.brand");
|
|
||||||
if (!(int) $brand) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Session::put("crud.$table.brand", $brand);
|
|
||||||
$query->where('customer_infos.brand_id', $brand);
|
|
||||||
|
|
||||||
$questionModels = Question::getAllModelsFromBrand($brand);
|
|
||||||
|
|
||||||
if (($request->filled('question') || Session::has("crud.$table.question")) && $questionModels->count()) {
|
|
||||||
$question = $request->question ?? Session::get("crud.$table.question");
|
|
||||||
Session::put("crud.$table.question", $question);
|
|
||||||
|
|
||||||
$answerModels = Answer::getAllAnswersFromQuestion($question);
|
|
||||||
$questionAnswers = Question::find($question)?->answers->modelKeys() ?? [];
|
|
||||||
|
|
||||||
$query->whereHas('customer.answers', fn($q) => $q->whereIn('answer_id', $questionAnswers));
|
|
||||||
|
|
||||||
if (
|
|
||||||
($request->filled('answer') || Session::has("crud.$table.answer"))
|
|
||||||
&& $questionModels->count()
|
|
||||||
&& $answerModels->count()
|
|
||||||
) {
|
|
||||||
$answer = $request->answer ?? Session::get("crud.$table.answer");
|
|
||||||
Session::put("crud.$table.answer", $answer);
|
|
||||||
|
|
||||||
$query->whereHas('customer.answers', fn($q) => $q->whereKey($answer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the search filter.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @param string $table
|
|
||||||
* @param array $columns
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function applySearchFilter(Request $request, Builder &$query, string $table, array $columns): void
|
|
||||||
{
|
|
||||||
$search = $request->search ?? Session::get("crud.$table.search");
|
|
||||||
Session::put("crud.$table.search", $search);
|
|
||||||
|
|
||||||
$query->where(function ($q) use ($columns, $search) {
|
|
||||||
foreach ($columns as $column) {
|
|
||||||
$q->orWhere($column, 'LIKE', "%$search%");
|
|
||||||
}
|
|
||||||
|
|
||||||
$q->orWhere('customers.email', 'LIKE', "%$search%")
|
|
||||||
->orWhere('customer_logins.last_connection', 'LIKE', "%$search%");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply sorts.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @param string $table
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function applySort(Request $request, Builder &$query, string $table): void
|
|
||||||
{
|
|
||||||
$sortCol = $request->sort_col ?? Session::get("crud.$table.sort_col");
|
|
||||||
$sortWay = $request->sort_way ?? Session::get("crud.$table.sort_way");
|
|
||||||
|
|
||||||
if ($sortCol) {
|
|
||||||
Session::put("crud.$table.sort_col", $sortCol);
|
|
||||||
}
|
|
||||||
if ($sortWay) {
|
|
||||||
Session::put("crud.$table.sort_way", $sortWay);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sortable = [
|
|
||||||
'brands.name',
|
|
||||||
'customers.email',
|
|
||||||
'customer_infos.firstname',
|
|
||||||
'customer_infos.lastname',
|
|
||||||
'customer_infos.opt_in',
|
|
||||||
'customer_logins.last_connection',
|
|
||||||
'customer_logins.status',
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($sortCol && $sortWay && (Schema::hasColumn($table, $sortCol) || in_array($sortCol, $sortable))) {
|
|
||||||
$query->orderBy($sortCol, $sortWay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
|
|
||||||
class DashboardController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Dashboard page.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
return view('bo.pages.dashboard');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,288 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\QuestionExport;
|
|
||||||
use App\Http\Requests\Bo\Questions\StoreQuestionRequest;
|
|
||||||
use App\Http\Requests\Bo\Questions\UpdateQuestionRequest;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\Customer;
|
|
||||||
use App\Models\Question;
|
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use League\Csv\Writer;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class QuestionController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Question::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 = Question::query()->when(
|
|
||||||
$request->filled('brand'),
|
|
||||||
fn($q) => $q->whereHas('brand', fn($q) => $q->where('id', $request->brand))
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'question',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($query);
|
|
||||||
$searchFields = trans('Question');
|
|
||||||
|
|
||||||
$query->with(['brand', 'answers']);
|
|
||||||
|
|
||||||
/** @var \Illuminate\Pagination\AbstractPaginator */
|
|
||||||
$questionModels = $query->paginate($this->getPagination());
|
|
||||||
|
|
||||||
return view('bo.pages.questions.index', compact('questionModels', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create(Question $question): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$brandModels = Brand::query()->orderBy('name', 'ASC')->paginate($this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.questions.create', [
|
|
||||||
'questionModel' => $question,
|
|
||||||
'brandModels' => $brandModels
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Questions\StoreQuestionRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreQuestionRequest $request): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$question = new Question();
|
|
||||||
$question->fill($request->validated());
|
|
||||||
if ($question->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.questions.edit', $question)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.questions'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.questions'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(Question $question): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$brandModels = Brand::query()->orderBy('name', 'ASC')->paginate($this->jsonItemPerPagination);
|
|
||||||
$question->load('brand');
|
|
||||||
return view('bo.pages.questions.edit', [
|
|
||||||
'questionModel' => $question,
|
|
||||||
'brandModels' => $brandModels
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a spacific resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Questions\UpdateQuestionRequest $request
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateQuestionRequest $request, Question $question): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $question) {
|
|
||||||
$question->fill($request->validated());
|
|
||||||
if ($question->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.questions.edit', $question)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.questions'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.questions'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function show(Question $question): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
return view('bo.pages.questions.show', [
|
|
||||||
'questionModel' => $question
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Question $question
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(Question $question): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
if ($question->deleteOrFail()) {
|
|
||||||
return redirect()->route('bo.questions.index')
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été supprimé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.questions'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas pu être supprimé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.questions'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the question export form
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function export(): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$this->authorize('export', Question::class);
|
|
||||||
$brands = Brand::all();
|
|
||||||
return view('bo.pages.questions.export', compact('brands'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exports questions as csv the requested export type
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\QuestionExport $request
|
|
||||||
* @return \Symfony\Component\HttpFoundation\StreamedResponse
|
|
||||||
*/
|
|
||||||
public function exportSubmit(QuestionExport $request): \Symfony\Component\HttpFoundation\StreamedResponse
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
/** @var \App\Models\Brand $brand */
|
|
||||||
$brand = Brand::query()->where('id', $request->brand)->firstOrFail();
|
|
||||||
$questions = $brand->questions->load('answers');
|
|
||||||
|
|
||||||
foreach ($questions as $question) {
|
|
||||||
$answersCounts = DB::query()
|
|
||||||
->selectRaw('count(*) as total, answer_id')
|
|
||||||
->from('model_answer')
|
|
||||||
->where('model_type', '=', Customer::class)
|
|
||||||
->whereIn('answer_id', $question->answers->modelKeys())
|
|
||||||
->groupBy('answer_id')
|
|
||||||
->get()
|
|
||||||
->keyBy('answer_id');
|
|
||||||
|
|
||||||
$results[$question->id] = [
|
|
||||||
'question' => $question->question,
|
|
||||||
'answers' => []
|
|
||||||
];
|
|
||||||
foreach ($question->answers as $answer) {
|
|
||||||
$results[$question->id]['answers'][] =
|
|
||||||
[
|
|
||||||
"$answer->answer ",
|
|
||||||
$answersCounts[$answer->id]->total ?? 0
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} //end foreach
|
|
||||||
|
|
||||||
$w = Writer::createFromString('');
|
|
||||||
$w->setDelimiter(';');
|
|
||||||
$w->setEnclosure('"');
|
|
||||||
$w->setOutputBOM(Writer::BOM_UTF8);
|
|
||||||
|
|
||||||
// * We send the CSV using Symfony StreamedResponse.
|
|
||||||
$response = new StreamedResponse();
|
|
||||||
$response->headers->set('Content-Encoding', 'none');
|
|
||||||
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
|
|
||||||
$response->headers->set('Description', 'File Transfer');
|
|
||||||
$response->headers->set(
|
|
||||||
'Content-Disposition',
|
|
||||||
sprintf(
|
|
||||||
'attachment; filename="Export pour newsletter %s %s.csv"',
|
|
||||||
Carbon::now()->isoFormat('DD-MM-YYYY_HH-mm'),
|
|
||||||
Str::slug($brand->name)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($results as $result) {
|
|
||||||
$w->insertOne([
|
|
||||||
'question' => $result['question'],
|
|
||||||
]);
|
|
||||||
foreach ($result['answers'] as $answer) {
|
|
||||||
$w->insertOne($answer);
|
|
||||||
}
|
|
||||||
$w->insertOne([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// * Push empty line if nothing to export
|
|
||||||
if (empty($results)) {
|
|
||||||
$w->insertOne([
|
|
||||||
'Aucune question pour cette marque'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
We create a callable to output the CSV in chunk
|
|
||||||
with Symfony StreamResponse you can flush the body content if necessary
|
|
||||||
see Symfony documentation for more information
|
|
||||||
*/
|
|
||||||
|
|
||||||
// * The flush value should depend on your CSV size.
|
|
||||||
$flush_threshold = 1000;
|
|
||||||
|
|
||||||
$response->setCallback(function () use ($w, $flush_threshold) {
|
|
||||||
foreach ($w->chunk(1024) as $offset => $chunk) {
|
|
||||||
echo $chunk;
|
|
||||||
if ($offset % $flush_threshold === 0) {
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,211 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\GenerateServiceToken;
|
|
||||||
use App\Http\Requests\Bo\Services\StoreServiceRequest;
|
|
||||||
use App\Http\Requests\Bo\Services\UpdateServiceRequest;
|
|
||||||
use App\Mail\ServiceCredentialRenewed;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\Service;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Uwil\LaravelCommon\Helpers\CollectionHelper;
|
|
||||||
|
|
||||||
class ServiceController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(Service::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function index(Request $request): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Builder $query */
|
|
||||||
$query = Service::query()->when(
|
|
||||||
$request->filled('brand'),
|
|
||||||
fn($q) => $q->whereHas('brand', fn($q) => $q->where('id', $request->brand))
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($request->search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$request->search,
|
|
||||||
null,
|
|
||||||
'name',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->sortQuery($query);
|
|
||||||
$searchFields = trans('Nom');
|
|
||||||
|
|
||||||
$query->with(['brand']);
|
|
||||||
|
|
||||||
$serviceModels = $query->paginate($this->getPagination());
|
|
||||||
|
|
||||||
return view('bo.pages.services.index', compact('serviceModels', 'searchFields'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function create(Service $service): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$brandModels = CollectionHelper::paginate(Brand::getUserAssociatedBrands(), $this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.services.create', [
|
|
||||||
'serviceModel' => $service,
|
|
||||||
'brandModels' => $brandModels
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Services\StoreServiceRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreServiceRequest $request): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$service = new Service();
|
|
||||||
$service->fill($request->validated());
|
|
||||||
$service->generateBearerToken();
|
|
||||||
$this->generateServicePassword($service);
|
|
||||||
if ($service->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.services.edit', $service)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été créé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function edit(Service $service): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
$brandModels = CollectionHelper::paginate(Brand::getUserAssociatedBrands(), $this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.services.edit', [
|
|
||||||
'serviceModel' => $service,
|
|
||||||
'brandModels' => $brandModels
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a spacific resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Services\Bo\UpdateServiceRequest $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateServiceRequest $request, Service $service): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $service) {
|
|
||||||
$service->fill($request->validated());
|
|
||||||
if ($service->saveOrFail()) {
|
|
||||||
return redirect()
|
|
||||||
->route('bo.services.edit', $service)
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas été mis à jour.',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the specified resource.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function show(Service $service): \Illuminate\Contracts\View\View
|
|
||||||
{
|
|
||||||
return view('bo.pages.services.show', [
|
|
||||||
'serviceModel' => $service
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(Service $service): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
if ($service->deleteOrFail()) {
|
|
||||||
return redirect()->route('bo.services.index')
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été supprimé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas pu être supprimé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.services'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Regen service credentials.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\GenerateServiceToken $request
|
|
||||||
* @param \App\Models\Service $service
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed, Squiz.Commenting.FunctionComment.Missing
|
|
||||||
public function generateServicePassword(
|
|
||||||
Service $service,
|
|
||||||
GenerateServiceToken $request = null
|
|
||||||
): \Illuminate\Http\RedirectResponse {
|
|
||||||
/** @var \App\Models\User $user */
|
|
||||||
$user = auth('backend')->user();
|
|
||||||
|
|
||||||
// * Special Condition for migration from v2 to v3.
|
|
||||||
$service->bearer_token = !Hash::needsRehash($service->bearer_token) ?
|
|
||||||
$service->generateBearerToken() : $service->bearer_token;
|
|
||||||
|
|
||||||
$bearerPwd = $service->generateBearerPassword();
|
|
||||||
$service->saveOrFail();
|
|
||||||
Mail::send(new ServiceCredentialRenewed($service, $user));
|
|
||||||
return back()
|
|
||||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
|
||||||
->with('error', "ATTENTION : METTEZ À JOUR LE SITE ! \nNouveau token d'API de $service->name : '$service->bearer_token' et mot de passe '$bearerPwd'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Models\Answer;
|
|
||||||
use App\Models\Question;
|
|
||||||
use App\Models\SingleOptin;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class SingleOptinController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Create the controller instance.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->authorizeResource(SingleOptin::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
|
|
||||||
{
|
|
||||||
$questionModels = null;
|
|
||||||
$answerModels = null;
|
|
||||||
$searchFields = trans('E-mail');
|
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
|
||||||
$query = SingleOptin::query();
|
|
||||||
|
|
||||||
$this->applyBrandAndAnswerFilters($request, $query, $questionModels, $answerModels);
|
|
||||||
$this->applySearch($request, $query);
|
|
||||||
$this->sortQuery($query);
|
|
||||||
|
|
||||||
$query->with('brand');
|
|
||||||
$singleoptinModels = $query->simplePaginate($this->getPagination());
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('bo.pages.singleoptins.index', [
|
|
||||||
'singleoptinModels' => $singleoptinModels ?? collect(),
|
|
||||||
'searchFields' => $searchFields,
|
|
||||||
'questionModels' => $questionModels,
|
|
||||||
'answerModels' => $answerModels,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*
|
|
||||||
* @param \App\Models\SingleOptin $singleoptin
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function destroy(SingleOptin $singleoptin): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
$singleoptin->answers()->detach();
|
|
||||||
if ($singleoptin->deleteOrFail()) {
|
|
||||||
return redirect()->route('bo.single_optins.index')
|
|
||||||
->with('success', trans(
|
|
||||||
':model a été supprimé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.singleoptins'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return redirect()->back()
|
|
||||||
->with('error', trans(
|
|
||||||
':model n\'a pas pu être supprimé.',
|
|
||||||
['model' => Str::singular(trans('models.classes.singleoptins'))]
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Undocumented function
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @param \Illuminate\Support\Collection|null $questionModels
|
|
||||||
* @param \Illuminate\Support\Collection|null $answerModels
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function applyBrandAndAnswerFilters(
|
|
||||||
Request $request,
|
|
||||||
Builder $query,
|
|
||||||
?Collection &$questionModels,
|
|
||||||
?Collection &$answerModels
|
|
||||||
): void {
|
|
||||||
if (!$request->filled('brand') || !(int) $request->brand) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$brandId = $request->brand;
|
|
||||||
$query->whereHas('brand', fn($q) => $q->whereKey($brandId));
|
|
||||||
$questionModels = Question::getAllModelsFromBrand($brandId);
|
|
||||||
|
|
||||||
if (!$request->filled('question')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$questionId = $request->question;
|
|
||||||
$question = Question::find($questionId);
|
|
||||||
|
|
||||||
if ($question) {
|
|
||||||
$questionAnswers = $question->answers->modelKeys();
|
|
||||||
$query->whereHas('answers', fn($q) => $q->whereIn('answer_id', $questionAnswers));
|
|
||||||
$answerModels = Answer::getAllAnswersFromQuestion($questionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->filled('answer')) {
|
|
||||||
$query->whereHas('answers', fn($q) => $q->whereKey($request->answer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply search filter.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function applySearch(Request $request, Builder $query): void
|
|
||||||
{
|
|
||||||
if ($request->filled('search')) {
|
|
||||||
$this->searchQuery($query, $request->search, null, 'email');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use App\Http\Requests\Bo\Users\StoreUserRequest;
|
|
||||||
use App\Http\Requests\Bo\Users\UpdateUserRequest;
|
|
||||||
use App\Models\Brand;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Traits\Controllers\UpdateModelPublished;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Uwil\LaravelCommon\Helpers\CollectionHelper;
|
|
||||||
|
|
||||||
class UserController extends Controller
|
|
||||||
{
|
|
||||||
use UpdateModelPublished;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 $query */
|
|
||||||
$query = User::query();
|
|
||||||
|
|
||||||
/** @var string $search Search field */
|
|
||||||
$search = $request->search;
|
|
||||||
if ($search) {
|
|
||||||
$this->searchQuery(
|
|
||||||
$query,
|
|
||||||
$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($query);
|
|
||||||
|
|
||||||
/** Custom pagination */
|
|
||||||
$userModels = $query->paginate($this->getPagination());
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
$brandModels = CollectionHelper::paginate(Brand::getUserAssociatedBrands(), $this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.users.create', ['userModel' => $user, 'brandModels' => $brandModels]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Users\StoreUserRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function store(StoreUserRequest $request): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request) {
|
|
||||||
$user = new User();
|
|
||||||
$user->fill($request->validated());
|
|
||||||
|
|
||||||
if ($user->saveOrFail()) {
|
|
||||||
$user->brands()->sync(collect($request->validated()['brand_id'])->pluck('id')->toArray());
|
|
||||||
return redirect()->route('bo.users.edit', $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
|
|
||||||
{
|
|
||||||
$brandModels = CollectionHelper::paginate(Brand::getUserAssociatedBrands(), $this->jsonItemPerPagination);
|
|
||||||
return view('bo.pages.users.edit', ['userModel' => $user, 'brandModels' => $brandModels]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\Users\UpdateUserRequest $request
|
|
||||||
* @param \App\Models\User $user
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
public function update(UpdateUserRequest $request, User $user): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
return DB::transaction(function () use ($request, $user) {
|
|
||||||
$user->fill($request->validated());
|
|
||||||
|
|
||||||
if ($user->saveOrFail()) {
|
|
||||||
$user->brands()->sync(collect($request->validated()['brand_id'])->pluck('id')->toArray());
|
|
||||||
return redirect()->route('bo.users.edit', $user)
|
|
||||||
->with('success', __('crud.messages.has_been_updated', [
|
|
||||||
'model' => Str::ucfirst(__('models.classes.user'))
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
return redirect()->route('bo.users.edit', $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')
|
|
||||||
->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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
30
app/Http/Controllers/BrandController.php
Normal file
30
app/Http/Controllers/BrandController.php
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Brand;
|
||||||
|
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
|
||||||
|
use Kwaadpepper\CrudPolicies\Traits\CrudController;
|
||||||
|
|
||||||
|
class BrandController extends Controller
|
||||||
|
{
|
||||||
|
use CrudController {
|
||||||
|
index as crudIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Brand */
|
||||||
|
public static $modelClass = Brand::class;
|
||||||
|
|
||||||
|
public static $layout = 'layouts.app';
|
||||||
|
|
||||||
|
public function index(CrudIndexRequest $request)
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\View\View */
|
||||||
|
$view = $this->crudIndex($request);
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
return view('brand.index', $view->getData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,246 +2,14 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Enums\Pagination\ItemsPerPaginationEnum;
|
|
||||||
use App\Enums\Theme\BootstrapThemeEnum;
|
|
||||||
use App\Http\Requests\Bo\PaginateModelsRequest;
|
|
||||||
use App\Http\Requests\Bo\ThemeRequest;
|
|
||||||
use App\Lib\Helpers\ToolboxHelper;
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||||
|
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||||
use Illuminate\Routing\Controller as BaseController;
|
use Illuminate\Routing\Controller as BaseController;
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class Controller extends BaseController
|
class Controller extends BaseController
|
||||||
{
|
{
|
||||||
use AuthorizesRequests;
|
use AuthorizesRequests;
|
||||||
|
use DispatchesJobs;
|
||||||
use ValidatesRequests;
|
use ValidatesRequests;
|
||||||
|
|
||||||
/** @var integer $itemPerPagination */
|
|
||||||
public $jsonItemPerPagination = 5;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build Search query on specified fields
|
|
||||||
* splitting search into words or using whole sentence
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query The eloquent query builder.
|
|
||||||
* @param string $search The query string.
|
|
||||||
* @param callable $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.
|
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
|
||||||
*/
|
|
||||||
protected function searchQuery(
|
|
||||||
Builder $query,
|
|
||||||
string $search,
|
|
||||||
callable $searchQuery = null,
|
|
||||||
string ...$fields
|
|
||||||
): \Illuminate\Database\Eloquent\Builder {
|
|
||||||
if (count($fields)) {
|
|
||||||
// Search using words.
|
|
||||||
$words = explode(' ', $search);
|
|
||||||
$query->where(function ($query) use ($searchQuery, $words, $search, $fields) {
|
|
||||||
foreach ($words as $word) {
|
|
||||||
if (!strlen($word)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->searchOnFields($query, $word, $fields);
|
|
||||||
} //end foreach
|
|
||||||
// Search whole using whole sentence.
|
|
||||||
$this->searchOnFields($query, $search, $fields);
|
|
||||||
if ($searchQuery) {
|
|
||||||
$searchQuery($query);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} //end if
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build query search on all fields
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @param string $search
|
|
||||||
* @param array $fields
|
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
|
||||||
*/
|
|
||||||
private function searchOnFields(
|
|
||||||
Builder $query,
|
|
||||||
string $search,
|
|
||||||
array $fields
|
|
||||||
): \Illuminate\Database\Eloquent\Builder {
|
|
||||||
$table = $query->getModel()->getTable();
|
|
||||||
foreach ($fields as $field) {
|
|
||||||
$field = str_replace('?', '\?', $field);
|
|
||||||
if (is_array($field)) {
|
|
||||||
$query->orWhereRaw(
|
|
||||||
sprintf("UPPER(CONCAT(%s)) LIKE UPPER(?)", collect($field)->map(function ($q) use ($table) {
|
|
||||||
return "`$table`.`$q`";
|
|
||||||
})->implode(', \' \', ')),
|
|
||||||
['%' . htmlspecialchars($search) . '%']
|
|
||||||
);
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
// Get models woth enum's label.
|
|
||||||
if (is_array($this->getSearchValue($query, $search, $field))) {
|
|
||||||
foreach ($this->getSearchValue($query, $search, $field) as $array) {
|
|
||||||
$query->orWhereRaw(
|
|
||||||
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
|
|
||||||
['%' . htmlspecialchars($array->value) . '%']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
// Get models with relation's name/label.
|
|
||||||
if (Str::endsWith($field, '_id') && $query->getModel()->has(Str::remove('_id', $field))) {
|
|
||||||
$query->orWhereHas(Str::remove('_id', $field), function ($queryRelation) use ($field, $search) {
|
|
||||||
if (Schema::hasColumn(Str::remove('_id', $field) . 's', 'name')) {
|
|
||||||
$queryRelation->where('name', 'like', '%' . $search . '%');
|
|
||||||
} elseif (Schema::hasColumn(Str::remove('_id', $field) . 's', 'label')) {
|
|
||||||
$queryRelation->where('label', 'like', '%' . $search . '%');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
$query->orWhereRaw(
|
|
||||||
"UPPER(`$table`.`$field`) LIKE UPPER(?)",
|
|
||||||
['%' . htmlspecialchars($this->getSearchValue($query, $search, $field)) . '%']
|
|
||||||
);
|
|
||||||
} //end foreach
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the search value (on string or Enum).
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @param string $search
|
|
||||||
* @param string $field
|
|
||||||
* @return string|array
|
|
||||||
*/
|
|
||||||
protected function getSearchValue(Builder $query, string $search, string $field): string|array
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
count($query->getModel()->getCasts()) and // Check if the model has casts.
|
|
||||||
isset($query->getModel()->getCasts()[$field]) and // Check if there is cast about specific field.
|
|
||||||
enum_exists($query->getModel()->getCasts()[$field]) // Check if the cast is an enum.
|
|
||||||
) {
|
|
||||||
$cases = collect($query->getModel()->getCasts()[$field]::toArray());
|
|
||||||
$enum = $cases->filter(function ($item) use ($search) {
|
|
||||||
return preg_match('/' . Str::lower($search) . '/', Str::lower($item->label));
|
|
||||||
});
|
|
||||||
return $enum->toArray();
|
|
||||||
} else {
|
|
||||||
return $search;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort columns with a query.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
|
||||||
* @param array $ignore
|
|
||||||
* @return \Illuminate\Database\Eloquent\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);
|
|
||||||
Session::put("$rName.sorted", true);
|
|
||||||
}
|
|
||||||
if (request()->sort_way) {
|
|
||||||
Session::put("$rName.sort_way", request()->sort_way);
|
|
||||||
Session::put("$rName.sorted", true);
|
|
||||||
}
|
|
||||||
if (request()->rstSrts) {
|
|
||||||
Session::remove("$rName.sorted");
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} elseif (Schema::hasColumn($table, 'order')) {
|
|
||||||
$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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the number of items per page.
|
|
||||||
*
|
|
||||||
* @param \App\Enums\Pagination\ItemsPerPaginationEnum|null $pagination
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
protected function getPagination(ItemsPerPaginationEnum $pagination = null): int
|
|
||||||
{
|
|
||||||
$currentRoutePath = Str::slug(request()->route()->getName());
|
|
||||||
$cacheKey = "pagination.{$currentRoutePath}";
|
|
||||||
$pagination = $pagination ?? ItemsPerPaginationEnum::twelve;
|
|
||||||
$pagination = ToolboxHelper::getValidatedEnum(
|
|
||||||
Cache::get($cacheKey, $pagination->value()),
|
|
||||||
'pagination',
|
|
||||||
'\App\Enums\Pagination\ItemsPerPaginationEnum',
|
|
||||||
);
|
|
||||||
if (Cache::get($cacheKey) !== $pagination) {
|
|
||||||
Cache::put($cacheKey, $pagination);
|
|
||||||
}
|
|
||||||
return $pagination;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a paginate resource.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\PaginateModelsRequest $request
|
|
||||||
* @return \Illuminate\Http\JsonResponse
|
|
||||||
*/
|
|
||||||
public function jsonPaginateModels(PaginateModelsRequest $request): \Illuminate\Http\JsonResponse
|
|
||||||
{
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Model $models */
|
|
||||||
$models = $request->targetModel::query()
|
|
||||||
->where($request->input('fieldName') ?? 'name', 'like', "%{$request->input('search')}%")
|
|
||||||
->orderBy($request->input('fieldName') ?? 'name', 'ASC')
|
|
||||||
->paginate($request->input('paginate') ?? 10);
|
|
||||||
return \response()->json($models);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the bootstrap theme or light (default).
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\ThemeRequest $request
|
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
|
||||||
*/
|
|
||||||
protected function setTheme(ThemeRequest $request): \Illuminate\Http\RedirectResponse
|
|
||||||
{
|
|
||||||
$theme = ToolboxHelper::getValidatedEnum(
|
|
||||||
$request->validated('theme') ?: Cache::get('theme', BootstrapThemeEnum::light->value()),
|
|
||||||
'theme',
|
|
||||||
'\App\Http\Controllers\BootstrapThemeEnum',
|
|
||||||
);
|
|
||||||
if (Cache::get("theme") !== $theme) {
|
|
||||||
Cache::put("theme", $theme);
|
|
||||||
}
|
|
||||||
return redirect()->back()->with('success', __('crud.messages.theme_updated'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
231
app/Http/Controllers/CustomerController.php
Normal file
231
app/Http/Controllers/CustomerController.php
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Enums\CustomerExportType;
|
||||||
|
use App\Http\Requests\CustomerExport;
|
||||||
|
use App\Models\Brand;
|
||||||
|
use App\Models\Customer;
|
||||||
|
use App\Models\CustomerInfo;
|
||||||
|
use App\Models\CustomerLogin;
|
||||||
|
use App\Models\SingleOptin;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Database\Query\JoinClause;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use League\Csv\Writer;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
|
class CustomerController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$modelTable = (new Customer())->getTable();
|
||||||
|
$modelClass = Customer::class;
|
||||||
|
$brands = Brand::select('id', 'name')->get();
|
||||||
|
$columns = ['customer_infos.lastname', 'customer_infos.firstname'];
|
||||||
|
|
||||||
|
// Jointure pour pouvoir trier les colonnes
|
||||||
|
/** @var \Illuminate\Database\Eloquent\Builder */
|
||||||
|
$query = CustomerInfo::join('customer_logins', function (JoinClause $join) {
|
||||||
|
$join->on('customer_logins.brand_id', '=', 'customer_infos.brand_id')
|
||||||
|
->on('customer_logins.customer_id', '=', 'customer_infos.customer_id');
|
||||||
|
})
|
||||||
|
->join('customers', function (JoinClause $join) {
|
||||||
|
$join->on('customers.id', '=', 'customer_infos.customer_id');
|
||||||
|
})
|
||||||
|
->join('brands', function (JoinClause $join) {
|
||||||
|
$join->on('brands.id', '=', 'customer_infos.brand_id');
|
||||||
|
});
|
||||||
|
if (request()->brand or Session::has("crud.$modelTable.brand")) {
|
||||||
|
$brand = $request->brand ?? Session::get("crud.$modelTable.brand");
|
||||||
|
Session::put("crud.$modelTable.brand", $brand);
|
||||||
|
$query = $query->where('customer_infos.brand_id', $brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search on crud Label column
|
||||||
|
if ($request->search or Session::has("crud.$modelTable.search")) {
|
||||||
|
$search = $request->search ?? Session::get("crud.$modelTable.search");
|
||||||
|
Session::put("crud.$modelTable.search", $search);
|
||||||
|
$query->where(function ($q) use ($columns, $search) {
|
||||||
|
foreach ($columns as $column) {
|
||||||
|
$q = $q->orWhere($column, 'LIKE', "%$search%");
|
||||||
|
}
|
||||||
|
$q = $q->orWhere('customers.email', 'LIKE', "%$search%");
|
||||||
|
$q = $q->orWhere('customer_logins.last_connection', 'LIKE', "%$search%");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort columns
|
||||||
|
if ($request->sort_col) {
|
||||||
|
Session::put("crud.$modelTable.sort_col", $request->sort_col);
|
||||||
|
}
|
||||||
|
if ($request->sort_way) {
|
||||||
|
Session::put("crud.$modelTable.sort_way", $request->sort_way);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->rst) {
|
||||||
|
Session::remove("crud.$modelTable.brand");
|
||||||
|
Session::remove("crud.$modelTable.search");
|
||||||
|
Session::remove("crud.$modelTable.sort_way");
|
||||||
|
Session::remove("crud.$modelTable.sort_col");
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
Session::has("crud.$modelTable.sort_col") and
|
||||||
|
Session::has("crud.$modelTable.sort_way") and
|
||||||
|
(Schema::hasColumn($modelTable, Session::get("crud.$modelTable.sort_col")) or
|
||||||
|
in_array(Session::get("crud.$modelTable.sort_col"), [
|
||||||
|
'brands.name',
|
||||||
|
'customers.email',
|
||||||
|
'customer_infos.firstname',
|
||||||
|
'customer_infos.lastname',
|
||||||
|
'customer_infos.opt_in',
|
||||||
|
'customer_logins.last_connection',
|
||||||
|
'customer_logins.status'
|
||||||
|
]))
|
||||||
|
) {
|
||||||
|
$query = $query->orderBy(
|
||||||
|
Session::get("crud.$modelTable.sort_col"),
|
||||||
|
Session::get("crud.$modelTable.sort_way")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \Illuminate\Pagination\AbstractPaginator */
|
||||||
|
$customers = $query->paginate(config('crud.paginate', 50));
|
||||||
|
|
||||||
|
return view('customer.index', compact(
|
||||||
|
'modelClass',
|
||||||
|
'modelTable',
|
||||||
|
'customers',
|
||||||
|
'brands'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Customer $customer, Brand $brand)
|
||||||
|
{
|
||||||
|
$customerInfos = CustomerInfo::where('customer_id', $customer->id)
|
||||||
|
->where('brand_id', $brand->id)->firstOrFail();
|
||||||
|
$customerLogin = CustomerLogin::where('customer_id', $customer->id)
|
||||||
|
->where('brand_id', $brand->id)->first();
|
||||||
|
|
||||||
|
return view('customer.show', compact(
|
||||||
|
'customerInfos',
|
||||||
|
'customerLogin'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Customer $customer, Brand $brand)
|
||||||
|
{
|
||||||
|
$nbBrand = $customer->infos()->count();
|
||||||
|
|
||||||
|
$customer->infos()->where('brand_id', $brand->id)->delete();
|
||||||
|
$customer->logins()->where('brand_id', $brand->id)->delete();
|
||||||
|
$customer->optInHistory()->where('brand_id', $brand->id)->delete();
|
||||||
|
|
||||||
|
if ($nbBrand === 1) {
|
||||||
|
$customer->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('customers.index')->with('success', "Compte supprimé.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$brands = Brand::all();
|
||||||
|
return view('customer.export', compact(
|
||||||
|
'brands'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportSubmit(CustomerExport $request)
|
||||||
|
{
|
||||||
|
$pagination = 2000;
|
||||||
|
$header = '"lastname";"firstname";"email";"hashcode"';
|
||||||
|
|
||||||
|
$w = Writer::createFromString($header . PHP_EOL);
|
||||||
|
$w->setDelimiter(';');
|
||||||
|
$w->setEnclosure('"');
|
||||||
|
$w->setOutputBOM(Writer::BOM_UTF8);
|
||||||
|
|
||||||
|
$exportType = CustomerExportType::make(\intval($request->export_type));
|
||||||
|
|
||||||
|
//We send the CSV using Symfony StreamedResponse
|
||||||
|
$response = new StreamedResponse();
|
||||||
|
$response->headers->set('Content-Encoding', 'none');
|
||||||
|
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
|
||||||
|
$response->headers->set('Description', 'File Transfer');
|
||||||
|
$response->headers->set(
|
||||||
|
'Content-Disposition',
|
||||||
|
sprintf(
|
||||||
|
'attachment; filename="Export pour newsletter %s %s.csv"',
|
||||||
|
Carbon::now()->format('d-m-Y_H-i'),
|
||||||
|
Str::slug($exportType)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
switch ($exportType) {
|
||||||
|
case CustomerExportType::both():
|
||||||
|
$continue = true;
|
||||||
|
// continue
|
||||||
|
case CustomerExportType::customer():
|
||||||
|
$page = 1;
|
||||||
|
/** @var \Illuminate\Database\Eloquent\Builder $req */
|
||||||
|
$req = CustomerInfo::where('brand_id', $request->brand);
|
||||||
|
$total = $req->count();
|
||||||
|
$pages = \ceil($total / $pagination);
|
||||||
|
do {
|
||||||
|
/** @var \Illuminate\Pagination\LengthAwarePaginator $items */
|
||||||
|
$items = $req->with('customer', function ($q) {
|
||||||
|
$q->select(['id', 'email']);
|
||||||
|
})->paginate(
|
||||||
|
$pagination,
|
||||||
|
['lastname', 'firstname', 'hashcode', 'customer_id'],
|
||||||
|
'page',
|
||||||
|
$page
|
||||||
|
);
|
||||||
|
$items->map(function (CustomerInfo $customerInfo) use ($w) {
|
||||||
|
$w->insertOne([
|
||||||
|
'lastname' => $customerInfo->lastname,
|
||||||
|
'firstname' => $customerInfo->firstname,
|
||||||
|
'email' => $customerInfo->customer->email,
|
||||||
|
'hashcode' => $customerInfo->hashcode
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
} while ($page++ <= $pages);
|
||||||
|
if (!isset($continue)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// continue
|
||||||
|
case CustomerExportType::singleOptin():
|
||||||
|
SingleOptin::where('brand_id', $request->brand)->get()
|
||||||
|
->map(function (SingleOptin $singleOptin) use ($w) {
|
||||||
|
$w->insertOne([
|
||||||
|
'lastname' => '',
|
||||||
|
'firstname' => '',
|
||||||
|
'email' => $singleOptin->email,
|
||||||
|
'hashcode' => ''
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(sprintf('Unhandled CustomerExportType %s', $exportType->label));
|
||||||
|
}
|
||||||
|
|
||||||
|
//we create a callable to output the CSV in chunk
|
||||||
|
//with Symfony StreamResponse you can flush the body content if necessary
|
||||||
|
//see Symfony documentation for more information
|
||||||
|
$flush_threshold = 1000; //the flush value should depend on your CSV size.
|
||||||
|
$response->setCallback(function () use ($w, $flush_threshold) {
|
||||||
|
foreach ($w->chunk(1024) as $offset => $chunk) {
|
||||||
|
echo $chunk;
|
||||||
|
if ($offset % $flush_threshold === 0) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
app/Http/Controllers/LoginController.php
Normal file
36
app/Http/Controllers/LoginController.php
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class LoginController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authenticate(Request $request)
|
||||||
|
{
|
||||||
|
// phpcs:ignore PSR2.ControlStructures.ControlStructureSpacing.SpacingAfterOpenBrace
|
||||||
|
if (
|
||||||
|
Auth::attempt(
|
||||||
|
["email" => $request->email, "password" => $request->password],
|
||||||
|
$request->remember !== null ? true : false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return redirect()->route('customers.index');
|
||||||
|
} else {
|
||||||
|
return back()->withInput($request->except("password"))
|
||||||
|
->withErrors("Les identifiants entrés sont incorrects, veuillez réessayer.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout()
|
||||||
|
{
|
||||||
|
Auth::logout();
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
}
|
||||||
125
app/Http/Controllers/QuestionController.php
Normal file
125
app/Http/Controllers/QuestionController.php
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\QuestionExport;
|
||||||
|
use App\Models\Brand;
|
||||||
|
use App\Models\Question;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
|
||||||
|
use Kwaadpepper\CrudPolicies\Traits\CrudController;
|
||||||
|
use League\Csv\Writer;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
|
class QuestionController extends Controller
|
||||||
|
{
|
||||||
|
use CrudController {
|
||||||
|
index as crudIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Question */
|
||||||
|
public static $modelClass = Question::class;
|
||||||
|
|
||||||
|
public static $layout = 'layouts.app';
|
||||||
|
|
||||||
|
public function index(CrudIndexRequest $request)
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\View\View */
|
||||||
|
$view = $this->crudIndex($request);
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
return view('question.index', $view->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexQuery(Builder $query): Builder
|
||||||
|
{
|
||||||
|
if (request()->brand) {
|
||||||
|
$query = $query->where('brand_id', '=', request()->brand);
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function export()
|
||||||
|
{
|
||||||
|
$brands = Brand::all();
|
||||||
|
return view('question.export', compact('brands'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportSubmit(QuestionExport $request)
|
||||||
|
{
|
||||||
|
$results = [];
|
||||||
|
$brand = Brand::findOrFail($request->brand);
|
||||||
|
$questions = $brand->questions->load('answers');
|
||||||
|
|
||||||
|
foreach ($questions as $question) {
|
||||||
|
$answersCounts = DB::query()
|
||||||
|
->selectRaw('count(*) as total, answer_id')
|
||||||
|
->from('customer_answer')
|
||||||
|
->whereIn('answer_id', $question->answers->pluck('id'))
|
||||||
|
->groupBy('answer_id')
|
||||||
|
->get()->keyBy('answer_id');
|
||||||
|
|
||||||
|
$results[$question->id] = [
|
||||||
|
'question' => $question->question,
|
||||||
|
'answers' => []
|
||||||
|
];
|
||||||
|
foreach ($question->answers as $answer) {
|
||||||
|
$results[$question->id]['answers'][] =
|
||||||
|
[
|
||||||
|
"$answer->answer ",
|
||||||
|
$answersCounts[$answer->id]->total ?? 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pagination = 2000;
|
||||||
|
|
||||||
|
$w = Writer::createFromString('');
|
||||||
|
$w->setDelimiter(';');
|
||||||
|
$w->setEnclosure('"');
|
||||||
|
$w->setOutputBOM(Writer::BOM_UTF8);
|
||||||
|
|
||||||
|
//We send the CSV using Symfony StreamedResponse
|
||||||
|
$response = new StreamedResponse();
|
||||||
|
$response->headers->set('Content-Encoding', 'none');
|
||||||
|
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
|
||||||
|
$response->headers->set('Description', 'File Transfer');
|
||||||
|
$response->headers->set(
|
||||||
|
'Content-Disposition',
|
||||||
|
sprintf(
|
||||||
|
'attachment; filename="Export pour newsletter %s %s.csv"',
|
||||||
|
Carbon::now()->format('d-m-Y_H-i'),
|
||||||
|
Str::slug($brand->name)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$w->insertOne([
|
||||||
|
'question' => $result['question'],
|
||||||
|
]);
|
||||||
|
foreach ($result['answers'] as $answer) {
|
||||||
|
$w->insertOne($answer);
|
||||||
|
}
|
||||||
|
$w->insertOne([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//we create a callable to output the CSV in chunk
|
||||||
|
//with Symfony StreamResponse you can flush the body content if necessary
|
||||||
|
//see Symfony documentation for more information
|
||||||
|
$flush_threshold = 1000; //the flush value should depend on your CSV size.
|
||||||
|
$response->setCallback(function () use ($w, $flush_threshold) {
|
||||||
|
foreach ($w->chunk(1024) as $offset => $chunk) {
|
||||||
|
echo $chunk;
|
||||||
|
if ($offset % $flush_threshold === 0) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
46
app/Http/Controllers/ServiceController.php
Normal file
46
app/Http/Controllers/ServiceController.php
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Requests\GenerateApiToken;
|
||||||
|
use App\Mail\ServiceCredentialRenewed;
|
||||||
|
use App\Models\Service;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
|
||||||
|
use Kwaadpepper\CrudPolicies\Traits\CrudController;
|
||||||
|
|
||||||
|
class ServiceController extends Controller
|
||||||
|
{
|
||||||
|
use CrudController {
|
||||||
|
index as crudIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Service */
|
||||||
|
public static $modelClass = Service::class;
|
||||||
|
|
||||||
|
public static $layout = 'layouts.app';
|
||||||
|
|
||||||
|
public function index(CrudIndexRequest $request)
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\View\View */
|
||||||
|
$view = $this->crudIndex($request);
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
return view('service.index', $view->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
|
||||||
|
public function generateApiToken(GenerateApiToken $request, Service $service)
|
||||||
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
$bearerToken = $service->generateBearerToken();
|
||||||
|
$bearerPwd = $service->bearer_pwd;
|
||||||
|
$service->saveOrFail();
|
||||||
|
Mail::send(new ServiceCredentialRenewed($service, $user));
|
||||||
|
return back()
|
||||||
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||||
|
->with('error', "ATTENTION : METTEZ À JOUR LE SITE ! \nNouveau token d'API de $service->name : '$bearerToken' et mot de passe '$bearerPwd'");
|
||||||
|
}
|
||||||
|
}
|
||||||
38
app/Http/Controllers/SingleOptinController.php
Normal file
38
app/Http/Controllers/SingleOptinController.php
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\SingleOptin;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest;
|
||||||
|
use Kwaadpepper\CrudPolicies\Traits\CrudController;
|
||||||
|
|
||||||
|
class SingleOptinController extends Controller
|
||||||
|
{
|
||||||
|
use CrudController {
|
||||||
|
index as crudIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var SingleOptin */
|
||||||
|
public static $modelClass = SingleOptin::class;
|
||||||
|
|
||||||
|
public static $layout = 'layouts.app';
|
||||||
|
|
||||||
|
public function index(CrudIndexRequest $request)
|
||||||
|
{
|
||||||
|
/** @var \Illuminate\View\View */
|
||||||
|
$view = $this->crudIndex($request);
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
return view('single_optin.index', $view->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexQuery(Builder $query): Builder
|
||||||
|
{
|
||||||
|
if (request()->brand) {
|
||||||
|
$query = $query->where('brand_id', request()->brand);
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,50 +1,35 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers\Bo;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Requests\StatsByBrandRequest;
|
||||||
use App\Http\Requests\Bo\StatsByBrandRequest;
|
use App\Http\Requests\StatsByQuestionRequest;
|
||||||
use App\Http\Requests\Bo\StatsByQuestionRequest;
|
|
||||||
use App\Models\Brand;
|
use App\Models\Brand;
|
||||||
use App\Models\BrandStat;
|
use App\Models\BrandStat;
|
||||||
use App\Models\ModelAnswer;
|
use App\Models\CustomerAnswer;
|
||||||
use App\Models\Question;
|
use App\Models\Question;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Gate;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use League\Csv\Writer;
|
use League\Csv\Writer;
|
||||||
|
|
||||||
class StatsController extends Controller
|
class StatsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Shows stats by brand.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\StatsByBrandRequest $request
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function viewStatsByBrand(StatsByBrandRequest $request)
|
public function viewStatsByBrand(StatsByBrandRequest $request)
|
||||||
{
|
{
|
||||||
Gate::authorize('viewStatsByBrand');
|
|
||||||
$stats = null;
|
$stats = null;
|
||||||
if ($request->post()) {
|
if ($request->post()) {
|
||||||
$stats = BrandStat::query()->whereDate('created_at', '>=', $request->start)
|
$stats = BrandStat::whereDate('created_at', '>=', $request->start)
|
||||||
->whereDate('created_at', '<=', $request->end)
|
->whereDate('created_at', '<=', $request->end)
|
||||||
->whereBrandId($request->brand)->get();
|
->whereBrandId($request->brand)->get();
|
||||||
}
|
}
|
||||||
return view('bo.pages.stats.view-stats-by-brands', \compact('stats'));
|
return view('stats.view-stats-by-brands', \compact('stats'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function exportByBrandCsv(StatsByBrandRequest $request)
|
||||||
* Exports stats by brand as a csv file.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\StatsByBrandRequest $request
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function exportByBrandCsv(StatsByBrandRequest $request): \Illuminate\Http\Response
|
|
||||||
{
|
{
|
||||||
$brand = Brand::query()->findOrFail($request->brand);
|
$brand = Brand::findOrFail($request->brand);
|
||||||
$stats = BrandStat::query()->with('brand')->whereDate('created_at', '>=', $request->start)
|
$stats = BrandStat::with('brand')->whereDate('created_at', '>=', $request->start)
|
||||||
->whereDate('created_at', '<=', $request->end)
|
->whereDate('created_at', '<=', $request->end)
|
||||||
->whereBrandId($request->brand)->get();
|
->whereBrandId($request->brand)->get();
|
||||||
|
|
||||||
|
|
@ -62,7 +47,7 @@ class StatsController extends Controller
|
||||||
|
|
||||||
foreach ($stats as $stat) {
|
foreach ($stats as $stat) {
|
||||||
$cols = [
|
$cols = [
|
||||||
$stat->created_at->isoFormat('YYYY-MM-DD'),
|
$stat->created_at->format('Y-m-d'),
|
||||||
$stat->brand->name
|
$stat->brand->name
|
||||||
];
|
];
|
||||||
foreach ($columns as $colname) {
|
foreach ($columns as $colname) {
|
||||||
|
|
@ -70,7 +55,7 @@ class StatsController extends Controller
|
||||||
}
|
}
|
||||||
$w->insertOne($cols);
|
$w->insertOne($cols);
|
||||||
}
|
}
|
||||||
return response((string) $w, 200, [
|
return response((string)$w, 200, [
|
||||||
'Content-Encoding' => 'none',
|
'Content-Encoding' => 'none',
|
||||||
'Content-Type' => 'text/csv; charset=UTF-8',
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
||||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||||
|
|
@ -79,20 +64,13 @@ class StatsController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function viewByQuestion(StatsByQuestionRequest $request)
|
||||||
* Views stats for a specific question.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\StatsByQuestionRequest $request
|
|
||||||
* @return \Illuminate\Contracts\View\View
|
|
||||||
*/
|
|
||||||
public function viewByQuestion(StatsByQuestionRequest $request): \Illuminate\Contracts\View\View
|
|
||||||
{
|
{
|
||||||
Gate::authorize('viewByQuestion');
|
|
||||||
$question = null;
|
$question = null;
|
||||||
$answers = null;
|
$answers = null;
|
||||||
$answersByDays = null;
|
$answersByDays = null;
|
||||||
if ($request->post()) {
|
if ($request->post()) {
|
||||||
$question = Question::query()->findOrFail($request->question);
|
$question = Question::findOrFail($request->question);
|
||||||
$answers = $question->answers;
|
$answers = $question->answers;
|
||||||
$start = Carbon::parse($request->start);
|
$start = Carbon::parse($request->start);
|
||||||
$end = Carbon::parse($request->end);
|
$end = Carbon::parse($request->end);
|
||||||
|
|
@ -100,18 +78,12 @@ class StatsController extends Controller
|
||||||
$answersByDays = $this->answersByDays($answers, $start, $end);
|
$answersByDays = $this->answersByDays($answers, $start, $end);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('bo.pages.stats.view-stats-by-questions', \compact('question', 'answers', 'answersByDays'));
|
return view('stats.view-stats-by-questions', \compact('question', 'answers', 'answersByDays'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function exportByQuestionCsv(StatsByQuestionRequest $request)
|
||||||
* Exports stats for a specific question as csv.
|
|
||||||
*
|
|
||||||
* @param \App\Http\Requests\Bo\StatsByQuestionRequest $request
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function exportByQuestionCsv(StatsByQuestionRequest $request): \Illuminate\Http\Response
|
|
||||||
{
|
{
|
||||||
$question = Question::query()->findOrFail($request->question);
|
$question = Question::findOrFail($request->question);
|
||||||
$answers = $question->answers;
|
$answers = $question->answers;
|
||||||
$start = Carbon::parse($request->start);
|
$start = Carbon::parse($request->start);
|
||||||
$end = Carbon::parse($request->end);
|
$end = Carbon::parse($request->end);
|
||||||
|
|
@ -135,7 +107,7 @@ class StatsController extends Controller
|
||||||
$dayAnswers->values()->all()
|
$dayAnswers->values()->all()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return response((string) $w, 200, [
|
return response((string)$w, 200, [
|
||||||
'Content-Encoding' => 'none',
|
'Content-Encoding' => 'none',
|
||||||
'Content-Type' => 'text/csv; charset=UTF-8',
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
||||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||||
|
|
@ -144,27 +116,16 @@ class StatsController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function answersByDays(Collection $answers, Carbon $start, Carbon $end): Collection
|
||||||
* Makes a collection of total users answers by day.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Support\Collection $answers A collection of Answer.
|
|
||||||
* @param \Illuminate\Support\Carbon $start The wanted start period.
|
|
||||||
* @param \Illuminate\Support\Carbon $end The wanted end period.
|
|
||||||
* @return \Illuminate\Support\Collection A collection with date as Y_m_d index
|
|
||||||
* with array of answers and their total.
|
|
||||||
*/
|
|
||||||
private function answersByDays(Collection $answers, Carbon $start, Carbon $end): \Illuminate\Support\Collection
|
|
||||||
{
|
{
|
||||||
Gate::authorize('answersByDays');
|
// Totalize by date all answers
|
||||||
// * Totalize by date all answers.
|
$answersByDays = CustomerAnswer::whereDate('created_at', '>=', $start)
|
||||||
$answersByDays = ModelAnswer::query()
|
|
||||||
->whereDate('created_at', '>=', $start)
|
|
||||||
->whereDate('created_at', '<=', $end)
|
->whereDate('created_at', '<=', $end)
|
||||||
->whereIn('answer_id', $answers->modelKeys())
|
->whereIn('answer_id', $answers->pluck('id'))
|
||||||
->get()->map(function ($custAnswer) {
|
->get()->map(function ($custAnswer) {
|
||||||
return [
|
return [
|
||||||
'answer_id' => $custAnswer->answer_id,
|
'answer_id' => $custAnswer->answer_id,
|
||||||
'created_at' => $custAnswer->created_at->isoFormat('YYYY-MM-DD'),
|
'created_at' => $custAnswer->created_at->format('Y-m-d'),
|
||||||
];
|
];
|
||||||
})->groupBy(['created_at', 'answer_id'])->map(function ($day) {
|
})->groupBy(['created_at', 'answer_id'])->map(function ($day) {
|
||||||
return $day->map(function ($custAnswers) {
|
return $day->map(function ($custAnswers) {
|
||||||
|
|
@ -173,7 +134,7 @@ class StatsController extends Controller
|
||||||
});
|
});
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$currentDate = $start->isoFormat('YYYY-MM-DD');
|
$currentDate = $start->format('Y-m-d');
|
||||||
/** @var \Illuminate\Support\Collection $answersByDays */
|
/** @var \Illuminate\Support\Collection $answersByDays */
|
||||||
if (!$answersByDays->has($currentDate)) {
|
if (!$answersByDays->has($currentDate)) {
|
||||||
$answersByDays->put(
|
$answersByDays->put(
|
||||||
|
|
@ -189,7 +150,7 @@ class StatsController extends Controller
|
||||||
$answers->mapWithKeys(function ($answer) use ($curentAnswers) {
|
$answers->mapWithKeys(function ($answer) use ($curentAnswers) {
|
||||||
return [$answer->answer =>
|
return [$answer->answer =>
|
||||||
$curentAnswers->has($answer->id) ?
|
$curentAnswers->has($answer->id) ?
|
||||||
$curentAnswers->get($answer->id) : 0];
|
$curentAnswers->get($answer->id) : 0];
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||||
|
|
||||||
class Kernel extends HttpKernel
|
class Kernel extends HttpKernel
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The application's global HTTP middleware stack.
|
* The application's global HTTP middleware stack.
|
||||||
*
|
*
|
||||||
|
|
@ -14,12 +15,13 @@ class Kernel extends HttpKernel
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $middleware = [
|
protected $middleware = [
|
||||||
\App\Http\Middleware\TrustHosts::class,
|
|
||||||
\App\Http\Middleware\TrustProxies::class,
|
\App\Http\Middleware\TrustProxies::class,
|
||||||
\Illuminate\Http\Middleware\HandleCors::class,
|
\Fruitcake\Cors\HandleCors::class,
|
||||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||||
\App\Http\Middleware\TrimStrings::class,
|
\App\Http\Middleware\TrimStrings::class,
|
||||||
|
\App\Http\Middleware\XssSanitizer::class,
|
||||||
|
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -29,27 +31,21 @@ class Kernel extends HttpKernel
|
||||||
*/
|
*/
|
||||||
protected $middlewareGroups = [
|
protected $middlewareGroups = [
|
||||||
'web' => [
|
'web' => [
|
||||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
|
||||||
\App\Http\Middleware\EncryptCookies::class,
|
\App\Http\Middleware\EncryptCookies::class,
|
||||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||||
\Illuminate\Session\Middleware\StartSession::class,
|
\Illuminate\Session\Middleware\StartSession::class,
|
||||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
\App\Http\Middleware\SecureHeaders::class
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
|
'throttle:api',
|
||||||
\App\Http\Middleware\JsonOnly::class,
|
\App\Http\Middleware\JsonOnly::class,
|
||||||
\App\Http\Middleware\ApiResponse::class,
|
\App\Http\Middleware\ApiResponse::class,
|
||||||
\App\Http\Middleware\ApiCheckTimeStamps::class,
|
\App\Http\Middleware\ApiCheckTimeStamps::class,
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class
|
\Illuminate\Routing\Middleware\SubstituteBindings::class
|
||||||
],
|
],
|
||||||
'saml' => [
|
|
||||||
\App\Http\Middleware\EncryptCookies::class,
|
|
||||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
|
||||||
\Illuminate\Session\Middleware\StartSession::class,
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -60,17 +56,15 @@ class Kernel extends HttpKernel
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $routeMiddleware = [
|
protected $routeMiddleware = [
|
||||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||||
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
'check-brand' => \App\Http\Middleware\CheckBrand::class,
|
||||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
'htmlsanitize' => \App\Http\Middleware\HtmlSanitizer::class,
|
|
||||||
'logoutusers' => \App\Http\Middleware\LogoutUnpublishedUsers::class,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use App\Enums\ApiError;
|
use App\Enums\ApiError;
|
||||||
use App\Exceptions\Api\V4\ApiErrorException;
|
use App\Exceptions\Api\V2\ApiErrorException;
|
||||||
use App\Lib\Helper;
|
use App\Lib\Helper;
|
||||||
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check Http Header Timestamp with request timestamp
|
* Check Http Header Timestamp with request timestamp
|
||||||
|
|
@ -18,26 +18,25 @@ class ApiCheckTimeStamps
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param \Closure $next
|
* @param \Closure $next
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws \App\Exceptions\Api\V4\ApiErrorException With ApiError::wrongTimeStamp
|
|
||||||
* if timestamp has an incorrect
|
|
||||||
* format or is timed out.
|
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, \Closure $next): mixed
|
public function handle(Request $request, Closure $next)
|
||||||
{
|
{
|
||||||
if (Helper::isRequestForApiV2($request) || Helper::isRequestForApiV4($request)) {
|
if (Helper::isRequestForApiV2($request)) {
|
||||||
if (!\is_string($request->timestamp) or !Carbon::hasFormat($request->timestamp, 'Y-m-d H:i:s')) {
|
if (!$request->hasHeader('X-API-TIMESTAMP') or !is_numeric($request->header('X-API-TIMESTAMP'))) {
|
||||||
throw new ApiErrorException(ApiError::wrongTimeStamp);
|
throw new ApiErrorException(ApiError::wrongTimeStamp());
|
||||||
}
|
}
|
||||||
if (
|
if (!$request->timestamp or !is_numeric($request->timestamp)) {
|
||||||
Carbon::parse($request->timestamp, 'utc')
|
throw new ApiErrorException(ApiError::wrongTimeStamp());
|
||||||
->isBefore(Carbon::now('UTC')->subSeconds(config('api.timestampTimeout', 10)))
|
}
|
||||||
) {
|
$diff = intval($request->timestamp) - intval($request->header('X-API-TIMESTAMP'));
|
||||||
throw new ApiErrorException(ApiError::wrongTimeStamp);
|
$maxDiff = 120;
|
||||||
|
if (abs($diff) > $maxDiff) {
|
||||||
|
throw new ApiErrorException(ApiError::wrongTimeStamp());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,61 +4,83 @@ namespace App\Http\Middleware;
|
||||||
|
|
||||||
use App\Enums\ApiStatus;
|
use App\Enums\ApiStatus;
|
||||||
use App\Http\Resources\Api\V2\ApiResponse as V2ApiResponse;
|
use App\Http\Resources\Api\V2\ApiResponse as V2ApiResponse;
|
||||||
use App\Http\Resources\Api\V4\ApiResponse as V4ApiResponse;
|
|
||||||
use App\Lib\Helper;
|
use App\Lib\Helper;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Closure;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class ApiResponse
|
class ApiResponse
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @param \Closure $next
|
* @param \Closure $next
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws \ErrorException If the received response is not a JsonResponse.
|
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, \Closure $next): mixed
|
public function handle(Request $request, Closure $next)
|
||||||
{
|
{
|
||||||
/** @var \Illuminate\Http\JsonResponse $response */
|
/** @var \Illuminate\Http\JsonResponse $response */
|
||||||
$response = $next($request);
|
$response = $next($request);
|
||||||
|
|
||||||
if (\get_class($response) !== JsonResponse::class) {
|
// Set no cache header
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
throw new \ErrorException('All api responses should be json.');
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set no cache header.
|
|
||||||
$response->header('Cache-Control', 'No-Store');
|
$response->header('Cache-Control', 'No-Store');
|
||||||
|
|
||||||
/** @var \App\Models\Service|null */
|
$isApiV1Request = Helper::isRequestForApiV1($request);
|
||||||
if (\optional($service = app(Service::class))->id) {
|
$isApiV2Request = Helper::isRequestForApiV2($request);
|
||||||
$service->incrementStat();
|
|
||||||
|
if ($isApiV1Request) {
|
||||||
|
// Use patched v1 Auth mecanism (without bearer reimplementation)
|
||||||
|
$bearerToken = Helper::getBearerTokenFromRequest($request) ?? $request->api_token;
|
||||||
|
try {
|
||||||
|
$service = Service::getFromBearerToken($bearerToken);
|
||||||
|
$service->incrementStat();
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
Log::error(sprintf('Could not increment stats %s', $e->getMessage()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var object $data */
|
if ($isApiV2Request) {
|
||||||
$data = $response->getData();
|
$service = null;
|
||||||
|
$bearerToken = Helper::getBearerTokenFromRequest($request);
|
||||||
|
try {
|
||||||
|
if ($bearerToken) {
|
||||||
|
$service = Service::getFromBearerToken($bearerToken);
|
||||||
|
}
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
try {
|
||||||
|
if (!$service and $request->api_token) {
|
||||||
|
$service = Service::getFromApiToken($request->api_token);
|
||||||
|
}
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
Log::error(sprintf('Could not increment stats %s', $e->getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($service) {
|
||||||
|
$service->incrementStat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Check if it's V2 or V4 response. */
|
if ($isApiV1Request) {
|
||||||
if (
|
|
||||||
gettype($data) === "object" and
|
|
||||||
isset($data->status) and
|
|
||||||
isset($data->data) and
|
|
||||||
isset($data->version) and
|
|
||||||
in_array($data->status, [ApiStatus::OK->value(), ApiStatus::KO->value()])
|
|
||||||
) {
|
|
||||||
/** Return direct ApiResponse */
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
$status = intval($response->getStatusCode() / 100) == 2 ? ApiStatus::OK : ApiStatus::KO;
|
$data = $response->getData();
|
||||||
|
|
||||||
if (Helper::isRequestForApiV2($request)) {
|
// Is reponse is already a V2ApiResponse then just return it
|
||||||
return $response->setData(new V2ApiResponse($status, (object) $data));
|
if (
|
||||||
|
isset($data->status) and
|
||||||
|
isset($data->data) and
|
||||||
|
isset($data->version) and
|
||||||
|
in_array($data->status, [ApiStatus::OK()->value, ApiStatus::KO()->value])
|
||||||
|
) {
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
return $response->setData(new V4ApiResponse($status, (object) $data));
|
|
||||||
|
/** @ var \App\Enums\ApiStatus */
|
||||||
|
$status = intval($response->getStatusCode() / 100) == 2 ? ApiStatus::OK() : ApiStatus::KO();
|
||||||
|
return $response->setData(new V2ApiResponse((object)$response->getData(), $status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,38 +2,55 @@
|
||||||
|
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Lib\Helper;
|
||||||
|
use App\Models\Service;
|
||||||
|
use Closure;
|
||||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Session;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updated for ApiV2
|
||||||
|
*/
|
||||||
class Authenticate extends Middleware
|
class Authenticate extends Middleware
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get the path the user should be redirected to when they are not authenticated.
|
* Handle an incoming request.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return string|null
|
* @param \Closure $next
|
||||||
|
* @param string[] ...$guards
|
||||||
|
* @return mixed
|
||||||
|
*
|
||||||
|
* @throws \Illuminate\Auth\AuthenticationException
|
||||||
*/
|
*/
|
||||||
protected function redirectTo(Request $request): ?string
|
public function handle($request, Closure $next, ...$guards)
|
||||||
{
|
{
|
||||||
$logins = [
|
// TODO: check this works
|
||||||
'backend' => route('bo.login')
|
if (Helper::isRequestForApiV1($request)) {
|
||||||
];
|
// Use patched v1 Auth mecanism (without bearer reimplementation)
|
||||||
if (!$request->expectsJson()) {
|
$bearerToken = Helper::getBearerTokenFromRequest($request) ?? $request->api_token ?? '';
|
||||||
// * Notify must login
|
$brand = Service::getFromBearerToken($bearerToken)->brand;
|
||||||
Session::flash('warning', trans('Veuillez vous connecter pour continuer'));
|
$request->request->add(['brand_id' => $brand->id]);
|
||||||
|
$response = $next($request);
|
||||||
foreach ($request->route()->gatherMiddleware() as $middleware) {
|
} else {
|
||||||
if (\is_string($middleware) and strpos($middleware, 'auth:') !== false) {
|
// Use Laravel auth check mecanism
|
||||||
$route = $logins[str_replace('auth:', '', $middleware)] ?? null;
|
$response = \call_user_func_array(
|
||||||
if ($route) {
|
[$this, 'parent::' . __FUNCTION__],
|
||||||
return $route;
|
array_merge([$request, $next], $guards)
|
||||||
}
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
return route('bo.login');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return $response;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the path the user should be redirected to when they are not authenticated.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
protected function redirectTo($request)
|
||||||
|
{
|
||||||
|
if (! $request->expectsJson()) {
|
||||||
|
return route('login');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
37
app/Http/Middleware/CheckBrand.php
Normal file
37
app/Http/Middleware/CheckBrand.php
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Lib\Helper;
|
||||||
|
use App\Models\Service;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class CheckBrand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param \Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
$apiToken = Helper::getBearerTokenFromRequest($request) ?? $request->api_token;
|
||||||
|
|
||||||
|
if ($apiToken === null) {
|
||||||
|
abort(401, 'Le token d\'authentification est incorrect dfd' . \json_encode($request->all()));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$brand = Service::getFromBearerToken($apiToken)->brand;
|
||||||
|
} catch (ModelNotFoundException $e) {
|
||||||
|
abort(401, 'Le token d\'authentification est incorrect ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->request->add(['brand_id' => $brand->id]);
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,10 +6,13 @@ use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
||||||
|
|
||||||
class EncryptCookies extends Middleware
|
class EncryptCookies extends Middleware
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The names of the cookies that should not be encrypted.
|
* The names of the cookies that should not be encrypted.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $except = [];
|
protected $except = [
|
||||||
|
//
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue