From d3325f6e5d2665c67ec757b1ef0aea6a324e1bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 26 Aug 2021 15:14:05 +0200 Subject: [PATCH 01/19] composer bump dependencies --- composer.lock | 153 ++++++++++++++++++++++++++------------------------ 1 file changed, 81 insertions(+), 72 deletions(-) diff --git a/composer.lock b/composer.lock index 39cc9e3..da781a3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0df11a64ace2bcbbbc3710af5cc6868f", + "content-hash": "5b5341478a5d91d067fb818f97d244fd", "packages": [ { "name": "arondeparon/laravel-request-sanitizer", @@ -128,16 +128,16 @@ }, { "name": "brick/math", - "version": "0.9.2", + "version": "0.9.3", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", "shasum": "" }, "require": { @@ -147,7 +147,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.3.2" + "vimeo/psalm": "4.9.2" }, "type": "library", "autoload": { @@ -172,15 +172,19 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.2" + "source": "https://github.com/brick/math/tree/0.9.3" }, "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/brick/math", "type": "tidelift" } ], - "time": "2021-01-20T22:51:39+00:00" + "time": "2021-08-15T20:50:18+00:00" }, { "name": "cache/adapter-common", @@ -447,16 +451,16 @@ }, { "name": "composer/package-versions-deprecated", - "version": "1.11.99.2", + "version": "1.11.99.3", "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c" + "reference": "fff576ac850c045158a250e7e27666e146e78d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c", - "reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/fff576ac850c045158a250e7e27666e146e78d18", + "reference": "fff576ac850c045158a250e7e27666e146e78d18", "shasum": "" }, "require": { @@ -500,7 +504,7 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.2" + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.3" }, "funding": [ { @@ -516,7 +520,7 @@ "type": "tidelift" } ], - "time": "2021-05-24T07:46:03+00:00" + "time": "2021-08-17T13:49:14+00:00" }, { "name": "doctrine/cache", @@ -1708,16 +1712,16 @@ }, { "name": "laravel/framework", - "version": "v8.53.1", + "version": "v8.56.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "5df423c2790f32b26baee90518bb659572aa404f" + "reference": "d700f336dc672dcbfe46db05d4e5fe9347b3a5b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/5df423c2790f32b26baee90518bb659572aa404f", - "reference": "5df423c2790f32b26baee90518bb659572aa404f", + "url": "https://api.github.com/repos/laravel/framework/zipball/d700f336dc672dcbfe46db05d4e5fe9347b3a5b6", + "reference": "d700f336dc672dcbfe46db05d4e5fe9347b3a5b6", "shasum": "" }, "require": { @@ -1790,7 +1794,7 @@ "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "^3.186.4", + "aws/aws-sdk-php": "^3.189.0", "doctrine/dbal": "^2.6|^3.0", "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^6.5.5|^7.0.1", @@ -1803,7 +1807,7 @@ "symfony/cache": "^5.1.4" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.186.4).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.189.0).", "brianium/paratest": "Required to run tests in parallel (^6.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", "ext-ftp": "Required to use the Flysystem FTP driver.", @@ -1872,7 +1876,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-08-05T14:04:08+00:00" + "time": "2021-08-24T13:46:30+00:00" }, { "name": "laravel/tinker", @@ -2045,16 +2049,16 @@ }, { "name": "league/flysystem", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32" + "reference": "18634df356bfd4119fe3d6156bdb990c414c14ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f3ad69181b8afed2c9edf7be5a2918144ff4ea32", - "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/18634df356bfd4119fe3d6156bdb990c414c14ea", + "reference": "18634df356bfd4119fe3d6156bdb990c414c14ea", "shasum": "" }, "require": { @@ -2127,7 +2131,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.4" + "source": "https://github.com/thephpleague/flysystem/tree/1.1.5" }, "funding": [ { @@ -2135,7 +2139,7 @@ "type": "other" } ], - "time": "2021-06-23T21:56:05+00:00" + "time": "2021-08-17T13:49:42+00:00" }, { "name": "league/mime-type-detection", @@ -2291,16 +2295,16 @@ }, { "name": "nesbot/carbon", - "version": "2.51.1", + "version": "2.52.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922" + "reference": "369c0e2737c56a0f39c946dd261855255a6fccbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922", - "reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/369c0e2737c56a0f39c946dd261855255a6fccbe", + "reference": "369c0e2737c56a0f39c946dd261855255a6fccbe", "shasum": "" }, "require": { @@ -2381,7 +2385,7 @@ "type": "tidelift" } ], - "time": "2021-07-28T13:16:28+00:00" + "time": "2021-08-14T19:10:52+00:00" }, { "name": "nikic/php-parser", @@ -3181,16 +3185,16 @@ }, { "name": "ramsey/uuid", - "version": "4.1.1", + "version": "4.2.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "cd4032040a750077205918c86049aa0f43d22947" + "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", - "reference": "cd4032040a750077205918c86049aa0f43d22947", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fe665a03df4f056aa65af552a96e1976df8c8dae", + "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae", "shasum": "" }, "require": { @@ -3204,26 +3208,26 @@ "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "doctrine/annotations": "^1.8", - "goaop/framework": "^2", + "ergebnis/composer-normalize": "^2.15", "mockery/mockery": "^1.3", "moontoast/math": "^1.1", "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", "php-mock/php-mock-mockery": "^1.3", - "php-mock/php-mock-phpunit": "^2.5", "php-parallel-lint/php-parallel-lint": "^1.1", - "phpbench/phpbench": "^0.17.1", + "phpbench/phpbench": "^1.0", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^0.12", "phpstan/phpstan-mockery": "^0.12", "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^8.5", - "psy/psysh": "^0.10.0", - "slevomat/coding-standard": "^6.0", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "3.9.4" + "vimeo/psalm": "^4.9" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", @@ -3236,7 +3240,10 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true } }, "autoload": { @@ -3252,7 +3259,6 @@ "MIT" ], "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", - "homepage": "https://github.com/ramsey/uuid", "keywords": [ "guid", "identifier", @@ -3260,16 +3266,19 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "rss": "https://github.com/ramsey/uuid/releases.atom", - "source": "https://github.com/ramsey/uuid" + "source": "https://github.com/ramsey/uuid/tree/4.2.1" }, "funding": [ { "url": "https://github.com/ramsey", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" } ], - "time": "2020-08-18T17:17:46+00:00" + "time": "2021-08-11T01:06:55+00:00" }, { "name": "rennokki/laravel-eloquent-query-cache", @@ -6139,16 +6148,16 @@ }, { "name": "facade/ignition", - "version": "2.11.2", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "7c4e7a7da184cd00c7ce6eacc590200bb9672de7" + "reference": "74dcc32a2895a126d1e5f2cd3bbab499cac66db1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/7c4e7a7da184cd00c7ce6eacc590200bb9672de7", - "reference": "7c4e7a7da184cd00c7ce6eacc590200bb9672de7", + "url": "https://api.github.com/repos/facade/ignition/zipball/74dcc32a2895a126d1e5f2cd3bbab499cac66db1", + "reference": "74dcc32a2895a126d1e5f2cd3bbab499cac66db1", "shasum": "" }, "require": { @@ -6211,7 +6220,7 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2021-07-20T14:01:22+00:00" + "time": "2021-08-24T09:53:54+00:00" }, { "name": "facade/ignition-contracts", @@ -6585,16 +6594,16 @@ }, { "name": "nunomaduro/collision", - "version": "v5.6.0", + "version": "v5.8.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "0122ac6b03c75279ef78d1c0ad49725dfc52a8d2" + "reference": "0c3c393462eada1233513664e2d22bb9f69ca393" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/0122ac6b03c75279ef78d1c0ad49725dfc52a8d2", - "reference": "0122ac6b03c75279ef78d1c0ad49725dfc52a8d2", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/0c3c393462eada1233513664e2d22bb9f69ca393", + "reference": "0c3c393462eada1233513664e2d22bb9f69ca393", "shasum": "" }, "require": { @@ -6606,7 +6615,7 @@ "require-dev": { "brianium/paratest": "^6.1", "fideloper/proxy": "^4.4.1", - "friendsofphp/php-cs-fixer": "^2.17.3", + "friendsofphp/php-cs-fixer": "^3.0", "fruitcake/laravel-cors": "^2.0.3", "laravel/framework": "^8.0 || ^9.0", "nunomaduro/larastan": "^0.6.2", @@ -6669,7 +6678,7 @@ "type": "patreon" } ], - "time": "2021-07-26T20:39:06+00:00" + "time": "2021-08-13T14:23:01+00:00" }, { "name": "phar-io/manifest", @@ -8567,16 +8576,16 @@ }, { "name": "slevomat/coding-standard", - "version": "7.0.13", + "version": "7.0.14", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "122a9bf9a4a2195f74100f47dfb8375982f43cc9" + "reference": "15b2b4630c148775debea8e412bc7e128d9868a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/122a9bf9a4a2195f74100f47dfb8375982f43cc9", - "reference": "122a9bf9a4a2195f74100f47dfb8375982f43cc9", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/15b2b4630c148775debea8e412bc7e128d9868a3", + "reference": "15b2b4630c148775debea8e412bc7e128d9868a3", "shasum": "" }, "require": { @@ -8587,12 +8596,12 @@ }, "require-dev": { "phing/phing": "2.16.4", - "php-parallel-lint/php-parallel-lint": "1.3.0", - "phpstan/phpstan": "0.12.93", + "php-parallel-lint/php-parallel-lint": "1.3.1", + "phpstan/phpstan": "0.12.96", "phpstan/phpstan-deprecation-rules": "0.12.6", - "phpstan/phpstan-phpunit": "0.12.21", - "phpstan/phpstan-strict-rules": "0.12.10", - "phpunit/phpunit": "7.5.20|8.5.5|9.5.7" + "phpstan/phpstan-phpunit": "0.12.22", + "phpstan/phpstan-strict-rules": "0.12.11", + "phpunit/phpunit": "7.5.20|8.5.5|9.5.8" }, "type": "phpcodesniffer-standard", "extra": { @@ -8612,7 +8621,7 @@ "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/7.0.13" + "source": "https://github.com/slevomat/coding-standard/tree/7.0.14" }, "funding": [ { @@ -8624,7 +8633,7 @@ "type": "tidelift" } ], - "time": "2021-07-29T14:30:22+00:00" + "time": "2021-08-26T12:17:56+00:00" }, { "name": "squizlabs/php_codesniffer", From 72a5b739029cec8af78acd85a54c4d5b999fc8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Wed, 8 Sep 2021 16:43:44 +0200 Subject: [PATCH 02/19] overhaull UI upgrade using crud policies --- .gitignore | 1 + app/Http/Controllers/BrandController.php | 33 +- app/Http/Controllers/CustomerController.php | 29 +- app/Http/Controllers/LoginController.php | 2 +- app/Http/Controllers/ServiceController.php | 43 +- .../Controllers/SingleOptinController.php | 38 ++ .../Controllers/SingleOptinsController.php | 37 -- app/Models/Brand.php | 37 ++ app/Models/CustomerInfo.php | 10 + app/Models/Service.php | 34 ++ app/Models/SingleOptin.php | 61 +++ app/Policies/BrandPolicy.php | 28 ++ app/Policies/CustomerPolicy.php | 23 +- app/Policies/Rules/UserStaticRules.php | 17 + app/Policies/ServicePolicy.php | 29 ++ app/Policies/SingleOptinPolicy.php | 27 ++ app/Providers/AppServiceProvider.php | 13 + app/Providers/RouteServiceProvider.php | 7 + clients/V2 | 2 +- composer.json | 6 +- composer.lock | 369 ++++++++++++------ config/app.php | 4 +- package.json | 37 +- public/js/app.js.LICENSE.txt | 18 - public/mix-manifest.json | 4 +- .../assets}/images/logo_ldc.png | Bin resources/js/Components/SearchOptin.vue | 101 ----- resources/js/Components/SearchUser.vue | 87 ----- resources/js/app.js | 17 - resources/js/back.js | 5 + resources/js/pages/customer.delete.js | 34 ++ resources/js/pages/service.index.js | 36 ++ resources/js/pages/single_optin.index.js | 10 + resources/lang/en/models.php | 20 + resources/lang/fr/models.php | 20 + resources/sass/_dashboard.scss | 103 ----- resources/sass/_layout.scss | 17 + resources/sass/_variables.scss | 4 + resources/sass/app.scss | 10 - resources/sass/back.scss | 5 + resources/sass/pages/login.scss | 54 +++ resources/views/brand/index.blade.php | 158 ++++++++ resources/views/brands/index.blade.php | 28 -- resources/views/brands/manage.blade.php | 30 -- .../customer/index-tableHeaders.blade.php | 63 +++ resources/views/customer/index.blade.php | 104 +++++ resources/views/customer/show.blade.php | 113 ++++++ resources/views/customers/index.blade.php | 23 -- resources/views/customers/show.blade.php | 98 ----- resources/views/layout/app.blade.php | 68 ---- resources/views/layouts/app.blade.php | 35 ++ .../views/layouts/backend/footer.blade.php | 10 + .../views/layouts/backend/head.blade.php | 32 ++ .../views/layouts/backend/navbar.blade.php | 15 + .../views/layouts/backend/sidenav.blade.php | 90 +++++ resources/views/login.blade.php | 84 +--- resources/views/service/index.blade.php | 158 ++++++++ resources/views/services/index.blade.php | 36 -- resources/views/services/manage.blade.php | 42 -- resources/views/single-optins/index.blade.php | 5 - resources/views/single_optin/index.blade.php | 121 ++++++ routes/web.php | 36 +- webpack.mix.js | 58 ++- 63 files changed, 1838 insertions(+), 1001 deletions(-) create mode 100644 app/Http/Controllers/SingleOptinController.php delete mode 100644 app/Http/Controllers/SingleOptinsController.php create mode 100644 app/Policies/BrandPolicy.php create mode 100644 app/Policies/Rules/UserStaticRules.php create mode 100644 app/Policies/ServicePolicy.php create mode 100644 app/Policies/SingleOptinPolicy.php delete mode 100644 public/js/app.js.LICENSE.txt rename {public => resources/assets}/images/logo_ldc.png (100%) delete mode 100644 resources/js/Components/SearchOptin.vue delete mode 100644 resources/js/Components/SearchUser.vue delete mode 100644 resources/js/app.js create mode 100644 resources/js/back.js create mode 100644 resources/js/pages/customer.delete.js create mode 100644 resources/js/pages/service.index.js create mode 100644 resources/js/pages/single_optin.index.js create mode 100644 resources/lang/en/models.php create mode 100644 resources/lang/fr/models.php delete mode 100644 resources/sass/_dashboard.scss create mode 100644 resources/sass/_layout.scss delete mode 100644 resources/sass/app.scss create mode 100644 resources/sass/back.scss create mode 100644 resources/sass/pages/login.scss create mode 100644 resources/views/brand/index.blade.php delete mode 100644 resources/views/brands/index.blade.php delete mode 100644 resources/views/brands/manage.blade.php create mode 100644 resources/views/customer/index-tableHeaders.blade.php create mode 100644 resources/views/customer/index.blade.php create mode 100644 resources/views/customer/show.blade.php delete mode 100644 resources/views/customers/index.blade.php delete mode 100644 resources/views/customers/show.blade.php delete mode 100644 resources/views/layout/app.blade.php create mode 100644 resources/views/layouts/app.blade.php create mode 100644 resources/views/layouts/backend/footer.blade.php create mode 100644 resources/views/layouts/backend/head.blade.php create mode 100644 resources/views/layouts/backend/navbar.blade.php create mode 100644 resources/views/layouts/backend/sidenav.blade.php create mode 100644 resources/views/service/index.blade.php delete mode 100644 resources/views/services/index.blade.php delete mode 100644 resources/views/services/manage.blade.php delete mode 100644 resources/views/single-optins/index.blade.php create mode 100644 resources/views/single_optin/index.blade.php diff --git a/.gitignore b/.gitignore index d430557..de543e8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ storage/crm_migration.csv MIG/errors_sql.txt public/js public/css +public/assets diff --git a/app/Http/Controllers/BrandController.php b/app/Http/Controllers/BrandController.php index 482f5d9..0be8700 100644 --- a/app/Http/Controllers/BrandController.php +++ b/app/Http/Controllers/BrandController.php @@ -3,29 +3,28 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; -use App\Http\Requests\ManageBrandRequest; use App\Models\Brand; +use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest; +use Kwaadpepper\CrudPolicies\Traits\CrudController; class BrandController extends Controller { - public function index() - { - $brands = Brand::all(); - return view('brands.index', compact('brands')); + use CrudController { + index as crudIndex; } - public function manage(ManageBrandRequest $request, Brand $brand) - { - if ($request->isMethod('post')) { - if (!$brand) { - $brand = new Brand($request->validated()); - } else { - $brand->fill($request->validated()); - } - $brand->save(); - return redirect()->route('brands')->with('success', trans('Modifications enregistrées !')); - } + /** @var Brand */ + public static $modelClass = Brand::class; - return view('brands.manage', compact('brand')); + 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()); } } diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 22e5f26..837a3ea 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -12,7 +12,23 @@ class CustomerController extends Controller public function index() { $brands = Brand::select('id', 'name')->get(); - return view('customers.index', compact('brands')); + $query = CustomerInfo::with(['customer']); + if (request()->brand) { + $query = $query->where('brand_id', request()->brand); + } + $customers = $query->paginate(); + $modelTable = (new Customer())->getTable(); + $modelClass = Customer::class; + + // use a crud controller (any) to gather crudModels + $modelsClasses = (new BrandController())->getCrudModels(); + return view('customer.index', compact( + 'modelsClasses', + 'modelClass', + 'modelTable', + 'customers', + 'brands' + )); } public function show(Customer $customer, Brand $brand) @@ -21,7 +37,14 @@ class CustomerController extends Controller ->where('brand_id', $brand->id)->firstOrFail(); $customerLogin = CustomerLogin::where('customer_id', $customer->id) ->where('brand_id', $brand->id)->first(); - return view('customers.show', compact('customerInfos', 'customerLogin')); + + // use a crud controller (any) to gather crudModels + $modelsClasses = (new BrandController())->getCrudModels(); + return view('customer.show', compact( + 'modelsClasses', + 'customerInfos', + 'customerLogin' + )); } public function filter($texte, Brand $brand = null) @@ -77,6 +100,6 @@ class CustomerController extends Controller $customer->delete(); } - return redirect()->route('customers')->with('success', "Compte supprimé."); + return redirect()->route('customers.index')->with('success', "Compte supprimé."); } } diff --git a/app/Http/Controllers/LoginController.php b/app/Http/Controllers/LoginController.php index f7033f7..c1e18aa 100644 --- a/app/Http/Controllers/LoginController.php +++ b/app/Http/Controllers/LoginController.php @@ -21,7 +21,7 @@ class LoginController extends Controller $request->remember !== null ? true : false ) ) { - return redirect()->route('customers'); + return redirect()->route('customers.index'); } else { return back()->withInput($request->except("password")) ->withErrors("Les identifiants entrés sont incorrects, veuillez réessayer."); diff --git a/app/Http/Controllers/ServiceController.php b/app/Http/Controllers/ServiceController.php index 2d45863..ac752ed 100644 --- a/app/Http/Controllers/ServiceController.php +++ b/app/Http/Controllers/ServiceController.php @@ -2,40 +2,29 @@ namespace App\Http\Controllers; -use App\Http\Requests\ManageServiceRequest; -use App\Models\Brand; use App\Models\Service; +use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest; +use Kwaadpepper\CrudPolicies\Traits\CrudController; class ServiceController extends Controller { - public function index() - { - $services = Service::all(); - return view('services.index', compact('services')); + use CrudController { + index as crudIndex; } - public function manage(ManageServiceRequest $request, Service $service = null) + /** @var Service */ + public static $modelClass = Service::class; + + public static $layout = 'layouts.app'; + + public function index(CrudIndexRequest $request) { - $brands = Brand::all(); - $edit = $service ? true : false; - - if ($request->isMethod('post')) { - if (!$service) { - $service = new Service($request->validated()); - } else { - $service->fill($request->validated()); - } - $brand = Brand::findOrFail($request->brand_id); - $service->brand()->associate($brand); - $service->save(); - - return redirect()->route('services')->with('success', $edit ? 'Modifications enregistrées !' : sprintf( - 'Token du service : \'%s\'', - $service->bearer_token - )); + /** @var \Illuminate\View\View */ + $view = $this->crudIndex($request); + if ($request->ajax()) { + return $view; } - - return view('services.manage', compact('service', 'brands', 'edit')); + return view('service.index', $view->getData()); } public function generateApiToken(Service $service) @@ -45,6 +34,6 @@ class ServiceController extends Controller $service->saveOrFail(); return back() // phpcs:ignore Generic.Files.LineLength.TooLong - ->with('success', "Nouveau token d'API de $service->name : '$bearerToken' et mot de passe '$bearerPwd'"); + ->with('error', "ATTENTION : METTEZ À JOUR LE SITE ! \nNouveau token d'API de $service->name : '$bearerToken' et mot de passe '$bearerPwd'"); } } diff --git a/app/Http/Controllers/SingleOptinController.php b/app/Http/Controllers/SingleOptinController.php new file mode 100644 index 0000000..7174356 --- /dev/null +++ b/app/Http/Controllers/SingleOptinController.php @@ -0,0 +1,38 @@ +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; + } +} diff --git a/app/Http/Controllers/SingleOptinsController.php b/app/Http/Controllers/SingleOptinsController.php deleted file mode 100644 index 303585d..0000000 --- a/app/Http/Controllers/SingleOptinsController.php +++ /dev/null @@ -1,37 +0,0 @@ -get(); - return view('single-optins.index', compact('brands')); - } - - public function filter($texte, $brandId = null) - { - if ($brandId !== null) { - $customers = SingleOptin::where([['email', 'like', '%' . $texte . '%'], ['brand_id', $brandId]])->get(); - } else { - $customers = SingleOptin::where('email', 'like', '%' . $texte . '%')->get(); - } - - return response()->json($customers); - } - - public function delete($id) - { - // TODO : Gestion avec les stats - $optin = SingleOptin::find($id); - if ($optin) { - $optin->delete(); - } - return new StatusResource(['status' => "OK"]); - } -} diff --git a/app/Models/Brand.php b/app/Models/Brand.php index d80fae1..9db5006 100644 --- a/app/Models/Brand.php +++ b/app/Models/Brand.php @@ -4,13 +4,22 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; use Rennokki\QueryCache\Traits\QueryCacheable; class Brand extends Model { + use IsCrudModel; use HasFactory; use QueryCacheable; + protected $crudLabelColumn = 'name'; + + protected $crudValueColumn = 'id'; + protected $cacheFor = 0; protected $fillable = [ @@ -20,6 +29,34 @@ class Brand extends Model public function __construct(array $attributes = []) { $this->cacheFor = config('api.servicesDBCache') * 60; + + self::$editableProperties = [ + 'name' => [ + 'label' => Str::ucfirst(trans('models.common.name')), + 'type' => CrudType::string(), + 'validate' => [ + 'min:5', + 'max:255' + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ], + 'services' => [ + 'label' => Str::ucfirst(Str::plural(trans('models.models.service'))), + 'type' => CrudType::belongsToMany(), + 'belongsToMany' => Service::class, + 'belongsToManyLabel' => 'name', + 'actions' => [ + CrudAction::view(), + CrudAction::create(), + CrudAction::update(), + ] + ] + ]; parent::__construct($attributes); } diff --git a/app/Models/CustomerInfo.php b/app/Models/CustomerInfo.php index a47f6c0..b5ebb77 100644 --- a/app/Models/CustomerInfo.php +++ b/app/Models/CustomerInfo.php @@ -100,6 +100,16 @@ class CustomerInfo extends Model return $this->belongsTo(Customer::class); } + /** + * CustomerLogin HasOneThrough relation + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function login() + { + return $this->customer->login($this->brand); + } + /** * Brand BelongsTo relation * diff --git a/app/Models/Service.php b/app/Models/Service.php index fc571de..205fc6f 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -8,13 +8,21 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; use Rennokki\QueryCache\Traits\QueryCacheable; class Service extends Model { + use IsCrudModel; use HasFactory; use QueryCacheable; + protected $crudLabelColumn = 'name'; + + protected $crudValueColumn = 'id'; + protected $cacheFor = 0; protected $fillable = [ @@ -24,6 +32,32 @@ class Service extends Model public function __construct(array $attributes = []) { $this->cacheFor = config('api.servicesDBCache') * 60; + + self::$editableProperties = [ + 'name' => [ + 'label' => Str::ucfirst(trans('models.common.name')), + 'type' => CrudType::string(), + 'validate' => [ + 'min:5', + 'max:255' + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ], + 'brand_id' => [ + 'label' => Str::ucfirst(trans('models.models.brand')), + 'type' => CrudType::belongsTo(), + 'belongsTo' => Brand::class, + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view() + ] + ], + ]; parent::__construct($attributes); } diff --git a/app/Models/SingleOptin.php b/app/Models/SingleOptin.php index 7776219..f71f82c 100644 --- a/app/Models/SingleOptin.php +++ b/app/Models/SingleOptin.php @@ -4,15 +4,76 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; class SingleOptin extends Model { use HasFactory; + use IsCrudModel; + + protected $crudLabelColumn = 'email'; + + protected $crudValueColumn = 'id'; protected $fillable = [ 'email' ]; + public function __construct(array $attributes = []) + { + self::$editableProperties = [ + 'email' => [ + 'label' => Str::ucfirst(trans('models.common.email')), + 'type' => CrudType::email(), + 'validate' => [ + 'required', + 'email:rfc,dns', + // @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed + function ($attribute, $value, $fail) { + $q = static::query(); + if (request()->user) { + $q = $q->where('id', '!=', $this->id); + } + if ($q->where('email', $value)->exists()) { + $fail(__(':attribute est déjà utilisé', [ + 'attribute' => $attribute + ])); + } + } + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ], + 'brand_id' => [ + 'label' => Str::ucfirst(trans('models.models.brand')), + 'type' => CrudType::belongsTo(), + 'belongsTo' => Brand::class, + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view() + ] + ], + 'created_at' => [ + 'label' => Str::ucfirst(trans('models.common.optinDate')), + 'type' => CrudType::string(), + 'readonly' => true, + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::update() + ] + ], + ]; + parent::__construct($attributes); + } + /** * Brand BelongsTo relation * diff --git a/app/Policies/BrandPolicy.php b/app/Policies/BrandPolicy.php new file mode 100644 index 0000000..02579b1 --- /dev/null +++ b/app/Policies/BrandPolicy.php @@ -0,0 +1,28 @@ +policies = [ + 'brand' => [ + 'viewAny' => USR::make('everyOne'), + 'update' => USR::make('everyOne'), + 'create' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Policies/CustomerPolicy.php b/app/Policies/CustomerPolicy.php index 32e33ee..3eea775 100644 --- a/app/Policies/CustomerPolicy.php +++ b/app/Policies/CustomerPolicy.php @@ -4,12 +4,33 @@ namespace App\Policies; use App\Models\Customer; use App\Models\Service; +use App\Policies\Rules\UserStaticRules as USR; use Illuminate\Auth\Access\HandlesAuthorization; +use Kwaadpepper\CrudPolicies\Policies\RootPolicy; -class CustomerPolicy +class CustomerPolicy extends RootPolicy { use HandlesAuthorization; + /** + * Init policies on call + * + * @return void + */ + public function setPolicies() + { + /** + * This first rule to return true in a policy action authorises the action + */ + $this->policies = [ + 'customer' => [ + 'viewAny' => USR::make('everyOne'), + 'view' => USR::make('everyOne'), + 'delete' => USR::make('everyOne') + ] + ]; + } + public function customerBelongsToService(Service $service, Customer $customer) { return !\is_null($customer->login($service->brand)); diff --git a/app/Policies/Rules/UserStaticRules.php b/app/Policies/Rules/UserStaticRules.php new file mode 100644 index 0000000..e68624c --- /dev/null +++ b/app/Policies/Rules/UserStaticRules.php @@ -0,0 +1,17 @@ +policies = [ + 'service' => [ + 'viewAny' => USR::make('everyOne'), + 'view' => USR::make('everyOne'), + 'update' => USR::make('everyOne'), + 'create' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Policies/SingleOptinPolicy.php b/app/Policies/SingleOptinPolicy.php new file mode 100644 index 0000000..a47161b --- /dev/null +++ b/app/Policies/SingleOptinPolicy.php @@ -0,0 +1,27 @@ +policies = [ + 'singleoptin' => [ + 'viewAny' => USR::make('everyOne'), + 'delete' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index df4b423..73af49a 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,7 +3,11 @@ namespace App\Providers; use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Pagination\Paginator; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\URL; +use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -31,5 +35,14 @@ class AppServiceProvider extends ServiceProvider if (!in_array(config('app.env'), ['local', 'testing'])) { URL::forceScheme('https'); } + + Paginator::useBootstrap(); + + $appInfos = Cache::remember('composer', 360, function () { + return json_decode(File::get(\app_path('../composer.json'))); + }); + View::share('name', $appInfos->name); + View::share('version', $appInfos->version); + View::share('license', $appInfos->license); } } diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index c0b3794..f57fef8 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -2,8 +2,11 @@ namespace App\Providers; +use App\Models\Brand; use App\Models\Customer; use App\Models\CustomerInfo; +use App\Models\Service; +use App\Models\SingleOptin; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; @@ -36,6 +39,10 @@ class RouteServiceProvider extends ServiceProvider Route::middleware('web')->namespace($this->namespace)->group(base_path('routes/web.php')); }); + Route::model('brand', Brand::class); + Route::model('service', Service::class); + Route::model('single_optin', SingleOptin::class); + Route::bind('customer', function ($value) { if (\ctype_digit($value)) { $customer = Customer::where('id', '=', $value)->firstOrFail(); diff --git a/clients/V2 b/clients/V2 index b208c78..14d966a 160000 --- a/clients/V2 +++ b/clients/V2 @@ -1 +1 @@ -Subproject commit b208c78b97e68c078345620a5a023186a1753ee8 +Subproject commit 14d966a62b297a299e0602e2b4bc5a3abff6cb56 diff --git a/composer.json b/composer.json index 15400c8..5fb6fdd 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "ldc/ldccrmv2client", "type": "project", - "version": "2.1.5", + "version": "2.1.6", "description": "LDC CRM V2", "authors": [ { @@ -32,11 +32,13 @@ "fideloper/proxy": "^4.4", "fruitcake/laravel-cors": "^2.0", "guzzlehttp/guzzle": "^7.0.1", + "kwaadpepper/crud-policies": "^0.1.15", "kwaadpepper/enum": "^2.0", "laravel-lang/lang": "~7.0", "laravel/framework": "^8.39", "laravel/tinker": "^2.5", - "rennokki/laravel-eloquent-query-cache": "^3.0" + "rennokki/laravel-eloquent-query-cache": "^3.0", + "spatie/laravel-mix-preload": "^1.2" }, "require-dev": { "facade/ignition": "^2.5", diff --git a/composer.lock b/composer.lock index da781a3..833ee21 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5b5341478a5d91d067fb818f97d244fd", + "content-hash": "d0eded9c5677a512f367b9d29c701714", "packages": [ { "name": "arondeparon/laravel-request-sanitizer", @@ -1171,6 +1171,124 @@ ], "time": "2020-12-29T14:50:06+00:00" }, + { + "name": "facade/flare-client-php", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/facade/flare-client-php.git", + "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/47b639dc02bcfdfc4ebb83de703856fa01e35f5f", + "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f", + "shasum": "" + }, + "require": { + "facade/ignition-contracts": "~1.0", + "illuminate/pipeline": "^5.5|^6.0|^7.0|^8.0", + "php": "^7.1|^8.0", + "symfony/http-foundation": "^3.3|^4.1|^5.0", + "symfony/mime": "^3.4|^4.0|^5.1", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "phpunit/phpunit": "^7.5.16", + "spatie/phpunit-snapshot-assertions": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Facade\\FlareClient\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Send PHP errors to Flare", + "homepage": "https://github.com/facade/flare-client-php", + "keywords": [ + "exception", + "facade", + "flare", + "reporting" + ], + "support": { + "issues": "https://github.com/facade/flare-client-php/issues", + "source": "https://github.com/facade/flare-client-php/tree/1.8.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2021-05-31T19:23:29+00:00" + }, + { + "name": "facade/ignition-contracts", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition-contracts.git", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v2.15.8", + "phpunit/phpunit": "^9.3.11", + "vimeo/psalm": "^3.17.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Facade\\IgnitionContracts\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://flareapp.io", + "role": "Developer" + } + ], + "description": "Solution contracts for Ignition", + "homepage": "https://github.com/facade/ignition-contracts", + "keywords": [ + "contracts", + "flare", + "ignition" + ], + "support": { + "issues": "https://github.com/facade/ignition-contracts/issues", + "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" + }, + "time": "2020-10-16T08:27:54+00:00" + }, { "name": "fideloper/proxy", "version": "4.4.1", @@ -1610,6 +1728,69 @@ }, "time": "2021-06-30T20:03:07+00:00" }, + { + "name": "kwaadpepper/crud-policies", + "version": "0.1.15", + "source": { + "type": "git", + "url": "https://github.com/Kwaadpepper/crud-policies.git", + "reference": "cf471dc2dad7851474ee005fbc8dfdfe05096b84" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Kwaadpepper/crud-policies/zipball/cf471dc2dad7851474ee005fbc8dfdfe05096b84", + "reference": "cf471dc2dad7851474ee005fbc8dfdfe05096b84", + "shasum": "" + }, + "require": { + "facade/flare-client-php": "^1.8", + "illuminate/support": "~7|~8", + "kwaadpepper/enum": "^2.0", + "laravel/framework": "~7|~8" + }, + "require-dev": { + "orchestra/testbench": "^6.13", + "phpunit/phpunit": "~9.0", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Kwaadpepper\\CrudPolicies\\Providers\\CrudPoliciesServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Kwaadpepper\\CrudPolicies\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérémy Munsch", + "email": "github@jeremydev.ovh", + "homepage": "https://jeremydev.ovh" + } + ], + "description": "Makes CRUD easy, make policies easy and everyone happy", + "homepage": "https://github.com/kwaadpepper/crud-policies", + "keywords": [ + "Scafolding", + "crud", + "laravel", + "policies" + ], + "support": { + "issues": "https://github.com/Kwaadpepper/crud-policies/issues", + "source": "https://github.com/Kwaadpepper/crud-policies/tree/0.1.15" + }, + "time": "2021-08-27T10:42:55+00:00" + }, { "name": "kwaadpepper/enum", "version": "2.0.0", @@ -3345,6 +3526,74 @@ ], "time": "2021-07-17T17:42:40+00:00" }, + { + "name": "spatie/laravel-mix-preload", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-mix-preload.git", + "reference": "b89dc366fa8a714ecb3d6af836db3c038795a3b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-mix-preload/zipball/b89dc366fa8a714ecb3d6af836db3c038795a3b6", + "reference": "b89dc366fa8a714ecb3d6af836db3c038795a3b6", + "shasum": "" + }, + "require": { + "illuminate/support": "^6.0|^7.0|^8.0", + "php": "^7.2.5|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.0|^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\MixPreload\\MixPreloadServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\MixPreload\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian De Deyne", + "email": "sebastian@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Add preload and prefetch links based your Mix manifest", + "homepage": "https://github.com/spatie/laravel-mix-preload", + "keywords": [ + "laravel-mix-preload", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-mix-preload/issues", + "source": "https://github.com/spatie/laravel-mix-preload/tree/1.2.2" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://www.patreon.com/spatie", + "type": "patreon" + } + ], + "time": "2021-01-04T08:01:50+00:00" + }, { "name": "swiftmailer/swiftmailer", "version": "v6.2.7", @@ -6081,71 +6330,6 @@ ], "time": "2020-11-10T18:47:58+00:00" }, - { - "name": "facade/flare-client-php", - "version": "1.8.1", - "source": { - "type": "git", - "url": "https://github.com/facade/flare-client-php.git", - "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/47b639dc02bcfdfc4ebb83de703856fa01e35f5f", - "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f", - "shasum": "" - }, - "require": { - "facade/ignition-contracts": "~1.0", - "illuminate/pipeline": "^5.5|^6.0|^7.0|^8.0", - "php": "^7.1|^8.0", - "symfony/http-foundation": "^3.3|^4.1|^5.0", - "symfony/mime": "^3.4|^4.0|^5.1", - "symfony/var-dumper": "^3.4|^4.0|^5.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "phpunit/phpunit": "^7.5.16", - "spatie/phpunit-snapshot-assertions": "^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Facade\\FlareClient\\": "src" - }, - "files": [ - "src/helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Send PHP errors to Flare", - "homepage": "https://github.com/facade/flare-client-php", - "keywords": [ - "exception", - "facade", - "flare", - "reporting" - ], - "support": { - "issues": "https://github.com/facade/flare-client-php/issues", - "source": "https://github.com/facade/flare-client-php/tree/1.8.1" - }, - "funding": [ - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2021-05-31T19:23:29+00:00" - }, { "name": "facade/ignition", "version": "2.12.0", @@ -6222,59 +6406,6 @@ }, "time": "2021-08-24T09:53:54+00:00" }, - { - "name": "facade/ignition-contracts", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/facade/ignition-contracts.git", - "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", - "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", - "shasum": "" - }, - "require": { - "php": "^7.3|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^v2.15.8", - "phpunit/phpunit": "^9.3.11", - "vimeo/psalm": "^3.17.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Facade\\IgnitionContracts\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://flareapp.io", - "role": "Developer" - } - ], - "description": "Solution contracts for Ignition", - "homepage": "https://github.com/facade/ignition-contracts", - "keywords": [ - "contracts", - "flare", - "ignition" - ], - "support": { - "issues": "https://github.com/facade/ignition-contracts/issues", - "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" - }, - "time": "2020-10-16T08:27:54+00:00" - }, { "name": "fakerphp/faker", "version": "v1.15.0", diff --git a/config/app.php b/config/app.php index 5bdde92..5f50516 100644 --- a/config/app.php +++ b/config/app.php @@ -227,7 +227,9 @@ return [ 'View' => Illuminate\Support\Facades\View::class, 'Carbon' => Illuminate\Support\Carbon::class, 'ArcadiaMailType' => App\Enums\ArcadiaMailType::class, - 'ArcadiaOrderType' => App\Enums\ArcadiaOrderType::class + 'ArcadiaOrderType' => App\Enums\ArcadiaOrderType::class, + 'Brand' => App\Models\Brand::class, + 'Customer' => App\Models\Customer::class ], ]; diff --git a/package.json b/package.json index e329706..5df4967 100644 --- a/package.json +++ b/package.json @@ -2,28 +2,27 @@ "private": true, "scripts": { "dev": "npm run development", - "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js", - "watch": "npm run development -- --watch", - "watch-poll": "npm run watch -- --watch-poll", - "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --disable-host-check --config=node_modules/laravel-mix/setup/webpack.config.js", + "development": "mix", + "watch": "mix watch", + "watch-poll": "mix watch -- --watch-options-poll=1000", + "hot": "mix watch --hot", "prod": "npm run production", - "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js" + "production": "mix --production" }, "devDependencies": { - "axios": "^0.19", - "bootstrap": "^4.5.0", - "cross-env": "^7.0", - "jquery": "^3.2", - "laravel-mix": "^5.0.1", - "lodash": "^4.17.19", - "popper.js": "^1.12", - "resolve-url-loader": "^3.1.0", - "sass-loader": "^8.0.2", - "vue-template-compiler": "^2.6.12" - }, - "dependencies": { + "axios": "^0.21", + "clean-webpack-plugin": "^4.0.0-alpha.0", + "laravel-mix": "^6.0.6", + "laravel-mix-polyfill": "^3.0.0", "moment": "^2.29.1", - "sass": "^1.28.0", - "vue": "^2.6.12" + "postcss": "^8.1.14", + "postcss-discard-comments": "^4.0.2", + "resolve-url-loader": "^3.1.3", + "sass": "^1.32.11", + "sass-loader": "^11.0.1", + "swiper": "^6.6.1", + "vue": "^2.6.12", + "vue-loader": "^15.9.6", + "vue-template-compiler": "^2.6.12" } } diff --git a/public/js/app.js.LICENSE.txt b/public/js/app.js.LICENSE.txt deleted file mode 100644 index 953a26d..0000000 --- a/public/js/app.js.LICENSE.txt +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * Vue.js v2.6.12 - * (c) 2014-2020 Evan You - * Released under the MIT License. - */ - -/** - * @license - * Lodash - * Copyright OpenJS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ - -//! moment.js - -//! moment.js locale configuration diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 2d60117..6784ee9 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,4 +1,4 @@ { - "/js/app.js": "/js/app.js", - "/css/app.css": "/css/app.css" + "/js/preload-back.js": "/js/preload-back.js", + "/css/preload-back.css": "/css/preload-back.css" } diff --git a/public/images/logo_ldc.png b/resources/assets/images/logo_ldc.png similarity index 100% rename from public/images/logo_ldc.png rename to resources/assets/images/logo_ldc.png diff --git a/resources/js/Components/SearchOptin.vue b/resources/js/Components/SearchOptin.vue deleted file mode 100644 index 62c361b..0000000 --- a/resources/js/Components/SearchOptin.vue +++ /dev/null @@ -1,101 +0,0 @@ - - - diff --git a/resources/js/Components/SearchUser.vue b/resources/js/Components/SearchUser.vue deleted file mode 100644 index 2aa9470..0000000 --- a/resources/js/Components/SearchUser.vue +++ /dev/null @@ -1,87 +0,0 @@ - - - diff --git a/resources/js/app.js b/resources/js/app.js deleted file mode 100644 index 4c6aeb6..0000000 --- a/resources/js/app.js +++ /dev/null @@ -1,17 +0,0 @@ -require('./bootstrap'); -import moment from 'moment'; - -window.Vue = require('vue'); - -Vue.filter('formatDate', function(value) { - if (value) { - return moment(String(value)).format('DD/MM/YYYY H:mm') - } -}); - -Vue.component('search-user', require('./Components/SearchUser.vue').default); -Vue.component('search-optin', require('./Components/SearchOptin.vue').default); - -const app = new Vue({ - el: '#app', -}); diff --git a/resources/js/back.js b/resources/js/back.js new file mode 100644 index 0000000..7c36abb --- /dev/null +++ b/resources/js/back.js @@ -0,0 +1,5 @@ +require('./bootstrap'); + +require('./pages/customer.delete') +require('./pages/service.index') +require('./pages/single_optin.index') diff --git a/resources/js/pages/customer.delete.js b/resources/js/pages/customer.delete.js new file mode 100644 index 0000000..565824d --- /dev/null +++ b/resources/js/pages/customer.delete.js @@ -0,0 +1,34 @@ +let customerDelete = document.getElementById('customerDelete'); + +if (customerDelete) { + customerDelete.addEventListener('submit', (e) => { + let self = e.target + e.preventDefault() + Swal.fire({ + title: 'Supprimer ce client pour cette marque ?', + text: 'Attention cette action est irréversible, si le client n\'appartient plus à aucune marque il sera complètement retiré des bases', + icon: 'warning', + confirmButtonText: 'Je comprends le danger et suis conscient de ce que je fait', + showCancelButton: true, + cancelButtonText: 'Annuler', + confirmButtonColor: '#dc3545' + }).then((result) => { + if (result.isConfirmed) { + Swal.fire({ + title: 'Attention au conséquences', + html: 'La supression de ce compte dans la crm n\'entrainera pas ça supression dans MESBR ni dans le front cache DB (pour les sites WPCRM).

Une fois ne compte supprimé je ne pourrai plus récupérer le hashcode nécessaire pour effectuer ces opérations.

', + icon: 'info', + confirmButtonText: 'Je comprends le danger et suis conscient que celà aura des conséquences', + showCancelButton: true, + cancelButtonText: 'Annuler', + confirmButtonColor: '#dc3545' + }).then((result) => { + if (result.isConfirmed) { + self.submit() + } + }) + } + }) + }) +} + diff --git a/resources/js/pages/service.index.js b/resources/js/pages/service.index.js new file mode 100644 index 0000000..61a816d --- /dev/null +++ b/resources/js/pages/service.index.js @@ -0,0 +1,36 @@ +let genForms = document.getElementsByClassName('genToken'); + +if (genForms.length) { + for (let form of genForms) { + form.addEventListener('submit', (e) => { + let self = e.target + e.preventDefault() + Swal.fire({ + title: 'Regénérer un token ?', + text: 'Attention la regeneration empêchera le service de fonctionner tant que son token n\'aura pas été mis à jour', + icon: 'warning', + confirmButtonText: 'Je comprends le danger et suis conscient de ce que je fait', + showCancelButton: true, + cancelButtonText: 'Annuler', + confirmButtonColor: '#dc3545' + }).then((result) => { + if (result.isConfirmed) { + Swal.fire({ + title: 'Vous allez régénérer un token de service en production', + html: '

Je suis conscient que celà va avoir des implications et qu\'il me faudra mettre à jour le bearer token du service concerné dans son envirronement actuel

', + icon: 'info', + confirmButtonText: 'Oui, feu patate !!', + showCancelButton: true, + cancelButtonText: 'Annuler', + confirmButtonColor: '#dc3545' + }).then((result) => { + if (result.isConfirmed) { + self.submit() + } + }) + } + }) + }) + } +} + diff --git a/resources/js/pages/single_optin.index.js b/resources/js/pages/single_optin.index.js new file mode 100644 index 0000000..112407f --- /dev/null +++ b/resources/js/pages/single_optin.index.js @@ -0,0 +1,10 @@ +let brandSelect = document.getElementById('brandSelect'); +if (brandSelect) { + brandSelect.addEventListener('change', function (e) { + if (brandSelect.value !== '0') { + const url = new URL(location.href); + url.searchParams.set('brand', brandSelect.value); + location.assign(url.search); + } + }); +} diff --git a/resources/lang/en/models.php b/resources/lang/en/models.php new file mode 100644 index 0000000..4ad236d --- /dev/null +++ b/resources/lang/en/models.php @@ -0,0 +1,20 @@ + [ + 'services' => 'Services', + 'brands' => 'Brands', + 'customers' => 'Customers', + 'singleoptins' => 'Single Opt-ins' + ], + 'common' => [ + 'title' => 'Title', + 'name' => 'Name', + 'content' => 'Content', + 'visibility' => 'Visibility', + 'published' => 'Published', + 'group' => 'Group', + 'default' => 'Default', + 'optinDate' => 'Date opt-in' + ] +]; diff --git a/resources/lang/fr/models.php b/resources/lang/fr/models.php new file mode 100644 index 0000000..ddb1fee --- /dev/null +++ b/resources/lang/fr/models.php @@ -0,0 +1,20 @@ + [ + 'services' => 'Services', + 'brands' => 'Marques', + 'customers' => 'Clients', + 'singleoptins' => 'Opt-ins uniques' + ], + 'common' => [ + 'title' => 'Titre', + 'name' => 'Nom', + 'content' => 'Contenu', + 'visibility' => 'Visibilitée', + 'published' => 'Publié', + 'group' => 'Groupe', + 'default' => 'Par défaut', + 'optinDate' => 'Date opt-in' + ] +]; diff --git a/resources/sass/_dashboard.scss b/resources/sass/_dashboard.scss deleted file mode 100644 index 0a6abdb..0000000 --- a/resources/sass/_dashboard.scss +++ /dev/null @@ -1,103 +0,0 @@ -body { - font-size: .875rem; -} - -.feather { - width: 16px; - height: 16px; - vertical-align: text-bottom; -} - -/* - * Sidebar - */ - -.sidebar { - position: fixed; - top: 0; - bottom: 0; - left: 0; - z-index: 100; /* Behind the navbar */ - padding: 48px 0 0; /* Height of navbar */ - box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); -} - -@media (max-width: 767.98px) { - .sidebar { - top: 5rem; - } -} - -.sidebar-sticky { - position: relative; - top: 0; - height: calc(100vh - 48px); - padding-top: .5rem; - overflow-x: hidden; - overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ -} - -@supports ((position: -webkit-sticky) or (position: sticky)) { - .sidebar-sticky { - position: -webkit-sticky; - position: sticky; - } -} - -.sidebar .nav-link { - font-weight: 500; - color: #333; -} - -.sidebar .nav-link .feather { - margin-right: 4px; - color: #999; -} - -.sidebar .nav-link.active { - color: #007bff; -} - -.sidebar .nav-link:hover .feather, -.sidebar .nav-link.active .feather { - color: inherit; -} - -.sidebar-heading { - font-size: .75rem; - text-transform: uppercase; -} - -/* - * Navbar - */ - -.navbar-brand { - padding-top: .75rem; - padding-bottom: .75rem; - font-size: 1rem; - background-color: rgba(0, 0, 0, .25); - box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); -} - -.navbar .navbar-toggler { - top: .25rem; - right: 1rem; -} - -.navbar .form-control { - padding: .75rem 1rem; - border-width: 0; - border-radius: 0; -} - -.form-control-dark { - color: #fff; - background-color: rgba(255, 255, 255, .1); - border-color: rgba(255, 255, 255, .1); -} - -.form-control-dark:focus { - border-color: transparent; - box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); -} diff --git a/resources/sass/_layout.scss b/resources/sass/_layout.scss new file mode 100644 index 0000000..4b2e2f3 --- /dev/null +++ b/resources/sass/_layout.scss @@ -0,0 +1,17 @@ +.bodyFull { + margin: 0 !important; + padding: 0 !important; + min-height: calc(100vh - #{$navBarHeight} - #{$footerHeight}); +} + +#app { + & > .navbar { + height: $navBarHeight; + } + #footer { + height: $footerHeight; + padding: 0 !important; + color: $body-bg; + background-color: $footerBgColor; + } +} diff --git a/resources/sass/_variables.scss b/resources/sass/_variables.scss index 5af6218..b5d70bc 100644 --- a/resources/sass/_variables.scss +++ b/resources/sass/_variables.scss @@ -22,3 +22,7 @@ $theme-colors: ( "primary": #3176C4, "secondary": #E7374B ); + +$navBarHeight: 4rem; +$footerHeight: 3rem; +$footerBgColor: #161616; diff --git a/resources/sass/app.scss b/resources/sass/app.scss deleted file mode 100644 index 71428e3..0000000 --- a/resources/sass/app.scss +++ /dev/null @@ -1,10 +0,0 @@ -// Fonts -@import url('https://fonts.googleapis.com/css?family=Nunito'); - -// Variables -@import 'variables'; - -// Bootstrap -@import '~bootstrap/scss/bootstrap'; - -@import "dashboard"; diff --git a/resources/sass/back.scss b/resources/sass/back.scss new file mode 100644 index 0000000..55e4403 --- /dev/null +++ b/resources/sass/back.scss @@ -0,0 +1,5 @@ +// Variables +@import 'variables'; +@import 'layout'; + +@import "pages/login"; diff --git a/resources/sass/pages/login.scss b/resources/sass/pages/login.scss new file mode 100644 index 0000000..79f3d3c --- /dev/null +++ b/resources/sass/pages/login.scss @@ -0,0 +1,54 @@ +.bd-placeholder-img { + font-size: 1.125rem; + text-anchor: middle; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +@media (min-width: 768px) { + .bd-placeholder-img-lg { + font-size: 3.5rem; + } +} +div.login { + height: 100%; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding-top: 40px; + padding-bottom: 40px; + background-color: #f5f5f5; +} + +.form-signin { + width: 100%; + max-width: 330px; + padding: 15px; + margin: auto; +} +.form-signin .checkbox { + font-weight: 400; +} +.form-signin .form-control { + position: relative; + box-sizing: border-box; + height: auto; + padding: 10px; + font-size: 16px; +} +.form-signin .form-control:focus { + z-index: 2; +} +.form-signin input[type="email"] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.form-signin input[type="password"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} diff --git a/resources/views/brand/index.blade.php b/resources/views/brand/index.blade.php new file mode 100644 index 0000000..5d0906c --- /dev/null +++ b/resources/views/brand/index.blade.php @@ -0,0 +1,158 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ + + + @foreach ($modelClass::getEditableProperties() as $colname => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + + + + + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- INFO COLS --}} + + + + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ {{ $prop['label'] }} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + {{ __('Nombre de comptes')}} + + {{ __('Nombre d\'optins')}} + + {{ __('Date d\'ajout en base')}} + + @if(session("crud.$modelTable.sort_way") and session("crud.$modelTable.sort_col")) + ⌫ + @endif +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]){{ $model->getAccountsAttribute() }}{{ $model->getTotalOptinsAttribute() }}{{ $model->created_at->format('m/d/Y à H:i') }} +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan + @can('viewAny', \App\Models\Log::class) + {{ __('Journaux') }} + @endcan + @can('viewAny', \App\Models\File::class) + {{ __('Fichiers') }} + @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/brands/index.blade.php b/resources/views/brands/index.blade.php deleted file mode 100644 index 1c63dbd..0000000 --- a/resources/views/brands/index.blade.php +++ /dev/null @@ -1,28 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

{{ __('Gestion des marques') }} {{ __('Liste') }}

- {{ __('Ajouter') }} -
- - - - - - - - - - @foreach ($brands as $brand) - - - - - - - - @endforeach - -
{{ __('Nom de la marque') }}{{ __('Nombre de comptes') }}{{ __('Nombre d\'optins') }}{{ __('Date d\'ajout en base') }}
{{ $brand->name }}{{ $brand->accounts }}{{ $brand->total_optins }}{{ Carbon::parse($brand->created_at)->format('d/m/Y à H:i') }}{{ __('Modifier') }}
-@endsection diff --git a/resources/views/brands/manage.blade.php b/resources/views/brands/manage.blade.php deleted file mode 100644 index 036e0f0..0000000 --- a/resources/views/brands/manage.blade.php +++ /dev/null @@ -1,30 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

{{ __('Gestion des marques') }} {{ __('Gestion') }}

- @if ($errors->any()) -
    - @foreach(session('errors')->all(':message') as $error) -
  • {{ $error }}
  • - @endforeach -
- @endif - @if (session('success')) - {!! session('success') !!} - @endif - {{ __('Retour') }} -
-
-
- @csrf -
- - -
-
- -
-
-
-@endsection diff --git a/resources/views/customer/index-tableHeaders.blade.php b/resources/views/customer/index-tableHeaders.blade.php new file mode 100644 index 0000000..56cf8c8 --- /dev/null +++ b/resources/views/customer/index-tableHeaders.blade.php @@ -0,0 +1,63 @@ + + @php $colname = 'email' @endphp + {{ __('Email')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'lastname' @endphp + {{ __('Nom')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'firstname' @endphp + {{ __('Prénom')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'optin' @endphp + {{ __('Opt-In')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'brand_id' @endphp + {{ __('Marque')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'status' @endphp + {{ __('Activé ?')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + {{ __('Voir')}} + diff --git a/resources/views/customer/index.blade.php b/resources/views/customer/index.blade.php new file mode 100644 index 0000000..80c2959 --- /dev/null +++ b/resources/views/customer/index.blade.php @@ -0,0 +1,104 @@ +@extends('layouts.app') + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ + + + @include('customer.index-tableHeaders') + + + + + @if(count($customers)) + + {{-- DISPLAY MODELS --}} + @foreach($customers as $customerInfo) + + + + + + + + + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ @if(session("crud.$modelTable.sort_way") and session("crud.$modelTable.sort_col")) + ⌫ + @endif +
+ {{ $customerInfo->customer->email }} + + {{ $customerInfo->firstname }} + + {{ $customerInfo->lastname }} + + {{ $customerInfo->optin ? 'Oui' :'Non' }} + + {{ $customerInfo->brand->name }} + + {{ $customerInfo->login()->status ? 'Oui' :'Non' }} + + +
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $customers->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/customer/show.blade.php b/resources/views/customer/show.blade.php new file mode 100644 index 0000000..0b12f77 --- /dev/null +++ b/resources/views/customer/show.blade.php @@ -0,0 +1,113 @@ +@extends('layouts.app') + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ +
+
+
+
+
+

{{ __('Informations du client') }} {{ $customerInfos->firstname }} {{ $customerInfos->lastname }} - {{ Str::singular(__('models.classes.brands')) }} {{ $customerInfos->brand->name }}

+ Retour +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @if($customerInfos->customer->optInHistory()->orderBy('created_at', 'DESC')->exists()) + + @else + + @endif + + + + + + + + + + + + + + + + + + + + + + +
{{ __('Email') }}{{ $customerInfos->customer->email }}
Prénom{{ $customerInfos->firstname }}
Nom{{ $customerInfos->lastname }}
Date de naissance{{ \Carbon\Carbon::parse($customerInfos->birth_date)->format('d/m/Y') }}
Téléphone{{ $customerInfos->phone }}
Adresse{{ $customerInfos->address }}
Adresse complémentaire{{ $customerInfos->address2 }}
Pays{{ $customerInfos->country }}
Ville{{ $customerInfos->city }}
Code postal{{ $customerInfos->postcode }}
Abonné à la newsletter{{ $customerInfos->opt_in === 1 ? "Oui" : "Non" }}
Date de la dernière modification de l'abonnement{{ \Carbon\Carbon::parse($customerInfos->customer->optInHistory()->orderBy('created_at', 'DESC')->first()->created_at)->format('d/m/Y à H:i') }}
Dernière connexion{{ \Carbon\Carbon::parse($customerLogin->last_connection)->format('d/m/Y à H:i') }}
Status du compte{{ $customerLogin->status === 1 ? "Activé" : "Non activé" }}
Hashcode{{ $customerInfos->hashcode }}
Date de création{{ \Carbon\Carbon::parse($customerInfos->created_at)->format('d/m/Y à H:i') }}
Date de modification{{ \Carbon\Carbon::parse($customerInfos->updated_at)->format('d/m/Y à H:i') }}
+
+ @csrf + @method('DELETE') + +
+
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/customers/index.blade.php b/resources/views/customers/index.blade.php deleted file mode 100644 index ba4ad56..0000000 --- a/resources/views/customers/index.blade.php +++ /dev/null @@ -1,23 +0,0 @@ -@extends('layout.app') - -@section('content') -@if (session()->has('success')) -
-
-

{{ session()->get('success') }}

-
-
-@endif -@if ($errors->any()) -
-
-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
-
-@endif - -@endsection diff --git a/resources/views/customers/show.blade.php b/resources/views/customers/show.blade.php deleted file mode 100644 index 2005343..0000000 --- a/resources/views/customers/show.blade.php +++ /dev/null @@ -1,98 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

Informations du client {{ $customerInfos->firstname }} {{ $customerInfos->lastname }} - Marque {{ $customerInfos->brand->name }}

- Retour -
- @if ($errors->any()) -
-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @if($customerInfos->customer->optInHistory()->orderBy('created_at', 'DESC')->exists()) - - @else - - @endif - - - - - - - - - - - - - - - - - - - - - - -
Email{{ $customerInfos->customer->email }}
Prénom{{ $customerInfos->firstname }}
Nom{{ $customerInfos->lastname }}
Date de naissance{{ \Carbon\Carbon::parse($customerInfos->birth_date)->format('d/m/Y') }}
Téléphone{{ $customerInfos->phone }}
Adresse{{ $customerInfos->address }}
Adresse complémentaire{{ $customerInfos->address2 }}
Pays{{ $customerInfos->country }}
Ville{{ $customerInfos->city }}
Code postal{{ $customerInfos->postcode }}
Abonné à la newsletter{{ $customerInfos->opt_in === 1 ? "Oui" : "Non" }}
Date de la dernière modification de l'abonnement{{ \Carbon\Carbon::parse($customerInfos->customer->optInHistory()->orderBy('created_at', 'DESC')->first()->created_at)->format('d/m/Y à H:i') }}
Dernière connexion{{ \Carbon\Carbon::parse($customerLogin->last_connection)->format('d/m/Y à H:i') }}
Status du compte{{ $customerLogin->status === 1 ? "Activé" : "Non activé" }}
Hashcode{{ $customerInfos->hashcode }}
Date de création{{ \Carbon\Carbon::parse($customerInfos->created_at)->format('d/m/Y à H:i') }}
Date de modification{{ \Carbon\Carbon::parse($customerInfos->updated_at)->format('d/m/Y à H:i') }}
-
- @csrf - @method('DELETE') - -
-@endsection diff --git a/resources/views/layout/app.blade.php b/resources/views/layout/app.blade.php deleted file mode 100644 index 84fe32e..0000000 --- a/resources/views/layout/app.blade.php +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - Tableau de bord - - - - - - -
- - -
-
- - -
- @yield('content') -
-
-
-
- - @yield('scripts') - - diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..c93ef72 --- /dev/null +++ b/resources/views/layouts/app.blade.php @@ -0,0 +1,35 @@ + + + + @include('layouts.backend.head') + @stack('styles') + @crudPoliciesCSS() + + +
+ @include('layouts.backend.navbar') +
+
+ @if(isset($modelsClasses)) + @include('layouts.backend.sidenav') +
+ @else +
+ @endif + @yield('content') +
+
+
+ @include('layouts.backend.footer') +
+
+
+ @stack('scriptsConstants') + @include('crud-policies::crud.modules.scriptConstants') + + + + @crudPoliciesJS() + @stack('scripts') + + diff --git a/resources/views/layouts/backend/footer.blade.php b/resources/views/layouts/backend/footer.blade.php new file mode 100644 index 0000000..9a24737 --- /dev/null +++ b/resources/views/layouts/backend/footer.blade.php @@ -0,0 +1,10 @@ +
+
+ {{ $license }} + - + {{ $name }} - {{ $version }} + - + LDC Web Services + © {{ date('Y') }} +
+
diff --git a/resources/views/layouts/backend/head.blade.php b/resources/views/layouts/backend/head.blade.php new file mode 100644 index 0000000..668513b --- /dev/null +++ b/resources/views/layouts/backend/head.blade.php @@ -0,0 +1,32 @@ + + + +{{ config('app.name') }}@hasSection('title') - @yield('title')@endif + + + +@hasSection('canonical') + +@else + +@endif + + +@hasSection('metaIndex') + +@else + +@endif + + +{{-- + + + --}} + +@preload('mix-manifest.json') + + + + + diff --git a/resources/views/layouts/backend/navbar.blade.php b/resources/views/layouts/backend/navbar.blade.php new file mode 100644 index 0000000..177643a --- /dev/null +++ b/resources/views/layouts/backend/navbar.blade.php @@ -0,0 +1,15 @@ + diff --git a/resources/views/layouts/backend/sidenav.blade.php b/resources/views/layouts/backend/sidenav.blade.php new file mode 100644 index 0000000..0698851 --- /dev/null +++ b/resources/views/layouts/backend/sidenav.blade.php @@ -0,0 +1,90 @@ + +{{-- --}} diff --git a/resources/views/login.blade.php b/resources/views/login.blade.php index 2b35965..1c3d682 100644 --- a/resources/views/login.blade.php +++ b/resources/views/login.blade.php @@ -1,78 +1,10 @@ - - - - - - Tableau de bord +@extends('layouts.app') - - - - - - +@section('content') + +@endsection diff --git a/resources/views/service/index.blade.php b/resources/views/service/index.blade.php new file mode 100644 index 0000000..f400938 --- /dev/null +++ b/resources/views/service/index.blade.php @@ -0,0 +1,158 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ + + + @foreach ($modelClass::getEditableProperties() as $colname => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + + + + + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- INFO COLS --}} + + + + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ {{ $prop['label'] }} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + {{ __('Date du Bearer token')}} + + {{ __('Régénerer un token')}} + + {{ __('Date de création')}} + + @if(session("crud.$modelTable.sort_way") and session("crud.$modelTable.sort_col")) + ⌫ + @endif +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]){{ Carbon::parse($model->bearer_token_date)->format('m/d/Y à H:i') }}
@csrf
{{ $model->created_at->format('m/d/Y à H:i') }} +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan + @can('viewAny', \App\Models\Log::class) + {{ __('Journaux') }} + @endcan + @can('viewAny', \App\Models\File::class) + {{ __('Fichiers') }} + @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/services/index.blade.php b/resources/views/services/index.blade.php deleted file mode 100644 index 372f0de..0000000 --- a/resources/views/services/index.blade.php +++ /dev/null @@ -1,36 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

{{ __('Gestion des services') }} {{ __('Liste') }}

- @if (session('success')) - {!! session('success') !!} - @endif - @if (session('error')) - {!! session('error') !!} - @endif - {{ __('Ajouter') }} -
- - - - - - - - - - - @foreach ($services as $service) - - - - - - - - - @endforeach - -
{{ __('Nom') }}{{ __('Marque') }}{{ __('Date du token') }}{{ __('Regénérer un token') }}{{ __('Date de création') }}
{{ $service->name }}{{ $service->brand->name }}{{ Carbon::parse($service->bearer_token_date)->format('d/m/Y à H:i') }}{{ __('Générer') }}{{ Carbon::parse($service->created_at)->format('d/m/Y à H:i') }}{{ __('Modifier') }}
-@endsection diff --git a/resources/views/services/manage.blade.php b/resources/views/services/manage.blade.php deleted file mode 100644 index f888168..0000000 --- a/resources/views/services/manage.blade.php +++ /dev/null @@ -1,42 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

{{ __('Gestion des services') }} {{ __('Gestion') }}

- @if ($errors->any()) -
    - @foreach(session('errors')->all(':message') as $error) -
  • {{ $error }}
  • - @endforeach -
- @endif - @if (session('success')) - {!! session('success') !!} - @endif - {{ __('Retour') }} -
-
-
- @csrf -
- - -
- @if (!$edit) -
- - -
- @else - - @endif -
- -
-
-
-@endsection diff --git a/resources/views/single-optins/index.blade.php b/resources/views/single-optins/index.blade.php deleted file mode 100644 index df1e97a..0000000 --- a/resources/views/single-optins/index.blade.php +++ /dev/null @@ -1,5 +0,0 @@ -@extends('layout.app') - -@section('content') - -@endsection diff --git a/resources/views/single_optin/index.blade.php b/resources/views/single_optin/index.blade.php new file mode 100644 index 0000000..2d0c900 --- /dev/null +++ b/resources/views/single_optin/index.blade.php @@ -0,0 +1,121 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ + + @include('crud-policies::crud.modules.sorter') + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]) +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/routes/web.php b/routes/web.php index 55b9237..f5dc6bc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -4,7 +4,7 @@ use App\Http\Controllers\BrandController; use App\Http\Controllers\CustomerController; use App\Http\Controllers\LoginController; use App\Http\Controllers\ServiceController; -use App\Http\Controllers\SingleOptinsController; +use App\Http\Controllers\SingleOptinController; use Illuminate\Support\Facades\Route; /* @@ -22,30 +22,32 @@ Route::get('/login', [LoginController::class, 'index'])->name('login'); Route::post('/login', [LoginController::class, 'authenticate'])->name('authenticate'); Route::middleware(['auth'])->group(function () { Route::get('/', function () { - return redirect()->route('customers'); - }); - Route::get('/logout', [LoginController::class, 'logout'])->name('logout'); + return redirect()->route('brands.index'); + })->name('home'); + Route::post('/logout', [LoginController::class, 'logout'])->name('logout'); // Marques - Route::get('/brands', [BrandController::class, 'index'])->name('brands'); - Route::match(['get', 'post'], '/brand/manage/{brand?}', [BrandController::class, 'manage'])->name('manage-brand'); + Route::resource('brands', BrandController::class)->except([ + 'delete' + ]); + Route::match(['get', 'post'], '/brand/manage/{brand?}', [BrandController::class, 'manage']) + ->name('manage-brand'); // Services - Route::get('/services', [ServiceController::class, 'index'])->name('services'); - Route::match(['get', 'post'], '/service/manage/{service?}', [ServiceController::class, 'manage']) - ->name('manage-service'); - Route::get('/services/{service}/token/generate', [ServiceController::class, 'generateApiToken']) + Route::resource('services', ServiceController::class)->except([ + 'delete' + ]); + Route::post('/services/{service}/token/generate', [ServiceController::class, 'generateApiToken']) ->name('generate-token-service'); // Clients - Route::get('/customers', [CustomerController::class, 'index'])->name('customers'); - Route::get('/customers/filter/{texte}/{brand?}', [CustomerController::class, 'filter'])->name('filter-customer'); - Route::get('/customer/{customer}/{brand}', [CustomerController::class, 'show'])->name('show-customer'); - Route::delete('/customer/{customer}/{brand}', [CustomerController::class, 'delete'])->name('customers.delete'); + Route::get('/customers', [CustomerController::class, 'index'])->name('customers.index'); + Route::get('/customers/{customer}/{brand}', [CustomerController::class, 'show'])->name('customers.show'); + Route::delete('/customers/{customer}/{brand}', [CustomerController::class, 'delete'])->name('customers.delete'); // Single optins - Route::get('/single-optins', [SingleOptinsController::class, 'index'])->name('single-optins'); - Route::get('/single-optins/filter/{texte}/{brandId?}', [SingleOptinsController::class, 'filter']) + Route::resource('single_optins', SingleOptinController::class); + Route::get('/single_optins/filter/{texte}/{brandId?}', [SingleOptinController::class, 'filter']) ->name('filter-single-optins'); - Route::post('/single-optins/{id}/delete', [SingleOptinsController::class, 'delete'])->name('single-optins-delete'); + Route::post('/single_optins/{id}/delete', [SingleOptinController::class, 'delete'])->name('single-optins-delete'); }); diff --git a/webpack.mix.js b/webpack.mix.js index 434769a..ae418f1 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -1,15 +1,49 @@ +const path = require('path'); const mix = require('laravel-mix'); +const { CleanWebpackPlugin } = require('clean-webpack-plugin'); +require('laravel-mix-polyfill'); -/* - |-------------------------------------------------------------------------- - | Mix Asset Management - |-------------------------------------------------------------------------- - | - | Mix provides a clean, fluent API for defining some Webpack build steps - | for your Laravel applications. By default, we are compiling the CSS - | file for the application as well as bundling up all the JS files. - | - */ +mix.webpackConfig({ + resolve: { + alias: { + '@': path.resolve('resources/assets') + } + }, + plugins: [ + new CleanWebpackPlugin({ + cleanOnceBeforeBuildPatterns: [ + 'css/*', + 'js/*', + 'images/*', + 'fonts/*', + 'assets/*' + ] + }) + ], +}); -mix.js('resources/js/app.js', 'public/js') - .sass('resources/sass/app.scss', 'public/css'); +let assetDir = 'assets'; +mix.options({ + fileLoaderDirs: { + images: `${assetDir}/images`, + fonts: `${assetDir}/fonts` + }, + postCss: [ + require('postcss-discard-comments')({ + removeAll: true + }) + ] +}); + +// mix Backend +mix.js("resources/js/back.js", "public/js/preload-back.js") + .sass("resources/sass/back.scss", "public/css/preload-back.css") + // .vue() + .polyfill({ + enabled: true, + useBuiltIns: "usage", + targets: { "firefox": "50", "ie": 11 } + }); + +// Copy Blade Images Assets +mix.copyDirectory('resources/assets', 'public/assets'); From de25ed732ce66fcbb99af8700cff98367dae82d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Wed, 8 Sep 2021 17:14:39 +0200 Subject: [PATCH 03/19] Mail alert on service token generate from BO --- app/Http/Controllers/ServiceController.php | 9 ++- app/Http/Requests/GenerateApiToken.php | 30 ++++++++++ app/Mail/ServiceCredentialRenewed.php | 55 +++++++++++++++++++ .../mail/service-renewed-plain.blade.php | 8 +++ .../views/mail/service-renewed.blade.php | 13 +++++ 5 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 app/Http/Requests/GenerateApiToken.php create mode 100644 app/Mail/ServiceCredentialRenewed.php create mode 100644 resources/views/mail/service-renewed-plain.blade.php create mode 100644 resources/views/mail/service-renewed.blade.php diff --git a/app/Http/Controllers/ServiceController.php b/app/Http/Controllers/ServiceController.php index ac752ed..98cdcff 100644 --- a/app/Http/Controllers/ServiceController.php +++ b/app/Http/Controllers/ServiceController.php @@ -2,7 +2,10 @@ 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; @@ -27,11 +30,15 @@ class ServiceController extends Controller return view('service.index', $view->getData()); } - public function generateApiToken(Service $service) + // 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'"); diff --git a/app/Http/Requests/GenerateApiToken.php b/app/Http/Requests/GenerateApiToken.php new file mode 100644 index 0000000..cecfde4 --- /dev/null +++ b/app/Http/Requests/GenerateApiToken.php @@ -0,0 +1,30 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + // + ]; + } +} diff --git a/app/Mail/ServiceCredentialRenewed.php b/app/Mail/ServiceCredentialRenewed.php new file mode 100644 index 0000000..5a32473 --- /dev/null +++ b/app/Mail/ServiceCredentialRenewed.php @@ -0,0 +1,55 @@ +service = $service; + $this->user = $user; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('mail.service-renewed') + ->subject('!!! Warning !!!, New service credential have been generated !') + ->text('mail.service-renewed-plain') + ->with('appName', config('app.name')) + ->with('service', $this->service) + ->with('by', sprintf('%s %s (%s)', $this->user->firstname, $this->user->lastname, $this->user->email)) + ->to( + config('mail.contactsList.serviceweb', 'equipe.web@ldc.fr'), + sprintf('%s service warning', config('app.name')) + ); + } +} diff --git a/resources/views/mail/service-renewed-plain.blade.php b/resources/views/mail/service-renewed-plain.blade.php new file mode 100644 index 0000000..b3b0c69 --- /dev/null +++ b/resources/views/mail/service-renewed-plain.blade.php @@ -0,0 +1,8 @@ + +{{ config('app.name') }} Service Warning + +Un service vient d'être régénéré sur {{ $appName }} +{{ $service->name }} (marque : {{ $service->brand->name }}) +Régénéré le {{ $service->updated_at->format('D/m/Y H:i') }} +par {{ $by }} +Celà va empêcher le service de fonctionner tant que les crédentials d'api n'auront pas été mis à jour sur le service concerné, veuillez faire au plus vite ! diff --git a/resources/views/mail/service-renewed.blade.php b/resources/views/mail/service-renewed.blade.php new file mode 100644 index 0000000..31a1180 --- /dev/null +++ b/resources/views/mail/service-renewed.blade.php @@ -0,0 +1,13 @@ + + + + {{ config('app.name') }} Service Warning + + + +

Un service vient d'être régénéré sur {{ $appName }}

+

{{ $service->name }} (marque : {{ $service->brand->name }})

+

Régénéré le {{ $service->updated_at->format('D d/m/Y H:i') }}
par {{ $by }}

+

Celà va empêcher le service de fonctionner tant que les crédentials d'api n'auront pas été mis à jour sur le service concerné, veuillez faire au plus vite !

+ + From 193a93715e0ac6f3a1c82a87396d274297476093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 9 Sep 2021 14:08:59 +0200 Subject: [PATCH 04/19] Newsletter export Function - composer require league/csv --- app/Enums/CustomerExportType.php | 33 ++++++ app/Http/Controllers/CustomerController.php | 103 ++++++++++++++++++ app/Http/Requests/CustomerExport.php | 41 +++++++ composer.json | 1 + composer.lock | 86 ++++++++++++++- config/app.php | 3 +- resources/views/customer/export.blade.php | 63 +++++++++++ .../views/layouts/backend/sidenav.blade.php | 42 ++----- routes/web.php | 2 + 9 files changed, 337 insertions(+), 37 deletions(-) create mode 100644 app/Enums/CustomerExportType.php create mode 100644 app/Http/Requests/CustomerExport.php create mode 100644 resources/views/customer/export.blade.php diff --git a/app/Enums/CustomerExportType.php b/app/Enums/CustomerExportType.php new file mode 100644 index 0000000..89ce1c1 --- /dev/null +++ b/app/Enums/CustomerExportType.php @@ -0,0 +1,33 @@ + 1, + 'customer' => 2, + 'both' => 3 + ]; + } + public static function labels(): array + { + return [ + 'singleOptin' => trans('Les single optins uniquement'), + 'customer' => trans('Les clients uniquement acceptant de recevoir les newsletters'), + 'both' => trans('La totalité des client acceptant de recevoir les newsletters') + ]; + } +} diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 837a3ea..3bf3384 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -2,10 +2,17 @@ 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 Illuminate\Support\Carbon; +use Illuminate\Support\Str; +use League\Csv\Writer; +use Symfony\Component\HttpFoundation\StreamedResponse; class CustomerController extends Controller { @@ -102,4 +109,100 @@ class CustomerController extends Controller return redirect()->route('customers.index')->with('success', "Compte supprimé."); } + + public function export() + { + // use a crud controller (any) to gather crudModels + $modelsClasses = (new BrandController())->getCrudModels(); + return view('customer.export', compact( + 'modelsClasses' + )); + } + + 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(): + $i = 0; + /** @var \Illuminate\Database\Eloquent\Builder $req */ + $req = CustomerInfo::where('brand_id', $request->brand); + $total = $req->count(); + $pages = $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', + $i + ); + $items->map(function (CustomerInfo $customerInfo) use ($w) { + $w->insertOne([ + 'lastname' => $customerInfo->lastname, + 'firstname' => $customerInfo->firstname, + 'email' => $customerInfo->customer->email, + 'hashcode' => $customerInfo->hashcode + ]); + }); + } while ($i++ <= $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; + } + + //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; + } } diff --git a/app/Http/Requests/CustomerExport.php b/app/Http/Requests/CustomerExport.php new file mode 100644 index 0000000..85b7c9d --- /dev/null +++ b/app/Http/Requests/CustomerExport.php @@ -0,0 +1,41 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'brand' => 'required|numeric|exists:brands,id', + 'export_type' => [ + 'required', + 'numeric', + // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed + function ($attribute, $value, $fail) { + if (!\in_array($value, CustomerExportType::values())) { + $fail(trans('Le type d\'export invalide')); + } + } + ] + ]; + } +} diff --git a/composer.json b/composer.json index 5fb6fdd..05936d8 100644 --- a/composer.json +++ b/composer.json @@ -37,6 +37,7 @@ "laravel-lang/lang": "~7.0", "laravel/framework": "^8.39", "laravel/tinker": "^2.5", + "league/csv": "^9.7", "rennokki/laravel-eloquent-query-cache": "^3.0", "spatie/laravel-mix-preload": "^1.2" }, diff --git a/composer.lock b/composer.lock index 833ee21..07ce438 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d0eded9c5677a512f367b9d29c701714", + "content-hash": "ad679e344512ce53865817160816c3fa", "packages": [ { "name": "arondeparon/laravel-request-sanitizer", @@ -2228,6 +2228,90 @@ ], "time": "2021-07-17T17:13:23+00:00" }, + { + "name": "league/csv", + "version": "9.7.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/csv.git", + "reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/0ec57e8264ec92565974ead0d1724cf1026e10c1", + "reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12.0", + "phpstan/phpstan-phpunit": "^0.12.0", + "phpstan/phpstan-strict-rules": "^0.12.0", + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes", + "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Csv\\": "src" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://github.com/nyamsprod/", + "role": "Developer" + } + ], + "description": "CSV data manipulation made easy in PHP", + "homepage": "http://csv.thephpleague.com", + "keywords": [ + "convert", + "csv", + "export", + "filter", + "import", + "read", + "transform", + "write" + ], + "support": { + "docs": "https://csv.thephpleague.com", + "issues": "https://github.com/thephpleague/csv/issues", + "rss": "https://github.com/thephpleague/csv/releases.atom", + "source": "https://github.com/thephpleague/csv" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2021-04-17T16:32:08+00:00" + }, { "name": "league/flysystem", "version": "1.1.5", diff --git a/config/app.php b/config/app.php index 5f50516..6fd73b5 100644 --- a/config/app.php +++ b/config/app.php @@ -228,8 +228,9 @@ return [ 'Carbon' => Illuminate\Support\Carbon::class, 'ArcadiaMailType' => App\Enums\ArcadiaMailType::class, 'ArcadiaOrderType' => App\Enums\ArcadiaOrderType::class, + 'CustomerExportType' => App\Enums\CustomerExportType::class, 'Brand' => App\Models\Brand::class, - 'Customer' => App\Models\Customer::class + 'Customer' => App\Models\Customer::class, ], ]; diff --git a/resources/views/customer/export.blade.php b/resources/views/customer/export.blade.php new file mode 100644 index 0000000..14e1fde --- /dev/null +++ b/resources/views/customer/export.blade.php @@ -0,0 +1,63 @@ +@extends('layouts.app') + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ +
+
+
+ @csrf +
+
+
+ {{ __('La marque concernée') }} +
+ + +
+
+
+
+
+
+
+ {{ __('Type d\'export') }} + @foreach(CustomerExportType::toArray() as $i => $exportType) +
+ + +
+ @endforeach +
+
+
+
+
+ +
+
+
+
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/layouts/backend/sidenav.blade.php b/resources/views/layouts/backend/sidenav.blade.php index 0698851..2d9c516 100644 --- a/resources/views/layouts/backend/sidenav.blade.php +++ b/resources/views/layouts/backend/sidenav.blade.php @@ -40,6 +40,13 @@
@endcan @endforeach + + +
-{{-- --}} diff --git a/routes/web.php b/routes/web.php index f5dc6bc..a6672f7 100644 --- a/routes/web.php +++ b/routes/web.php @@ -44,6 +44,8 @@ Route::middleware(['auth'])->group(function () { Route::get('/customers', [CustomerController::class, 'index'])->name('customers.index'); Route::get('/customers/{customer}/{brand}', [CustomerController::class, 'show'])->name('customers.show'); Route::delete('/customers/{customer}/{brand}', [CustomerController::class, 'delete'])->name('customers.delete'); + Route::get('/customers/export', [CustomerController::class, 'export'])->name('customers.export'); + Route::post('/customers/export', [CustomerController::class, 'exportSubmit'])->name('customers.exportSubmit'); // Single optins Route::resource('single_optins', SingleOptinController::class); From 78bbd8fafb5e4667882f1c4f6fa80c32b1cbe79c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 9 Sep 2021 15:09:13 +0200 Subject: [PATCH 05/19] bump kwaadpepper/crud-policies Customer search --- app/Http/Controllers/CustomerController.php | 55 ++++++++++++++++--- composer.json | 2 +- composer.lock | 15 ++--- .../customer/index-tableHeaders.blade.php | 35 +++--------- resources/views/customer/index.blade.php | 5 +- 5 files changed, 67 insertions(+), 45 deletions(-) diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 3bf3384..89cd738 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -9,23 +9,64 @@ use App\Models\Customer; use App\Models\CustomerInfo; use App\Models\CustomerLogin; use App\Models\SingleOptin; +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() + public function index(Request $request) { - $brands = Brand::select('id', 'name')->get(); - $query = CustomerInfo::with(['customer']); - if (request()->brand) { - $query = $query->where('brand_id', request()->brand); - } - $customers = $query->paginate(); $modelTable = (new Customer())->getTable(); $modelClass = Customer::class; + $brands = Brand::select('id', 'name')->get(); + $columns = ['lastname', 'firstname', 'opt_in']; + + /** @var \Illuminate\Database\Eloquent\Builder */ + $query = CustomerInfo::with(['customer']); + if (request()->brand) { + $query = $query->where('brand_id', $request->brand); + } + + // Search on crud Label column + if ($request->search) { + foreach ($columns as $column) { + $query = $query->orWhere($column, 'LIKE', "%$request->search%"); + } + $query = $query->orWhereHas('customer', function ($q) use ($request) { + $q->where('email', 'LIKE', "%$request->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.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")) + ) { + $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)); // use a crud controller (any) to gather crudModels $modelsClasses = (new BrandController())->getCrudModels(); diff --git a/composer.json b/composer.json index 05936d8..4317184 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "fideloper/proxy": "^4.4", "fruitcake/laravel-cors": "^2.0", "guzzlehttp/guzzle": "^7.0.1", - "kwaadpepper/crud-policies": "^0.1.15", + "kwaadpepper/crud-policies": "^0.1.17", "kwaadpepper/enum": "^2.0", "laravel-lang/lang": "~7.0", "laravel/framework": "^8.39", diff --git a/composer.lock b/composer.lock index 07ce438..c9b2e40 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ad679e344512ce53865817160816c3fa", + "content-hash": "52ddf0e771e6661178474f2a87aeaf7e", "packages": [ { "name": "arondeparon/laravel-request-sanitizer", @@ -1730,16 +1730,16 @@ }, { "name": "kwaadpepper/crud-policies", - "version": "0.1.15", + "version": "0.1.17", "source": { "type": "git", "url": "https://github.com/Kwaadpepper/crud-policies.git", - "reference": "cf471dc2dad7851474ee005fbc8dfdfe05096b84" + "reference": "007552cbc9f34790acadf1fde1da2eed347be1b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Kwaadpepper/crud-policies/zipball/cf471dc2dad7851474ee005fbc8dfdfe05096b84", - "reference": "cf471dc2dad7851474ee005fbc8dfdfe05096b84", + "url": "https://api.github.com/repos/Kwaadpepper/crud-policies/zipball/007552cbc9f34790acadf1fde1da2eed347be1b9", + "reference": "007552cbc9f34790acadf1fde1da2eed347be1b9", "shasum": "" }, "require": { @@ -1751,6 +1751,7 @@ "require-dev": { "orchestra/testbench": "^6.13", "phpunit/phpunit": "~9.0", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5" }, "type": "library", @@ -1787,9 +1788,9 @@ ], "support": { "issues": "https://github.com/Kwaadpepper/crud-policies/issues", - "source": "https://github.com/Kwaadpepper/crud-policies/tree/0.1.15" + "source": "https://github.com/Kwaadpepper/crud-policies/tree/0.1.17" }, - "time": "2021-08-27T10:42:55+00:00" + "time": "2021-09-09T12:42:59+00:00" }, { "name": "kwaadpepper/enum", diff --git a/resources/views/customer/index-tableHeaders.blade.php b/resources/views/customer/index-tableHeaders.blade.php index 56cf8c8..2286d8b 100644 --- a/resources/views/customer/index-tableHeaders.blade.php +++ b/resources/views/customer/index-tableHeaders.blade.php @@ -1,62 +1,41 @@ - @php $colname = 'email' @endphp {{ __('Email')}} - @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) -  ↓  - @endif - @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) -  ↑  - @endif @php $colname = 'lastname' @endphp {{ __('Nom')}} @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) -  ↓  +  ↓  @endif @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) -  ↑  +  ↑  @endif @php $colname = 'firstname' @endphp {{ __('Prénom')}} @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) -  ↓  +  ↓  @endif @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) -  ↑  +  ↑  @endif - @php $colname = 'optin' @endphp + @php $colname = 'opt_in' @endphp {{ __('Opt-In')}} @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) -  ↓  +  ↓  @endif @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) -  ↑  +  ↑  @endif - @php $colname = 'brand_id' @endphp {{ __('Marque')}} - @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) -  ↓  - @endif - @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) -  ↑  - @endif - @php $colname = 'status' @endphp {{ __('Activé ?')}} - @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) -  ↓  - @endif - @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) -  ↑  - @endif {{ __('Voir')}} diff --git a/resources/views/customer/index.blade.php b/resources/views/customer/index.blade.php index 80c2959..14926dc 100644 --- a/resources/views/customer/index.blade.php +++ b/resources/views/customer/index.blade.php @@ -38,6 +38,7 @@ + {{ $customers->appends(Request::except('rst'))->links() }} @@ -66,7 +67,7 @@ {{ $customerInfo->lastname }}
- {{ $customerInfo->optin ? 'Oui' :'Non' }} + {{ $customerInfo->opt_in ? 'Oui' :'Non' }} {{ $customerInfo->brand->name }} @@ -97,7 +98,7 @@ @endif
- {{ $customers->links() }} + {{ $customers->appends(Request::except('rst'))->links() }} @include('crud-policies::crud.modules.scriptConstants') From b9ab21b43a8845831f19efeee3285cf17ef9c5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 9 Sep 2021 15:15:23 +0200 Subject: [PATCH 06/19] Fix front translations --- app/Models/Brand.php | 2 +- app/Models/Service.php | 2 +- app/Models/SingleOptin.php | 2 +- resources/lang/en/models.php | 2 ++ resources/lang/fr/models.php | 2 ++ 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/Models/Brand.php b/app/Models/Brand.php index 9db5006..32ce105 100644 --- a/app/Models/Brand.php +++ b/app/Models/Brand.php @@ -46,7 +46,7 @@ class Brand extends Model ] ], 'services' => [ - 'label' => Str::ucfirst(Str::plural(trans('models.models.service'))), + 'label' => Str::ucfirst(Str::plural(trans('models.classes.services'))), 'type' => CrudType::belongsToMany(), 'belongsToMany' => Service::class, 'belongsToManyLabel' => 'name', diff --git a/app/Models/Service.php b/app/Models/Service.php index 205fc6f..b358d7b 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -49,7 +49,7 @@ class Service extends Model ] ], 'brand_id' => [ - 'label' => Str::ucfirst(trans('models.models.brand')), + 'label' => Str::ucfirst(trans('models.classes.brand')), 'type' => CrudType::belongsTo(), 'belongsTo' => Brand::class, 'actions' => [ diff --git a/app/Models/SingleOptin.php b/app/Models/SingleOptin.php index f71f82c..ea9ede0 100644 --- a/app/Models/SingleOptin.php +++ b/app/Models/SingleOptin.php @@ -52,7 +52,7 @@ class SingleOptin extends Model ] ], 'brand_id' => [ - 'label' => Str::ucfirst(trans('models.models.brand')), + 'label' => Str::ucfirst(trans('models.classes.brand')), 'type' => CrudType::belongsTo(), 'belongsTo' => Brand::class, 'actions' => [ diff --git a/resources/lang/en/models.php b/resources/lang/en/models.php index 4ad236d..d469201 100644 --- a/resources/lang/en/models.php +++ b/resources/lang/en/models.php @@ -4,12 +4,14 @@ return [ 'classes' => [ 'services' => 'Services', 'brands' => 'Brands', + 'brand' => 'Brand', 'customers' => 'Customers', 'singleoptins' => 'Single Opt-ins' ], 'common' => [ 'title' => 'Title', 'name' => 'Name', + 'email' => 'Email', 'content' => 'Content', 'visibility' => 'Visibility', 'published' => 'Published', diff --git a/resources/lang/fr/models.php b/resources/lang/fr/models.php index ddb1fee..f6c6b42 100644 --- a/resources/lang/fr/models.php +++ b/resources/lang/fr/models.php @@ -4,12 +4,14 @@ return [ 'classes' => [ 'services' => 'Services', 'brands' => 'Marques', + 'brand' => 'Marque', 'customers' => 'Clients', 'singleoptins' => 'Opt-ins uniques' ], 'common' => [ 'title' => 'Titre', 'name' => 'Nom', + 'email' => 'E-mail', 'content' => 'Contenu', 'visibility' => 'Visibilitée', 'published' => 'Publié', From fc4b9502da5fbe9f5c0444ac8d8e4d53b08dc7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 9 Sep 2021 15:45:16 +0200 Subject: [PATCH 07/19] add check is memcached running ? --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 4317184..7c6c88d 100644 --- a/composer.json +++ b/composer.json @@ -84,6 +84,7 @@ "prefer-stable": true, "scripts": { "test": [ + "echo 'check memcached is running';netcat -z localhost 11211", "@configclear", "./test.sh" ], From 2b8e26ad1c364e9763221c4e65bfe18a6c46020c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 9 Sep 2021 15:50:51 +0200 Subject: [PATCH 08/19] Fix unit test testRoutesGet --- tests/Unit/CrmClientV2RouterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/CrmClientV2RouterTest.php b/tests/Unit/CrmClientV2RouterTest.php index c4e9321..a2a87f6 100644 --- a/tests/Unit/CrmClientV2RouterTest.php +++ b/tests/Unit/CrmClientV2RouterTest.php @@ -20,7 +20,7 @@ class CrmClientV2RouterTest extends CrmClientTester $this->assertEquals($route->methods(), $routes[$route->getName()]['methods']); $this->assertEquals($route->uri(), $routes[$route->getName()]['uri']); } else { - $this->assertArrayNotHasKey($route->getName(), $routes); + $this->assertArrayNotHasKey($route->getName() ?? '', $routes); } } } From e3065974f7afe979b4fd4739746092c7b15f95de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 9 Sep 2021 16:29:05 +0200 Subject: [PATCH 09/19] remove unused filter methods --- app/Http/Controllers/CustomerController.php | 41 --------------------- routes/web.php | 2 - 2 files changed, 43 deletions(-) diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 89cd738..cd77bc8 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -95,47 +95,6 @@ class CustomerController extends Controller )); } - public function filter($texte, Brand $brand = null) - { - if ($brand) { - $customers = Customer::join('customer_infos', 'customers.id', '=', 'customer_infos.customer_id') - ->join('customer_logins', 'customers.id', '=', 'customer_logins.customer_id')->select( - 'customer_infos.customer_id', - 'customer_infos.firstname', - 'customer_infos.lastname', - 'customer_infos.opt_in', - 'customers.email', - 'customer_infos.brand_id', - 'customer_logins.last_connection' - )->where([ - ['lastname', 'like', '%' . $texte . '%'], - ['customer_infos.brand_id', $brand->id], - ['customer_logins.brand_id', $brand->id] - ])->orWhere([ - ['email', 'like', '%' . $texte . '%'], - ['customer_infos.brand_id', $brand->id], - ['customer_logins.brand_id', $brand->id] - ])->get(); - } else { - $customers = CustomerInfo::join('customers', 'customers.id', '=', 'customer_infos.customer_id') - ->join('customer_logins', function ($join) { - $join->on('customer_logins.customer_id', '=', 'customer_infos.customer_id'); - $join->on('customer_logins.brand_id', '=', 'customer_infos.brand_id'); - })->select( - 'customer_infos.customer_id', - 'customer_infos.firstname', - 'customer_infos.lastname', - 'customer_infos.opt_in', - 'customers.email', - 'customer_infos.brand_id', - 'customer_logins.last_connection' - )->where('lastname', 'like', '%' . $texte . '%') - ->orWhere('email', 'like', '%' . $texte . '%')->get(); - } - - return response()->json($customers); - } - public function delete(Customer $customer, Brand $brand) { $nbBrand = $customer->infos()->count(); diff --git a/routes/web.php b/routes/web.php index a6672f7..8fb6add 100644 --- a/routes/web.php +++ b/routes/web.php @@ -49,7 +49,5 @@ Route::middleware(['auth'])->group(function () { // Single optins Route::resource('single_optins', SingleOptinController::class); - Route::get('/single_optins/filter/{texte}/{brandId?}', [SingleOptinController::class, 'filter']) - ->name('filter-single-optins'); Route::post('/single_optins/{id}/delete', [SingleOptinController::class, 'delete'])->name('single-optins-delete'); }); From a8aa32af19cc6757e747be9fcb0d00b349caeae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Thu, 9 Sep 2021 16:29:32 +0200 Subject: [PATCH 10/19] fix export file --- app/Http/Controllers/CustomerController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index cd77bc8..7bbf48e 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -139,7 +139,7 @@ class CustomerController extends Controller $response->headers->set( 'Content-Disposition', sprintf( - 'attachment; filename=\"Export pour newsletter %s %s.csv\"', + 'attachment; filename="Export pour newsletter %s %s.csv"', Carbon::now()->format('d-m-Y_H-i'), Str::slug($exportType) ) From 7cbbeb3cb43a700bfb09d46bfd9f6b099e43fec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Fri, 10 Sep 2021 15:43:27 +0200 Subject: [PATCH 11/19] Add question UI + Fix search and filters --- app/Enums/ApiError.php | 5 +- app/Http/Controllers/AnswerController.php | 42 ++++++ app/Http/Controllers/CustomerController.php | 35 +++-- app/Http/Controllers/QuestionController.php | 39 ++++++ app/Models/Answer.php | 30 +++++ app/Models/CustomerInfo.php | 4 +- app/Models/Question.php | 60 +++++++++ app/Policies/AnswerPolicy.php | 29 ++++ app/Policies/QuestionPolicy.php | 30 +++++ app/Providers/RouteServiceProvider.php | 4 + config/app.php | 1 + resources/lang/en/models.php | 7 +- resources/lang/fr/models.php | 7 +- resources/views/answer/index.blade.php | 119 +++++++++++++++++ .../customer/index-tableHeaders.blade.php | 37 ++++- resources/views/customer/index.blade.php | 9 +- .../views/layouts/backend/sidenav.blade.php | 3 +- resources/views/modules/crudAction.blade.php | 4 + .../views/modules/flashMessage.blade.php | 44 ++++++ resources/views/question/index.blade.php | 126 ++++++++++++++++++ .../crud/modules/actionbar/bar.blade.php | 21 +++ .../crud/modules/actionbar/create.blade.php | 3 + .../crud/modules/actionbar/delete.blade.php | 7 + .../crud/modules/actionbar/update.blade.php | 3 + .../crud/modules/actionbar/view.blade.php | 3 + routes/web.php | 9 ++ 26 files changed, 660 insertions(+), 21 deletions(-) create mode 100644 app/Http/Controllers/AnswerController.php create mode 100644 app/Http/Controllers/QuestionController.php create mode 100644 app/Policies/AnswerPolicy.php create mode 100644 app/Policies/QuestionPolicy.php create mode 100644 resources/views/answer/index.blade.php create mode 100644 resources/views/modules/crudAction.blade.php create mode 100644 resources/views/modules/flashMessage.blade.php create mode 100644 resources/views/question/index.blade.php create mode 100644 resources/views/vendor/crud-policies/crud/modules/actionbar/bar.blade.php create mode 100644 resources/views/vendor/crud-policies/crud/modules/actionbar/create.blade.php create mode 100644 resources/views/vendor/crud-policies/crud/modules/actionbar/delete.blade.php create mode 100644 resources/views/vendor/crud-policies/crud/modules/actionbar/update.blade.php create mode 100644 resources/views/vendor/crud-policies/crud/modules/actionbar/view.blade.php diff --git a/app/Enums/ApiError.php b/app/Enums/ApiError.php index 4b822d7..f381e49 100644 --- a/app/Enums/ApiError.php +++ b/app/Enums/ApiError.php @@ -95,9 +95,10 @@ class ApiError extends BaseEnumRoutable 'customerExists' => 'L\'utilisateur est déjà enregistré sur ce site', 'customerNotActivated' => 'Le compte n\'est pas activé', 'customerAlreadyActive' => 'Le compte est déjà activé', - 'singleOptinCustomerExists' => 'Le signle optin ne peut être ajouté car un compte existe.', - 'authFailed' => 'Echec de l\'authentification', + 'singleOptinCustomerExists' => 'Le single optin ne peut être ajouté car un compte existe.', + 'authFailed' => 'Echec de l\'authentification du compte', 'needAuth' => 'Vous devez être authentifié', + 'apiAuthFailed' => 'Echec de l\'authentification client à l\'Api LDC-CRM pour ce service', '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', diff --git a/app/Http/Controllers/AnswerController.php b/app/Http/Controllers/AnswerController.php new file mode 100644 index 0000000..976befe --- /dev/null +++ b/app/Http/Controllers/AnswerController.php @@ -0,0 +1,42 @@ +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()); + } +} diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 7bbf48e..a005c0f 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -9,6 +9,7 @@ use App\Models\Customer; use App\Models\CustomerInfo; use App\Models\CustomerLogin; use App\Models\SingleOptin; +use Illuminate\Database\Query\JoinClause; use Illuminate\Http\Request; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Schema; @@ -21,15 +22,25 @@ class CustomerController extends Controller { public function index(Request $request) { - $modelTable = (new Customer())->getTable(); - $modelClass = Customer::class; + $modelTable = (new CustomerInfo())->getTable(); + $modelClass = CustomerInfo::class; $brands = Brand::select('id', 'name')->get(); $columns = ['lastname', 'firstname', 'opt_in']; + // Jointure pour pouvoir trier les colonnes /** @var \Illuminate\Database\Eloquent\Builder */ - $query = CustomerInfo::with(['customer']); + $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) { - $query = $query->where('brand_id', $request->brand); + $query = $query->where('customer_infos.brand_id', $request->brand); } // Search on crud Label column @@ -37,9 +48,8 @@ class CustomerController extends Controller foreach ($columns as $column) { $query = $query->orWhere($column, 'LIKE', "%$request->search%"); } - $query = $query->orWhereHas('customer', function ($q) use ($request) { - $q->where('email', 'LIKE', "%$request->search%"); - }); + $query = $query->orWhere('customers.email', 'LIKE', "%$request->search%"); + $query = $query->orWhere('customer_logins.last_connection', 'LIKE', "%$request->search%"); } // Sort columns @@ -57,7 +67,16 @@ class CustomerController extends Controller if ( Session::has("crud.$modelTable.sort_col") and Session::has("crud.$modelTable.sort_way") and - Schema::hasColumn($modelTable, Session::get("crud.$modelTable.sort_col")) + (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"), diff --git a/app/Http/Controllers/QuestionController.php b/app/Http/Controllers/QuestionController.php new file mode 100644 index 0000000..2fab894 --- /dev/null +++ b/app/Http/Controllers/QuestionController.php @@ -0,0 +1,39 @@ +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; + } +} diff --git a/app/Models/Answer.php b/app/Models/Answer.php index f85e234..6ce9028 100644 --- a/app/Models/Answer.php +++ b/app/Models/Answer.php @@ -4,15 +4,45 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; class Answer extends Model { use HasFactory; + use IsCrudModel; + + protected $crudLabelColumn = 'answer'; + + protected $crudValueColumn = 'id'; protected $fillable = [ 'answer' ]; + public function __construct(array $attributes = []) + { + self::$editableProperties = [ + 'answer' => [ + 'label' => Str::ucfirst(trans('models.common.answer')), + 'type' => CrudType::string(), + 'validate' => [ + 'min:1', + 'max:255' + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ] + ]; + parent::__construct($attributes); + } + /** * Question BelongsTo relation * diff --git a/app/Models/CustomerInfo.php b/app/Models/CustomerInfo.php index b5ebb77..e657fc6 100644 --- a/app/Models/CustomerInfo.php +++ b/app/Models/CustomerInfo.php @@ -101,9 +101,9 @@ class CustomerInfo extends Model } /** - * CustomerLogin HasOneThrough relation + * get Login * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + * @return \App\Models\CustomerLogin */ public function login() { diff --git a/app/Models/Question.php b/app/Models/Question.php index e69f3e0..1b6dacd 100644 --- a/app/Models/Question.php +++ b/app/Models/Question.php @@ -5,12 +5,21 @@ namespace App\Models; use App\Enums\QuestionType; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; use Kwaadpepper\Enum\Traits\CastsEnums; class Question extends Model { use CastsEnums; use HasFactory; + use IsCrudModel; + + protected $crudLabelColumn = 'question'; + + protected $crudValueColumn = 'id'; protected $enumCasts = [ 'type' => QuestionType::class @@ -21,6 +30,57 @@ class Question extends Model 'type' ]; + public function __construct(array $attributes = []) + { + self::$editableProperties = [ + 'question' => [ + 'label' => Str::ucfirst(trans('models.common.question')), + 'type' => CrudType::string(), + 'validate' => [ + 'min:10', + 'max:255' + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ], + 'type' => [ + 'label' => Str::ucfirst(trans('models.common.type')), + 'type' => CrudType::enum(), + 'enum' => QuestionType::class, + 'actions' => [ + CrudAction::view(), + CrudAction::create(), + CrudAction::update(), + ] + ], + 'brand_id' => [ + 'label' => Str::ucfirst(trans('models.classes.brand')), + 'type' => CrudType::belongsTo(), + 'belongsTo' => Brand::class, + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update(), + ] + ], + 'answers' => [ + 'label' => Str::ucfirst(Str::plural(trans('models.classes.answers'))), + 'type' => CrudType::belongsToMany(), + 'belongsToMany' => Answer::class, + 'belongsToManyLabel' => 'answer', + 'actions' => [ + CrudAction::view() + ] + ] + ]; + parent::__construct($attributes); + } + /** * Brand BelongsTo relation * diff --git a/app/Policies/AnswerPolicy.php b/app/Policies/AnswerPolicy.php new file mode 100644 index 0000000..c38607e --- /dev/null +++ b/app/Policies/AnswerPolicy.php @@ -0,0 +1,29 @@ +policies = [ + 'answer' => [ + 'viewAny' => USR::make('everyOne'), + 'update' => USR::make('everyOne'), + 'create' => USR::make('everyOne'), + 'delete' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Policies/QuestionPolicy.php b/app/Policies/QuestionPolicy.php new file mode 100644 index 0000000..ee18d37 --- /dev/null +++ b/app/Policies/QuestionPolicy.php @@ -0,0 +1,30 @@ +policies = [ + 'question' => [ + 'viewAny' => USR::make('everyOne'), + 'view' => USR::make('everyOne'), + 'update' => USR::make('everyOne'), + 'create' => USR::make('everyOne'), + 'delete' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index f57fef8..fe05944 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -2,9 +2,11 @@ namespace App\Providers; +use App\Models\Answer; use App\Models\Brand; use App\Models\Customer; use App\Models\CustomerInfo; +use App\Models\Question; use App\Models\Service; use App\Models\SingleOptin; use Illuminate\Cache\RateLimiting\Limit; @@ -42,6 +44,8 @@ class RouteServiceProvider extends ServiceProvider Route::model('brand', Brand::class); Route::model('service', Service::class); Route::model('single_optin', SingleOptin::class); + Route::model('question', Question::class); + Route::model('answer', Answer::class); Route::bind('customer', function ($value) { if (\ctype_digit($value)) { diff --git a/config/app.php b/config/app.php index 6fd73b5..ea1878b 100644 --- a/config/app.php +++ b/config/app.php @@ -231,6 +231,7 @@ return [ 'CustomerExportType' => App\Enums\CustomerExportType::class, 'Brand' => App\Models\Brand::class, 'Customer' => App\Models\Customer::class, + 'Answer' => App\Models\Answer::class, ], ]; diff --git a/resources/lang/en/models.php b/resources/lang/en/models.php index d469201..ff61fae 100644 --- a/resources/lang/en/models.php +++ b/resources/lang/en/models.php @@ -6,6 +6,8 @@ return [ 'brands' => 'Brands', 'brand' => 'Brand', 'customers' => 'Customers', + 'questions' => 'Questions', + 'answers' => 'Answers', 'singleoptins' => 'Single Opt-ins' ], 'common' => [ @@ -17,6 +19,9 @@ return [ 'published' => 'Published', 'group' => 'Group', 'default' => 'Default', - 'optinDate' => 'Date opt-in' + 'optinDate' => 'Date opt-in', + 'question' => 'Question', + 'answer' => 'Answer', + 'type' => 'Type' ] ]; diff --git a/resources/lang/fr/models.php b/resources/lang/fr/models.php index f6c6b42..1c38697 100644 --- a/resources/lang/fr/models.php +++ b/resources/lang/fr/models.php @@ -5,6 +5,8 @@ return [ 'services' => 'Services', 'brands' => 'Marques', 'brand' => 'Marque', + 'questions' => 'Questions', + 'answers' => 'Réponses', 'customers' => 'Clients', 'singleoptins' => 'Opt-ins uniques' ], @@ -17,6 +19,9 @@ return [ 'published' => 'Publié', 'group' => 'Groupe', 'default' => 'Par défaut', - 'optinDate' => 'Date opt-in' + 'optinDate' => 'Date opt-in', + 'question' => 'Question', + 'type' => 'Type', + 'answer' => 'Réponse' ] ]; diff --git a/resources/views/answer/index.blade.php b/resources/views/answer/index.blade.php new file mode 100644 index 0000000..e7d898f --- /dev/null +++ b/resources/views/answer/index.blade.php @@ -0,0 +1,119 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+ {{ $models->links() }} +
+
+
+
+ + + + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+
+

{{ request()->question->question }}

+
+ + + @include('crud-policies::crud.modules.sorter') + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]) +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+
{{ $models->links() }}
+
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/customer/index-tableHeaders.blade.php b/resources/views/customer/index-tableHeaders.blade.php index 2286d8b..cfee811 100644 --- a/resources/views/customer/index-tableHeaders.blade.php +++ b/resources/views/customer/index-tableHeaders.blade.php @@ -1,8 +1,15 @@ + @php $colname = 'customers.email' @endphp {{ __('Email')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif - @php $colname = 'lastname' @endphp + @php $colname = 'customer_infos.lastname' @endphp {{ __('Nom')}} @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname))  ↓  @@ -12,7 +19,7 @@ @endif - @php $colname = 'firstname' @endphp + @php $colname = 'customer_infos.firstname' @endphp {{ __('Prénom')}} @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname))  ↓  @@ -22,7 +29,7 @@ @endif - @php $colname = 'opt_in' @endphp + @php $colname = 'customer_infos.opt_in' @endphp {{ __('Opt-In')}} @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname))  ↓  @@ -32,10 +39,34 @@ @endif + @php $colname = 'brands.name' @endphp {{ __('Marque')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + @php $colname = 'customer_logins.status' @endphp {{ __('Activé ?')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'customer_logins.last_connection' @endphp + {{ __('Dernière connexion')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif {{ __('Voir')}} diff --git a/resources/views/customer/index.blade.php b/resources/views/customer/index.blade.php index 14926dc..0b73358 100644 --- a/resources/views/customer/index.blade.php +++ b/resources/views/customer/index.blade.php @@ -1,7 +1,7 @@ @extends('layouts.app') -@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) -@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('title', sprintf('%s - %s', Str::ucfirst(Str::plural(trans('models.classes.customers'))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), Str::ucfirst(Str::plural(trans('models.classes.customers'))))) @section('metaIndex', 'noindex,nofollow') @section('content') @@ -73,7 +73,10 @@ {{ $customerInfo->brand->name }} - {{ $customerInfo->login()->status ? 'Oui' :'Non' }} + {{ $customerInfo->status ? 'Oui' :'Non' }} + + + {{ $customerInfo->last_connection }} {{-- MODEL ACTIONS --}} diff --git a/resources/views/layouts/backend/sidenav.blade.php b/resources/views/layouts/backend/sidenav.blade.php index 2d9c516..306b120 100644 --- a/resources/views/layouts/backend/sidenav.blade.php +++ b/resources/views/layouts/backend/sidenav.blade.php @@ -18,7 +18,8 @@
@foreach($modelsClasses as $crudModel) - @php if($crudModel === Customer::class) continue; @endphp + @php if($crudModel === \App\Models\Answer::class) continue; @endphp + @php if($crudModel === \App\Models\Customer::class) continue; @endphp @if( auth()->user()->can('viewAny', $crudModel) or auth()->user()->can('create', $crudModel) diff --git a/resources/views/modules/crudAction.blade.php b/resources/views/modules/crudAction.blade.php new file mode 100644 index 0000000..7536740 --- /dev/null +++ b/resources/views/modules/crudAction.blade.php @@ -0,0 +1,4 @@ +@if(request()->question) +{{ Str::ucfirst(__('models.common.question')) }} +{{ Str::ucfirst(__('models.classes.answers')) }} +@endif diff --git a/resources/views/modules/flashMessage.blade.php b/resources/views/modules/flashMessage.blade.php new file mode 100644 index 0000000..919668a --- /dev/null +++ b/resources/views/modules/flashMessage.blade.php @@ -0,0 +1,44 @@ +@if ($message = Session::get('success')) +
+ + {!! nl2br(e($message)) !!} +
+@endif + + +@if ($message = Session::get('error')) +
+ + {!! nl2br(e($message)) !!} +
+@endif + + +@if ($message = Session::get('warning')) +
+ + {!! nl2br(e($message)) !!} +
+@endif + + +@if ($message = Session::get('info')) +
+ + {!! nl2br(e($message)) !!} +
+@endif + + +@if ($errors->any()) +
+ + @if ($errors->any()) +
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+ @endif +
+@endif diff --git a/resources/views/question/index.blade.php b/resources/views/question/index.blade.php new file mode 100644 index 0000000..b37c792 --- /dev/null +++ b/resources/views/question/index.blade.php @@ -0,0 +1,126 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+
+ + + + + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ {{ $models->appends(Request::except('rst'))->links() }} + + + @include('crud-policies::crud.modules.sorter') + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]) +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan + @can('viewAny', \App\Models\Answer::class) + {{ Str::ucfirst(__('models.classes.answers')) }} + @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/bar.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/bar.blade.php new file mode 100644 index 0000000..131ec85 --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/bar.blade.php @@ -0,0 +1,21 @@ +
+ @switch($action) + @case(CrudAction::viewAny()) + @include('modules.crudAction') + @include('crud-policies::crud.modules.actionbar.create') + @break + @case(CrudAction::view()) + @include('modules.crudAction') + @include('crud-policies::crud.modules.actionbar.update') + @include('crud-policies::crud.modules.actionbar.delete') + @break + @case(CrudAction::create()) + @include('modules.crudAction') + @break + @case(CrudAction::update()) + @include('modules.crudAction') + @include('crud-policies::crud.modules.actionbar.view') + @include('crud-policies::crud.modules.actionbar.delete') + @break + @endswitch +
diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/create.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/create.blade.php new file mode 100644 index 0000000..3cc5251 --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/create.blade.php @@ -0,0 +1,3 @@ +@can('create', $modelClass) +{{ __('crud-policies::crud.create') }} +@endcan diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/delete.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/delete.blade.php new file mode 100644 index 0000000..dc1fdcc --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/delete.blade.php @@ -0,0 +1,7 @@ +@can('delete', $model) +
+ @csrf + @method('DELETE') + +
+@endcan diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/update.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/update.blade.php new file mode 100644 index 0000000..9e2008f --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/update.blade.php @@ -0,0 +1,3 @@ +@can('update', $model) +{{ __('crud-policies::crud.update') }} +@endcan diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/view.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/view.blade.php new file mode 100644 index 0000000..2419cd7 --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/view.blade.php @@ -0,0 +1,3 @@ +@can('view', $model) +{{ __('crud-policies::crud.view') }} +@endcan diff --git a/routes/web.php b/routes/web.php index 8fb6add..53b3760 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,8 +1,10 @@ group(function () { // Single optins Route::resource('single_optins', SingleOptinController::class); Route::post('/single_optins/{id}/delete', [SingleOptinController::class, 'delete'])->name('single-optins-delete'); + + // Questions + Route::resource('questions', QuestionController::class); + Route::resource('questions.answers', AnswerController::class); + + // Answers + // Route::resource('answers', AnswerController::class); }); From 9aaa9a25be8e4339ccabe1e21beb31af5bdee78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Fri, 10 Sep 2021 15:45:18 +0200 Subject: [PATCH 12/19] fix typo on customer delete --- resources/js/pages/customer.delete.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/pages/customer.delete.js b/resources/js/pages/customer.delete.js index 565824d..4d9674d 100644 --- a/resources/js/pages/customer.delete.js +++ b/resources/js/pages/customer.delete.js @@ -16,7 +16,7 @@ if (customerDelete) { if (result.isConfirmed) { Swal.fire({ title: 'Attention au conséquences', - html: 'La supression de ce compte dans la crm n\'entrainera pas ça supression dans MESBR ni dans le front cache DB (pour les sites WPCRM).

Une fois ne compte supprimé je ne pourrai plus récupérer le hashcode nécessaire pour effectuer ces opérations.

', + html: 'La supression de ce compte dans la crm n\'entrainera pas ça supression dans MESBR ni dans le front cache DB (pour les sites WPCRM).

Une fois le compte supprimé je ne pourrai plus récupérer le hashcode nécessaire pour effectuer ces opérations.

', icon: 'info', confirmButtonText: 'Je comprends le danger et suis conscient que celà aura des conséquences', showCancelButton: true, From 34e6a42f8d7379ff6db7be9977ecc2b6ff7fc9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Fri, 10 Sep 2021 15:56:01 +0200 Subject: [PATCH 13/19] Fix customer search --- app/Http/Controllers/CustomerController.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index a005c0f..58b5299 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -25,7 +25,7 @@ class CustomerController extends Controller $modelTable = (new CustomerInfo())->getTable(); $modelClass = CustomerInfo::class; $brands = Brand::select('id', 'name')->get(); - $columns = ['lastname', 'firstname', 'opt_in']; + $columns = ['customer_infos.lastname', 'customer_infos.firstname']; // Jointure pour pouvoir trier les colonnes /** @var \Illuminate\Database\Eloquent\Builder */ @@ -45,11 +45,13 @@ class CustomerController extends Controller // Search on crud Label column if ($request->search) { - foreach ($columns as $column) { - $query = $query->orWhere($column, 'LIKE', "%$request->search%"); - } - $query = $query->orWhere('customers.email', 'LIKE', "%$request->search%"); - $query = $query->orWhere('customer_logins.last_connection', 'LIKE', "%$request->search%"); + $query->where(function ($q) use ($columns, $request) { + foreach ($columns as $column) { + $q = $q->orWhere($column, 'LIKE', "%$request->search%"); + } + $q = $q->orWhere('customers.email', 'LIKE', "%$request->search%"); + $q = $q->orWhere('customer_logins.last_connection', 'LIKE', "%$request->search%"); + }); } // Sort columns From df7131aa7a3a536ff8b7af56a1e287b686ff7e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Fri, 10 Sep 2021 16:11:52 +0200 Subject: [PATCH 14/19] memorize customer filters on session --- app/Http/Controllers/CustomerController.php | 20 +++++++++++++------- resources/views/customer/index.blade.php | 4 ++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 58b5299..0ca0a9f 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -39,18 +39,22 @@ class CustomerController extends Controller ->join('brands', function (JoinClause $join) { $join->on('brands.id', '=', 'customer_infos.brand_id'); }); - if (request()->brand) { - $query = $query->where('customer_infos.brand_id', $request->brand); + 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) { - $query->where(function ($q) use ($columns, $request) { + 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', "%$request->search%"); + $q = $q->orWhere($column, 'LIKE', "%$search%"); } - $q = $q->orWhere('customers.email', 'LIKE', "%$request->search%"); - $q = $q->orWhere('customer_logins.last_connection', 'LIKE', "%$request->search%"); + $q = $q->orWhere('customers.email', 'LIKE', "%$search%"); + $q = $q->orWhere('customer_logins.last_connection', 'LIKE', "%$search%"); }); } @@ -63,6 +67,8 @@ class CustomerController extends Controller } 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"); } diff --git a/resources/views/customer/index.blade.php b/resources/views/customer/index.blade.php index 0b73358..b700135 100644 --- a/resources/views/customer/index.blade.php +++ b/resources/views/customer/index.blade.php @@ -20,11 +20,11 @@ - + @if(request()->brand) From 0a7d61011f59c62bdc3dd474dba2dbaccbdd5dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Fri, 10 Sep 2021 16:26:45 +0200 Subject: [PATCH 15/19] fix sorter reset and bump kwaadpepper/crud-policies to 0.1.17 --- app/Http/Controllers/CustomerController.php | 4 ++-- composer.lock | 8 ++++---- resources/views/customer/index.blade.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 0ca0a9f..5767015 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -22,8 +22,8 @@ class CustomerController extends Controller { public function index(Request $request) { - $modelTable = (new CustomerInfo())->getTable(); - $modelClass = CustomerInfo::class; + $modelTable = (new Customer())->getTable(); + $modelClass = Customer::class; $brands = Brand::select('id', 'name')->get(); $columns = ['customer_infos.lastname', 'customer_infos.firstname']; diff --git a/composer.lock b/composer.lock index c9b2e40..146429d 100644 --- a/composer.lock +++ b/composer.lock @@ -1734,12 +1734,12 @@ "source": { "type": "git", "url": "https://github.com/Kwaadpepper/crud-policies.git", - "reference": "007552cbc9f34790acadf1fde1da2eed347be1b9" + "reference": "0cd52413f9ee2f95b2ebc2d2d4621cfc2a104e47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Kwaadpepper/crud-policies/zipball/007552cbc9f34790acadf1fde1da2eed347be1b9", - "reference": "007552cbc9f34790acadf1fde1da2eed347be1b9", + "url": "https://api.github.com/repos/Kwaadpepper/crud-policies/zipball/0cd52413f9ee2f95b2ebc2d2d4621cfc2a104e47", + "reference": "0cd52413f9ee2f95b2ebc2d2d4621cfc2a104e47", "shasum": "" }, "require": { @@ -1790,7 +1790,7 @@ "issues": "https://github.com/Kwaadpepper/crud-policies/issues", "source": "https://github.com/Kwaadpepper/crud-policies/tree/0.1.17" }, - "time": "2021-09-09T12:42:59+00:00" + "time": "2021-09-10T14:23:18+00:00" }, { "name": "kwaadpepper/enum", diff --git a/resources/views/customer/index.blade.php b/resources/views/customer/index.blade.php index b700135..1cc32f9 100644 --- a/resources/views/customer/index.blade.php +++ b/resources/views/customer/index.blade.php @@ -45,7 +45,7 @@ @include('customer.index-tableHeaders') @if(session("crud.$modelTable.sort_way") and session("crud.$modelTable.sort_col")) - ⌫ + ⌫ @endif From 41909ff8e0852fca8d0e2889fde1aace679a5d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Tue, 14 Sep 2021 10:58:00 +0200 Subject: [PATCH 16/19] Question export --- app/Http/Controllers/QuestionController.php | 86 +++++++++++++++++++ app/Http/Requests/QuestionExport.php | 30 +++++++ .../views/layouts/backend/sidenav.blade.php | 7 +- resources/views/question/export.blade.php | 53 ++++++++++++ resources/views/question/index.blade.php | 1 - routes/web.php | 5 +- 6 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 app/Http/Requests/QuestionExport.php create mode 100644 resources/views/question/export.blade.php diff --git a/app/Http/Controllers/QuestionController.php b/app/Http/Controllers/QuestionController.php index 2fab894..2d0284c 100644 --- a/app/Http/Controllers/QuestionController.php +++ b/app/Http/Controllers/QuestionController.php @@ -3,10 +3,17 @@ 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 { @@ -36,4 +43,83 @@ class QuestionController extends Controller } 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; + } } diff --git a/app/Http/Requests/QuestionExport.php b/app/Http/Requests/QuestionExport.php new file mode 100644 index 0000000..8ef5ca7 --- /dev/null +++ b/app/Http/Requests/QuestionExport.php @@ -0,0 +1,30 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'brand' => 'required|numeric|exists:brands,id' + ]; + } +} diff --git a/resources/views/layouts/backend/sidenav.blade.php b/resources/views/layouts/backend/sidenav.blade.php index 306b120..dd36dca 100644 --- a/resources/views/layouts/backend/sidenav.blade.php +++ b/resources/views/layouts/backend/sidenav.blade.php @@ -42,7 +42,12 @@ @endcan @endforeach + +
-
diff --git a/routes/web.php b/routes/web.php index 53b3760..cf418a2 100644 --- a/routes/web.php +++ b/routes/web.php @@ -54,9 +54,8 @@ Route::middleware(['auth'])->group(function () { Route::post('/single_optins/{id}/delete', [SingleOptinController::class, 'delete'])->name('single-optins-delete'); // Questions + Route::get('/questions/export', [QuestionController::class, 'export'])->name('questions.export'); + Route::post('/questions/export', [QuestionController::class, 'exportSubmit'])->name('questions.exportSubmit'); Route::resource('questions', QuestionController::class); Route::resource('questions.answers', AnswerController::class); - - // Answers - // Route::resource('answers', AnswerController::class); }); From d74333848535a8f487e9046780693b6b5f7ff39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Tue, 14 Sep 2021 10:58:11 +0200 Subject: [PATCH 17/19] Fix newsletter export --- app/Http/Controllers/CustomerController.php | 2 ++ resources/views/customer/export.blade.php | 11 ++++++++--- resources/views/layouts/backend/sidenav.blade.php | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 5767015..ef34a83 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -141,7 +141,9 @@ class CustomerController extends Controller { // use a crud controller (any) to gather crudModels $modelsClasses = (new BrandController())->getCrudModels(); + $brands = Brand::all(); return view('customer.export', compact( + 'brands', 'modelsClasses' )); } diff --git a/resources/views/customer/export.blade.php b/resources/views/customer/export.blade.php index 14e1fde..b7d8726 100644 --- a/resources/views/customer/export.blade.php +++ b/resources/views/customer/export.blade.php @@ -1,7 +1,7 @@ @extends('layouts.app') -@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) -@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('title', sprintf('%s - %s', __('Newsletter Contacts'), __('Export'))) +@section('description', sprintf('%s - %s', __('Newsletter Contacts'), __('Export'))) @section('metaIndex', 'noindex,nofollow') @section('content') @@ -20,6 +20,11 @@
@csrf +
+
+

{{ __('Exporter un liste de client pour une newsletter') }}

+
+
@@ -28,7 +33,7 @@ diff --git a/resources/views/layouts/backend/sidenav.blade.php b/resources/views/layouts/backend/sidenav.blade.php index dd36dca..280b08a 100644 --- a/resources/views/layouts/backend/sidenav.blade.php +++ b/resources/views/layouts/backend/sidenav.blade.php @@ -48,6 +48,8 @@
+