├── public
├── favicon.ico
├── robots.txt
├── .DS_Store
├── images
│ ├── .DS_Store
│ ├── faker
│ │ ├── 1.jpg
│ │ ├── 2.jpg
│ │ ├── 3.jpg
│ │ ├── 4.jpg
│ │ ├── 5.jpg
│ │ └── 6.jpg
│ └── default
│ │ ├── avatar.png
│ │ ├── no_image.png
│ │ ├── avatar_1024.png
│ │ ├── avatar_512.png
│ │ ├── no_image_512.png
│ │ ├── no_image_1024.png
│ │ ├── avatar_original.png
│ │ └── no_image_original.png
├── vendor
│ └── telescope
│ │ ├── favicon.ico
│ │ └── mix-manifest.json
├── .htaccess
├── web.config
└── index.php
├── database
├── .gitignore
├── migrations
│ ├── 2022_07_24_134939_add_title_column_to_roles_table.php
│ ├── 2022_04_02_045642_create_refresh_tokens_table.php
│ ├── 2019_08_19_000000_create_failed_jobs_table.php
│ ├── 2019_12_14_000001_create_personal_access_tokens_table.php
│ ├── 2021_10_31_110750_create_categories_table.php
│ ├── 2021_10_31_111105_create_resources_table.php
│ ├── 2021_10_31_182630_create_products_table.php
│ ├── 2021_10_12_000000_create_users_table.php
│ └── 2022_04_28_145148_create_logger_table.php
├── factories
│ └── RoleFactory.php
└── seeders
│ ├── AdminSeeder.php
│ ├── PermissionsSeeder.php
│ ├── TestSeeder.php
│ └── UserSeeder.php
├── app
├── Core
│ ├── Http
│ │ ├── Controllers
│ │ │ ├── .gitkeep
│ │ │ └── CoreController.php
│ │ └── Requests
│ │ │ ├── ChangeStatusRequest.php
│ │ │ └── GetAllFilteredRecordsRequest.php
│ ├── Helpers
│ │ └── Generators
│ │ │ ├── Stubs
│ │ │ ├── route.stub
│ │ │ ├── policy.stub
│ │ │ ├── repository.stub
│ │ │ ├── service.stub
│ │ │ └── featureResourceTest.stub
│ │ │ └── EditRoute.php
│ ├── Macros
│ │ ├── WhereInRelation.php
│ │ ├── Closure.php
│ │ ├── IsSearchable.php
│ │ ├── Relations.php
│ │ ├── IsTranslatable.php
│ │ ├── Pagination.php
│ │ ├── Appends.php
│ │ ├── IsDates.php
│ │ ├── DbQuery.php
│ │ ├── PaginationOrCollection.php
│ │ ├── IsActive.php
│ │ ├── Deleted.php
│ │ ├── WhereLike.php
│ │ ├── Namespaces
│ │ │ └── QueryBuilder.php
│ │ ├── GetBy.php
│ │ └── EloquentQuery.php
│ ├── Contracts
│ │ ├── EnumTranslateContract.php
│ │ ├── ResourceTestContract.php
│ │ ├── CoreServiceContract.php
│ │ └── CoreRepositoryContract.php
│ ├── Traits
│ │ ├── EnumCasts.php
│ │ └── Responsable.php
│ ├── Providers
│ │ └── CoreServiceProvider.php
│ ├── Enums
│ │ └── CoreEnum.php
│ ├── Test
│ │ └── Feature
│ │ │ └── CoreTest.php
│ ├── Policies
│ │ └── CorePolicy.php
│ └── Services
│ │ └── CoreService.php
├── Policies
│ ├── ProductPolicy.php
│ ├── CategoryPolicy.php
│ ├── UserPolicy.php
│ ├── RolePolicy.php
│ └── PermissionPolicy.php
├── Helpers
│ ├── SubText.php
│ ├── RefreshTokenGenerator.php
│ ├── ExistsCheck.php
│ ├── DateCasts.php
│ └── TranslatableJson.php
├── Events
│ ├── DestroyFiles.php
│ ├── LoggerEvent.php
│ ├── AttachImages.php
│ ├── UpdateFile.php
│ └── UpdateImage.php
├── Repositories
│ ├── ProductRepository.php
│ ├── CategoryRepository.php
│ ├── LoggerRepository.php
│ ├── RoleRepository.php
│ ├── PermissionRepository.php
│ ├── UserRepository.php
│ └── ResourceRepository.php
├── Services
│ ├── UserService.php
│ ├── ProductService.php
│ ├── CategoryService.php
│ ├── LoggerService.php
│ ├── BarcodeService.php
│ ├── PermissionService.php
│ └── RoleService.php
├── Http
│ ├── Middleware
│ │ ├── EncryptCookies.php
│ │ ├── VerifyCsrfToken.php
│ │ ├── TrustHosts.php
│ │ ├── PreventRequestsDuringMaintenance.php
│ │ ├── TrimStrings.php
│ │ ├── Authenticate.php
│ │ ├── IsActive.php
│ │ ├── SetAppLocale.php
│ │ ├── TrustProxies.php
│ │ └── RedirectIfAuthenticated.php
│ ├── Requests
│ │ ├── Role
│ │ │ ├── PermissionRequest.php
│ │ │ ├── CheckPermissionsRequest.php
│ │ │ ├── RolesPermissionsRequest.php
│ │ │ ├── SyncPermissionsRequest.php
│ │ │ ├── PermissionCreateRequest.php
│ │ │ ├── PermissionUpdateRequest.php
│ │ │ ├── RoleCreateRequest.php
│ │ │ └── RoleUpdateRequest.php
│ │ ├── Auth
│ │ │ ├── LoginRequest.php
│ │ │ └── RegistrationRequest.php
│ │ ├── ProfileUpdateRequest.php
│ │ ├── UserUpdateRequest.php
│ │ ├── UserCreateRequest.php
│ │ ├── ProductUpdateRequest.php
│ │ └── ProductCreateRequest.php
│ └── Controllers
│ │ ├── ProductController.php
│ │ ├── CategoryController.php
│ │ ├── LoggerController.php
│ │ └── AuthController.php
├── Listeners
│ ├── LoggerListener.php
│ ├── DestroyFilesListener.php
│ ├── AttachImagesListener.php
│ ├── UpdateImageListener.php
│ └── UpdateFileListener.php
├── Traits
│ ├── IsActive.php
│ └── Author.php
├── Providers
│ ├── BroadcastServiceProvider.php
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── EventServiceProvider.php
│ └── RouteServiceProvider.php
├── Models
│ ├── Role.php
│ ├── Resource.php
│ ├── RefreshToken.php
│ └── Logger.php
├── Rules
│ ├── PhoneRule.php
│ ├── CheckJsonExistsLocale.php
│ ├── PermissionRule.php
│ ├── UniqueRule.php
│ ├── UniqueJsonRule.php
│ ├── CheckJsonExistsNullableLocale.php
│ ├── checkActiveRule.php
│ └── ExistsRule.php
├── Observers
│ ├── CategoryObserver.php
│ ├── UserObserver.php
│ └── ProductObserver.php
├── Jobs
│ └── LoggerJob.php
└── Console
│ └── Kernel.php
├── bootstrap
├── cache
│ └── .gitignore
└── app.php
├── storage
├── logs
│ └── .gitignore
├── app
│ ├── public
│ │ └── .gitignore
│ └── .gitignore
└── framework
│ ├── testing
│ └── .gitignore
│ ├── views
│ └── .gitignore
│ ├── cache
│ ├── data
│ │ └── .gitignore
│ └── .gitignore
│ ├── sessions
│ └── .gitignore
│ └── .gitignore
├── .DS_Store
├── .docker
├── web
│ ├── container-start
│ ├── crontab.txt
│ ├── php-custom.ini
│ ├── php-fpm.conf
│ ├── opcache.ini
│ ├── nginx.conf
│ ├── app.conf
│ └── supervisord.conf
├── web.debug
│ ├── container-start
│ ├── crontab.txt
│ ├── php-custom.ini
│ ├── xdebug.ini
│ ├── opcache.ini
│ ├── nginx.conf
│ ├── app.conf
│ └── supervisord.conf
├── web.dev
│ ├── container-start
│ ├── crontab.txt
│ ├── php-custom.ini
│ ├── xdebug.ini
│ ├── opcache.ini
│ ├── nginx.conf
│ ├── app.conf
│ └── supervisord.conf
└── web.loc
│ ├── container-start
│ ├── crontab.txt
│ ├── php-custom.ini
│ ├── opcache.ini
│ ├── nginx.conf
│ ├── app.conf
│ └── supervisord.conf
├── phpunit.phar
├── lang
├── en
│ ├── errors.php
│ ├── attributes.php
│ ├── pagination.php
│ ├── passwords.php
│ ├── auth.php
│ └── messages.php
├── ru
│ ├── errors.php
│ ├── attributes.php
│ ├── pagination.php
│ ├── auth.php
│ ├── passwords.php
│ └── messages.php
├── uz
│ ├── errors.php
│ ├── attributes.php
│ ├── pagination.php
│ ├── auth.php
│ ├── passwords.php
│ └── messages.php
└── en.json
├── routes
├── api
│ ├── products.php
│ ├── categories.php
│ ├── logger.php
│ ├── auth.php
│ ├── users.php
│ └── roles.php
├── web.php
├── channels.php
└── console.php
├── .gitattributes
├── tests
├── TestCase.php
├── CreatesApplication.php
└── Unit
│ └── BarcodeGenerateTest.php
├── .styleci.yml
├── stubs
├── model.stub
├── migration.stub
├── request.stub
├── migration.create.stub
├── migration.update.stub
├── policy.stub
└── observer.stub
├── .gitignore
├── .editorconfig
├── package.json
├── webpack.mix.js
├── server.php
├── .github
└── workflows
│ ├── conteyner-info.txt
│ └── tests.yml
├── config
├── cors.php
├── modulegenerator.php
├── filesystems.php
├── services.php
├── view.php
└── hashing.php
├── phpunit.xml
├── .env.example
├── .env.testing.fail
├── .env.example.docker
├── docker-compose-mysql.yaml
├── docker-compose.yml
├── artisan
└── docker-compose-prod.yaml
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite*
2 |
--------------------------------------------------------------------------------
/app/Core/Http/Controllers/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/storage/app/public/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !public/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/storage/framework/testing/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/cache/data/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !data/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/.DS_Store
--------------------------------------------------------------------------------
/.docker/web/container-start:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | /usr/bin/supervisord -c /etc/supervisord.conf
3 |
--------------------------------------------------------------------------------
/phpunit.phar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/phpunit.phar
--------------------------------------------------------------------------------
/.docker/web.debug/container-start:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | /usr/bin/supervisord -c /etc/supervisord.conf
3 |
--------------------------------------------------------------------------------
/.docker/web.dev/container-start:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | /usr/bin/supervisord -c /etc/supervisord.conf
3 |
--------------------------------------------------------------------------------
/.docker/web.loc/container-start:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | /usr/bin/supervisord -c /etc/supervisord.conf
3 |
--------------------------------------------------------------------------------
/.docker/web/crontab.txt:
--------------------------------------------------------------------------------
1 | * * * * * php /var/www/artisan schedule:run >> /var/log/cron.log 2>&1
2 |
--------------------------------------------------------------------------------
/.docker/web.debug/crontab.txt:
--------------------------------------------------------------------------------
1 | * * * * * php /var/www/artisan schedule:run >> /var/log/cron.log 2>&1
2 |
--------------------------------------------------------------------------------
/.docker/web.dev/crontab.txt:
--------------------------------------------------------------------------------
1 | * * * * * php /var/www/artisan schedule:run >> /var/log/cron.log 2>&1
2 |
--------------------------------------------------------------------------------
/.docker/web.loc/crontab.txt:
--------------------------------------------------------------------------------
1 | * * * * * php /var/www/artisan schedule:run >> /var/log/cron.log 2>&1
2 |
--------------------------------------------------------------------------------
/public/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/.DS_Store
--------------------------------------------------------------------------------
/public/images/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/.DS_Store
--------------------------------------------------------------------------------
/lang/en/errors.php:
--------------------------------------------------------------------------------
1 | 'No records found, try another request',
5 | ];
6 |
--------------------------------------------------------------------------------
/lang/ru/errors.php:
--------------------------------------------------------------------------------
1 | 'No records found, try another request',
5 | ];
6 |
--------------------------------------------------------------------------------
/lang/uz/errors.php:
--------------------------------------------------------------------------------
1 | 'No records found, try another request',
5 | ];
6 |
--------------------------------------------------------------------------------
/public/images/faker/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/faker/1.jpg
--------------------------------------------------------------------------------
/public/images/faker/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/faker/2.jpg
--------------------------------------------------------------------------------
/public/images/faker/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/faker/3.jpg
--------------------------------------------------------------------------------
/public/images/faker/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/faker/4.jpg
--------------------------------------------------------------------------------
/public/images/faker/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/faker/5.jpg
--------------------------------------------------------------------------------
/public/images/faker/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/faker/6.jpg
--------------------------------------------------------------------------------
/public/images/default/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/default/avatar.png
--------------------------------------------------------------------------------
/public/images/default/no_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/default/no_image.png
--------------------------------------------------------------------------------
/public/vendor/telescope/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/vendor/telescope/favicon.ico
--------------------------------------------------------------------------------
/public/images/default/avatar_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/default/avatar_1024.png
--------------------------------------------------------------------------------
/public/images/default/avatar_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/default/avatar_512.png
--------------------------------------------------------------------------------
/public/images/default/no_image_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TursunboyevJahongir/laravel_api/HEAD/public/images/default/no_image_512.png
--------------------------------------------------------------------------------
/routes/api/products.php:
--------------------------------------------------------------------------------
1 | 'category',
5 | 'product' => 'product',
6 | 'user' => 'user',
7 | 'role' => 'role',
8 | ];
9 |
--------------------------------------------------------------------------------
/lang/ru/attributes.php:
--------------------------------------------------------------------------------
1 | 'category',
5 | 'product' => 'product',
6 | 'user' => 'user',
7 | 'role' => 'role',
8 | ];
9 |
--------------------------------------------------------------------------------
/lang/uz/attributes.php:
--------------------------------------------------------------------------------
1 | 'category',
5 | 'product' => 'product',
6 | 'user' => 'user',
7 | 'role' => 'role',
8 | ];
9 |
--------------------------------------------------------------------------------
/storage/framework/.gitignore:
--------------------------------------------------------------------------------
1 | compiled.php
2 | config.php
3 | down
4 | events.scanned.php
5 | maintenance.php
6 | routes.php
7 | routes.scanned.php
8 | schedule-*
9 | services.json
10 |
--------------------------------------------------------------------------------
/app/Core/Helpers/Generators/Stubs/route.stub:
--------------------------------------------------------------------------------
1 | middleware(['permission:read-logger'])
7 | ->controller('LoggerController')
8 | ->group(function () {
9 | Route::get('/', 'index');
10 | Route::get('/{logger}', 'show');
11 | });
12 |
--------------------------------------------------------------------------------
/app/Events/DestroyFiles.php:
--------------------------------------------------------------------------------
1 | whereHas($relation, function (Builder $query)
7 | use ($column, $value, $boolean) {
8 | $query->whereIn($column, $value, boolean: $boolean);
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 | where(\Closure::fromCallable([$class, $status]));
9 |
10 | return $this;
11 | });
12 | }
13 |
--------------------------------------------------------------------------------
/app/Http/Requests/Role/PermissionRequest.php:
--------------------------------------------------------------------------------
1 | rules();
12 | }
13 |
14 | public function authorize(): bool
15 | {
16 | return true;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/routes/api/auth.php:
--------------------------------------------------------------------------------
1 | controller('AuthController')
7 | ->withoutMiddleware(['auth:api', 'api', 'isActive'])
8 | ->group(function () {
9 | Route::post('register', 'register');
10 | Route::post('login', 'login');
11 | Route::post('refresh', 'refresh');
12 | Route::post('logout', 'logout');
13 | });
14 |
--------------------------------------------------------------------------------
/routes/api/users.php:
--------------------------------------------------------------------------------
1 | withoutMiddleware('isActive')
7 | ->controller(UserController::class)
8 | ->group(function () {
9 | Route::get('/', 'profile');
10 | Route::patch('/', 'updateProfile');
11 | });
12 |
13 | Route::apiResource('users', UserController::class);
14 |
--------------------------------------------------------------------------------
/app/Events/LoggerEvent.php:
--------------------------------------------------------------------------------
1 | allSubdomainsOfApplicationUrl(),
16 | ];
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Listeners/LoggerListener.php:
--------------------------------------------------------------------------------
1 | service->log($event->response, $event->response_status, $event->response_message);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/Core/Macros/IsSearchable.php:
--------------------------------------------------------------------------------
1 | getSearchable(), true);
7 | });
8 |
9 | EloquentBuilder::macro('getSearchable', function (): array {
10 | return method_exists($this->getModel(), 'getSearchable') ?
11 | $this->getModel()->getSearchable() : [];
12 | });
13 |
--------------------------------------------------------------------------------
/app/Listeners/DestroyFilesListener.php:
--------------------------------------------------------------------------------
1 | resource->destroyImages($event->imageIds);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Traits/IsActive.php:
--------------------------------------------------------------------------------
1 | fillable[] = 'is_active';
12 | $this->casts['is_active'] = 'bool';
13 | }
14 |
15 |
16 | public function scopeActive(Builder $query)
17 | {
18 | return $query->whereIsActive(true);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/app/Listeners/AttachImagesListener.php:
--------------------------------------------------------------------------------
1 | resource->attachImages($event->images, $event->relation, $event->path, $event->identifier);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/Listeners/UpdateImageListener.php:
--------------------------------------------------------------------------------
1 | resource->updateImage($event->file, $event->relation, $event->path, $event->identifier);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/Events/AttachImages.php:
--------------------------------------------------------------------------------
1 | resource->updateFile($event->file, $event->relation, path: $event->path, identifier: $event->identifier);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | 'required|regex:/^998[0-9]{9}/',
16 | 'password' => 'required'
17 | ];
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/Http/Requests/Role/CheckPermissionsRequest.php:
--------------------------------------------------------------------------------
1 | ['required', new PermissionRule()]];
13 | }
14 |
15 | public function authorize(): bool
16 | {
17 | return true;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/CreatesApplication.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class)->bootstrap();
18 |
19 | return $app;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Core/Macros/Relations.php:
--------------------------------------------------------------------------------
1 | with($relations);
13 | });
14 |
--------------------------------------------------------------------------------
/app/Events/UpdateFile.php:
--------------------------------------------------------------------------------
1 | "required|array",
12 | "roles.*" => "required|distinct|exists:roles,id",
13 | ];
14 | }
15 |
16 | public function authorize(): bool
17 | {
18 | return true;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.docker/web.debug/opcache.ini:
--------------------------------------------------------------------------------
1 | [opcache]
2 | opcache.max_accelerated_files=10000
3 | opcache.memory_consumption=192
4 | opcache.max_wasted_percentage=10
5 | opcache.interned_strings_buffer=16
6 | opcache.fast_shutdown=1
7 | ; 0 means it will check on every request
8 | ; 0 is irrelevant if opcache.validate_timestamps=0 which is desirable in production
9 | # https://www.php.net/manual/en/opcache.configuration.php
10 | opcache.enable=1
11 | opcache.enable_cli=0
12 | opcache.validate_timestamps=1
13 | opcache.revalidate_freq=0
14 |
--------------------------------------------------------------------------------
/.docker/web.dev/opcache.ini:
--------------------------------------------------------------------------------
1 | [opcache]
2 | opcache.max_accelerated_files=10000
3 | opcache.memory_consumption=192
4 | opcache.max_wasted_percentage=10
5 | opcache.interned_strings_buffer=16
6 | opcache.fast_shutdown=1
7 | ; 0 means it will check on every request
8 | ; 0 is irrelevant if opcache.validate_timestamps=0 which is desirable in production
9 | # https://www.php.net/manual/en/opcache.configuration.php
10 | opcache.enable=1
11 | opcache.enable_cli=0
12 | opcache.validate_timestamps=1
13 | opcache.revalidate_freq=0
14 |
--------------------------------------------------------------------------------
/.docker/web.loc/opcache.ini:
--------------------------------------------------------------------------------
1 | [opcache]
2 | opcache.max_accelerated_files=10000
3 | opcache.memory_consumption=192
4 | opcache.max_wasted_percentage=10
5 | opcache.interned_strings_buffer=16
6 | opcache.fast_shutdown=1
7 | ; 0 means it will check on every request
8 | ; 0 is irrelevant if opcache.validate_timestamps=0 which is desirable in production
9 | # https://www.php.net/manual/en/opcache.configuration.php
10 | opcache.enable=1
11 | opcache.enable_cli=0
12 | opcache.validate_timestamps=1
13 | opcache.revalidate_freq=0
14 |
--------------------------------------------------------------------------------
/app/Helpers/ExistsCheck.php:
--------------------------------------------------------------------------------
1 | when($softDeletes, function ($query) {
13 | $query->whereNull('deleted_at');
14 | })
15 | ->where($column, $value)
16 | ->exists();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Http/Requests/Role/SyncPermissionsRequest.php:
--------------------------------------------------------------------------------
1 | 'required|array',
13 | 'permissions.*' => ['required', new PermissionRule()]];
14 | }
15 |
16 | public function authorize(): bool
17 | {
18 | return true;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Http/Controllers/ProductController.php:
--------------------------------------------------------------------------------
1 | id();
13 | $table->timestamps();
14 | });
15 | }
16 |
17 | public function down()
18 | {
19 | Schema::dropIfExists('{{ table }}');
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/app/Models/Role.php:
--------------------------------------------------------------------------------
1 | TranslatableJson::class,
19 | ];
20 | }
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "npm run development",
5 | "development": "mix",
6 | "watch": "mix watch",
7 | "watch-poll": "mix watch -- --watch-options-poll=1000",
8 | "hot": "mix watch --hot",
9 | "prod": "npm run production",
10 | "production": "mix --production"
11 | },
12 | "devDependencies": {
13 | "axios": "^0.21",
14 | "laravel-mix": "^6.0.6",
15 | "lodash": "^4.17.19",
16 | "postcss": "^8.1.14"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/stubs/migration.update.stub:
--------------------------------------------------------------------------------
1 | 'Вперёд »',
16 | 'previous' => '« Назад',
17 | ];
18 |
--------------------------------------------------------------------------------
/app/Http/Controllers/CategoryController.php:
--------------------------------------------------------------------------------
1 | 'Keyingi »',
16 | 'previous' => '« Oldingi',
17 | ];
18 |
--------------------------------------------------------------------------------
/app/Core/Macros/IsTranslatable.php:
--------------------------------------------------------------------------------
1 | getLocale();
7 |
8 | return $this->isTranslatable($field) ? "$field->$lang" : $field;
9 | });
10 |
11 | EloquentBuilder::macro('isTranslatable', function (string $field): bool {
12 | return method_exists($this->getModel(), 'getTranslatableColumns') &&
13 | in_array($field, $this->getModel()->getTranslatableColumns(), true);
14 | });
15 |
--------------------------------------------------------------------------------
/database/migrations/2022_07_24_134939_add_title_column_to_roles_table.php:
--------------------------------------------------------------------------------
1 | jsonb('title');
12 | });
13 | }
14 |
15 | public function down(): void
16 | {
17 | Schema::table('roles', function (Blueprint $table) {
18 | });
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/app/Core/Http/Requests/ChangeStatusRequest.php:
--------------------------------------------------------------------------------
1 | 'required|boolean'];
15 | }
16 |
17 | /**
18 | * Determine if the user is authorized to make this request.
19 | */
20 | public function authorize(): bool
21 | {
22 | return true;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | expectsJson()) {
16 | return route('login');
17 | }
18 |
19 | return $request->expectsJson() ? null : route('login');
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Middleware/IsActive.php:
--------------------------------------------------------------------------------
1 | check() && !auth()->user()->is_active) {
19 | return $this->responseWith(code: 403, message: __("messages.account_not_active"));
20 | }
21 |
22 | return $next($request);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Core/Macros/Pagination.php:
--------------------------------------------------------------------------------
1 | paginate($per_page);
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/routes/api/roles.php:
--------------------------------------------------------------------------------
1 | controller('RoleController')
8 | ->group(function () {
9 | Route::post('/{role}/permissions/add', 'assignPermission');
10 | Route::post('/{role}/permissions/sub', 'revokePermission');
11 | Route::post('/{role}/permissions/sync', 'syncPermissions');
12 | });
13 |
14 | Route::apiResource('permissions', 'PermissionController');
15 | Route::post('permissions/check-permission/{user?}', 'PermissionController@hasAllPermissions');
16 |
--------------------------------------------------------------------------------
/lang/en/pagination.php:
--------------------------------------------------------------------------------
1 | '« Previous',
17 | 'next' => 'Next »',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/webpack.mix.js:
--------------------------------------------------------------------------------
1 | const mix = require('laravel-mix');
2 |
3 | /*
4 | |--------------------------------------------------------------------------
5 | | Mix Asset Management
6 | |--------------------------------------------------------------------------
7 | |
8 | | Mix provides a clean, fluent API for defining some Webpack build steps
9 | | for your Laravel applications. By default, we are compiling the CSS
10 | | file for the application as well as bundling up all the JS files.
11 | |
12 | */
13 |
14 | mix.js('resources/js/app.js', 'public/js')
15 | .postCss('resources/css/app.css', 'public/css', [
16 | //
17 | ]);
18 |
--------------------------------------------------------------------------------
/app/Core/Http/Controllers/CoreController.php:
--------------------------------------------------------------------------------
1 | service = $service;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/routes/channels.php:
--------------------------------------------------------------------------------
1 | id === (int) $id;
18 | });
19 |
--------------------------------------------------------------------------------
/app/Policies/UserPolicy.php:
--------------------------------------------------------------------------------
1 | $this->faker->slug,
16 | 'title' => [
17 | 'uz' => $this->faker->title,
18 | 'ru' => $this->faker->title,
19 | 'en' => $this->faker->title,
20 | ],
21 | 'guard_name' => 'api',
22 | ];
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Policies/RolePolicy.php:
--------------------------------------------------------------------------------
1 | name === "superadmin") {
20 | return Response::deny(__('messages.not_access'));
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/server.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 |
10 | $uri = urldecode(
11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
12 | );
13 |
14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the
15 | // built-in PHP web server. This provides a convenient way to test a Laravel
16 | // application without having installed a "real" web server software here.
17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
18 | return false;
19 | }
20 |
21 | require_once __DIR__.'/public/index.php';
22 |
--------------------------------------------------------------------------------
/.github/workflows/conteyner-info.txt:
--------------------------------------------------------------------------------
1 | The ${{matrix.php}} is a reference to a value in the matrix strategy, which specifies a list of values for the php key.
2 |
3 | This strategy creates multiple jobs based on the php values, allowing the same test suite to be run against different versions of PHP in parallel.
4 |
5 | For example, if the matrix was defined as:
6 |
7 | python
8 | Copy code
9 | matrix:
10 | php: ['7.0', '7.1', '7.2']
11 | Then three jobs would be created, one for each PHP version:
12 |
13 | Copy code
14 | PHP 7.0
15 | PHP 7.1
16 | PHP 7.2
17 | In the job, the value of ${{matrix.php}} is used to set up the correct version of PHP and run the tests.
18 |
--------------------------------------------------------------------------------
/app/Policies/PermissionPolicy.php:
--------------------------------------------------------------------------------
1 | append($appends);
18 | }
19 |
20 | return $this;
21 | });
22 |
--------------------------------------------------------------------------------
/app/Http/Requests/Role/PermissionCreateRequest.php:
--------------------------------------------------------------------------------
1 | merge(['name' => Str::kebab(trim($this->name))]);
13 | }
14 |
15 | public function rules(): array
16 | {
17 | return ['name' => 'required|string|unique:permissions,name',
18 | 'guard_name' => 'string'];
19 | }
20 |
21 | public function authorize(): bool
22 | {
23 | return true;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/routes/console.php:
--------------------------------------------------------------------------------
1 | comment(Inspiring::quote());
19 | })->purpose('Display an inspiring quote');
20 |
--------------------------------------------------------------------------------
/tests/Unit/BarcodeGenerateTest.php:
--------------------------------------------------------------------------------
1 | assertIsArray($barcode);
14 | $this->assertArrayHasKey('barcode', $barcode);
15 | $this->assertArrayHasKey('barcode_path', $barcode);
16 | \Storage::disk('public')->assertExists(data_get($barcode, 'barcode_path'));
17 | \Storage::disk('public')->delete(data_get($barcode, 'barcode_path'));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lang/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "The :attribute must contain at least one letter.": "The :attribute must contain at least one letter.",
3 | "The :attribute must contain at least one number.": "The :attribute must contain at least one number.",
4 | "The :attribute must contain at least one symbol.": "The :attribute must contain at least one symbol.",
5 | "The :attribute must contain at least one uppercase and one lowercase letter.": "The :attribute must contain at least one uppercase and one lowercase letter.",
6 | "The given :attribute has appeared in a data leak. Please choose a different :attribute.": "The given :attribute has appeared in a data leak. Please choose a different :attribute."
7 | }
8 |
--------------------------------------------------------------------------------
/database/seeders/AdminSeeder.php:
--------------------------------------------------------------------------------
1 | activated()
21 | ->create(['phone' => '998999999999',
22 | 'password' => '111111',
23 | ])->assignRole('superadmin');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Helpers/DateCasts.php:
--------------------------------------------------------------------------------
1 | format($this->format) : null;
19 | }
20 |
21 | public function set($model, string $key, $value, array $attributes)
22 | {
23 | return $value ? Carbon::parse($value) : null;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Rules/CheckJsonExistsLocale.php:
--------------------------------------------------------------------------------
1 | config('laravel_api.main_locale')]);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/public/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews -Indexes
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Handle Authorization Header
9 | RewriteCond %{HTTP:Authorization} .
10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
11 |
12 | # Redirect Trailing Slashes If Not A Folder...
13 | RewriteCond %{REQUEST_FILENAME} !-d
14 | RewriteCond %{REQUEST_URI} (.+)/$
15 | RewriteRule ^ %1 [L,R=301]
16 |
17 | # Send Requests To Front Controller...
18 | RewriteCond %{REQUEST_FILENAME} !-d
19 | RewriteCond %{REQUEST_FILENAME} !-f
20 | RewriteRule ^ index.php [L]
21 |
22 |
--------------------------------------------------------------------------------
/app/Http/Middleware/SetAppLocale.php:
--------------------------------------------------------------------------------
1 | hasHeader('accept-language') &&
17 | in_array($request->header('accept-language'), config('laravel_api.available_locales', []), true)) {
18 | $locale = $request->header('accept-language');
19 | }
20 | app()->setLocale($locale);
21 |
22 | return $next($request);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Core/Helpers/Generators/Stubs/featureResourceTest.stub:
--------------------------------------------------------------------------------
1 | merge(['name' => Str::kebab($this->name)]);
13 | }
14 |
15 | public function rules(): array
16 | {
17 | return ['name' => 'required|string|unique:permissions,name,' . $this->route('permission')->id,
18 | 'guard_name' => 'string',
19 | ];
20 | }
21 |
22 | public function authorize(): bool
23 | {
24 | return true;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lang/ru/auth.php:
--------------------------------------------------------------------------------
1 | 'Эти учетные данные не соответствуют нашим записям.',
16 | 'password' => 'Неверный номер телефона или пароль.',
17 | 'throttle' => 'Слишком много попыток входа. Пожалуйста, попробуйте еще раз через :seconds секунд.',
18 | ];
19 |
--------------------------------------------------------------------------------
/lang/uz/auth.php:
--------------------------------------------------------------------------------
1 | 'Bunday maʼlumotlarga ega foydalanuvchi mavjud emas.',
16 | 'password' => 'Telefon raqami yoki parol noto‘g‘ri.',
17 | 'throttle' => 'Kirish uchun juda ko‘p urinishlar aniqlandi. Iltimos :seconds soniyadan so‘ng yana urinib ko‘ring.',
18 | ];
19 |
--------------------------------------------------------------------------------
/database/seeders/PermissionsSeeder.php:
--------------------------------------------------------------------------------
1 | 'system']);
14 | Role::findByName('superadmin')->syncPermissions(Permission::all());
15 | $manager = Role::findByName('moderator');
16 | $manager->syncPermissions(
17 | ['read-user',
18 | 'create-user',
19 | 'update-user',
20 | 'read-category',
21 | 'create-category',
22 | 'update-category',]
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Observers/CategoryObserver.php:
--------------------------------------------------------------------------------
1 | ico?->id);
14 | }
15 |
16 | public function created(Category $category)
17 | {
18 | if (request()->hasFile('ico')) {
19 | UpdateImage::dispatch(request('ico'), $category->ico());
20 | }
21 | }
22 |
23 | public function updated(Category $category)
24 | {
25 | if (request()->hasFile('ico')) {
26 | UpdateImage::dispatch(request('ico'), $category->ico());
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrustProxies.php:
--------------------------------------------------------------------------------
1 | app->environment('local')) {
16 | $this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
17 | $this->app->register(TelescopeServiceProvider::class);
18 | }
19 | }
20 |
21 | /**
22 | * Bootstrap any application services.
23 | */
24 | public function boot()
25 | {
26 | Model::preventLazyLoading(!app()->isProduction());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Http/Requests/Auth/RegistrationRequest.php:
--------------------------------------------------------------------------------
1 | [
18 | 'required',
19 | new PhoneRule(),
20 | new UniqueRule('users', 'phone'),
21 | ],
22 | 'first_name' => 'required|string',
23 | 'last_name' => 'nullable|string',
24 | 'password' => 'required|confirmed|min:6',
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Traits/Author.php:
--------------------------------------------------------------------------------
1 | author_id = $query->author_id ?? auth()->id();
14 | });
15 | }
16 |
17 | public function initializeAuthor(): void
18 | {
19 | $this->fillable[] = 'author_id';
20 | $this->casts['author_id'] = 'int';
21 | }
22 |
23 | public function isMine($id): bool
24 | {
25 | return $id === auth()->id();
26 | }
27 |
28 | public function author(): BelongsTo
29 | {
30 | return $this->belongsTo(User::class, 'author_id');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Services/BarcodeService.php:
--------------------------------------------------------------------------------
1 | where($column, $random)->doesntExist() ? : self::generate($table, $column, $path);
14 | $generator = new BarcodeGeneratorSVG();
15 | Storage::disk('public')
16 | ->put("uploads/$path/barcodes/$random.svg", $generator
17 | ->getBarcode($random, $generator::TYPE_CODE_128));
18 |
19 | return [$column => $random, $column . "_path" => "/uploads/$path/barcodes/$random.svg"];
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Helpers/TranslatableJson.php:
--------------------------------------------------------------------------------
1 | getLocale()) : null;
12 | }
13 |
14 | public function set($model, string $key, $value, array $attributes)
15 | {
16 | return json_encode($value);
17 | }
18 |
19 | public static function translatable($attribute, $key = null)
20 | {
21 | $arr = json_decode($attribute, true);
22 | if (request()->has('edit_json')) {
23 | return $arr;
24 | }
25 |
26 | return $arr[$key] ?? $arr[config('laravel_api.main_locale')];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lang/ru/passwords.php:
--------------------------------------------------------------------------------
1 | 'Ваш пароль был сброшен!',
16 | 'sent' => 'Ссылка на сброс пароля была отправлена!',
17 | 'throttled' => 'Пожалуйста, подождите перед повторной попыткой.',
18 | 'token' => 'Ошибочный код сброса пароля.',
19 | 'user' => 'Не удалось найти пользователя с указанным электронным адресом.',
20 | ];
21 |
--------------------------------------------------------------------------------
/database/migrations/2022_04_02_045642_create_refresh_tokens_table.php:
--------------------------------------------------------------------------------
1 | id();
13 | $table->text('token');
14 | $table->text('refresh_token');
15 | $table->dateTime('expired_at')->nullable();
16 | $table->dateTime('refresh_expired_at');
17 | $table->morphs('user');
18 | $table->timestamps();
19 | });
20 | }
21 |
22 | public function down(): void
23 | {
24 | Schema::dropIfExists('refresh_tokens');
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/lang/en/passwords.php:
--------------------------------------------------------------------------------
1 | 'Your password has been reset!',
17 | 'sent' => 'We have emailed your password reset link!',
18 | 'throttled' => 'Please wait before retrying.',
19 | 'token' => 'This password reset token is invalid.',
20 | 'user' => "We can't find a user with that email address.",
21 |
22 | ];
23 |
--------------------------------------------------------------------------------
/app/Core/Macros/IsDates.php:
--------------------------------------------------------------------------------
1 | getModel()->getTable() . 'inDates', 86400, function () {//60 * 60 * 24=day
8 | $keys = collect($this->getModel()->getCasts())
9 | ->filter(function ($value, $key) {
10 | if (str_contains($value, 'DateCasts')
11 | || str_contains($value, 'datetime')
12 | || str_contains($value, 'date')) {
13 | return $key;
14 | }
15 | });
16 |
17 | return array_unique($keys->keys()->toArray() + $this->getModel()->getDates());
18 | });
19 |
20 |
21 | return in_array($field, $dates);
22 | });
23 |
--------------------------------------------------------------------------------
/lang/uz/passwords.php:
--------------------------------------------------------------------------------
1 | 'Sizning parolingiz tiklandi!',
16 | 'sent' => 'Parolni tiklash havolasini elektron pochta orqali yubordik!',
17 | 'throttled' => 'Iltimos birozdan so‘ng qayta urinib ko‘ring.',
18 | 'token' => 'Ushbu parolni qayta tiklash kodi noto‘g‘ri.',
19 | 'user' => 'Ushbu elektron pochta manziliga ega foydalanuvchi topilmadi.',
20 | ];
21 |
--------------------------------------------------------------------------------
/app/Http/Requests/ProfileUpdateRequest.php:
--------------------------------------------------------------------------------
1 | 'filled|string',
16 | 'last_name' => 'nullable|string',
17 | 'phone' => [
18 | 'filled',
19 | new PhoneRule(),
20 | new UniqueRule('users', 'phone', $this->route('user', auth()->user())->id),
21 | ],
22 | 'password' => ['filled', 'string', 'confirmed', Password::min(8)->letters()->numbers()],
23 | 'avatar' => 'image',
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/database/seeders/TestSeeder.php:
--------------------------------------------------------------------------------
1 | call(RolesTableSeeder::class);
17 | $this->call(AdminSeeder::class);
18 |
19 | dump('create active user');
20 | User::factory(2)->activated()->create();
21 | User::factory(5)->createQuietly();
22 |
23 | dump('create Category with products');
24 | Category::factory(2)->hasProducts(random_int(5, 10))->create();
25 | Category::factory(5)->hasProducts(random_int(5, 10))->create();
26 | Category::factory(5)->hasProducts(random_int(5, 10))->create();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Core/Macros/DbQuery.php:
--------------------------------------------------------------------------------
1 | make(request()->all(), [
11 | config('laravel_api.request.columns', 'columns') => 'string',
12 | ]);
13 |
14 | if ($validator->fails()) {
15 | throw ValidationException::withMessages($validator->messages()->toArray());
16 | }
17 | $requestColumns = request(config('laravel_api.request.columns', 'columns'), ['*']);
18 |
19 | if ($requestColumns !== ['*']) {
20 | $requestColumns = explode(',', $requestColumns);
21 | }
22 | $columns = $columns ?? $requestColumns;
23 |
24 | return $query->select($columns);
25 | });
26 |
--------------------------------------------------------------------------------
/app/Core/Traits/EnumCasts.php:
--------------------------------------------------------------------------------
1 | $this->getTranslate($value)] : null;
10 | if (request()->exists('enums')) {
11 | return $data ? $data + $this->getTranslateValuesToArray() : $this->getTranslateValuesToArray();
12 | }
13 |
14 | return $data;
15 | }
16 |
17 | //before set check if value is valid else return exception and rollback
18 | public function set($model, string $key, $value, array $attributes)
19 | {
20 | if (!$this->isValid($value)) {
21 | throw new \Exception(__('validation.in_array',
22 | ['attribute' => $value, 'other' => "$key:" . $this]), 422);
23 | }
24 |
25 | return $value;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/database/migrations/2019_08_19_000000_create_failed_jobs_table.php:
--------------------------------------------------------------------------------
1 | tableName, function (Blueprint $table) {
13 | $table->id();
14 | $table->string('uuid')->unique();
15 | $table->text('connection');
16 | $table->text('queue');
17 | $table->longText('payload');
18 | $table->longText('exception');
19 | $table->timestamp('failed_at')->useCurrent();
20 | });
21 | }
22 |
23 | public function down(): void
24 | {
25 | Schema::dropIfExists($this->tableName);
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/.docker/web.dev/nginx.conf:
--------------------------------------------------------------------------------
1 | user www;
2 | worker_processes 4;
3 | error_log /var/log/nginx/error.log notice;
4 | pid /var/run/nginx.pid;
5 |
6 | events {
7 | worker_connections 4096;
8 | }
9 |
10 | http {
11 | include /etc/nginx/mime.types;
12 | include /etc/nginx/fastcgi.conf;
13 | index index.html index.php;
14 | ssl_session_cache shared:SSL:10m;
15 | ssl_session_timeout 10m;
16 | default_type application/octet-stream;
17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
18 | '$status $body_bytes_sent "$http_referer" '
19 | '"$http_user_agent" "$http_x_forwarded_for"';
20 | access_log /var/log/nginx/access.log main;
21 | sendfile on;
22 | tcp_nopush on;
23 | server_names_hash_bucket_size 128;
24 | keepalive_timeout 65;
25 | gzip on;
26 |
27 | include /etc/nginx/conf.d/*.conf;
28 | }
29 |
--------------------------------------------------------------------------------
/.docker/web.loc/nginx.conf:
--------------------------------------------------------------------------------
1 | user www;
2 | worker_processes 4;
3 | error_log /var/log/nginx/error.log notice;
4 | pid /var/run/nginx.pid;
5 |
6 | events {
7 | worker_connections 4096;
8 | }
9 |
10 | http {
11 | include /etc/nginx/mime.types;
12 | include /etc/nginx/fastcgi.conf;
13 | index index.html index.php;
14 | ssl_session_cache shared:SSL:10m;
15 | ssl_session_timeout 10m;
16 | default_type application/octet-stream;
17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
18 | '$status $body_bytes_sent "$http_referer" '
19 | '"$http_user_agent" "$http_x_forwarded_for"';
20 | access_log /var/log/nginx/access.log main;
21 | sendfile on;
22 | tcp_nopush on;
23 | server_names_hash_bucket_size 128;
24 | keepalive_timeout 65;
25 | gzip on;
26 |
27 | include /etc/nginx/conf.d/*.conf;
28 | }
29 |
--------------------------------------------------------------------------------
/.docker/web/nginx.conf:
--------------------------------------------------------------------------------
1 | user www;
2 | worker_processes 4;
3 | error_log /var/log/nginx/error.log notice;
4 | pid /var/run/nginx.pid;
5 |
6 | events {
7 | worker_connections 4096;
8 | }
9 |
10 | http {
11 | include /etc/nginx/mime.types;
12 | include /etc/nginx/fastcgi.conf;
13 | index index.html index.php;
14 | ssl_session_cache shared:SSL:10m;
15 | ssl_session_timeout 10m;
16 | default_type application/octet-stream;
17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
18 | '$status $body_bytes_sent "$http_referer" '
19 | '"$http_user_agent" "$http_x_forwarded_for"';
20 | access_log /var/log/nginx/access.log main;
21 | sendfile on;
22 | tcp_nopush on;
23 | server_names_hash_bucket_size 128;
24 | keepalive_timeout 65;
25 | gzip on;
26 |
27 | include /etc/nginx/conf.d/*.conf;
28 | }
29 |
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfAuthenticated.php:
--------------------------------------------------------------------------------
1 | check()) {
24 | return redirect(RouteServiceProvider::HOME);
25 | }
26 | }
27 |
28 | return $next($request);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.docker/web.debug/nginx.conf:
--------------------------------------------------------------------------------
1 | user www;
2 | worker_processes 4;
3 | error_log /var/log/nginx/error.log notice;
4 | pid /var/run/nginx.pid;
5 |
6 | events {
7 | worker_connections 4096;
8 | }
9 |
10 | http {
11 | include /etc/nginx/mime.types;
12 | include /etc/nginx/fastcgi.conf;
13 | index index.html index.php;
14 | ssl_session_cache shared:SSL:10m;
15 | ssl_session_timeout 10m;
16 | default_type application/octet-stream;
17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
18 | '$status $body_bytes_sent "$http_referer" '
19 | '"$http_user_agent" "$http_x_forwarded_for"';
20 | access_log /var/log/nginx/access.log main;
21 | sendfile on;
22 | tcp_nopush on;
23 | server_names_hash_bucket_size 128;
24 | keepalive_timeout 65;
25 | gzip on;
26 |
27 | include /etc/nginx/conf.d/*.conf;
28 | }
29 |
--------------------------------------------------------------------------------
/lang/en/auth.php:
--------------------------------------------------------------------------------
1 | 'These credentials do not match our records.',
17 | 'password' => 'Wrong phone number or password.',
18 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
19 | 'profile_requires_activation' => 'You are not activated in the system - contact administrator',
20 |
21 | ];
22 |
--------------------------------------------------------------------------------
/app/Jobs/LoggerJob.php:
--------------------------------------------------------------------------------
1 | log($this->response, $this->status, $this->message);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Http/Requests/Role/RoleCreateRequest.php:
--------------------------------------------------------------------------------
1 | merge(['name' => Str::snake(trim($this->name))]);
13 | }
14 |
15 | public function rules(): array
16 | {
17 | return ['title' => 'required|array',
18 | 'title.' . config('laravel_api.main_locale') => 'required|string',
19 | 'title.*' => 'nullable|string',
20 | 'name' => 'required|string|unique:roles,name',
21 | 'guard_name' => 'string'];
22 | }
23 |
24 | public function authorize(): bool
25 | {
26 | return true;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Core/Contracts/CoreServiceContract.php:
--------------------------------------------------------------------------------
1 | tableName, function (Blueprint $table) {
13 | $table->id();
14 | $table->morphs('tokenable');
15 | $table->string('name');
16 | $table->string('token', 64)->unique();
17 | $table->text('abilities')->nullable();
18 | $table->timestamp('last_used_at')->nullable();
19 | $table->timestamp('expires_at')->nullable();
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | public function down(): void
25 | {
26 | Schema::dropIfExists($this->tableName);
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/config/cors.php:
--------------------------------------------------------------------------------
1 | ['api/*', 'sanctum/csrf-cookie'],
19 |
20 | 'allowed_methods' => ['*'],
21 |
22 | 'allowed_origins' => ['*'],
23 |
24 | 'allowed_origins_patterns' => [],
25 |
26 | 'allowed_headers' => ['*'],
27 |
28 | 'exposed_headers' => [],
29 |
30 | 'max_age' => 0,
31 |
32 | 'supports_credentials' => false,
33 |
34 | ];
35 |
--------------------------------------------------------------------------------
/app/Http/Requests/Role/RoleUpdateRequest.php:
--------------------------------------------------------------------------------
1 | merge(['name' => Str::snake(trim($this->name))]);
13 | }
14 |
15 | public function rules(): array
16 | {
17 | return ['title' => 'filled|array',
18 | 'title.' . config('laravel_api.main_locale') => 'required_with:title|string',
19 | 'title.*' => 'nullable|string',
20 | 'name' => 'required|string|unique:roles,name,' . $this->route('role')->id,
21 | 'guard_name' => 'string',
22 | ];
23 | }
24 |
25 | public function authorize(): bool
26 | {
27 | return true;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Core/Macros/PaginationOrCollection.php:
--------------------------------------------------------------------------------
1 | config('laravel_api.request.list_type', 'list_type')]));
13 | }
14 |
15 | return $this->when($listType == 'collection',
16 | fn($q): Collection => $q->collection(),
17 | fn($q): LengthAwarePaginator => $q->pagination()
18 | );
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/app/Services/PermissionService.php:
--------------------------------------------------------------------------------
1 | user();
22 |
23 | return $user->hasAllPermissions($request->permission);
24 | }
25 |
26 | public function create(Validator|FormRequest $request): mixed
27 | {
28 | $permission = parent::create($request);
29 | $this->repository->attachToAdmin($permission);
30 |
31 | return $permission;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('inspire')->hourly();
27 | $schedule->command('cache:prune-stale-tags')->daily();
28 | }
29 |
30 | /**
31 | * Register the commands for the application.
32 | */
33 | protected function commands(): void
34 | {
35 | $this->load(__DIR__ . '/Commands');
36 |
37 | require base_path('routes/console.php');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/Rules/PermissionRule.php:
--------------------------------------------------------------------------------
1 | message = __('messages.error_type');
21 | }
22 | if (!$permission) {
23 | $this->message = __('messages.not_found');
24 | }
25 | if (!hasRole() && !hasPermission($permission)) {
26 | $this->message = __('messages.not_access');
27 | }
28 |
29 | return true;
30 | }
31 |
32 | public function message(): string
33 | {
34 | return $this->message;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/database/seeders/UserSeeder.php:
--------------------------------------------------------------------------------
1 | fake()->firstName(),
18 | 'last_name' => fake()->lastName,
19 | 'phone' => fake()->phoneNumber,
20 | 'password' => fake()->password,
21 | 'phone_confirmed' => fake()->boolean,
22 | 'is_active' => fake()->boolean,
23 | 'created_at' => fake()->dateTime,
24 | 'updated_at' => fake()->dateTime,
25 | ]);
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/config/modulegenerator.php:
--------------------------------------------------------------------------------
1 | 'App\Core\Http\Controllers\CoreController',
5 | 'core_service' => 'App\Core\Services\CoreService',
6 | 'core_repository' => 'App\Core\Repositories\CoreRepository',
7 | 'core_policy' => 'App\Core\Repositories\CoreRepository',
8 |
9 | 'route_path' => 'Routes\api',
10 | 'repository_path' => 'App\Repositories',
11 | 'service_path' => 'App\Services',
12 | 'model_path' => 'App\Models',
13 | 'request_path' => 'App\Http\Requests',
14 | 'policy_path' => 'App\Policies',
15 | 'controller_path' => 'App\Http\Controllers',
16 | 'api' => [
17 | 'controller_path' => 'App\Http\Controllers\Api',
18 | 'request_path' => 'App\Http\Requests',
19 | 'route' => 'Routes\api.php',
20 | ],
21 |
22 | 'web' => [
23 | 'controller_path' => 'App\Http\Controllers',
24 | 'request_path' => 'App\Http\Requests',
25 | 'route' => 'Routes\web.php',
26 | ],
27 | ];
28 |
--------------------------------------------------------------------------------
/database/migrations/2021_10_31_110750_create_categories_table.php:
--------------------------------------------------------------------------------
1 | tableName, function (Blueprint $table) {
13 | $table->id();
14 | $table->jsonb('name');
15 | $table->jsonb('description')->nullable();
16 | $table->unsignedBigInteger('position')->default(0);
17 | $table->boolean('is_active')->default(true);
18 | $table->foreignId('author_id')->constrained('users');
19 | $table->foreignId('parent_id')->nullable()->constrained('categories');
20 | $table->softDeletes();
21 | $table->timestamps();
22 | });
23 | }
24 |
25 | public function down(): void
26 | {
27 | Schema::dropIfExists($this->tableName);
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/database/migrations/2021_10_31_111105_create_resources_table.php:
--------------------------------------------------------------------------------
1 | tableName, function (Blueprint $table) {
13 | $table->id();
14 | $table->string('display_name')->nullable();
15 | $table->string('additional_identifier')->nullable();
16 | $table->string('type')->nullable();
17 | $table->string('path_original');
18 | $table->string('path_1024')->nullable();//if file not image it will be null
19 | $table->string('path_512')->nullable();
20 | $table->morphs('resource');
21 | $table->timestamps();
22 | });
23 | }
24 |
25 | public function down(): void
26 | {
27 | Schema::dropIfExists($this->tableName);
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/stubs/policy.stub:
--------------------------------------------------------------------------------
1 | 'filled|string',
16 | 'last_name' => 'nullable|string',
17 | 'phone' => [
18 | 'filled',
19 | new PhoneRule(),
20 | new UniqueRule('users', 'phone', auth()->user()->id),
21 | ],
22 | 'password' => ['filled', 'string', 'confirmed', Password::min(8)->letters()->numbers()],
23 | 'birthday' => 'nullable|date|before_or_equal:' . now(),
24 | 'is_active' => 'bool',
25 | 'avatar' => 'image',
26 | 'roles' => 'array',
27 | 'roles.*' => 'nullable|exists:roles,name|not_in:superadmin',
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/Observers/UserObserver.php:
--------------------------------------------------------------------------------
1 | avatar->id);
14 | }
15 |
16 | public function created(User $user)
17 | {
18 | (request('roles') && !in_array('superadmin', request('roles'))) ?
19 | $user->syncRoles(request('roles')) : $user->syncRoles(['customer']);
20 |
21 | if (request()->hasFile('avatar')) {
22 | UpdateImage::dispatch(request('avatar'), $user->avatar());
23 | }
24 | }
25 |
26 | public function updating(User $user)
27 | {
28 | if (request('roles')) {
29 | $user->syncRoles(request('roles'));
30 | }
31 | }
32 | public function updated(User $user)
33 | {
34 | if (request()->hasFile('avatar')) {
35 | UpdateImage::dispatch(request('avatar'), $user->avatar());
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/stubs/observer.stub:
--------------------------------------------------------------------------------
1 | table)
27 | ->when($this->softDeletes, function ($query) {
28 | $query->whereNull('deleted_at');
29 | })
30 | ->where($this->column, $value)
31 | ->when($this->id, fn($query) => $query->where('id', '!=', $this->id))
32 | ->doesntExist();
33 | }
34 |
35 | public function message()
36 | {
37 | return __('validation.unique', ['attribute' => $this->column]);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/config/filesystems.php:
--------------------------------------------------------------------------------
1 | env('FILESYSTEM_DRIVER', 'local'),
5 |
6 | 'disks' => [
7 |
8 | 'local' => [
9 | 'driver' => 'local',
10 | 'root' => storage_path('/app/public/uploads'),
11 | ],
12 |
13 | 'public' => [
14 | 'driver' => 'local',
15 | 'root' => storage_path('/app/public'),
16 | 'url' => env('APP_URL') . '/storage',
17 | 'visibility' => 'public',
18 | ],
19 |
20 | 's3' => [
21 | 'driver' => 's3',
22 | 'key' => env('AWS_ACCESS_KEY_ID'),
23 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
24 | 'region' => env('AWS_DEFAULT_REGION'),
25 | 'bucket' => env('AWS_BUCKET'),
26 | 'url' => env('AWS_URL'),
27 | 'endpoint' => env('AWS_ENDPOINT'),
28 | ],
29 |
30 | ],
31 |
32 | //php artisan storage:link
33 | 'links' => [
34 | public_path('uploads') => storage_path('app/public/uploads'),
35 | ],
36 | ];
37 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
21 | ],
22 |
23 | 'postmark' => [
24 | 'token' => env('POSTMARK_TOKEN'),
25 | ],
26 |
27 | 'ses' => [
28 | 'key' => env('AWS_ACCESS_KEY_ID'),
29 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
30 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
31 | ],
32 |
33 | ];
34 |
--------------------------------------------------------------------------------
/app/Providers/AuthServiceProvider.php:
--------------------------------------------------------------------------------
1 | UserPolicy::class,
20 | Category::class => CategoryPolicy::class,
21 | Product::class => ProductPolicy::class,
22 | Role::class => RolePolicy::class,
23 | Permission::class => PermissionPolicy::class,
24 | ];
25 |
26 | /**
27 | * Register any authentication / authorization services.
28 | */
29 | public function boot(): void
30 | {
31 | $this->registerPolicies();
32 | //
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Rules/UniqueJsonRule.php:
--------------------------------------------------------------------------------
1 | table)->where($this->column . '->' . $lang, '=', $value)
20 | ->when($this->id, function ($query) {
21 | $query->where('id', '!=', $this->id);
22 | })
23 | ->doesntExist();
24 | }
25 |
26 | /**
27 | * Create a new rule instance.
28 | */
29 | public function __construct(protected string $table, protected string $column, protected int|null $id = null)
30 | {
31 | }
32 |
33 | /**
34 | * Get the validation error message.
35 | */
36 | public function message(): string
37 | {
38 | return __('validation.unique', ['attribute' => $this->column]);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Rules/CheckJsonExistsNullableLocale.php:
--------------------------------------------------------------------------------
1 | config('laravel_api.main_locale')]);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/Core/Macros/IsActive.php:
--------------------------------------------------------------------------------
1 | when(!is_null($status), function (EloquentBuilder|QueryBuilder $query) use ($status) {
11 | $acceptable = [true, false, 0, 1, '0', '1'];
12 |
13 | if (!in_array($status, $acceptable, true)) {
14 | throw new \Exception(__('validation.array', ['attribute' => config('laravel_api.request.is_active', 'is_active')]));
15 | }
16 | $query->where(config('laravel_api.check.is_active', 'is_active'), $status);
17 | });
18 |
19 | return $this;
20 | });
21 |
22 | $builder::macro('active', function () {
23 | $this->where(config('laravel_api.check.is_active', 'is_active'), '=', true);
24 |
25 | return $this;
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/.docker/web.loc/app.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80 default_server;
3 | root /var/www/public;
4 | server_name laravel.api;
5 | keepalive_timeout 70;
6 |
7 | add_header X-Frame-Options "SAMEORIGIN";
8 | add_header X-Content-Type-Options "nosniff";
9 |
10 | index index.php index.html;
11 | charset utf-8;
12 |
13 | location = /favicon.ico { access_log off; log_not_found off; }
14 | location = /robots.txt { access_log off; log_not_found off; }
15 |
16 | error_page 404 /index.php;
17 |
18 | location ~ \.php$ {
19 | try_files $uri =404;
20 | fastcgi_split_path_info ^(.+\.php)(/.+)$;
21 | fastcgi_pass localhost:9000;
22 | fastcgi_index index.php;
23 | include fastcgi_params;
24 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
25 | fastcgi_param PATH_INFO $fastcgi_path_info;
26 | fastcgi_buffering off;
27 | }
28 |
29 | location / {
30 | try_files $uri $uri/ /index.php?$query_string;
31 | gzip_static on;
32 | }
33 |
34 | location ~ /\.(?!well-known).* {
35 | deny all;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | ./tests/Unit
10 |
11 |
12 | ./tests/Feature
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/Core/Providers/CoreServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapWithKeys(function ($path) {
23 | return [$path => pathinfo($path, PATHINFO_FILENAME)];
24 | })
25 | ->each(function ($macro, $path) {
26 | require_once $path;
27 | });
28 |
29 | $this->app->bind(CoreServiceContract::class, CoreService::class);
30 | $this->app->bind(CoreRepositoryContract::class, CoreRepository::class);
31 | }
32 |
33 | /**
34 | * Bootstrap any application services.
35 | */
36 | public function boot()
37 | {
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/database/migrations/2021_10_31_182630_create_products_table.php:
--------------------------------------------------------------------------------
1 | tableName, function (Blueprint $table) {
13 | $table->id();
14 | $table->foreignId('author_id')->constrained('users');
15 | $table->foreignId('category_id')->constrained()->cascadeOnDelete();
16 | $table->jsonb('name');
17 | $table->jsonb('description')->nullable();
18 | $table->unsignedBigInteger('position')->default(0);
19 | $table->boolean('is_active')->default(true);
20 | $table->string('barcode_path');
21 | $table->string('barcode')->unique();
22 | $table->softDeletes();
23 | $table->timestamps();
24 | });
25 | }
26 |
27 | public function down(): void
28 | {
29 | Schema::dropIfExists($this->tableName);
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | APP_NAME=LaravelApi
2 | APP_ENV=local
3 | APP_KEY=base64:8KfiBETfRmptGovlHVXHJ/Xzq3t0ABWjeoyNGEI6VC4=
4 | APP_DEBUG=true
5 | APP_URL=http://localhost
6 |
7 | LOG_CHANNEL=stack
8 | LOG_DEPRECATIONS_CHANNEL=null
9 | LOG_LEVEL=debug
10 |
11 | DB_CONNECTION=mysql
12 | DB_HOST=mysql
13 | DB_PORT=3306
14 | DB_DATABASE=test
15 | DB_USERNAME=root
16 | DB_PASSWORD=password
17 |
18 | BROADCAST_DRIVER=log
19 | CACHE_DRIVER=file
20 | FILESYSTEM_DRIVER=local
21 | QUEUE_CONNECTION=sync
22 | SESSION_DRIVER=file
23 | SESSION_LIFETIME=120
24 |
25 | MEMCACHED_HOST=127.0.0.1
26 |
27 | REDIS_HOST=127.0.0.1
28 | REDIS_PASSWORD=null
29 | REDIS_PORT=6379
30 |
31 | MAIL_MAILER=smtp
32 | MAIL_HOST=mailhog
33 | MAIL_PORT=1025
34 | MAIL_USERNAME=null
35 | MAIL_PASSWORD=null
36 | MAIL_ENCRYPTION=null
37 | MAIL_FROM_ADDRESS=null
38 | MAIL_FROM_NAME="${APP_NAME}"
39 |
40 | AWS_ACCESS_KEY_ID=
41 | AWS_SECRET_ACCESS_KEY=
42 | AWS_DEFAULT_REGION=us-east-1
43 | AWS_BUCKET=
44 | AWS_USE_PATH_STYLE_ENDPOINT=false
45 |
46 | PUSHER_APP_ID=
47 | PUSHER_APP_KEY=
48 | PUSHER_APP_SECRET=
49 | PUSHER_APP_CLUSTER=mt1
50 |
51 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
52 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
53 |
--------------------------------------------------------------------------------
/app/Core/Helpers/Generators/EditRoute.php:
--------------------------------------------------------------------------------
1 | config('laravel_api.request.onlyDeleted', 'onlyDeleted'),
12 | ]));
13 | }
14 |
15 | return $this->when($trashed, fn($query) => $query->onlyTrashed());
16 | });
17 |
18 | Builder::macro('withDeleted', function (bool $trashed = null): Builder {
19 | $trashed = $trashed ?? (bool)request(config('laravel_api.request.withDeleted', 'withDeleted'), false);
20 |
21 | $acceptable = [true, false, 0, 1, '0', '1'];
22 |
23 | if (!in_array($trashed, $acceptable, true)) {
24 | throw new \Exception(__('validation.boolean', ['attribute' => config('laravel_api.request.withDeleted', 'withDeleted'),
25 | ]));
26 | }
27 |
28 | return $this->when($trashed, fn($query) => $query->withTrashed());
29 | });
30 |
--------------------------------------------------------------------------------
/app/Rules/checkActiveRule.php:
--------------------------------------------------------------------------------
1 | table)->where($this->column, $value)->first();
23 | if (!$user) {
24 | $this->message = __('messages.attribute_not_found', ['attribute' => __('attributes.' . $this->attribute)]);
25 |
26 | return false;
27 | }
28 | if ($user->is_active === false || $user->deleted_at) {
29 | $this->message = __('messages.inactive', ['attribute' => __('attributes.' . $this->attribute)]);
30 |
31 | return false;
32 | }
33 |
34 | return true;
35 | }
36 |
37 | public function message(): string
38 | {
39 | return $this->message;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/database/migrations/2021_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | tableName, function (Blueprint $table) {
13 | $table->id();
14 | $table->string('first_name');
15 | $table->string('last_name')->nullable();
16 | $table->string('phone');
17 | $table->string('password');
18 | $table->boolean('is_active')->default(false);
19 | $table->boolean('phone_confirmed')->default(false);
20 | $table->dateTime('phone_confirmed_at')->nullable();
21 | $table->date('birthday')->nullable();
22 | $table->foreignId('author_id')->nullable()->constrained('users');
23 | $table->softDeletes();
24 | $table->timestamps();
25 | });
26 | }
27 |
28 | public function down(): void
29 | {
30 | Schema::dropIfExists($this->tableName);
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/app/Http/Controllers/LoggerController.php:
--------------------------------------------------------------------------------
1 | service->index();
20 |
21 | return $this->responseWith(['loggers' => $loggers]);
22 | }
23 |
24 | public function show(Logger $logger): JsonResponse
25 | {
26 | $logger = $this->service->show($logger);
27 |
28 | return $this->responseWith(compact('logger'));
29 | }
30 |
31 | public function destroy(Logger $logger): JsonResponse
32 | {
33 | try {
34 | $this->service->delete($logger);
35 |
36 | return $this->responseWith(code: 204);
37 | } catch (\Exception $e) {
38 | return $this->responseWith(code: $e->getCode(), message: $e->getMessage(), logging: true);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => env(
32 | 'VIEW_COMPILED_PATH',
33 | realpath(storage_path('framework/views'))
34 | ),
35 |
36 | ];
37 |
--------------------------------------------------------------------------------
/database/migrations/2022_04_28_145148_create_logger_table.php:
--------------------------------------------------------------------------------
1 | id();
12 | $table->string('ip');
13 | $table->text('user_agent');
14 | $table->foreignId('user_id')
15 | ->nullable()->constrained()
16 | ->cascadeOnDelete()->cascadeOnUpdate();
17 | $table->json('action');
18 | $table->string('uri');
19 | $table->string('method');
20 | $table->json('headers');
21 | $table->json('payload')->nullable();
22 | $table->json('response')->nullable();
23 | $table->integer('response_status')->nullable();
24 | $table->text('response_message')->nullable();
25 | $table->dateTime('date')->useCurrent();
26 | });
27 | }
28 |
29 | public function down(): void
30 | {
31 | Schema::dropIfExists('logger');
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/app/Http/Requests/UserCreateRequest.php:
--------------------------------------------------------------------------------
1 | 'required|string',
27 | 'last_name' => 'nullable|string',
28 | 'phone' => [
29 | 'required',
30 | new PhoneRule(),
31 | new UniqueRule('users', 'phone'),
32 | ],
33 | 'password' => ['required', 'string', 'confirmed', Password::min(8)->letters()->numbers()],
34 | 'avatar' => 'image',
35 | 'roles' => 'array',
36 | 'roles.*' => 'nullable|exists:roles,name|not_in:superadmin',
37 | ];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.docker/web.dev/app.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 443 ssl default_server;
3 | listen [::]:443 ssl default_server;
4 | root /var/www/public;
5 | server_name _;
6 | ssl_certificate _;
7 | ssl_certificate_key _;
8 | keepalive_timeout 70;
9 |
10 | add_header X-Frame-Options "SAMEORIGIN";
11 | add_header X-Content-Type-Options "nosniff";
12 |
13 | index index.php index.html;
14 | charset utf-8;
15 |
16 | location = /favicon.ico { access_log off; log_not_found off; }
17 | location = /robots.txt { access_log off; log_not_found off; }
18 |
19 | error_page 404 /index.php;
20 |
21 | location ~ \.php$ {
22 | try_files $uri =404;
23 | fastcgi_split_path_info ^(.+\.php)(/.+)$;
24 | fastcgi_pass localhost:9000;
25 | fastcgi_index index.php;
26 | include fastcgi_params;
27 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
28 | fastcgi_param PATH_INFO $fastcgi_path_info;
29 | fastcgi_buffering off;
30 | }
31 |
32 | location / {
33 | try_files $uri $uri/ /index.php?$query_string;
34 | gzip_static on;
35 | }
36 |
37 | location ~ /\.(?!well-known).* {
38 | deny all;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/.docker/web/app.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 443 ssl default_server;
3 | listen [::]:443 ssl default_server;
4 | root /var/www/public;
5 | server_name _;
6 | ssl_certificate _;
7 | ssl_certificate_key _;
8 | keepalive_timeout 70;
9 |
10 | add_header X-Frame-Options "SAMEORIGIN";
11 | add_header X-Content-Type-Options "nosniff";
12 |
13 | index index.php index.html;
14 | charset utf-8;
15 |
16 | location = /favicon.ico { access_log off; log_not_found off; }
17 | location = /robots.txt { access_log off; log_not_found off; }
18 |
19 | error_page 404 /index.php;
20 |
21 | location ~ \.php$ {
22 | try_files $uri =404;
23 | fastcgi_split_path_info ^(.+\.php)(/.+)$;
24 | fastcgi_pass localhost:9000;
25 | fastcgi_index index.php;
26 | include fastcgi_params;
27 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
28 | fastcgi_param PATH_INFO $fastcgi_path_info;
29 | fastcgi_buffering off;
30 | }
31 |
32 | location / {
33 | try_files $uri $uri/ /index.php?$query_string;
34 | gzip_static on;
35 | }
36 |
37 | location ~ /\.(?!well-known).* {
38 | deny all;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/.docker/web.debug/app.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 443 ssl default_server;
3 | listen [::]:443 ssl default_server;
4 | root /var/www/public;
5 | server_name laravel.api;
6 | ssl_certificate _;
7 | ssl_certificate_key _;
8 | keepalive_timeout 70;
9 |
10 | add_header X-Frame-Options "SAMEORIGIN";
11 | add_header X-Content-Type-Options "nosniff";
12 |
13 | index index.php index.html;
14 | charset utf-8;
15 |
16 | location = /favicon.ico { access_log off; log_not_found off; }
17 | location = /robots.txt { access_log off; log_not_found off; }
18 |
19 | error_page 404 /index.php;
20 |
21 | location ~ \.php$ {
22 | try_files $uri =404;
23 | fastcgi_split_path_info ^(.+\.php)(/.+)$;
24 | fastcgi_pass localhost:9000;
25 | fastcgi_index index.php;
26 | include fastcgi_params;
27 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
28 | fastcgi_param PATH_INFO $fastcgi_path_info;
29 | fastcgi_buffering off;
30 | }
31 |
32 | location / {
33 | try_files $uri $uri/ /index.php?$query_string;
34 | gzip_static on;
35 | }
36 |
37 | location ~ /\.(?!well-known).* {
38 | deny all;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Core/Enums/CoreEnum.php:
--------------------------------------------------------------------------------
1 | getConstants());
25 | }
26 |
27 | /**
28 | * Returns class constant keys
29 | */
30 | public static function getKeys(): array
31 | {
32 | return array_keys(self::reflection()->getConstants());
33 | }
34 |
35 | public function __toString(): string
36 | {
37 | return implode(',', static::toArray());
38 | }
39 |
40 | /**
41 | * validator enum abilities
42 | */
43 | public static function isValid(string $value): bool
44 | {
45 | return in_array($value, static::toArray());
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/Services/RoleService.php:
--------------------------------------------------------------------------------
1 | repository->givePermissionTo($role, $request->get('permission'));
24 | }
25 |
26 | /**
27 | * Revoke permission to
28 | */
29 | public function revokePermissionTo(Role $role, PermissionRequest $request): mixed
30 | {
31 | return $this->repository->revokePermissionTo($role, $request->get('permission'));
32 | }
33 |
34 | /**
35 | * Sync Role permissions
36 | */
37 | public function syncPermissions(Role $role, SyncPermissionsRequest $request): mixed
38 | {
39 | return $this->repository->syncRolePermissions($role, $request->get('permissions'));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/public/web.config:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.docker/web/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | user=root
3 | nodaemon=true
4 | logfile=/dev/stdout
5 | logfile_maxbytes=0
6 | pidfile=/var/run/supervisord.pid
7 | loglevel=INFO
8 |
9 | [program:php-fpm]
10 | command=/usr/local/sbin/php-fpm
11 | autostart=true
12 | autorestart=true
13 | priority=5
14 | stdout_logfile=/dev/stdout
15 | stdout_logfile_maxbytes=0
16 | stderr_logfile=/dev/stderr
17 | stderr_logfile_maxbytes=0
18 |
19 | [program:nginx]
20 | command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;'
21 | process_name=%(program_name)s_%(process_num)02d
22 | numprocs=1
23 | autostart=true
24 | autorestart=false
25 | startsecs=0
26 | redirect_stderr=true
27 | stdout_logfile=/dev/stdout
28 | stdout_logfile_maxbytes=0
29 |
30 | [program:laravel-worker]
31 | process_name=%(program_name)s_%(process_num)02d
32 | command=php /var/www/artisan queue:work database --sleep=3 --tries=3 --max-time=3600
33 | autostart=true
34 | autorestart=true
35 | stopasgroup=true
36 | killasgroup=true
37 | user=www
38 | numprocs=1
39 | redirect_stderr=true
40 | stdout_logfile=/dev/stdout
41 | stdout_logfile_maxbytes=0
42 | stderr_logfile=/var/log/supervisor/laravel-queue-error.log
43 | stderr_logfile_maxbytes=0
44 | stopwaitsecs=3600
45 |
46 | [program:cron]
47 | command=/usr/sbin/crond -f
48 | user=root
49 | autostart=true
50 | autorestart=true
51 |
--------------------------------------------------------------------------------
/app/Models/Resource.php:
--------------------------------------------------------------------------------
1 | path_original);
30 | }
31 |
32 | public function getUrl1024Attribute(): ?string
33 | {
34 | return $this->attributes['path_1024'] ? URL::to($this->attributes['path_1024']) : null;
35 | }
36 |
37 | public function getUrl512Attribute(): ?string
38 | {
39 | return $this->attributes['path_512'] ? URL::to($this->attributes['path_512']) : null;
40 | }
41 |
42 | public function resource(): MorphTo
43 | {
44 | return $this->morphTo();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/Repositories/LoggerRepository.php:
--------------------------------------------------------------------------------
1 | create(['ip' => request()->getClientIp(),
21 | 'user_agent' => request()->header('User-Agent'),
22 | "user_id" => auth()->user()?->id,
23 | 'action' => request()->route()->getAction(),
24 | 'uri' => request()->url(),
25 | 'method' => request()->method(),
26 | 'headers' => request()->header(),
27 | 'payload' => request()->input(),
28 | 'response_headers' => request()->header(),
29 | 'response_message' => $message,
30 | 'response_status' => $status,
31 | 'response' => $response]);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Rules/ExistsRule.php:
--------------------------------------------------------------------------------
1 | table)
18 | ->when($this->softDeletes, function ($query) {
19 | $query->whereNull('deleted_at');
20 | })
21 | ->when($this->pivotColumn && $this->pivotValue, function ($query) {
22 | $query->where($this->pivotColumn, $this->pivotValue);
23 | })
24 | ->where($this->column, $value)
25 | ->exists();
26 | }
27 |
28 | /**
29 | * Create a new rule instance.
30 | */
31 | public function __construct(
32 | protected string $table,
33 | protected string $column,
34 | protected string|null $pivotColumn = null,
35 | protected string|null $pivotValue = null,
36 | protected bool $softDeletes = true
37 | ) {
38 | }
39 |
40 | /**
41 | * Get the validation error message.
42 | */
43 | public function message(): string
44 | {
45 | return __('validation.exists', ['attribute' => $this->column]);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lang/en/messages.php:
--------------------------------------------------------------------------------
1 | 'Success',
5 | 'fail' => 'fail',
6 | 'invalid_login' => 'login or password is incorrect',
7 | 'cant_logged' => 'Sorry, user cannot be logged out',
8 | 'phone_invalid_format' => 'The phone format is invalid.',
9 | 'invalid_password' => 'password is incorrect',
10 | 'cannot_delete_using_element' => 'You cannot delete the used element,but can edit',
11 | 'cannot_change_admin' => "You don't have access to delete or update Admin",
12 | 'not_found' => 'Не найдено',
13 | 'not_access' => 'Нет доступа',
14 | 'attribute_not_found' => ':attribute не найдено',
15 | 'account_not_active' => 'Your account is not active',
16 | 'position_deleted' => "':attribute' position removed",
17 | 'employee_deleted' => "Director ':attribute' removed",
18 | 'user_deleted' => "':attribute' User removed",
19 | 'company_deleted' => "':attribute' company removed",
20 | 'isnt_your_worker' => "This is not your worker",
21 | 'product_not_found' => "Product not found",
22 | 'logout' => 'Logged out',
23 | 'error_type' => "Error type",
24 | ];
25 |
--------------------------------------------------------------------------------
/lang/uz/messages.php:
--------------------------------------------------------------------------------
1 | 'Success',
5 | 'fail' => 'fail',
6 | 'invalid_login' => 'login or password is incorrect',
7 | 'cant_logged' => 'Sorry, user cannot be logged out',
8 | 'phone_invalid_format' => 'The phone format is invalid.',
9 | 'invalid_password' => 'password is incorrect',
10 | 'cannot_delete_using_element' => 'You cannot delete the used element,but can edit',
11 | 'cannot_change_admin' => "You don't have access to delete or update Admin",
12 | 'not_found' => 'Не найдено',
13 | 'not_access' => 'Нет доступа',
14 | 'attribute_not_found' => ':attribute не найдено',
15 | 'account_not_active' => 'Sizning accountinggiz faol emas',
16 | 'position_deleted' => "':attribute' position removed",
17 | 'employee_deleted' => "Director ':attribute' removed",
18 | 'user_deleted' => "':attribute' User removed",
19 | 'company_deleted' => "':attribute' company removed",
20 | 'isnt_your_worker' => "This is not your worker",
21 | 'product_not_found' => "Product not found",
22 | 'logout' => 'Logged out',
23 | 'error_type' => "Error type",
24 | ];
25 |
--------------------------------------------------------------------------------
/app/Core/Contracts/CoreRepositoryContract.php:
--------------------------------------------------------------------------------
1 | where(function ($query) use ($columns, $search) {
13 | foreach ($columns as $column) {
14 | $query->orWhere($column, like(), "%$search%");
15 | }
16 | });
17 |
18 | return $this;
19 | });
20 |
21 | $builder::macro('orWhereLike', function (array|string $columns, string $search) {
22 | $search = rtrim($search, " \t.");
23 | $columns = \Arr::wrap($columns);
24 | $this->orWhere(function ($query) use ($columns, $search) {
25 | foreach ($columns as $column) {
26 | $query->orWhere($column, like(), "%$search%");
27 | }
28 | });
29 |
30 | return $this;
31 | });
32 | }
33 |
34 | EloquentBuilder::macro('orWhereLikeRelation', function (string $relation, string $column, string $search) {
35 | $search = rtrim($search, " \t.");
36 | $this->orWhereRelation($relation, $column, like(), "%$search%");
37 |
38 | return $this;
39 | });
40 |
--------------------------------------------------------------------------------
/.docker/web.debug/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | user=root
3 | nodaemon=true
4 | logfile=/dev/stdout
5 | logfile_maxbytes=0
6 | pidfile=/var/run/supervisord.pid
7 | loglevel=INFO
8 |
9 | [program:php-fpm]
10 | command=/usr/local/sbin/php-fpm
11 | autostart=true
12 | autorestart=true
13 | priority=5
14 | stdout_logfile=/dev/stdout
15 | stdout_logfile_maxbytes=0
16 | stderr_logfile=/var/log/supervisor/php-fpm-error.log
17 | stderr_logfile_maxbytes=0
18 |
19 | [program:nginx]
20 | command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;'
21 | process_name=%(program_name)s_%(process_num)02d
22 | numprocs=1
23 | autostart=true
24 | autorestart=true
25 | startsecs=0
26 | stdout_logfile=/dev/stdout
27 | stdout_logfile_maxbytes=0
28 | stderr_logfile=/var/log/supervisor/php-fpm-error.log
29 | stderr_logfile_maxbytes=0
30 |
31 | [program:laravel-worker]
32 | process_name=%(program_name)s_%(process_num)02d
33 | command=php /var/www/artisan queue:work database --sleep=3 --tries=3 --max-time=3600
34 | autostart=true
35 | autorestart=true
36 | stopasgroup=true
37 | killasgroup=true
38 | user=www
39 | numprocs=1
40 | redirect_stderr=true
41 | stdout_logfile=/dev/stdout
42 | stdout_logfile_maxbytes=0
43 | stderr_logfile=/var/log/supervisor/laravel-queue-error.log
44 | stderr_logfile_maxbytes=0
45 | stopwaitsecs=3600
46 |
47 | [program:cron]
48 | command=/usr/sbin/crond -f
49 | user=root
50 | autostart=true
51 | autorestart=true
52 |
--------------------------------------------------------------------------------
/.docker/web.dev/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | user=root
3 | nodaemon=true
4 | logfile=/dev/stdout
5 | logfile_maxbytes=0
6 | pidfile=/var/run/supervisord.pid
7 | loglevel=INFO
8 |
9 | [program:php-fpm]
10 | command=/usr/local/sbin/php-fpm
11 | autostart=true
12 | autorestart=true
13 | priority=5
14 | stdout_logfile=/dev/stdout
15 | stdout_logfile_maxbytes=0
16 | stderr_logfile=/var/log/supervisor/php-fpm-error.log
17 | stderr_logfile_maxbytes=0
18 |
19 | [program:nginx]
20 | command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;'
21 | process_name=%(program_name)s_%(process_num)02d
22 | numprocs=1
23 | autostart=true
24 | autorestart=true
25 | startsecs=0
26 | stdout_logfile=/dev/stdout
27 | stdout_logfile_maxbytes=0
28 | stderr_logfile=/var/log/supervisor/php-fpm-error.log
29 | stderr_logfile_maxbytes=0
30 |
31 | [program:laravel-worker]
32 | process_name=%(program_name)s_%(process_num)02d
33 | command=php /var/www/artisan queue:work database --sleep=3 --tries=3 --max-time=3600
34 | autostart=true
35 | autorestart=true
36 | stopasgroup=true
37 | killasgroup=true
38 | user=www
39 | numprocs=1
40 | redirect_stderr=true
41 | stdout_logfile=/dev/stdout
42 | stdout_logfile_maxbytes=0
43 | stderr_logfile=/var/log/supervisor/laravel-queue-error.log
44 | stderr_logfile_maxbytes=0
45 | stopwaitsecs=3600
46 |
47 | [program:cron]
48 | command=/usr/sbin/crond -f
49 | user=root
50 | autostart=true
51 | autorestart=true
52 |
--------------------------------------------------------------------------------
/.docker/web.loc/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | user=root
3 | nodaemon=true
4 | logfile=/dev/stdout
5 | logfile_maxbytes=0
6 | pidfile=/var/run/supervisord.pid
7 | loglevel=INFO
8 |
9 | [program:php-fpm]
10 | command=/usr/local/sbin/php-fpm
11 | autostart=true
12 | autorestart=true
13 | priority=5
14 | stdout_logfile=/dev/stdout
15 | stdout_logfile_maxbytes=0
16 | stderr_logfile=/var/log/supervisor/php-fpm-error.log
17 | stderr_logfile_maxbytes=0
18 |
19 | [program:nginx]
20 | command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;'
21 | process_name=%(program_name)s_%(process_num)02d
22 | numprocs=1
23 | autostart=true
24 | autorestart=true
25 | startsecs=0
26 | stdout_logfile=/dev/stdout
27 | stdout_logfile_maxbytes=0
28 | stderr_logfile=/var/log/supervisor/php-fpm-error.log
29 | stderr_logfile_maxbytes=0
30 |
31 | [program:laravel-worker]
32 | process_name=%(program_name)s_%(process_num)02d
33 | command=php /var/www/artisan queue:work database --sleep=3 --tries=3 --max-time=3600
34 | autostart=true
35 | autorestart=true
36 | stopasgroup=true
37 | killasgroup=true
38 | user=www
39 | numprocs=1
40 | redirect_stderr=true
41 | stdout_logfile=/dev/stdout
42 | stdout_logfile_maxbytes=0
43 | stderr_logfile=/var/log/supervisor/laravel-queue-error.log
44 | stderr_logfile_maxbytes=0
45 | stopwaitsecs=3600
46 |
47 | [program:cron]
48 | command=/usr/sbin/crond -f
49 | user=root
50 | autostart=true
51 | autorestart=true
52 |
--------------------------------------------------------------------------------
/app/Providers/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
15 | LoggerListener::class,
16 | ],
17 | UpdateImage::class => [
18 | UpdateImageListener::class,
19 | ],
20 | UpdateFile::class => [
21 | UpdateFileListener::class,
22 | ],
23 | AttachImages::class => [
24 | AttachImagesListener::class,
25 | ],
26 | DestroyFiles::class => [
27 | DestroyFilesListener::class,
28 | ],
29 | ];
30 |
31 | protected $observers = [
32 | Category::class => [CategoryObserver::class],
33 | User::class => [UserObserver::class],
34 | Product::class => [ProductObserver::class],
35 | ];
36 |
37 | /**
38 | * Register any events for your application.
39 | */
40 | public function boot(): void { }
41 | }
42 |
--------------------------------------------------------------------------------
/lang/ru/messages.php:
--------------------------------------------------------------------------------
1 | 'Success',
5 | 'fail' => 'fail',
6 | 'invalid_login' => 'login or password is incorrect',
7 | 'cant_logged' => 'Sorry, user cannot be logged out',
8 | 'phone_invalid_format' => 'The phone format is invalid.',
9 | 'invalid_password' => 'password is incorrect',
10 | 'cannot_delete_using_element' => 'You cannot delete the used element,but can edit',
11 | 'cannot_change_admin' => "You don't have access to delete or update Admin",
12 | 'not_found' => 'Не найдено',
13 | 'not_access' => 'Нет доступа',
14 | 'attribute_not_found' => ':attribute не найдено',
15 | 'account_not_active' => 'Ваш аккаунт не активен',
16 | 'inactive' => ':attribute неактивен',
17 | 'position_deleted' => "':attribute' position removed",
18 | 'employee_deleted' => "Director ':attribute' removed",
19 | 'user_deleted' => "':attribute' User removed",
20 | 'company_deleted' => "':attribute' company removed",
21 | 'isnt_your_worker' => "This is not your worker",
22 | 'product_not_found' => "Product not found",
23 | 'logout' => 'Logged out',
24 | 'error_type' => "Error type",
25 | ];
26 |
--------------------------------------------------------------------------------
/app/Models/RefreshToken.php:
--------------------------------------------------------------------------------
1 | 'datetime:Y.m.d H:i:s',
21 | 'refresh_expired_at' => 'datetime:Y.m.d H:i:s',
22 | ];
23 | protected $with = ['user'];
24 |
25 | /**
26 | * to set creator_id
27 | */
28 | protected static function boot(): void
29 | {
30 | parent::boot();
31 | static::creating(function ($query) {
32 | $query->refresh_token = RefreshTokenGenerator::tokenGenerate();
33 | $query->expired_at = now()->addMinutes(config('sanctum.expiration'));
34 | $query->refresh_expired_at = now()->addMinutes(config('sanctum.refresh_expiration'));
35 | });
36 | }
37 |
38 | protected $hidden = ['user_id', 'user_type', 'created_at', 'updated_at'];
39 |
40 | public function getRefreshTokenAttribute(): string
41 | {
42 | return encrypt($this->attributes['refresh_token']);
43 | }
44 |
45 | public function user(): MorphTo
46 | {
47 | return $this->morphTo();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/Repositories/RoleRepository.php:
--------------------------------------------------------------------------------
1 | when(notSystem(),
23 | function (Builder $query) {
24 | $query->whereDoesntHave('permissions', function ($query) {
25 | $query->where('name', 'system');
26 | })->whereNotIn('name', ['owner', 'demo']);
27 | });
28 | }
29 |
30 | public function givePermissionTo(Model $role, int|string $permission): mixed
31 | {
32 | return $role->givePermissionTo($permission);
33 | }
34 |
35 | public function revokePermissionTo(Model $role, int|string $permission): mixed
36 | {
37 | return $role->revokePermissionTo($permission);
38 | }
39 |
40 | /**
41 | * Sync Role permissions
42 | */
43 | public function syncRolePermissions(Model $role, array $permissions): mixed
44 | {
45 | return $role->syncPermissions($permissions);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/Core/Test/Feature/CoreTest.php:
--------------------------------------------------------------------------------
1 | getDatabaseName());
24 | //$this->seed(TestSeeder::class);
25 |
26 | [$this->user, $this->phone, $this->pass] = $this->createUser($this->roles);
27 | }
28 |
29 | protected function tearDown(): void
30 | {
31 | $this->deleteUser($this->user);
32 | parent::tearDown();
33 | }
34 |
35 | public function createUser(string|array $roles = null)
36 | {
37 | $roles = $roles ?? 'customer';
38 | $user = User::factory()
39 | ->create(['phone' => $phone = '998' . rand(100000000, 999999999),
40 | 'password' => $password = $this->faker->password(8) . '1a',
41 | 'is_active' => 1,
42 | ])->assignRole(Arr::wrap($roles));
43 |
44 |
45 | return [$user, $phone, $password];
46 | }
47 |
48 | public function deleteUser(User $user)
49 | {
50 | $user->forceDelete();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/Core/Macros/Namespaces/QueryBuilder.php:
--------------------------------------------------------------------------------
1 | configureRateLimiting();
18 | $this->aliasMiddleware('setAppLocale', SetAppLocale::class);
19 | $this->aliasMiddleware('isActive', IsActive::class);
20 |
21 | $routeFiles = array_slice(scandir(base_path('routes/api')), 2);
22 | foreach ($routeFiles as $file) {
23 | Route::middleware(['api', 'setAppLocale', 'isActive', 'bindings'])
24 | ->namespace('App\Http\Controllers')
25 | ->group(base_path('routes/api/' . $file));
26 | }
27 |
28 | $this->routes(function () {
29 | Route::middleware('web')
30 | ->group(base_path('routes/web.php'));
31 | });
32 | }
33 |
34 | /**
35 | * Configure the rate limiters for the application.
36 | */
37 | protected function configureRateLimiting()
38 | {
39 | RateLimiter::for('api', function (Request $request) {
40 | return Limit::perMinute(60)->by(optional($request->user())->id ? : $request->ip());
41 | });
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/.env.testing.fail:
--------------------------------------------------------------------------------
1 | APP_NAME=LaravelApi
2 | APP_ENV=local
3 | APP_KEY=base64:8KfiBETfRmptGovlHVXHJ/Xzq3t0ABWjeoyNGEI6VC4=
4 | APP_DEBUG=true
5 | APP_URL=http://localhost
6 | APP_DOMAIN=localhost
7 | TELESCOPE_ENABLED=true
8 | APP_PORT=80
9 | PHP_IDE_CONFIG="serverName=localhost"
10 | PHP_IDE_KEY="PHPSTORM"
11 | WWWUSER=overlord
12 | WWWUSERID=1000
13 | SAIL_XDEBUG=true
14 |
15 | LOG_CHANNEL=stack
16 | LOG_DEPRECATIONS_CHANNEL=null
17 | LOG_LEVEL=debug
18 |
19 | FORWARD_DB_PORT=8011
20 | FORWARD_TEST_DB_PORT=8011
21 | FORWARD_REDIS_PORT=6380
22 |
23 | DB_CONNECTION=mysql
24 | DB_HOST=mariadb-testing
25 | DB_PORT=3306
26 | DB_DATABASE=laravel
27 | DB_USERNAME=sail
28 | DB_PASSWORD=password
29 | DATABASE_PATH=/etc/docker/laravel-api/laravel-api-database:/var/lib/mysql_2
30 |
31 | BROADCAST_DRIVER=log
32 | CACHE_DRIVER=redis
33 | FILESYSTEM_DRIVER=local
34 | QUEUE_CONNECTION=sync
35 | SESSION_DRIVER=file
36 | SESSION_LIFETIME=120
37 |
38 | MEMCACHED_HOST=127.0.0.1
39 |
40 | REDIS_HOST=redis
41 | REDIS_PASSWORD=null
42 | REDIS_PORT=6379
43 |
44 | MAIL_MAILER=smtp
45 | MAIL_HOST=mailhog
46 | MAIL_PORT=1025
47 | MAIL_USERNAME=null
48 | MAIL_PASSWORD=null
49 | MAIL_ENCRYPTION=null
50 | MAIL_FROM_ADDRESS=null
51 | MAIL_FROM_NAME="${APP_NAME}"
52 |
53 | AWS_ACCESS_KEY_ID=
54 | AWS_SECRET_ACCESS_KEY=
55 | AWS_DEFAULT_REGION=us-east-1
56 | AWS_BUCKET=
57 | AWS_USE_PATH_STYLE_ENDPOINT=false
58 |
59 | PUSHER_APP_ID=
60 | PUSHER_APP_KEY=
61 | PUSHER_APP_SECRET=
62 | PUSHER_APP_CLUSTER=mt1
63 |
64 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
65 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
66 |
--------------------------------------------------------------------------------
/app/Http/Requests/ProductUpdateRequest.php:
--------------------------------------------------------------------------------
1 | ['filled',
14 | new checkActiveRule('categories', request('category_id'), 'category')],
15 | 'name' => 'filled|array',
16 | 'name.' . config('laravel_api.main_locale') => 'filled|string',
17 | 'name.*' => 'nullable|string',
18 | 'description' => 'nullable|array',
19 | 'description.' . config('laravel_api.main_locale') => 'required_with:description|string',
20 | 'description.*' => 'nullable|string',
21 | 'position' => 'integer',
22 | 'main_image' => 'nullable|image|max:10000',
23 | 'images.*' => 'nullable|image|max:10000',
24 | 'video' => 'nullable|mimetypes:video/*|max:20000',
25 | ];
26 | }
27 |
28 | public function authorize(): bool
29 | {
30 | return true;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/.env.example.docker:
--------------------------------------------------------------------------------
1 | APP_NAME=LaravelApi
2 | APP_ENV=local
3 | APP_KEY=base64:8KfiBETfRmptGovlHVXHJ/Xzq3t0ABWjeoyNGEI6VC4=
4 | APP_DEBUG=true
5 | APP_URL=http://localhost
6 | APP_DOMAIN=localhost
7 | TELESCOPE_ENABLED=${APP_DEBUG}
8 | APP_PORT=80
9 | FORWARD_DB_PORT=3306
10 | FORWARD_REDIS_PORT=6380
11 | PHP_IDE_CONFIG="serverName=localhost"
12 | PHP_IDE_KEY="PHPSTORM"
13 | WWWUSER=overlord
14 | WWWUSERID=1000
15 |
16 | LOG_CHANNEL=stack
17 | LOG_DEPRECATIONS_CHANNEL=null
18 | LOG_LEVEL=debug
19 |
20 | FORWARD_DB_PORT=3307
21 | FORWARD_REDIS_PORT=6380
22 |
23 | DB_HOST=mysql
24 | DB_PORT=3306
25 | DB_DATABASE=test_db
26 | DB_USERNAME=test_user
27 | DB_PASSWORD=secret
28 | DATABASE_PATH = /etc/docker/laravel-api/laravel-api-database:/var/lib/mysql_1
29 |
30 | BROADCAST_DRIVER=log
31 | CACHE_DRIVER=redis
32 | FILESYSTEM_DRIVER=local
33 | QUEUE_CONNECTION=sync
34 | SESSION_DRIVER=file
35 | SESSION_LIFETIME=120
36 |
37 | MEMCACHED_HOST=127.0.0.1
38 |
39 | REDIS_HOST=redis
40 | REDIS_PORT=6379
41 | REDIS_PASSWORD=null
42 | REDIS_PORT=6379
43 |
44 | MAIL_MAILER=smtp
45 | MAIL_HOST=mailhog
46 | MAIL_PORT=1025
47 | MAIL_USERNAME=null
48 | MAIL_PASSWORD=null
49 | MAIL_ENCRYPTION=null
50 | MAIL_FROM_ADDRESS=null
51 | MAIL_FROM_NAME="${APP_NAME}"
52 |
53 | AWS_ACCESS_KEY_ID=
54 | AWS_SECRET_ACCESS_KEY=
55 | AWS_DEFAULT_REGION=us-east-1
56 | AWS_BUCKET=
57 | AWS_USE_PATH_STYLE_ENDPOINT=false
58 |
59 | PUSHER_APP_ID=
60 | PUSHER_APP_KEY=
61 | PUSHER_APP_SECRET=
62 | PUSHER_APP_CLUSTER=mt1
63 |
64 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
65 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
66 |
--------------------------------------------------------------------------------
/app/Http/Requests/ProductCreateRequest.php:
--------------------------------------------------------------------------------
1 | ['required',
14 | new checkActiveRule('categories', request('category_id'), 'category')],
15 | 'name' => 'required|array',
16 | 'name.' . config('laravel_api.main_locale') => 'required|string',
17 | 'name.*' => 'nullable|string',
18 | 'description' => 'nullable|array',
19 | 'description.' . config('laravel_api.main_locale') => 'required_with:description|string',
20 | 'description.*' => 'nullable|string',
21 | 'position' => 'integer',
22 | 'main_image' => 'nullable|image|max:10000',
23 | 'images.*' => 'nullable|image|max:10000',
24 | 'video' => 'nullable|mimetypes:video/*|max:20000',
25 | ];
26 | }
27 |
28 | public function authorize(): bool
29 | {
30 | return true;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Repositories/PermissionRepository.php:
--------------------------------------------------------------------------------
1 | when(notSystem(),
20 | function (Builder $query) {
21 | $query->whereIn('name', auth()->user()->getAllPermissions()->pluck('name'));
22 | });
23 | }
24 |
25 | public function appends(Builder $query): void
26 | {
27 | $this->role($query, request('role'));
28 | }
29 |
30 | public function attachToAdmin(Permission|int|string $permission)
31 | {
32 | $this->firstBy('superadmin', 'name', Role::query())->givePermissionTo($permission);
33 | }
34 |
35 | public function role(
36 | Builder $query,
37 | $role = null,
38 | ) {
39 | return $query->when($role, function (Builder $query) use ($role) {
40 | $query->whereHas('roles', function (Builder $query) use ($role) {
41 | if (is_array($role)) {
42 | $query->whereIn('name', $role);
43 | } else {
44 | $query->where('name', $role);
45 | }
46 | });
47 | });
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | - develop
8 | - '*.x'
9 | pull_request:
10 | branches:
11 | - master
12 | - develop
13 | schedule:
14 | - cron: '0 0 * * *'
15 |
16 | # Allows you to run this workflow manually from the Actions tab
17 | workflow_dispatch:
18 |
19 | jobs:
20 | phpunit:
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | php-versions: [ 'kirschbaumdevelopment/laravel-test-runner:8.1','kirschbaumdevelopment/laravel-test-runner:8.2']
25 | runs-on: ubuntu-latest
26 | container:
27 | image: ${{ matrix.php-versions }}
28 |
29 | services:
30 | mysql:
31 | image: mysql:8.0
32 | env:
33 | MYSQL_ROOT_PASSWORD: password
34 | MYSQL_DATABASE: test
35 | ports:
36 | - 3306:3306
37 | options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
38 |
39 | steps:
40 | - uses: actions/checkout@v1
41 | with:
42 | fetch-depth: 1
43 |
44 | - name: Install composer dependencies
45 | run: |
46 | composer install --no-scripts
47 |
48 | - name: Prepare Laravel Application
49 | run: |
50 | cp .env.example .env
51 | php artisan key:generate
52 | - name: Migrate seed
53 | run: |
54 | php artisan migrate --force
55 | php artisan db:seed --class=TestSeeder
56 |
57 | - name: Run Testsuite
58 | run: php artisan test
59 |
--------------------------------------------------------------------------------
/app/Models/Logger.php:
--------------------------------------------------------------------------------
1 | 'datetime:Y-m-d H:i:s',
29 | 'action' => 'array',
30 | 'headers' => 'array',
31 | 'payload' => 'array',
32 | 'response' => 'array',
33 | ];
34 |
35 | protected $dates = ['date'];
36 |
37 | public $timestamps = false;
38 |
39 | protected array $searchable = [
40 | 'uri',
41 | 'user_agent',
42 | 'response_message',
43 | ];
44 |
45 | protected $appends = ['happened'];
46 |
47 | //show diff with date at now method Happened
48 | public function getHappenedAttribute()
49 | {
50 | return $this->date->diffForHumans();
51 | }
52 |
53 | public function user(): BelongsTo
54 | {
55 | return $this->belongsTo(User::class);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/Core/Macros/GetBy.php:
--------------------------------------------------------------------------------
1 | config('laravel_api.request.getBy', 'getBy'),
25 | 'other' => implode(',', $inGetBy)]));
26 | }
27 |
28 | return match ($getBy) {
29 | 'sum' => (float)$this->sum(DB::raw($column)),//sum:price*quantity
30 | 'avg' => (float)$this->avg(DB::raw($column)),
31 | 'count' => (int)$this->count($column ?? "*"),
32 | 'max' => (float)$this->max(DB::raw($column)),
33 | 'min' => (float)$this->min(DB::raw($column)),
34 | 'exists' => (boolean)$this->exists(),
35 | 'collection' => $this->collection(),
36 | default => $this->pagination(),
37 | };
38 | });
39 | }
40 |
--------------------------------------------------------------------------------
/app/Core/Policies/CorePolicy.php:
--------------------------------------------------------------------------------
1 | name}", $user)
23 | ? Response::allow()
24 | : Response::deny(__('messages.not_access'));
25 | }
26 |
27 | public function view(User $user, Model $model): Response
28 | {
29 | return hasPermission("read-{$this->name}", $user)
30 | ? Response::allow()
31 | : Response::deny(__('messages.not_access'));
32 | }
33 |
34 | public function create(User $user): Response
35 | {
36 | return hasPermission("create-{$this->name}", $user)
37 | ? Response::allow()
38 | : Response::deny(__('messages.not_access'));
39 | }
40 |
41 | public function update(User $user, Model $model)
42 | {
43 | $this->updateDelete($user, $model);
44 |
45 | return hasPermission("update-{$this->name}", $user)
46 | ? Response::allow()
47 | : Response::deny(__('messages.not_access'));
48 | }
49 |
50 | public function delete(User $user, Model $model)
51 | {
52 | $this->updateDelete($user, $model);
53 |
54 | return hasPermission("delete-{$this->name}", $user)
55 | ? Response::allow()
56 | : Response::deny(__('messages.not_access'));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/Observers/ProductObserver.php:
--------------------------------------------------------------------------------
1 | hasFile('mainImage')) {
18 | UpdateImage::dispatch(request('mainImage'), $model->mainImage(), $model->getFilePath(), $model::MAIN_IMAGE);
19 | }
20 | if (request()->hasFile('video')) {
21 | UpdateFile::dispatch(request('mainImage'), $model->video(), $model->getFilePath(), $model::VIDEO);
22 | }
23 | if (request()->hasFile('images')) {
24 | AttachImages::dispatch(request('images'), $model->images(), $model->getFilePath(), $model::IMAGES);
25 | }
26 | }
27 |
28 | public function creating(Product $product)
29 | {
30 | $barcode = BarcodeService::generate('products', 'barcode', $product->getFilePath());
31 | $product['barcode'] = $barcode['barcode'];
32 | $product['barcode_path'] = $barcode['barcode_path'];
33 | }
34 |
35 | public function created(Product $product)
36 | {
37 | $this->checkFile($product);
38 | }
39 |
40 | public function updated(Product $product)
41 | {
42 | $this->checkFile($product);
43 | }
44 |
45 | public function deleting(Product $product)
46 | {
47 | DestroyFiles::dispatch($product->images?->pluck('id')->toArray());
48 | DestroyFiles::dispatch($product->mainImage?->id);
49 | DestroyFiles::dispatch($product->video?->id);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/Repositories/UserRepository.php:
--------------------------------------------------------------------------------
1 | selfExclude($query, request('self_exclude', false));
21 |
22 | $this->filterByRole($query, request('role'));
23 | }
24 |
25 | public function selfExclude(
26 | Builder $query,
27 | bool $selfExclude = false
28 | ) {
29 | return $query->when($selfExclude, fn($q) => $q->where('id', '!=', auth()->id()));
30 | }
31 |
32 | public function filterByRole(
33 | Builder $query,
34 | array|string $role = null,
35 | ) {
36 | return $query->when($role, function ($query) use ($role) {
37 | $query->role($role);
38 | });
39 | }
40 |
41 | public function generateRefreshToken(User $user): RefreshToken
42 | {
43 | $token = $user->createToken('user_' . $user->phone)->plainTextToken;
44 |
45 | return $user->token()->create(['token' => $token])->load('user.avatar');
46 | }
47 |
48 | public function firstByRefreshToken(Request $request): ?RefreshToken
49 | {
50 | return RefreshToken::firstWhere('refresh_token', decrypt($request->bearerToken()));
51 | }
52 |
53 | public function firstByToken(Request $request): ?RefreshToken
54 | {
55 | return RefreshToken::firstWhere('token', $request->bearerToken());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'bcrypt',
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Bcrypt Options
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may specify the configuration options that should be used when
26 | | passwords are hashed using the Bcrypt algorithm. This will allow you
27 | | to control the amount of time it takes to hash the given password.
28 | |
29 | */
30 |
31 | 'bcrypt' => [
32 | 'rounds' => env('BCRYPT_ROUNDS', 10),
33 | ],
34 |
35 | /*
36 | |--------------------------------------------------------------------------
37 | | Argon Options
38 | |--------------------------------------------------------------------------
39 | |
40 | | Here you may specify the configuration options that should be used when
41 | | passwords are hashed using the Argon algorithm. These will allow you
42 | | to control the amount of time it takes to hash the given password.
43 | |
44 | */
45 |
46 | 'argon' => [
47 | 'memory' => 1024,
48 | 'threads' => 2,
49 | 'time' => 2,
50 | ],
51 |
52 | ];
53 |
--------------------------------------------------------------------------------
/app/Repositories/ResourceRepository.php:
--------------------------------------------------------------------------------
1 | delete($model->path_original);
21 | \Storage::disk('public')->delete($model->path_1024);
22 | \Storage::disk('public')->delete($model->path_512);
23 | }
24 |
25 | public function create(
26 | $relation,
27 | $type,
28 | $identifier,
29 | $path_original,
30 | $displayName = null,
31 | $path_1024 = null,
32 | $path_512 = null
33 | ) {
34 | $relation->create(['path_original' => $path_original,
35 | 'path_1024' => $path_1024,
36 | 'path_512' => $path_512,
37 | 'type' => $type,
38 | 'additional_identifier' => $identifier,
39 | 'display_name' => $displayName,
40 | ]);
41 | }
42 |
43 | public function firstBy(int $modelId): ?Model
44 | {
45 | return $this->model->findOrFail($modelId);
46 | }
47 |
48 | public function destroy(array $images)
49 | {
50 | foreach ($images as $image) {
51 | $this->delete($this->firstBy($image));
52 | }
53 | }
54 |
55 | public function delete(Model $image)
56 | {
57 | $this->removeFile($image);
58 | $image->delete();
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/docker-compose-mysql.yaml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 | services:
3 | web:
4 | container_name: laravel-api-db
5 | restart: always
6 | build:
7 | context: .
8 | dockerfile: ./.docker/web.loc/Dockerfile
9 | environment:
10 | TZ: 'Asia/Tashkent'
11 | PHP_IDE_CONFIG: "serverName=localhost"
12 | PHP_MEMORY_LIMIT: "2048M"
13 | volumes:
14 | - '.:/var/www/'
15 | - './.docker/web.loc/supervisord.conf:/etc/supervisord.conf'
16 | - './.docker/web.loc/nginx.conf:/etc/nginx/nginx.conf'
17 | - './.docker/web.loc/app.conf:/etc/nginx/conf.d/default.conf'
18 | - './.docker/web.loc/php-fpm.conf:/usr/local/etc/php-fpm.d/www.conf'
19 | - '/etc/docker/laravel-api/uploads:/var/www/storage/app/public/uploads'
20 | extra_hosts:
21 | - 'host.docker.internal:host-gateway'
22 | ports:
23 | - '${APP_PORT:-80}:80'
24 | networks:
25 | - 'laravel-api-network'
26 | depends_on:
27 | - mariadb
28 | mariadb:
29 | container_name: laravel-api-database
30 | restart: always
31 | image: 'mariadb:10'
32 | ports:
33 | - '${FORWARD_DB_PORT:-3307}:3306'
34 | environment:
35 | MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
36 | MYSQL_DATABASE: '${DB_DATABASE}'
37 | MYSQL_USER: '${DB_USERNAME}'
38 | MYSQL_PASSWORD: '${DB_PASSWORD}'
39 | MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
40 | TZ: 'Asia/Tashkent'
41 | volumes:
42 | - '${DATABASE_PATH:-/etc/docker/laravel-api/laravel-api-database:/var/lib/mysql}'
43 | networks:
44 | - 'laravel-api-network'
45 | healthcheck:
46 | test: [ "CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}" ]
47 | retries: 3
48 | timeout: 5s
49 | networks:
50 | laravel-api-network:
51 | driver: bridge
52 | volumes:
53 | laravel-api-database:
54 | driver: local
55 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | App\Http\Kernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | App\Console\Kernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | App\Exceptions\Handler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | # For more information: https://laravel.com/docs/sail
2 | version: '3'
3 | services:
4 | laravel.test:
5 | build:
6 | context: ./vendor/laravel/sail/runtimes/8.1
7 | dockerfile: Dockerfile
8 | args:
9 | WWWGROUP: '${WWWGROUP}'
10 | image: sail-8.1/app
11 | ports:
12 | - '${APP_PORT:-80}:80'
13 | environment:
14 | WWWUSER: '${WWWUSER}'
15 | LARAVEL_SAIL: 1
16 | volumes:
17 | - '.:/var/www/html'
18 | networks:
19 | - sail
20 | depends_on:
21 | - mariadb
22 | - rediska
23 | mariadb:
24 | image: 'mariadb:10'
25 | ports:
26 | - '${FORWARD_DB_PORT:-3306}:3306'
27 | environment:
28 | MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
29 | MYSQL_DATABASE: '${DB_DATABASE}'
30 | MYSQL_USER: '${DB_USERNAME}'
31 | MYSQL_PASSWORD: '${DB_PASSWORD}'
32 | MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
33 | volumes:
34 | - 'sailmariadb:/var/lib/mysql'
35 | networks:
36 | - sail
37 | healthcheck:
38 | test: [ "CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}" ]
39 | retries: 3
40 | timeout: 5s
41 | rediska:
42 | image: 'redis:alpine'
43 | ports:
44 | - '${FORWARD_REDIS_PORT:-6379}:6379'
45 | volumes:
46 | - 'sailredis:/data'
47 | networks:
48 | - sail
49 | healthcheck:
50 | test: [ "CMD", "redis-cli", "ping" ]
51 | retries: 3
52 | timeout: 5s
53 | networks:
54 | sail:
55 | driver: bridge
56 | volumes:
57 | sailmariadb:
58 | driver: local
59 | sailredis:
60 | driver: local
61 |
--------------------------------------------------------------------------------
/app/Http/Controllers/AuthController.php:
--------------------------------------------------------------------------------
1 | service->register($request);
22 |
23 | return $this->responseWith(compact('result'), 201);
24 | }
25 |
26 | public function login(LoginRequest $request): JsonResponse
27 | {
28 | try {
29 | $result = $this->service->login($request);
30 |
31 | return $this->responseWith(compact('result'));
32 | } catch (\Exception $e) {
33 | return $this->responseWith(code: $e->getCode(), message: $e->getMessage());
34 | }
35 | }
36 |
37 | public function refresh(Request $request)
38 | {
39 | try {
40 | $result = $this->service->refresh($request);
41 |
42 | return $this->responseWith(compact('result'));
43 | } catch (\Exception $e) {
44 | return $this->responseWith(code: $e->getCode(), message: $e->getMessage());
45 | }
46 | }
47 |
48 | public function logout(Request $request): JsonResponse
49 | {
50 | try {
51 | $this->service->logout($request);
52 |
53 | return $this->responseWith(message: __('messages.logout'));
54 | } catch (\Exception $e) {
55 | return $this->responseWith(code: $e->getCode(), message: $e->getMessage());
56 | }
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/app/Core/Traits/Responsable.php:
--------------------------------------------------------------------------------
1 | message = empty($message) ? Response::$statusTexts[$code] : $message;
42 | $this->data = $data;
43 | $this->statusCode = match ($code) {
44 | 200 => 200,
45 | 204 => 204,
46 | 201 => 201,
47 | 401 => 401,
48 | 403 => 403,
49 | 404 => 404,
50 | 422 => 422,
51 | 500, 0 => 500,
52 | };
53 |
54 | if ($logging) {
55 | event(new LoggerEvent(response: $this->data, response_status: $this->statusCode,
56 | response_message: $this->message));
57 | }
58 |
59 | return $this->response();
60 | }
61 |
62 | /**
63 | * Send response
64 | */
65 | private function response(): JsonResponse
66 | {
67 | $data = ['code' => $this->statusCode, 'message' => $this->message, 'data' => $this->data];
68 |
69 | return response()->json($data, $this->statusCode);
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/docker-compose-prod.yaml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 | services:
3 | web:
4 | container_name: laravel-api-web
5 | restart: always
6 | build:
7 | context: .
8 | dockerfile: ./.docker/web/Dockerfile
9 | environment:
10 | TZ: 'Asia/Tashkent'
11 | ports:
12 | - '443:443'
13 | volumes:
14 | - '/etc/letsencrypt:/etc/letsencrypt'
15 | - '/etc/docker/laravel-api/uploads:/var/www/storage/app/public/uploads'
16 | networks:
17 | - 'laravel-api-network'
18 | depends_on:
19 | - mariadb
20 | - redis
21 | mariadb:
22 | container_name: laravel-api-database
23 | restart: always
24 | image: 'mariadb:10'
25 | ports:
26 | - '${FORWARD_DB_PORT:-3307}:3306'
27 | environment:
28 | MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
29 | MYSQL_DATABASE: '${DB_DATABASE}'
30 | MYSQL_USER: '${DB_USERNAME}'
31 | MYSQL_PASSWORD: '${DB_PASSWORD}'
32 | MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
33 | TZ: 'Asia/Tashkent'
34 | volumes:
35 | - '/etc/docker/laravel-api/laravel-api-database:/var/lib/mysql'
36 | networks:
37 | - 'laravel-api-network'
38 | healthcheck:
39 | test: [ "CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}" ]
40 | retries: 3
41 | timeout: 5s
42 | redis:
43 | container_name: laravel-api-redis
44 | restart: always
45 | image: 'redis:alpine'
46 | ports:
47 | - '${FORWARD_REDIS_PORT:-6380}:6379'
48 | environment:
49 | TZ: 'Asia/Tashkent'
50 | volumes:
51 | - '/etc/docker/laravel-api/laravel-api-redis:/data'
52 | networks:
53 | - 'laravel-api-network'
54 | healthcheck:
55 | test: [ "CMD", "redis-cli", "ping" ]
56 | retries: 3
57 | timeout: 5s
58 | networks:
59 | laravel-api-network:
60 | driver: bridge
61 | volumes:
62 | laravel-api-database:
63 | driver: local
64 | laravel-api-redis:
65 | driver: local
66 |
--------------------------------------------------------------------------------
/app/Core/Macros/EloquentQuery.php:
--------------------------------------------------------------------------------
1 | make(request()->all(), [
12 | // //config('laravel_api.request.columns', 'columns') => 'string',
13 | // //config('laravel_api.request.relations', 'relations') => 'string',
14 | // //config('laravel_api.request.only_deleted', 'only_deleted') => ['bool',
15 | // // function ($attribute, $value, $fail) {
16 | // // if (!hasPermission('system')) {
17 | // // $fail(__('messages.you_havnt_permission'));
18 | // // }
19 | // // }],
20 | //]);
21 | //
22 | //if ($validator->fails()) {
23 | // throw ValidationException::withMessages($validator->messages()->toArray());
24 | //}
25 | //$trashed = $trashed ?? request(config('laravel_api.request.only_deleted', 'only_deleted'), false);
26 |
27 | $requestColumns = request(config('laravel_api.request.columns', 'columns'), ['*']);
28 |
29 | if (is_string($requestColumns)) {
30 | $requestColumns = explode(',', $requestColumns);
31 | }
32 |
33 | $columns = $columns ?? $requestColumns;
34 |
35 |
36 | return ($query ?? $this)
37 | ->select($columns);
38 | //->when($trashed, fn($query) => $query->onlyTrashed())
39 | });
40 |
--------------------------------------------------------------------------------
/app/Core/Services/CoreService.php:
--------------------------------------------------------------------------------
1 | repository->index(query: $query);
21 | }
22 |
23 | public function indexDb(
24 | QueryBuilder $query
25 | ): mixed {
26 | return $this->repository->indexDb(query: $query);
27 | }
28 |
29 | public function dbFirstBy(
30 | QueryBuilder $query,
31 | mixed $value,
32 | string $column = 'id',
33 | ) {
34 | return $this->repository->dbFirstBy($query, $value, $column);
35 | }
36 |
37 | public function show(Model|int $model, Builder|Relation $query = null): ?Model
38 | {
39 | return $this->repository->show($model, query: $query);
40 | }
41 |
42 | public function create(FormRequest|Validator $request): mixed
43 | {
44 | return $this->repository->create($request->validated());
45 | }
46 |
47 | public function update(Model|int $model, FormRequest|Validator $request): bool
48 | {
49 | $model = $this->repository->show($model);
50 | $this->repository->update($model, $request->validated());
51 |
52 | return true;
53 | }
54 |
55 | public function delete(Model|int $model): bool
56 | {
57 | $model = $this->repository->show($model);
58 |
59 | return $this->repository->delete($model);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/Core/Http/Requests/GetAllFilteredRecordsRequest.php:
--------------------------------------------------------------------------------
1 | 'in:pagination,collection',
15 | 'columns' => 'array',
16 | 'relations' => 'array',
17 | 'appends' => 'array',
18 | 'limit' => [function ($attribute, $value, $fail) {
19 | is_numeric($value) || $value === 'all' ? : $fail("$attribute must be numeric or 'all'");
20 | }],
21 | 'per_page' => 'integer',
22 | 'is_active' => 'boolean',
23 | 'search' => 'nullable|string',
24 | 'search_by' => 'nullable|array',
25 | 'conditions' => 'array',
26 | 'not_conditions' => 'array',
27 | 'or_conditions' => 'array',
28 | 'pluck' => !is_array($this->get('pluck')) ? 'string' : "array|required_array_keys:column",
29 | 'only_deleted' => ['bool',
30 | function ($attribute, $value, $fail) {
31 | if (!hasPermission('system')) {
32 | $fail(__('messages.you_havnt_permission'));
33 | }
34 | }],
35 | 'order' => 'string',
36 | 'sort' => 'in:desc,asc',
37 | ];
38 | }
39 |
40 | /**
41 | * Determine if the user is authorized to make this request.
42 | */
43 | public function authorize(): bool
44 | {
45 | return true;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class);
50 |
51 | $response = tap($kernel->handle(
52 | $request = Request::capture()
53 | ))->send();
54 |
55 | $kernel->terminate($request, $response);
56 |
--------------------------------------------------------------------------------