Compare commits
84 Commits
3b8b62d599
...
feature/Ge
| Author | SHA1 | Date | |
|---|---|---|---|
| 8be89d350f | |||
| d31c641216 | |||
| aa363d1695 | |||
| ca2ec66fb5 | |||
| 5c757e1823 | |||
| d9f895c382 | |||
| 9ad3d6cea0 | |||
| 8554f4cc55 | |||
| 5e48777e1c | |||
| 01bae8474b | |||
| 463ca3f006 | |||
| 1ba141e715 | |||
| 76e6ab4e0c | |||
| fb35ed58b1 | |||
| ffb4179e0d | |||
| a7fa1097b7 | |||
| f2f9d38907 | |||
| 5b79cefe28 | |||
| 41b7ead69e | |||
| 5ea986db40 | |||
| d04637b1ef | |||
| 3c61e279ec | |||
| e9f6ee71fa | |||
| 60129f5abb | |||
| 2d8f2dbcc5 | |||
| 86e353749a | |||
| f3a9b5e788 | |||
| d04277ece5 | |||
| e53a89016f | |||
| 53f2303253 | |||
| c6dc5256e6 | |||
| 19abb28acf | |||
| 431acd9279 | |||
| 9fcd8045db | |||
| 7c82556d93 | |||
| 581e7af1fd | |||
| b433d2ff52 | |||
| 6f06218cb2 | |||
| af23df5527 | |||
| 1a2077a164 | |||
| e33aac7eed | |||
| 7b0507bdda | |||
| ae8ca057fd | |||
| 32c14bd6c4 | |||
| 363c7005d0 | |||
| f29510d76e | |||
| 5596943b70 | |||
| 5831a5594a | |||
| 12736d53c5 | |||
| fda129875e | |||
| ca71547657 | |||
| 2d31eccc4a | |||
| abb92b4e22 | |||
| ea68943354 | |||
| e3831e98c9 | |||
| 9794aa1f54 | |||
| 4afcd5c81e | |||
| 74bc255d82 | |||
| ca094cff9f | |||
| c2328ec666 | |||
| e4f7b96b92 | |||
| f072bd1ee8 | |||
| f01992368e | |||
| 161fa3ae1e | |||
| 05c54fb2d7 | |||
| b32ee444ca | |||
| 264ed1ecb9 | |||
| cee480fff5 | |||
| 5024a242d2 | |||
| 0bba710b7d | |||
| f788f9a7ea | |||
| e74619d0ab | |||
| 5b42e23afc | |||
| 51aa3b157c | |||
| b24b61c754 | |||
| 5d2501c71c | |||
| 7fb9e345a2 | |||
| 9d86e329fb | |||
| 4596025ba3 | |||
| 1dbd816da2 | |||
| 52ed10f831 | |||
| e99aa9b8f1 | |||
| ccd2de26df | |||
| 9cdf4c129b |
8
.env.example
Normal file
8
.env.example
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
PROJECT_NAME=""
|
||||||
|
|
||||||
|
BACKEND_PATH="./Backend"
|
||||||
|
FRONTEND_PATH=""
|
||||||
|
|
||||||
|
POSTGRES_USER=""
|
||||||
|
POSTGRES_DB=""
|
||||||
|
POSTGRES_PASSWORD=""
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.idea
|
||||||
|
.env
|
||||||
|
front
|
||||||
18
backend/.dockerignore
Executable file
18
backend/.dockerignore
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#.git
|
||||||
|
#.gitignore
|
||||||
|
#README.md
|
||||||
|
#.env
|
||||||
|
#.env.backup
|
||||||
|
#node_modules
|
||||||
|
#npm-debug.log
|
||||||
|
#yarn-error.log
|
||||||
|
#vendor/
|
||||||
|
#storage/logs/*
|
||||||
|
#storage/framework/cache/*
|
||||||
|
#storage/framework/sessions/*
|
||||||
|
#storage/framework/views/*
|
||||||
|
#bootstrap/cache/*
|
||||||
|
#.phpunit.result.cache
|
||||||
|
#Homestead.json
|
||||||
|
#Homestead.yaml
|
||||||
|
#auth.json
|
||||||
18
backend/.editorconfig
Executable file
18
backend/.editorconfig
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[{compose,docker-compose}.{yml,yaml}]
|
||||||
|
indent_size = 4
|
||||||
77
backend/.env.example
Executable file
77
backend/.env.example
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
APP_NAME=Laravel
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost
|
||||||
|
|
||||||
|
APP_LOCALE=en
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=en_US
|
||||||
|
|
||||||
|
APP_MAINTENANCE_DRIVER=file
|
||||||
|
# APP_MAINTENANCE_STORE=database
|
||||||
|
|
||||||
|
# PHP_CLI_SERVER_WORKERS=4
|
||||||
|
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_STACK=single
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=pgsql
|
||||||
|
DB_HOST=127.0.0.1
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_DATABASE=backend
|
||||||
|
DB_USERNAME=root
|
||||||
|
DB_PASSWORD=
|
||||||
|
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=log
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
|
CACHE_STORE=database
|
||||||
|
# CACHE_PREFIX=
|
||||||
|
|
||||||
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
|
REDIS_CLIENT=phpredis
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_SCHEME=null
|
||||||
|
MAIL_HOST=127.0.0.1
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@example.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
FIB_AUTHORIZATION_URL=
|
||||||
|
FIB_CLIENT_ID=
|
||||||
|
FIB_CLIENT_SECRET=
|
||||||
|
|
||||||
|
FIB_CREATE_PAYMENT_URL
|
||||||
|
|
||||||
|
FIB_CHECK_PAYMENT_STATUS_URL
|
||||||
|
|
||||||
|
FIB_CANCEL_PAYMENT_URL
|
||||||
|
|
||||||
|
FIB_REFUND_URL
|
||||||
11
backend/.gitattributes
vendored
Executable file
11
backend/.gitattributes
vendored
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.blade.php diff=html
|
||||||
|
*.css diff=css
|
||||||
|
*.html diff=html
|
||||||
|
*.md diff=markdown
|
||||||
|
*.php diff=php
|
||||||
|
|
||||||
|
/.github export-ignore
|
||||||
|
CHANGELOG.md export-ignore
|
||||||
|
.styleci.yml export-ignore
|
||||||
26
backend/.gitignore
vendored
Executable file
26
backend/.gitignore
vendored
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
.env
|
||||||
|
.env.backup
|
||||||
|
.env.production
|
||||||
|
.phpactor.json
|
||||||
|
.phpunit.result.cache
|
||||||
|
/.codex
|
||||||
|
/.cursor/
|
||||||
|
/.idea
|
||||||
|
/.nova
|
||||||
|
/.phpunit.cache
|
||||||
|
/.vscode
|
||||||
|
/.zed
|
||||||
|
/auth.json
|
||||||
|
/node_modules
|
||||||
|
/public/build
|
||||||
|
/public/hot
|
||||||
|
/public/storage
|
||||||
|
/storage/*.key
|
||||||
|
/storage/pail
|
||||||
|
/vendor
|
||||||
|
_ide_helper.php
|
||||||
|
Homestead.json
|
||||||
|
Homestead.yaml
|
||||||
|
Thumbs.db
|
||||||
2
backend/.npmrc
Executable file
2
backend/.npmrc
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
ignore-scripts=true
|
||||||
|
audit=true
|
||||||
35
backend/Dockerfile
Executable file
35
backend/Dockerfile
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
FROM php:8.5.3-fpm-alpine3.23
|
||||||
|
|
||||||
|
# Install common PHP extension dependencies
|
||||||
|
RUN apk update && apk add --no-cache \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
libpng \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
freetype-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
unzip \
|
||||||
|
libzip-dev \
|
||||||
|
libpq-dev \
|
||||||
|
&& docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
|
||||||
|
&& docker-php-ext-install pdo_pgsql gd zip
|
||||||
|
|
||||||
|
# Set the working directory
|
||||||
|
WORKDIR /var/www/payment
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN chmod -R 775 /var/www/payment/storage /var/www/payment/bootstrap/cache
|
||||||
|
|
||||||
|
# Install Composer
|
||||||
|
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||||
|
ENV COMPOSER_ALLOW_SUPERUSER=1
|
||||||
|
|
||||||
|
# Default command
|
||||||
|
CMD composer install ;\
|
||||||
|
composer dump-autoload --optimize --classmap-authoritative ;\
|
||||||
|
php artisan migrate ;\
|
||||||
|
php artisan db:seed ;\
|
||||||
|
php-fpm
|
||||||
41
backend/Dockerfile.production
Executable file
41
backend/Dockerfile.production
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
FROM docker.arvancloud.ir/composer:latest AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY composer.json composer.lock ./
|
||||||
|
|
||||||
|
RUN composer install \
|
||||||
|
--no-dev \
|
||||||
|
--no-scripts \
|
||||||
|
--no-autoloader \
|
||||||
|
--prefer-dist
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN composer dump-autoload --optimize --classmap-authoritative
|
||||||
|
|
||||||
|
FROM php:8.5.3-fpm-alpine3.23 AS application
|
||||||
|
|
||||||
|
RUN apk update && apk add --no-cache \
|
||||||
|
bash \
|
||||||
|
curl \
|
||||||
|
libpng \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
freetype-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
unzip \
|
||||||
|
libzip-dev \
|
||||||
|
libpq-dev \
|
||||||
|
&& docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
|
||||||
|
&& docker-php-ext-install pdo_pgsql gd zip
|
||||||
|
|
||||||
|
WORKDIR /var/www/payment
|
||||||
|
|
||||||
|
COPY --from=builder /app /var/www/payment
|
||||||
|
|
||||||
|
RUN chown -R www-data:www-data /var/www/payment \
|
||||||
|
&& chmod -R 665 storage bootstrap/cache
|
||||||
|
|
||||||
|
CMD ["php-fpm"]
|
||||||
58
backend/README.md
Executable file
58
backend/README.md
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## About Laravel
|
||||||
|
|
||||||
|
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||||
|
|
||||||
|
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||||
|
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||||
|
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||||
|
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||||
|
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||||
|
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||||
|
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||||
|
|
||||||
|
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||||
|
|
||||||
|
## Learning Laravel
|
||||||
|
|
||||||
|
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
|
||||||
|
|
||||||
|
In addition, [Laracasts](https://laracasts.com) contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||||
|
|
||||||
|
You can also watch bite-sized lessons with real-world projects on [Laravel Learn](https://laravel.com/learn), where you will be guided through building a Laravel application from scratch while learning PHP fundamentals.
|
||||||
|
|
||||||
|
## Agentic Development
|
||||||
|
|
||||||
|
Laravel's predictable structure and conventions make it ideal for AI coding agents like Claude Code, Cursor, and GitHub Copilot. Install [Laravel Boost](https://laravel.com/docs/ai) to supercharge your AI workflow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require laravel/boost --dev
|
||||||
|
|
||||||
|
php artisan boost:install
|
||||||
|
```
|
||||||
|
|
||||||
|
Boost provides your agent 15+ tools and skills that help agents build Laravel applications while following best practices.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||||
|
|
||||||
|
## Security Vulnerabilities
|
||||||
|
|
||||||
|
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||||
62
backend/app/Admin/Controllers/AuthController.php
Executable file
62
backend/app/Admin/Controllers/AuthController.php
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Requests\Auth\LoginRequest;
|
||||||
|
use App\Admin\Requests\Auth\RegisterRequest;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Expert;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
class AuthController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function register(RegisterRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
Expert::query()->create([
|
||||||
|
'username' => $request->username,
|
||||||
|
'email' => $request->email,
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(LoginRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$credentials = ['password' => $request->password];
|
||||||
|
|
||||||
|
if (filter_var($request->login, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$credentials['email'] = $request->login;
|
||||||
|
} else {
|
||||||
|
$credentials['username'] = $request->login;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Auth::attempt($credentials))
|
||||||
|
{
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->errorResponse(__('messages.incorrect_or_username_password'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
Auth::guard('expert')->logout();
|
||||||
|
|
||||||
|
$request->session()->invalidate();
|
||||||
|
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
55
backend/app/Admin/Controllers/DocumentationController.php
Executable file
55
backend/app/Admin/Controllers/DocumentationController.php
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Requests\Documentation\RejectRequest;
|
||||||
|
use App\Facades\DataTable\DataTableFacade;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class DocumentationController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function index(Request $request): array
|
||||||
|
{
|
||||||
|
return DataTableFacade::run(
|
||||||
|
User::query(),
|
||||||
|
$request,
|
||||||
|
allowedFilters: ['*'],
|
||||||
|
allowedSortings: ['*'],
|
||||||
|
allowedSelects: [
|
||||||
|
'id', 'first_name', 'last_name', 'national_id',
|
||||||
|
'phone_number', 'postal_code', 'city_id', 'province_id',
|
||||||
|
'province_name', 'city_name', 'address'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function files(User $user): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse($user->load('documents'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function confirm(User $user): JsonResponse
|
||||||
|
{
|
||||||
|
$user->update([
|
||||||
|
'authority_level' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reject(RejectRequest $request, User $user): JsonResponse
|
||||||
|
{
|
||||||
|
$user->update([
|
||||||
|
'kyc_status' => 0,
|
||||||
|
'kyc_reject_reason' => $request->kyc_reject_reason
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
112
backend/app/Admin/Controllers/ExpertManagementController.php
Executable file
112
backend/app/Admin/Controllers/ExpertManagementController.php
Executable file
@@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Requests\ExpertManagement\StoreRequest;
|
||||||
|
use App\Admin\Requests\ExpertManagement\UpdateRequest;
|
||||||
|
use App\Facades\DataTable\DataTableFacade;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\City;
|
||||||
|
use App\Models\Expert;
|
||||||
|
use App\Models\Province;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ExpertManagementController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = DataTableFacade::run(
|
||||||
|
Expert::query(),
|
||||||
|
$request,
|
||||||
|
allowedFilters: ['*'],
|
||||||
|
allowedSortings: ['*'],
|
||||||
|
allowedSelects: ['id', 'username', 'first_name', 'last_name', 'phone_number', 'email', 'national_id'],
|
||||||
|
);
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(StoreRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$province = Province::query()->find($request->province_id);
|
||||||
|
$city = City::query()->find($request->city_id);
|
||||||
|
|
||||||
|
Expert::query()->create([
|
||||||
|
'username' => $request->username,
|
||||||
|
'first_name' => $request->first_name,
|
||||||
|
'last_name' => $request->last_name,
|
||||||
|
'national_id' => $request->national_id,
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
'email' => $request->email,
|
||||||
|
'phone_number' => $request->phone_number,
|
||||||
|
'province_id' => $request->province_id,
|
||||||
|
'province_name' => $province->name,
|
||||||
|
'city_id' => $request->city_id,
|
||||||
|
'city_name' => $city->name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(Expert $expert): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse($expert->load(['roles','permissions'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(UpdateRequest $request, Expert $expert): JsonResponse
|
||||||
|
{
|
||||||
|
$province = Province::query()->find($request->province_id);
|
||||||
|
$city = City::query()->find($request->city_id);
|
||||||
|
|
||||||
|
$expert->update([
|
||||||
|
'username' => $request->username,
|
||||||
|
'first_name' => $request->first_name,
|
||||||
|
'last_name' => $request->last_name,
|
||||||
|
'national_id' => $request->national_id,
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
'email' => $request->email,
|
||||||
|
'phone_number' => $request->phone_number,
|
||||||
|
'province_id' => $request->province_id,
|
||||||
|
'province_name' => $province->name,
|
||||||
|
'city_id' => $request->city_id,
|
||||||
|
'city_name' => $city->name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function destroy(Expert $expert): JsonResponse
|
||||||
|
{
|
||||||
|
DB::transaction(function () use ($expert) {
|
||||||
|
$expert->roles()->detach();
|
||||||
|
$expert->permissions()->detach();
|
||||||
|
$expert->delete();
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
78
backend/app/Admin/Controllers/PermissionManagementController.php
Executable file
78
backend/app/Admin/Controllers/PermissionManagementController.php
Executable file
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Requests\PermissionManagement\StoreRequest;
|
||||||
|
use App\Admin\Requests\PermissionManagement\UpdateRequest;
|
||||||
|
use App\Facades\DataTable\DataTableFacade;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Spatie\Permission\Models\Permission;
|
||||||
|
|
||||||
|
class PermissionManagementController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*/
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json(
|
||||||
|
DataTableFacade::run(
|
||||||
|
Permission::query(),
|
||||||
|
$request,
|
||||||
|
allowedFilters: ['*'],
|
||||||
|
allowedSortings: ['*']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(StoreRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
Permission::create([
|
||||||
|
'name' => $request->name,
|
||||||
|
'guard_name' => 'web',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(Permission $permission): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse($permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(UpdateRequest $request, Permission $permission): JsonResponse
|
||||||
|
{
|
||||||
|
$permission->update([
|
||||||
|
'name' => $request->name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*/
|
||||||
|
public function destroy(Permission $permission): JsonResponse
|
||||||
|
{
|
||||||
|
$permission->delete();
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
56
backend/app/Admin/Controllers/ProfileController.php
Executable file
56
backend/app/Admin/Controllers/ProfileController.php
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Requests\Profile\ChangePasswordRequest;
|
||||||
|
use App\Admin\Requests\Profile\EditRequest;
|
||||||
|
use App\Admin\Resources\ExpertResource;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function info(): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse(new ExpertResource(Auth::guard('expert')->user()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(EditRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$expert = $request->user('expert');
|
||||||
|
|
||||||
|
$expert->update([
|
||||||
|
'username' => $request->username,
|
||||||
|
'first_name' => $request->first_name,
|
||||||
|
'last_name' => $request->last_name,
|
||||||
|
'email' => $expert->email,
|
||||||
|
'national_id' => $request->national_id,
|
||||||
|
'phone_number' => $request->phone_number,
|
||||||
|
'province_id' => $request->province_id,
|
||||||
|
'city_id' => $request->city_id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function changePassword(ChangePasswordRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$expert = Auth::guard('expert')->user();
|
||||||
|
|
||||||
|
if (! Hash::check($request->current_password, $expert->password))
|
||||||
|
{
|
||||||
|
return $this->errorResponse(__('messages.incorrect_current_password'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$expert->update([
|
||||||
|
'password' => Hash::make($request->new_password)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
77
backend/app/Admin/Controllers/RoleManagementController.php
Executable file
77
backend/app/Admin/Controllers/RoleManagementController.php
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Requests\RoleManagement\StoreRequest;
|
||||||
|
use App\Admin\Requests\RoleManagement\UpdateRequest;
|
||||||
|
use App\Facades\DataTable\DataTableFacade;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Spatie\Permission\Models\Role;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class RoleManagementController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = DataTableFacade::run(
|
||||||
|
Role::query(),
|
||||||
|
$request,
|
||||||
|
allowedFilters: ['*'],
|
||||||
|
allowedSortings: ['*'],
|
||||||
|
allowedSelects: ['id', 'name']
|
||||||
|
);
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function store(StoreRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
DB::transaction(function () use ($request) {
|
||||||
|
$role = Role::create([
|
||||||
|
'name' => $request->name,
|
||||||
|
'guard_name' => 'web',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$role->givePermissionTo($request->permissions);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function update(UpdateRequest $request, Role $role): JsonResponse
|
||||||
|
{
|
||||||
|
DB::transaction(function () use ($request, $role) {
|
||||||
|
$role->update([
|
||||||
|
'name' => $request->name,
|
||||||
|
'guard_name' => 'web',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$role->syncPermissions($request->permissions);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Role $role): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse($role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Role $role): JsonResponse
|
||||||
|
{
|
||||||
|
$role->delete();
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
113
backend/app/Admin/Controllers/UserManagementController.php
Executable file
113
backend/app/Admin/Controllers/UserManagementController.php
Executable file
@@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Requests\UserManagement\StoreRequest;
|
||||||
|
use App\Admin\Requests\UserManagement\UpdateRequest;
|
||||||
|
use App\Facades\DataTable\DataTableFacade;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\City;
|
||||||
|
use App\Models\Province;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class UserManagementController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = DataTableFacade::run(
|
||||||
|
User::query(),
|
||||||
|
$request,
|
||||||
|
allowedFilters: ['*'],
|
||||||
|
allowedSortings: ['*'],
|
||||||
|
allowedSelects: ['id', 'username','first_name', 'last_name','kyc_status','national_id',
|
||||||
|
'phone_number','postal_code','province_id','province_name', 'city_id', 'city_name',
|
||||||
|
'birth_date','tax_id', 'password', 'email'],
|
||||||
|
);
|
||||||
|
|
||||||
|
return response()->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*/
|
||||||
|
public function store(StoreRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$province = Province::query()->find($request->province_id);
|
||||||
|
$city = City::query()->find($request->city_id);
|
||||||
|
|
||||||
|
User::query()->create([
|
||||||
|
'username' => $request->username,
|
||||||
|
'first_name' => $request->first_name,
|
||||||
|
'last_name' => $request->last_name,
|
||||||
|
'national_id' => $request->national_id,
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
'email' => $request->email,
|
||||||
|
'birth_date' => $request->birth_date,
|
||||||
|
'phone_number' => $request->phone_number,
|
||||||
|
'postal_code' => $request->postal_code,
|
||||||
|
'address' => $request->address,
|
||||||
|
'province_id' => $request->province_id,
|
||||||
|
'province_name' => $province->name,
|
||||||
|
'city_id' => $request->city_id,
|
||||||
|
'city_name' => $city->name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the specified resource.
|
||||||
|
*/
|
||||||
|
public function show(User $user): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse($user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*/
|
||||||
|
public function update(UpdateRequest $request, User $user): JsonResponse
|
||||||
|
{
|
||||||
|
$province = Province::query()->find($request->province_id);
|
||||||
|
$city = City::query()->find($request->city_id);
|
||||||
|
|
||||||
|
$user->update([
|
||||||
|
'first_name' => $request->first_name,
|
||||||
|
'username' => $request->username,
|
||||||
|
'last_name' => $request->last_name,
|
||||||
|
'national_id' => $request->national_id,
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
'email' => $request->email,
|
||||||
|
'birth_date' => $request->birth_date,
|
||||||
|
'phone_number' => $request->phone_number,
|
||||||
|
'postal_code' => $request->postal_code,
|
||||||
|
'address' => $request->address,
|
||||||
|
'province_id' => $request->province_id,
|
||||||
|
'province_name' => $province->name,
|
||||||
|
'city_id' => $request->city_id,
|
||||||
|
'city_name' => $city->name,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function destroy(User $user): JsonResponse
|
||||||
|
{
|
||||||
|
$user->delete();
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/Admin/Requests/Auth/LoginRequest.php
Executable file
30
backend/app/Admin/Requests/Auth/LoginRequest.php
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class LoginRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'login' => 'required|string',
|
||||||
|
'password' => 'required|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/Admin/Requests/Auth/RegisterRequest.php
Executable file
31
backend/app/Admin/Requests/Auth/RegisterRequest.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class RegisterRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'username' => 'required|unique:experts,username',
|
||||||
|
'email' => 'required|email|unique:experts,email',
|
||||||
|
'password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:6|confirmed',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
29
backend/app/Admin/Requests/Documentation/RejectRequest.php
Executable file
29
backend/app/Admin/Requests/Documentation/RejectRequest.php
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\Documentation;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class RejectRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'kyc_reject_reason' => 'required|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
37
backend/app/Admin/Requests/ExpertManagement/StoreRequest.php
Executable file
37
backend/app/Admin/Requests/ExpertManagement/StoreRequest.php
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\ExpertManagement;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'username' => 'required|string|max:255|unique:experts,username',
|
||||||
|
'first_name' => 'required|string|max:255',
|
||||||
|
'last_name' => 'required|string|max:255',
|
||||||
|
'national_id' => 'required|string|max:20|unique:experts,national_id',
|
||||||
|
'password' => 'required|string|min:8|confirmed',
|
||||||
|
'email' => 'required|email|max:255|unique:experts,email',
|
||||||
|
'phone_number' => 'required|string|max:20|unique:experts,phone_number',
|
||||||
|
'province_id' => 'required|integer|exists:provinces,id',
|
||||||
|
'city_id' => 'required|integer|exists:cities,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
45
backend/app/Admin/Requests/ExpertManagement/UpdateRequest.php
Executable file
45
backend/app/Admin/Requests/ExpertManagement/UpdateRequest.php
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\ExpertManagement;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property mixed $expert
|
||||||
|
*/
|
||||||
|
class UpdateRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'username' => ['string', 'max:255',
|
||||||
|
Rule::unique('experts', 'username')->ignore($this->expert->id),],
|
||||||
|
'first_name' => 'string|max:255',
|
||||||
|
'last_name' => 'string|max:255',
|
||||||
|
'national_id' => ['string', 'max:20',
|
||||||
|
Rule::unique('experts', 'national_id')->ignore($this->expert->id),],
|
||||||
|
'password' => 'string|min:8|confirmed',
|
||||||
|
'email' => ['email', 'max:255',
|
||||||
|
Rule::unique('experts', 'email')->ignore($this->expert->id),],
|
||||||
|
'phone_number' => ['string', 'max:20',
|
||||||
|
Rule::unique('experts', 'phone_number')->ignore($this->expert->id),],
|
||||||
|
'province_id' => 'required|integer|exists:provinces,id',
|
||||||
|
'city_id' => 'required|integer|exists:cities,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
29
backend/app/Admin/Requests/PermissionManagement/StoreRequest.php
Executable file
29
backend/app/Admin/Requests/PermissionManagement/StoreRequest.php
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\PermissionManagement;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|unique:permissions,name',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
33
backend/app/Admin/Requests/PermissionManagement/UpdateRequest.php
Executable file
33
backend/app/Admin/Requests/PermissionManagement/UpdateRequest.php
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\PermissionManagement;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property mixed $permission
|
||||||
|
*/
|
||||||
|
class UpdateRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => ['required', 'string', 'max:255', Rule::unique('permissions', 'name')->ignore($this->permission->id)],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/Admin/Requests/Profile/ChangePasswordRequest.php
Executable file
30
backend/app/Admin/Requests/Profile/ChangePasswordRequest.php
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class ChangePasswordRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'current_password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:8',
|
||||||
|
'new_password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:8',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
38
backend/app/Admin/Requests/Profile/EditRequest.php
Executable file
38
backend/app/Admin/Requests/Profile/EditRequest.php
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\Profile;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Illuminate\Validation\Validator;
|
||||||
|
|
||||||
|
class EditRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'username' => 'string|max:255',
|
||||||
|
'first_name' => 'required|string',
|
||||||
|
'last_name' => 'required|string',
|
||||||
|
'national_id' => 'required',
|
||||||
|
'email' => 'string|email|max:255',
|
||||||
|
'phone_number' => 'string',
|
||||||
|
'province_id' => 'string',
|
||||||
|
'city_id' => 'string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/Admin/Requests/RoleManagement/StoreRequest.php
Executable file
31
backend/app/Admin/Requests/RoleManagement/StoreRequest.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\RoleManagement;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|unique:roles,name',
|
||||||
|
'permissions' => 'array',
|
||||||
|
'permissions.*' => 'integer|exists:permissions,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
35
backend/app/Admin/Requests/RoleManagement/UpdateRequest.php
Executable file
35
backend/app/Admin/Requests/RoleManagement/UpdateRequest.php
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\RoleManagement;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property mixed $role
|
||||||
|
*/
|
||||||
|
class UpdateRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => ['string', 'max:255', Rule::unique('roles', 'name')->ignore($this->role->id)],
|
||||||
|
'permissions' => 'array',
|
||||||
|
'permissions.*' => 'integer|exists:permissions,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
40
backend/app/Admin/Requests/UserManagement/StoreRequest.php
Executable file
40
backend/app/Admin/Requests/UserManagement/StoreRequest.php
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\UserManagement;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class StoreRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'username' => 'required|string|max:255|unique:users,username',
|
||||||
|
'first_name' => 'required|string|max:255',
|
||||||
|
'last_name' => 'required|string|max:255',
|
||||||
|
'national_id' => 'required|string|max:20|unique:users,national_id',
|
||||||
|
'password' => 'required|string|min:6|confirmed',
|
||||||
|
'email' => 'required|email|max:255|unique:users,email',
|
||||||
|
'birth_date' => 'nullable|date',
|
||||||
|
'phone_number' => 'required|string|max:20|unique:users,phone_number',
|
||||||
|
'postal_code' => 'nullable|string|max:20',
|
||||||
|
'address' => 'nullable|string|max:1000',
|
||||||
|
'province_id' => 'required|integer|exists:provinces,id',
|
||||||
|
'city_id' => 'required|integer|exists:cities,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
49
backend/app/Admin/Requests/UserManagement/UpdateRequest.php
Executable file
49
backend/app/Admin/Requests/UserManagement/UpdateRequest.php
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Requests\UserManagement;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property mixed $user
|
||||||
|
*/
|
||||||
|
class UpdateRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
|
||||||
|
return [
|
||||||
|
'username' => ['string', 'max:255',
|
||||||
|
Rule::unique('users', 'username')->ignore($this->user->id),],
|
||||||
|
'first_name' => 'string|max:255',
|
||||||
|
'last_name' => 'string|max:255',
|
||||||
|
'national_id' => ['string', 'max:20',
|
||||||
|
Rule::unique('users', 'national_id')->ignore($this->user->id),],
|
||||||
|
'password' => 'string|min:8|confirmed',
|
||||||
|
'email' => ['email', 'max:255',
|
||||||
|
Rule::unique('users', 'email')->ignore($this->user->id),],
|
||||||
|
'birth_date' => 'nullable|date',
|
||||||
|
'phone_number' => ['string', 'max:20',
|
||||||
|
Rule::unique('users', 'phone_number')->ignore($this->user->id),],
|
||||||
|
'postal_code' => 'nullable|string|max:20',
|
||||||
|
'address' => 'nullable|string|max:1000',
|
||||||
|
'province_id' => 'integer|exists:provinces,id',
|
||||||
|
'city_id' => 'integer|exists:cities,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
24
backend/app/Admin/Resources/ExpertResource.php
Executable file
24
backend/app/Admin/Resources/ExpertResource.php
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class ExpertResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function toArray(Request $request): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
|
'username' => $this->username,
|
||||||
|
'email' => $this->email,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
66
backend/app/Enums/BusinessTypeEnum.php
Normal file
66
backend/app/Enums/BusinessTypeEnum.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum BusinessTypeEnum: int
|
||||||
|
{
|
||||||
|
case MEDICAL = 1;
|
||||||
|
case LEGAL = 2;
|
||||||
|
case ENGINEERING = 3;
|
||||||
|
case EDUCATION = 4;
|
||||||
|
case CONSULTING = 5;
|
||||||
|
case BEAUTY = 6;
|
||||||
|
case TECHNICAL_SERVICES = 7;
|
||||||
|
case FINANCIAL = 8;
|
||||||
|
case REAL_ESTATE = 9;
|
||||||
|
case RESTAURANT = 10;
|
||||||
|
case SHOP = 11;
|
||||||
|
case TRANSPORTATION = 12;
|
||||||
|
case ART = 13;
|
||||||
|
case SPORT = 14;
|
||||||
|
case OTHER = 15;
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::MEDICAL => 'medical',
|
||||||
|
self::LEGAL => 'legal',
|
||||||
|
self::ENGINEERING => 'engineering',
|
||||||
|
self::EDUCATION => 'education',
|
||||||
|
self::CONSULTING => 'consulting',
|
||||||
|
self::BEAUTY => 'beauty',
|
||||||
|
self::TECHNICAL_SERVICES => 'technical_services',
|
||||||
|
self::FINANCIAL => 'financial',
|
||||||
|
self::REAL_ESTATE => 'real_estate',
|
||||||
|
self::RESTAURANT => 'restaurant',
|
||||||
|
self::SHOP => 'shop',
|
||||||
|
self::TRANSPORTATION => 'transportation',
|
||||||
|
self::ART => 'art',
|
||||||
|
self::SPORT => 'sport',
|
||||||
|
self::OTHER => 'other',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function name($id): string
|
||||||
|
{
|
||||||
|
$mapArray = [
|
||||||
|
1 => 'medical',
|
||||||
|
2 => 'legal',
|
||||||
|
3 => 'engineering',
|
||||||
|
4 => 'education',
|
||||||
|
5 => 'consulting',
|
||||||
|
6 => 'beauty',
|
||||||
|
7 => 'technical_services',
|
||||||
|
8 => 'financial',
|
||||||
|
9 => 'real_estate',
|
||||||
|
10 => 'restaurant',
|
||||||
|
11 => 'shop',
|
||||||
|
12 => 'transportation',
|
||||||
|
13 => 'art',
|
||||||
|
14 => 'sport',
|
||||||
|
15 => 'other',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $mapArray[$id];
|
||||||
|
}
|
||||||
|
}
|
||||||
23
backend/app/Enums/PaymentStatusEnum.php
Normal file
23
backend/app/Enums/PaymentStatusEnum.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum PaymentStatusEnum:int
|
||||||
|
{
|
||||||
|
case Unpaid = 0;
|
||||||
|
case Cancelled = 1;
|
||||||
|
case Expired = 2;
|
||||||
|
case Paid = 3;
|
||||||
|
case Refunded = 4;
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::Unpaid => 'unpaid',
|
||||||
|
self::Cancelled => 'cancelled',
|
||||||
|
self::Expired => 'expired',
|
||||||
|
self::Paid => 'paid',
|
||||||
|
self::Refunded => 'refunded',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
67
backend/app/Facades/DataTable/DataTable.php
Executable file
67
backend/app/Facades/DataTable/DataTable.php
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Facades\DataTable;
|
||||||
|
|
||||||
|
use App\Services\DataTable\DataTableInput;
|
||||||
|
use App\Services\DataTable\DataTableService;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Services\DataTable\Exceptions\InvalidParameterInterface;
|
||||||
|
|
||||||
|
class DataTable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Extracts data from request, passes to datatable service and prepares data for response.
|
||||||
|
* @param Model|Builder $mixed
|
||||||
|
* @param Request $request
|
||||||
|
* @param array $allowedFilters
|
||||||
|
* @param array $allowedRelations
|
||||||
|
* @param array $allowedSortings
|
||||||
|
* @param array $allowedSelects
|
||||||
|
* @return array
|
||||||
|
* @throws InvalidParameterInterface if input parameters are invalid.
|
||||||
|
*/
|
||||||
|
public function run(
|
||||||
|
Model|Builder $mixed,
|
||||||
|
Request $request,
|
||||||
|
array $allowedFilters = [],
|
||||||
|
array $allowedRelations = [],
|
||||||
|
array $allowedSortings = [],
|
||||||
|
array $allowedSelects = [],
|
||||||
|
array $allowedGroupBy = []
|
||||||
|
): array
|
||||||
|
{
|
||||||
|
|
||||||
|
$filters = json_decode($request->filters);
|
||||||
|
$sorting = json_decode($request->sorting);
|
||||||
|
$rels = $request->rels ?: array();
|
||||||
|
|
||||||
|
$dataTableInput = new DataTableInput(
|
||||||
|
$request->start,
|
||||||
|
$request->size,
|
||||||
|
$filters,
|
||||||
|
$sorting,
|
||||||
|
$rels,
|
||||||
|
$allowedFilters,
|
||||||
|
$allowedSortings,
|
||||||
|
$allowedGroupBy
|
||||||
|
);
|
||||||
|
|
||||||
|
$query = $this->makeQueryFromModel($mixed);
|
||||||
|
|
||||||
|
$dataTableService = (new DataTableService($query, $dataTableInput))
|
||||||
|
->setAllowedFilters($allowedFilters)
|
||||||
|
->setAllowedRelations($allowedRelations)
|
||||||
|
->setAllowedSortings($allowedSortings)
|
||||||
|
->setAllowedSelects($allowedSelects)
|
||||||
|
->setAllowedGroupBy($allowedGroupBy);
|
||||||
|
|
||||||
|
return $dataTableService->getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function makeQueryFromModel(Model|Builder $mixed): Builder
|
||||||
|
{
|
||||||
|
return ($mixed instanceof Model) ? $mixed->query() : $mixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
backend/app/Facades/DataTable/DataTableFacade.php
Executable file
13
backend/app/Facades/DataTable/DataTableFacade.php
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Facades\DataTable;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
|
class DataTableFacade extends Facade
|
||||||
|
{
|
||||||
|
protected static function getFacadeAccessor(): string
|
||||||
|
{
|
||||||
|
return DataTable::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
113
backend/app/Facades/File/File.php
Executable file
113
backend/app/Facades/File/File.php
Executable file
@@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Facades\File;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Http\File as HttpFile;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
class File
|
||||||
|
{
|
||||||
|
public function save(HttpFile|UploadedFile $file, string $path, string $name = null, string $disk = 'public'): string
|
||||||
|
{
|
||||||
|
return Storage::disk($disk)->putFileAs(
|
||||||
|
$path,
|
||||||
|
$file,
|
||||||
|
$name ?? Str::uuid() . '.' . $file->extension()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filePath
|
||||||
|
* @param bool $url_is_absolute
|
||||||
|
* @param string $disk
|
||||||
|
* @return void
|
||||||
|
* @throws InvalidArgumentException when filePath is empty.
|
||||||
|
*/
|
||||||
|
public function delete(string $filePath, bool $url_is_absolute = false, string $disk = 'public'): void
|
||||||
|
{
|
||||||
|
if (!$filePath){
|
||||||
|
throw new InvalidArgumentException('File path is invalid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($url_is_absolute) {
|
||||||
|
$needle = 'storage/';
|
||||||
|
$pos = strpos($filePath, $needle);
|
||||||
|
$filePath = substr($filePath, $pos + strlen($needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Storage::disk($disk)->exists($filePath)) {
|
||||||
|
Storage::disk($disk)->delete($filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteContent($file_path): bool
|
||||||
|
{
|
||||||
|
if (file_exists($file_path)) {
|
||||||
|
file_put_contents($file_path, '');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tail($file_path, $lines = 100, $buffer = 2048): bool|string
|
||||||
|
{
|
||||||
|
// Open file
|
||||||
|
$file = @fopen($file_path, "rb");
|
||||||
|
if ($file === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump to last character
|
||||||
|
fseek($file, -1, SEEK_END);
|
||||||
|
|
||||||
|
// Read it and adjust line number if necessary
|
||||||
|
// (Otherwise the result would be wrong if file doesn't end with a blank line)
|
||||||
|
if (fread($file, 1) != "\n") {
|
||||||
|
$lines -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start reading
|
||||||
|
$output = '';
|
||||||
|
$chunk = '';
|
||||||
|
|
||||||
|
// While we would like more
|
||||||
|
while (ftell($file) > 0 && $lines >= 0) {
|
||||||
|
|
||||||
|
// Figure out how far back we should jump
|
||||||
|
$seek = min(ftell($file), $buffer);
|
||||||
|
|
||||||
|
// Do the jump (backwards, relative to where we are)
|
||||||
|
fseek($file, -$seek, SEEK_CUR);
|
||||||
|
|
||||||
|
// Read a chunk and prepend it to our output
|
||||||
|
$output = ($chunk = fread($file, $seek)) . $output;
|
||||||
|
|
||||||
|
// Jump back to where we started reading
|
||||||
|
fseek($file, -mb_strlen($chunk, '8bit'), SEEK_CUR);
|
||||||
|
|
||||||
|
// Decrease our line counter
|
||||||
|
$lines -= substr_count($chunk, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// While we have too many lines
|
||||||
|
// (Because of buffer size we might have read too many)
|
||||||
|
while ($lines++ < 0) {
|
||||||
|
|
||||||
|
// Find first newline and remove all text before that
|
||||||
|
$output = substr($output, strpos($output, "\n") + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close file and return
|
||||||
|
fclose($file);
|
||||||
|
return trim($output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteDirectory(string $path, string $disk = 'public'): void
|
||||||
|
{
|
||||||
|
Storage::disk($disk)->deleteDirectory($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
backend/app/Facades/File/FileFacade.php
Executable file
13
backend/app/Facades/File/FileFacade.php
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Facades\File;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
|
class FileFacade extends Facade
|
||||||
|
{
|
||||||
|
protected static function getFacadeAccessor(): string
|
||||||
|
{
|
||||||
|
return File::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
backend/app/Http/Controllers/Controller.php
Executable file
8
backend/app/Http/Controllers/Controller.php
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
abstract class Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
40
backend/app/Mail/LoginNotificationMail.php
Executable file
40
backend/app/Mail/LoginNotificationMail.php
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class LoginNotificationMail extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public User $user
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: 'Login Notification Mail',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
view: 'emails.login-notification',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
15
backend/app/Models/BusinessType.php
Normal file
15
backend/app/Models/BusinessType.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\BusinessTypeFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class BusinessType extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<BusinessTypeFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
15
backend/app/Models/City.php
Executable file
15
backend/app/Models/City.php
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\CityFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class City extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<CityFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
30
backend/app/Models/Document.php
Executable file
30
backend/app/Models/Document.php
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\DocumentFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class Document extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<DocumentFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
|
public function documentable(): MorphTo
|
||||||
|
{
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function url(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn($value) => Storage::disk('public')->url($value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
backend/app/Models/Expert.php
Executable file
22
backend/app/Models/Expert.php
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\ExpertFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Spatie\Permission\Traits\HasRoles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method roles()
|
||||||
|
* @method permissions()
|
||||||
|
*/
|
||||||
|
class Expert extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<ExpertFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
use HasRoles;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
protected string $guard_name = 'web';
|
||||||
|
}
|
||||||
12
backend/app/Models/FibTransaction.php
Normal file
12
backend/app/Models/FibTransaction.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class FibTransaction extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<\Database\Factories\FibTransactionFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
}
|
||||||
12
backend/app/Models/FibTransactionStatus.php
Normal file
12
backend/app/Models/FibTransactionStatus.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class FibTransactionStatus extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<\Database\Factories\FibTransactionStatusFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
}
|
||||||
15
backend/app/Models/Payment.php
Normal file
15
backend/app/Models/Payment.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\PaymentFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Payment extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<PaymentFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
15
backend/app/Models/PaymentStatus.php
Normal file
15
backend/app/Models/PaymentStatus.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\PaymentStatusFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class PaymentStatus extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<PaymentStatusFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
15
backend/app/Models/Province.php
Executable file
15
backend/app/Models/Province.php
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\ProvinceFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Province extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<ProvinceFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
15
backend/app/Models/Transaction.php
Normal file
15
backend/app/Models/Transaction.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\TransactionFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Transaction extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<TransactionFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
39
backend/app/Models/User.php
Executable file
39
backend/app/Models/User.php
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
use Database\Factories\UserFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Laravel\Passport\Bridge\Client;
|
||||||
|
use Laravel\Passport\HasApiTokens;
|
||||||
|
|
||||||
|
#[Guarded(['id'])]
|
||||||
|
#[Hidden(['password'])]
|
||||||
|
class User extends Authenticatable
|
||||||
|
{
|
||||||
|
/** @use HasFactory<UserFactory> */
|
||||||
|
use HasFactory, Notifiable, HasApiTokens;
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
|
public function documents(): MorphToMany
|
||||||
|
{
|
||||||
|
return $this->morphToMany(Document::class, 'documentable');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateForPassportPasswordGrant(string $password): bool
|
||||||
|
{
|
||||||
|
return Hash::check($password, $this->password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findForPassport(string $username, Client $client): User
|
||||||
|
{
|
||||||
|
return $this->where('username', $username)->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
backend/app/Models/UserGateway.php
Normal file
15
backend/app/Models/UserGateway.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Database\Factories\UserGatewayFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class UserGateway extends Model
|
||||||
|
{
|
||||||
|
/** @use HasFactory<UserGatewayFactory> */
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = ['id'];
|
||||||
|
}
|
||||||
29
backend/app/Providers/AppServiceProvider.php
Executable file
29
backend/app/Providers/AppServiceProvider.php
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Laravel\Passport\Passport;
|
||||||
|
use Carbon\CarbonInterval;
|
||||||
|
|
||||||
|
class AppServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register any application services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
Passport::enablePasswordGrant();
|
||||||
|
Passport::tokensExpireIn(CarbonInterval::minutes(1));
|
||||||
|
Passport::refreshTokensExpireIn(CarbonInterval::minutes(5));
|
||||||
|
Passport::personalAccessTokensExpireIn(CarbonInterval::minutes(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
27
backend/app/Providers/DataTableServiceProvider.php
Executable file
27
backend/app/Providers/DataTableServiceProvider.php
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Facades\DataTable\DataTable;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class DataTableServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->app->bind('datatable', function () {
|
||||||
|
return new DataTable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
27
backend/app/Providers/FileServiceProvider.php
Executable file
27
backend/app/Providers/FileServiceProvider.php
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Facades\File\File;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class FileServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->app->bind('file', function () {
|
||||||
|
return new File();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
83
backend/app/Services/DataTable/DataTableInput.php
Executable file
83
backend/app/Services/DataTable/DataTableInput.php
Executable file
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Filter\Filter;
|
||||||
|
use App\Services\DataTable\Sort\Sort;
|
||||||
|
|
||||||
|
class DataTableInput
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param int $start
|
||||||
|
* @param int $size
|
||||||
|
* @param array $filters
|
||||||
|
* @param array $sorting
|
||||||
|
* @param array $rels
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private ?int $start,
|
||||||
|
private ?int $size,
|
||||||
|
private array $filters,
|
||||||
|
private ?array $sorting,
|
||||||
|
private array $rels,
|
||||||
|
private array $allowedFilters,
|
||||||
|
private array $allowedSortings,
|
||||||
|
private ?array $GroupBy,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStart(): ?int
|
||||||
|
{
|
||||||
|
return $this->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSize(): ?int
|
||||||
|
{
|
||||||
|
return $this->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array returns an array of Filter objects
|
||||||
|
*/
|
||||||
|
public function getFilters(): array
|
||||||
|
{
|
||||||
|
$filters = array();
|
||||||
|
|
||||||
|
foreach ($this->filters as $filter) {
|
||||||
|
$filters[] = new Filter(
|
||||||
|
$filter->id,
|
||||||
|
$filter->value,
|
||||||
|
$filter->fn,
|
||||||
|
$filter->datatype,
|
||||||
|
$this->allowedFilters
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSorting(): ?array
|
||||||
|
{
|
||||||
|
$sorts = [];
|
||||||
|
if (!empty($this->sorting)){
|
||||||
|
foreach ($this->sorting as $sort) {
|
||||||
|
$sorts[] = new Sort($sort->id, $sort->desc, $this->allowedSortings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $sorts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelations(): array
|
||||||
|
{
|
||||||
|
return $this->rels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGroupBy(): ?array
|
||||||
|
{
|
||||||
|
return $this->GroupBy;
|
||||||
|
}
|
||||||
|
}
|
||||||
128
backend/app/Services/DataTable/DataTableService.php
Executable file
128
backend/app/Services/DataTable/DataTableService.php
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Filter\ApplyFilter;
|
||||||
|
use App\Services\DataTable\Sort\ApplySort;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class DataTableService
|
||||||
|
{
|
||||||
|
|
||||||
|
protected array $allowedFilters;
|
||||||
|
protected array $allowedRelations;
|
||||||
|
protected array $allowedSortings;
|
||||||
|
protected array $allowedSelects;
|
||||||
|
protected array $allowedGroupBy;
|
||||||
|
private int $totalRowCount;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
protected Builder $query,
|
||||||
|
private DataTableInput $dataTableInput
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAllowedFilters(array $allowedFilters): DataTableService
|
||||||
|
{
|
||||||
|
$this->allowedFilters = $allowedFilters;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAllowedRelations(array $allowedRelations): DataTableService
|
||||||
|
{
|
||||||
|
$this->allowedRelations = $allowedRelations;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAllowedSortings(array $allowedSortings): DataTableService
|
||||||
|
{
|
||||||
|
$this->allowedSortings = $allowedSortings;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAllowedSelects(array $allowedSelects): DataTableService
|
||||||
|
{
|
||||||
|
$this->allowedSelects = $allowedSelects;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAllowedGroupBy(array $allowedGroupBy): DataTableService
|
||||||
|
{
|
||||||
|
$this->allowedGroupBy = $allowedGroupBy;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle 'getData' operations
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getData(): array
|
||||||
|
{
|
||||||
|
$query = $this->buildQuery();
|
||||||
|
$data = $query->get();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'data' => $data,
|
||||||
|
'meta' => [
|
||||||
|
'totalRowCount' => $this->totalRowCount
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQuery(): Builder
|
||||||
|
{
|
||||||
|
$query = $this->query;
|
||||||
|
|
||||||
|
foreach ($this->dataTableInput->getFilters() as $filter) {
|
||||||
|
$query = (new ApplyFilter($query, $filter))->apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->applySelect($query, $this->allowedSelects);
|
||||||
|
$query = $this->includeRelationsInQuery($query, $this->allowedRelations);
|
||||||
|
$query = $this->applyGroupBy($query, $this->allowedGroupBy);
|
||||||
|
|
||||||
|
$this->totalRowCount = $query->count();
|
||||||
|
|
||||||
|
if (!is_null($this->dataTableInput->getStart())) {
|
||||||
|
$query->offset($this->dataTableInput->getStart());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_null($this->dataTableInput->getSize())){
|
||||||
|
$query->limit($this->dataTableInput->getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
$sorting = $this->dataTableInput->getSorting();
|
||||||
|
foreach ($sorting as $sort){
|
||||||
|
$query = (new ApplySort($query, $sort))->apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applySelect(Builder $query, array $selectedFields): Builder
|
||||||
|
{
|
||||||
|
if (!empty($selectedFields)) {
|
||||||
|
$query->select($selectedFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyGroupBy(Builder $query, array $groupBy): Builder
|
||||||
|
{
|
||||||
|
return empty($groupBy) ? $query : $query->groupBy($groupBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function includeRelationsInQuery(Builder $query, array $rels): Builder
|
||||||
|
{
|
||||||
|
if (!empty($rels)) {
|
||||||
|
$query->with($rels);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (later) define mapping of relation names to prevent relation name expose.
|
||||||
|
// (later) define mapping of column names to prevent column name expose.
|
||||||
|
}
|
||||||
15
backend/app/Services/DataTable/Enums/DataType.php
Executable file
15
backend/app/Services/DataTable/Enums/DataType.php
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Enums;
|
||||||
|
|
||||||
|
enum DataType: string
|
||||||
|
{
|
||||||
|
case NUMERIC = 'numeric';
|
||||||
|
case TEXT = 'text';
|
||||||
|
case DATE = 'date';
|
||||||
|
|
||||||
|
public static function values(): array
|
||||||
|
{
|
||||||
|
return array_column(self::cases(), 'value');
|
||||||
|
}
|
||||||
|
}
|
||||||
19
backend/app/Services/DataTable/Enums/SearchType.php
Executable file
19
backend/app/Services/DataTable/Enums/SearchType.php
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Enums;
|
||||||
|
|
||||||
|
enum SearchType: string
|
||||||
|
{
|
||||||
|
case CONTAINS = 'contains';
|
||||||
|
case EQUALS = 'equals';
|
||||||
|
case NOT_EQUALS = 'notEquals';
|
||||||
|
case BETWEEN = 'between';
|
||||||
|
case GREATER_THAN = 'greaterThan';
|
||||||
|
case LESS_THAN = 'lessThan';
|
||||||
|
case FUZZY = 'fuzzy';
|
||||||
|
|
||||||
|
public static function values(): array
|
||||||
|
{
|
||||||
|
return array_column(self::cases(), 'value');
|
||||||
|
}
|
||||||
|
}
|
||||||
21
backend/app/Services/DataTable/Exceptions/InvalidFilterException.php
Executable file
21
backend/app/Services/DataTable/Exceptions/InvalidFilterException.php
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class InvalidFilterException extends Exception implements InvalidParameterInterface
|
||||||
|
{
|
||||||
|
protected $fieldName;
|
||||||
|
|
||||||
|
public function __construct($fieldName, $message = "", $code = 400, \Throwable $previous = null)
|
||||||
|
{
|
||||||
|
$this->fieldName = $fieldName;
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldName()
|
||||||
|
{
|
||||||
|
return $this->fieldName;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
backend/app/Services/DataTable/Exceptions/InvalidParameterInterface.php
Executable file
7
backend/app/Services/DataTable/Exceptions/InvalidParameterInterface.php
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Exceptions;
|
||||||
|
|
||||||
|
interface InvalidParameterInterface
|
||||||
|
{
|
||||||
|
}
|
||||||
21
backend/app/Services/DataTable/Exceptions/InvalidRelationException.php
Executable file
21
backend/app/Services/DataTable/Exceptions/InvalidRelationException.php
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class InvalidRelationException extends Exception implements InvalidParameterInterface
|
||||||
|
{
|
||||||
|
protected $fieldName;
|
||||||
|
|
||||||
|
public function __construct($fieldName, $message = "", $code = 400, \Throwable $previous = null)
|
||||||
|
{
|
||||||
|
$this->fieldName = $fieldName;
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldName()
|
||||||
|
{
|
||||||
|
return $this->fieldName;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
backend/app/Services/DataTable/Exceptions/InvalidSortingException.php
Executable file
21
backend/app/Services/DataTable/Exceptions/InvalidSortingException.php
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class InvalidSortingException extends Exception implements InvalidParameterInterface
|
||||||
|
{
|
||||||
|
protected $fieldName;
|
||||||
|
|
||||||
|
public function __construct($fieldName, $message = "", $code = 400, \Throwable $previous = null)
|
||||||
|
{
|
||||||
|
$this->fieldName = $fieldName;
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldName()
|
||||||
|
{
|
||||||
|
return $this->fieldName;
|
||||||
|
}
|
||||||
|
}
|
||||||
84
backend/app/Services/DataTable/Filter/ApplyFilter.php
Executable file
84
backend/app/Services/DataTable/Filter/ApplyFilter.php
Executable file
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Enums\SearchType;
|
||||||
|
use App\Services\DataTable\Exceptions\InvalidFilterException;
|
||||||
|
use App\Services\DataTable\Filter\SearchFunctions\FilterBetween;
|
||||||
|
use App\Services\DataTable\Filter\SearchFunctions\FilterContains;
|
||||||
|
use App\Services\DataTable\Filter\SearchFunctions\FilterEquals;
|
||||||
|
use App\Services\DataTable\Filter\SearchFunctions\FilterGreaterThan;
|
||||||
|
use App\Services\DataTable\Filter\SearchFunctions\FilterLessThan;
|
||||||
|
use App\Services\DataTable\Filter\SearchFunctions\FilterNotEquals;
|
||||||
|
use App\Services\DataTable\Filter\SearchFunctions\SearchFilter;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class ApplyFilter
|
||||||
|
{
|
||||||
|
private SearchFilter $searchFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Builder $query
|
||||||
|
* @param Filter $filter
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private Builder $query,
|
||||||
|
private Filter $filter,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$filter = $this->filter;
|
||||||
|
$query = $this->query;
|
||||||
|
|
||||||
|
$searchType = SearchType::from($filter->getFn());
|
||||||
|
switch ($searchType) {
|
||||||
|
case SearchType::CONTAINS:
|
||||||
|
$this->searchFilter = new FilterContains($query, $filter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SearchType::EQUALS:
|
||||||
|
$this->searchFilter = new FilterEquals($query, $filter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SearchType::NOT_EQUALS:
|
||||||
|
$this->searchFilter = new FilterNotEquals($query, $filter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SearchType::BETWEEN:
|
||||||
|
$this->searchFilter = new FilterBetween($query, $filter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SearchType::GREATER_THAN:
|
||||||
|
$this->searchFilter = new FilterGreaterThan($query, $filter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SearchType::LESS_THAN:
|
||||||
|
$this->searchFilter = new FilterLessThan($query, $filter);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$searchFunction = $filter->getFn();
|
||||||
|
throw new InvalidFilterException($searchFunction, "search function `$searchFunction` is invalid.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$relation = $this->filter->getRelation();
|
||||||
|
return method_exists($this->query->getModel(), $relation) ? $this->applyFilterToRelation($relation) : $this->searchFilter->apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyFilterToRelation(string $relation): Builder
|
||||||
|
{
|
||||||
|
return $this->query->whereHas($relation, function (Builder $query) {
|
||||||
|
$this->filter->removeRelationFromId();
|
||||||
|
$this->applyFilter($query, $this->filter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyFilter(Builder $query, Filter $filter): Builder
|
||||||
|
{
|
||||||
|
return (new ApplyFilter($query, $filter))->apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
73
backend/app/Services/DataTable/Filter/Filter.php
Executable file
73
backend/app/Services/DataTable/Filter/Filter.php
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Validators\FilterValidator;
|
||||||
|
|
||||||
|
class Filter
|
||||||
|
{
|
||||||
|
private static FilterValidator $filterValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $id
|
||||||
|
* @param string|int|array $value
|
||||||
|
* @param string $fn
|
||||||
|
* @param string $datatype
|
||||||
|
* @param array $allowedFilters
|
||||||
|
* @throws \App\Services\DataTable\Exceptions\InvalidFilterException
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private string $id,
|
||||||
|
private string|int|array $value,
|
||||||
|
private string $fn,
|
||||||
|
private string $datatype,
|
||||||
|
private array $allowedFilters
|
||||||
|
)
|
||||||
|
{
|
||||||
|
self::$filterValidator = FilterValidator::getInstance();
|
||||||
|
self::$filterValidator->isValid($this, $this->allowedFilters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): string
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValue(): array|int|string
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFn(): string
|
||||||
|
{
|
||||||
|
return $this->fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDatatype(): string
|
||||||
|
{
|
||||||
|
return $this->datatype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRelation(): string
|
||||||
|
{
|
||||||
|
$fieldArray = explode('.', $this->id);
|
||||||
|
return count($fieldArray) > 1 ? $fieldArray[0] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getColumn(): string
|
||||||
|
{
|
||||||
|
$fieldArray = explode('.', $this->id);
|
||||||
|
return array_pop($fieldArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeRelationFromId(): void
|
||||||
|
{
|
||||||
|
$this->id = $this->getColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setValue(int|array|string $value): void
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
33
backend/app/Services/DataTable/Filter/SearchFunctions/FilterBetween.php
Executable file
33
backend/app/Services/DataTable/Filter/SearchFunctions/FilterBetween.php
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class FilterBetween extends SearchFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$query = $this->query;
|
||||||
|
[$minVal, $maxVal] = $this->filter->getValue();
|
||||||
|
|
||||||
|
if ($minVal) {
|
||||||
|
if ($this->filter->getDatatype() == "date") {
|
||||||
|
$minVal = $minVal . " 00:00:00";
|
||||||
|
}
|
||||||
|
$this->filter->setValue($minVal);
|
||||||
|
$query = (new FilterGreaterThanOrEqual($this->query, $this->filter))->apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($maxVal) {
|
||||||
|
if ($this->filter->getDatatype() == "date") {
|
||||||
|
$maxVal = $maxVal . " 23:59:59";
|
||||||
|
}
|
||||||
|
$this->filter->setValue($maxVal);
|
||||||
|
$query = (new FilterLessThanOrEqual($this->query, $this->filter))->apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/Services/DataTable/Filter/SearchFunctions/FilterContains.php
Executable file
31
backend/app/Services/DataTable/Filter/SearchFunctions/FilterContains.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Enums\DataType;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class FilterContains extends SearchFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$column = $this->filter->getId();
|
||||||
|
$value = '%' . $this->filter->getValue() . '%';
|
||||||
|
|
||||||
|
if ($this->filter->getDatatype() == DataType::TEXT->value) {
|
||||||
|
$query = $this->searchIgnoreCase($column, $value);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$query = $this->query->where($column, 'LIKE', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function searchIgnoreCase(string $column, string $value): Builder
|
||||||
|
{
|
||||||
|
$value = strtolower($value);
|
||||||
|
return $this->query->whereRaw("LOWER($column) LIKE ?", [$value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/Services/DataTable/Filter/SearchFunctions/FilterEquals.php
Executable file
30
backend/app/Services/DataTable/Filter/SearchFunctions/FilterEquals.php
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Enums\DataType;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class FilterEquals extends SearchFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$column = $this->filter->getId();
|
||||||
|
$value = $this->filter->getValue();
|
||||||
|
|
||||||
|
if ($this->filter->getDatatype() == DataType::TEXT->value) {
|
||||||
|
$query = $this->searchIgnoreCase($column, $value);
|
||||||
|
} else {
|
||||||
|
$query = $this->query->where($column, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function searchIgnoreCase(string $column, string $value): Builder
|
||||||
|
{
|
||||||
|
$value = strtolower($value);
|
||||||
|
return $this->query->whereRaw("LOWER($column) = ?", [$value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
backend/app/Services/DataTable/Filter/SearchFunctions/FilterGreaterThan.php
Executable file
18
backend/app/Services/DataTable/Filter/SearchFunctions/FilterGreaterThan.php
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Enums\DataType;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class FilterGreaterThan extends SearchFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$value = ($this->filter->getDatatype() == DataType::NUMERIC) ?
|
||||||
|
(float)$this->filter->getValue() : $this->filter->getValue();
|
||||||
|
|
||||||
|
return $this->query->where($this->filter->getId(), '>', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Enums\DataType;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class FilterGreaterThanOrEqual extends SearchFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$value = ($this->filter->getDatatype() == DataType::NUMERIC) ?
|
||||||
|
(float)$this->filter->getValue() : $this->filter->getValue();
|
||||||
|
|
||||||
|
return $this->query->where($this->filter->getId(), '>=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
backend/app/Services/DataTable/Filter/SearchFunctions/FilterLessThan.php
Executable file
18
backend/app/Services/DataTable/Filter/SearchFunctions/FilterLessThan.php
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Enums\DataType;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class FilterLessThan extends SearchFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$value = ($this->filter->getDatatype() == DataType::NUMERIC) ?
|
||||||
|
(float)$this->filter->getValue() : $this->filter->getValue();
|
||||||
|
|
||||||
|
return $this->query->where($this->filter->getId(), '<', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Enums\DataType;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class FilterLessThanOrEqual extends SearchFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$value = ($this->filter->getDatatype() == DataType::NUMERIC) ?
|
||||||
|
(float)$this->filter->getValue() : $this->filter->getValue();
|
||||||
|
|
||||||
|
return $this->query->where($this->filter->getId(), '<=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
backend/app/Services/DataTable/Filter/SearchFunctions/FilterNotEquals.php
Executable file
17
backend/app/Services/DataTable/Filter/SearchFunctions/FilterNotEquals.php
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class FilterNotEquals extends SearchFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$column = $this->filter->getId();
|
||||||
|
$value = $this->filter->getValue();
|
||||||
|
|
||||||
|
return $this->query->whereNot($column, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
backend/app/Services/DataTable/Filter/SearchFunctions/SearchFilter.php
Executable file
22
backend/app/Services/DataTable/Filter/SearchFunctions/SearchFilter.php
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Filter\SearchFunctions;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Filter\Filter;
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
abstract class SearchFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Builder $query
|
||||||
|
* @param Filter $filter
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
protected Builder $query,
|
||||||
|
protected Filter $filter,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function apply(): Builder;
|
||||||
|
}
|
||||||
31
backend/app/Services/DataTable/Sort/ApplySort.php
Executable file
31
backend/app/Services/DataTable/Sort/ApplySort.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Sort;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Database\Query\Builder;
|
||||||
|
|
||||||
|
class ApplySort
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Builder $query
|
||||||
|
* @param ?Sort $sort
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private Builder $query,
|
||||||
|
private ?Sort $sort,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apply(): Builder
|
||||||
|
{
|
||||||
|
$query = $this->query;
|
||||||
|
|
||||||
|
if (!is_null($this->sort)) {
|
||||||
|
$query->orderBy($this->sort->getId(), $this->sort->getDirection());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
backend/app/Services/DataTable/Sort/Sort.php
Executable file
39
backend/app/Services/DataTable/Sort/Sort.php
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Sort;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Validators\SortingValidator;
|
||||||
|
|
||||||
|
class Sort
|
||||||
|
{
|
||||||
|
private static SortingValidator $sortingValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $id
|
||||||
|
* @param bool $desc
|
||||||
|
* @param array $allowedSortings
|
||||||
|
* @throws \App\Services\DataTable\Exceptions\InvalidSortingException
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
private string $id,
|
||||||
|
private bool $desc,
|
||||||
|
private array $allowedSortings,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
self::$sortingValidator = SortingValidator::getInstance();
|
||||||
|
self::$sortingValidator->isValid($this, $this->allowedSortings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId(): string
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDirection(): string
|
||||||
|
{
|
||||||
|
return $this->desc === true ? 'desc' : 'asc';
|
||||||
|
}
|
||||||
|
}
|
||||||
69
backend/app/Services/DataTable/Validators/FilterValidator.php
Executable file
69
backend/app/Services/DataTable/Validators/FilterValidator.php
Executable file
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Validators;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Enums\SearchType;
|
||||||
|
use App\Services\DataTable\Enums\DataType;
|
||||||
|
use App\Services\DataTable\Exceptions\InvalidFilterException;
|
||||||
|
use App\Services\DataTable\Filter\Filter;
|
||||||
|
|
||||||
|
class FilterValidator
|
||||||
|
{
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getInstance(): FilterValidator
|
||||||
|
{
|
||||||
|
if (!isset(self::$instance)) {
|
||||||
|
self::$instance = new static();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isValid(Filter $filter, array $allowedFilters): bool
|
||||||
|
{
|
||||||
|
if (!$this->isAllowed($filter, $allowedFilters)) {
|
||||||
|
$filterId = $filter->getId();
|
||||||
|
throw new InvalidFilterException($filter->getId(), "filtering field `$filterId` is not allowed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->isValidSearchFunction($filter)) {
|
||||||
|
$searchFunction = $filter->getFn();
|
||||||
|
throw new InvalidFilterException($searchFunction, "search function `$searchFunction` is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isValidDataType($filter) == -1) {
|
||||||
|
throw new InvalidFilterException(null, "datatype property is not set in `filters` array.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->isValidDataType($filter)) {
|
||||||
|
$datatype = $filter->getDatatype();
|
||||||
|
throw new InvalidFilterException($datatype, "datatype `$datatype` is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isAllowed(Filter $filter, array $allowedFilters): bool
|
||||||
|
{
|
||||||
|
return $allowedFilters == ['*'] || in_array($filter->getId(), $allowedFilters);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isValidSearchFunction(Filter $filter): bool
|
||||||
|
{
|
||||||
|
$searchFunction = $filter->getFn();
|
||||||
|
return isset($searchFunction) && in_array($searchFunction, SearchType::values());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isValidDataType(Filter $filter): int
|
||||||
|
{
|
||||||
|
if (!property_exists($filter, 'datatype'))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return $filter->getDatatype() && in_array($filter->getDatatype(), DataType::values()) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
backend/app/Services/DataTable/Validators/RelationValidator.php
Executable file
25
backend/app/Services/DataTable/Validators/RelationValidator.php
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Validators;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Exceptions\InvalidRelationException;
|
||||||
|
|
||||||
|
class RelationValidator
|
||||||
|
{
|
||||||
|
public static function validate(?array $rels, array $allowedRelations): bool
|
||||||
|
{
|
||||||
|
foreach ($rels as $relation) {
|
||||||
|
|
||||||
|
if (!self::isAllowed($relation, $allowedRelations)) {
|
||||||
|
throw new InvalidRelationException($relation, "relation `$relation` is not allowed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isAllowed(string $relation, array $allowedRelations): bool
|
||||||
|
{
|
||||||
|
return !$relation || in_array($relation, $allowedRelations);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
backend/app/Services/DataTable/Validators/SortingValidator.php
Executable file
39
backend/app/Services/DataTable/Validators/SortingValidator.php
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\DataTable\Validators;
|
||||||
|
|
||||||
|
use App\Services\DataTable\Exceptions\InvalidSortingException;
|
||||||
|
use App\Services\DataTable\Sort\Sort;
|
||||||
|
|
||||||
|
class SortingValidator
|
||||||
|
{
|
||||||
|
private static $instance;
|
||||||
|
|
||||||
|
private function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getInstance(): SortingValidator
|
||||||
|
{
|
||||||
|
if (!isset(self::$instance)) {
|
||||||
|
self::$instance = new static();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isValid(Sort $sorting, array $allowedSortings): bool
|
||||||
|
{
|
||||||
|
if (!$this->isAllowed($sorting, $allowedSortings)) {
|
||||||
|
$sortId = $sorting->getId();
|
||||||
|
throw new InvalidSortingException($sortId, "sorting field `$sortId` is not allowed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isAllowed(Sort $sorting, array $allowedSortings): bool
|
||||||
|
{
|
||||||
|
return $allowedSortings == ['*'] || in_array($sorting->getId(), $allowedSortings);
|
||||||
|
}
|
||||||
|
}
|
||||||
57
backend/app/Services/FIB/AuthorizationService.php
Executable file
57
backend/app/Services/FIB/AuthorizationService.php
Executable file
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\FIB;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class AuthorizationService
|
||||||
|
{
|
||||||
|
protected string $url;
|
||||||
|
protected string $channelName;
|
||||||
|
protected array $inputParameters;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->url = config('fib.authorization.url');
|
||||||
|
$this->channelName = 'fib_authorization';
|
||||||
|
$this->inputParameters = [
|
||||||
|
'client_id' => config('fib.authorization.client_id'),
|
||||||
|
'client_secret' => config('fib.authorization.client_secret'),
|
||||||
|
'grant_type' => 'client_credentials',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->sendRequest();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
Log::channel($this->channelName)
|
||||||
|
->error(get_class($this),
|
||||||
|
[
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function sendRequest(): array
|
||||||
|
{
|
||||||
|
return Http::asForm()
|
||||||
|
->throw()
|
||||||
|
->post($this->url, $this->inputParameters)
|
||||||
|
->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
62
backend/app/Services/FIB/CancelPaymentService.php
Executable file
62
backend/app/Services/FIB/CancelPaymentService.php
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\FIB;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class CancelPaymentService
|
||||||
|
{
|
||||||
|
protected string $url;
|
||||||
|
protected string $channelName;
|
||||||
|
protected string $accessToken;
|
||||||
|
protected array $headers;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->url = config('fib.cancelPayment.url');
|
||||||
|
$this->channelName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHeaders(): void
|
||||||
|
{
|
||||||
|
$this->headers = [
|
||||||
|
'Authorization' => 'Bearer ' . $this->accessToken,
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->sendRequest();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
Log::channel($this->channelName)
|
||||||
|
->error(get_class($this),
|
||||||
|
[
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function sendRequest(): array
|
||||||
|
{
|
||||||
|
return Http::withHeaders($this->headers)
|
||||||
|
->throw()
|
||||||
|
->withoutVerifying()
|
||||||
|
->post($this->url)
|
||||||
|
->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
51
backend/app/Services/FIB/CheckPaymentStatusService.php
Executable file
51
backend/app/Services/FIB/CheckPaymentStatusService.php
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\FIB;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class CheckPaymentStatusService
|
||||||
|
{
|
||||||
|
protected string $url;
|
||||||
|
protected string $channelName;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->url = config('fib.checkPaymentStatus.url');
|
||||||
|
$this->channelName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->sendRequest();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
Log::channel($this->channelName)
|
||||||
|
->error(get_class($this),
|
||||||
|
[
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function sendRequest(): array
|
||||||
|
{
|
||||||
|
return Http::throw()
|
||||||
|
->withoutVerifying()
|
||||||
|
->post($this->url)
|
||||||
|
->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
73
backend/app/Services/FIB/CreatePaymentService.php
Executable file
73
backend/app/Services/FIB/CreatePaymentService.php
Executable file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\FIB;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class CreatePaymentService
|
||||||
|
{
|
||||||
|
protected string $url;
|
||||||
|
protected string $channelName;
|
||||||
|
protected string $accessToken;
|
||||||
|
protected array $headers;
|
||||||
|
protected array $inputParameters;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->url = config('fib.createPayment.url');
|
||||||
|
$this->channelName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAccessToken(string $accessToken): void
|
||||||
|
{
|
||||||
|
$this->accessToken = $accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHeaders(): void
|
||||||
|
{
|
||||||
|
$this->headers = [
|
||||||
|
'Authorization' => 'Bearer ' . $this->accessToken,
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setInputParameters(array $inputParameters): void
|
||||||
|
{
|
||||||
|
$this->inputParameters = $inputParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->sendRequest();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
Log::channel($this->channelName)
|
||||||
|
->error(get_class($this),
|
||||||
|
[
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function sendRequest(): array
|
||||||
|
{
|
||||||
|
return Http::withHeaders($this->headers)
|
||||||
|
->throw()
|
||||||
|
->withoutVerifying()
|
||||||
|
->post($this->url, $this->inputParameters)
|
||||||
|
->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
62
backend/app/Services/FIB/RefundService.php
Executable file
62
backend/app/Services/FIB/RefundService.php
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\FIB;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class RefundService
|
||||||
|
{
|
||||||
|
protected string $url;
|
||||||
|
protected string $channelName;
|
||||||
|
protected string $accessToken;
|
||||||
|
protected array $headers;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->url = config('fib.refund.url');
|
||||||
|
$this->channelName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHeaders(): void
|
||||||
|
{
|
||||||
|
$this->headers = [
|
||||||
|
'Authorization' => 'Bearer ' . $this->accessToken,
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function run(): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return $this->sendRequest();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
Log::channel($this->channelName)
|
||||||
|
->error(get_class($this),
|
||||||
|
[
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function sendRequest(): array
|
||||||
|
{
|
||||||
|
return Http::withHeaders($this->headers)
|
||||||
|
->throw()
|
||||||
|
->withoutVerifying()
|
||||||
|
->post($this->url)
|
||||||
|
->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/Traits/ApiResponse.php
Executable file
31
backend/app/Traits/ApiResponse.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Traits;
|
||||||
|
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
trait ApiResponse
|
||||||
|
{
|
||||||
|
public function successResponse(mixed $data = null, string $message = null, int $statusCode = 200): JsonResponse
|
||||||
|
{
|
||||||
|
if (!is_null($data)) {
|
||||||
|
return response()->json([
|
||||||
|
'data' => $data
|
||||||
|
], $statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = $message ?? __('messages.successful');
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => $message
|
||||||
|
], $statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function errorResponse(string $message, string $type = 'logical_exception', int $statusCode = 422): JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'type' => $type,
|
||||||
|
'message' => $message
|
||||||
|
], $statusCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
64
backend/app/User/Controllers/AuthController.php
Executable file
64
backend/app/User/Controllers/AuthController.php
Executable file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use App\User\Requests\Auth\LoginRequest;
|
||||||
|
use App\User\Requests\Auth\RegisterRequest;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
class AuthController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function register(RegisterRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$user = User::query()->create([
|
||||||
|
'username' => $request->username,
|
||||||
|
'email' => $request->email,
|
||||||
|
'password' => Hash::make($request->password),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Auth::guard('web')->login($user);
|
||||||
|
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(LoginRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$credentials = ['password' => $request->password,];
|
||||||
|
|
||||||
|
if (filter_var($request->login, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$credentials['email'] = $request->login;
|
||||||
|
} else {
|
||||||
|
$credentials['username'] = $request->login;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Auth::attempt($credentials))
|
||||||
|
{
|
||||||
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->errorResponse(__('messages.incorrect_or_username_password'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
Auth::guard('web')->logout();
|
||||||
|
|
||||||
|
$request->session()->invalidate();
|
||||||
|
|
||||||
|
$request->session()->regenerateToken();
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
24
backend/app/User/Controllers/CityController.php
Executable file
24
backend/app/User/Controllers/CityController.php
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\City;
|
||||||
|
use App\Models\Province;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class CityController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function list(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$cities = City::query()
|
||||||
|
->where('province_id', '=', $request->query('province_id'))
|
||||||
|
->get(['id', 'name']);
|
||||||
|
|
||||||
|
return $this->successResponse($cities);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
backend/app/User/Controllers/DocumentationController.php
Executable file
42
backend/app/User/Controllers/DocumentationController.php
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Controllers;
|
||||||
|
|
||||||
|
use App\Facades\File\FileFacade;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use App\User\Requests\Documentation\EditRequest;
|
||||||
|
use App\User\Requests\Documentation\UploadRequest;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class DocumentationController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function upload(UploadRequest $request): jsonResponse
|
||||||
|
{
|
||||||
|
$user = Auth::guard('web')->user();
|
||||||
|
|
||||||
|
foreach ($request->documents as $document) {
|
||||||
|
$user->documents()->create([
|
||||||
|
'title' => $document['title'],
|
||||||
|
'url' => FileFacade::save($document['file'], "/{$user->id}/documents", $document['title']),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(EditRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$user = Auth::guard('web')->user();
|
||||||
|
|
||||||
|
foreach ($request->documents as $document) {
|
||||||
|
$user->documents()->sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
97
backend/app/User/Controllers/GatewayManagementController.php
Normal file
97
backend/app/User/Controllers/GatewayManagementController.php
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Controllers;
|
||||||
|
|
||||||
|
use App\Enums\BusinessTypeEnum;
|
||||||
|
use App\Facades\DataTable\DataTableFacade;
|
||||||
|
use App\Facades\File\FileFacade;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\UserGateway;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use App\User\Requests\Gateway\StoreRequest;
|
||||||
|
use App\User\Requests\Gateway\UpdateRequest;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class GatewayManagementController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
return DataTableFacade::run(
|
||||||
|
UserGateway::query()->where('user_id', '=', Auth::guard('web')->id()),
|
||||||
|
$request,
|
||||||
|
allowedFilters: ['*'],
|
||||||
|
allowedSortings: ['*'],
|
||||||
|
allowedSelects: ['id', 'name', 'domain', 'tax_id', 'bank_name', 'account_holder', 'iban', 'business_type_id', 'business_type_name'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function store(StoreRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$user = Auth::guard('web')->user();
|
||||||
|
|
||||||
|
$logo = $request->has('logo') ? FileFacade::save($request->file('logo'), "{$user->id}") : null;
|
||||||
|
|
||||||
|
DB::transaction(function () use ($user, $logo, $request) {
|
||||||
|
UserGateway::query()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'username' => $user->username,
|
||||||
|
'name' => $request->name,
|
||||||
|
'domain' => $request->domain,
|
||||||
|
'tax_id' => $request->tax_id,
|
||||||
|
'bank_name' => $request->bank_name,
|
||||||
|
'account_holder' => $request->account_holder,
|
||||||
|
'iban' => $request->iban,
|
||||||
|
'business_type_id' => $request->business_type_id,
|
||||||
|
'business_type_name' => BusinessTypeEnum::name($request->business_type_id),
|
||||||
|
'logo' => $logo,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user->update(['authority_level' => 1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(UserGateway $gateway): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse($gateway);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(UpdateRequest $request, UserGateway $gateway): JsonResponse
|
||||||
|
{
|
||||||
|
$logo = null;
|
||||||
|
$user = Auth::guard('web')->user();
|
||||||
|
|
||||||
|
if ($request->has('logo'))
|
||||||
|
{
|
||||||
|
FileFacade::delete($gateway->logo, true);
|
||||||
|
$logo = FileFacade::save(request()->file('logo'), "{$user->id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway->update([
|
||||||
|
'name' => $request->name,
|
||||||
|
'domain' => $request->domain,
|
||||||
|
'business_type_id' => $request->business_type_id,
|
||||||
|
'business_type_name' => BusinessTypeEnum::name($request->business_type_id),
|
||||||
|
'logo' => $logo,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(UserGateway $gateway): JsonResponse
|
||||||
|
{
|
||||||
|
$gateway->delete();
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
80
backend/app/User/Controllers/ProfileController.php
Executable file
80
backend/app/User/Controllers/ProfileController.php
Executable file
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Controllers;
|
||||||
|
|
||||||
|
use App\Facades\File\FileFacade;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\City;
|
||||||
|
use App\Models\Province;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use App\User\Requests\Profile\ChangePasswordRequest;
|
||||||
|
use App\User\Requests\Profile\EditRequest;
|
||||||
|
use App\User\Resources\UserResource;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
|
||||||
|
public function info(): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse(new UserResource(Auth::user()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public function edit(EditRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
$province = Province::query()->find($request->province_id);
|
||||||
|
$city = City::query()->find($request->city_id);
|
||||||
|
|
||||||
|
DB::transaction(function () use ($user, $province, $city, $request) {
|
||||||
|
if ($user->kyc_status == 0)
|
||||||
|
{
|
||||||
|
$user->documents()->create([
|
||||||
|
'title' => 'id_card',
|
||||||
|
'url' => FileFacade::save($request->file('id_card'), "{$user->id}/"),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->update([
|
||||||
|
'first_name' => $request->first_name,
|
||||||
|
'last_name' => $request->last_name,
|
||||||
|
'national_id' => $request->national_id,
|
||||||
|
'address' => $request->address,
|
||||||
|
'postal_code' => $request->postal_code,
|
||||||
|
'phone_number' => $request->phone_number,
|
||||||
|
'province_id' => $province->id,
|
||||||
|
'province_name' => $province->name,
|
||||||
|
'city_id' => $city->id,
|
||||||
|
'city_name' => $city->name,
|
||||||
|
'birth_date' => $request->birth_date,
|
||||||
|
'email' => $request->email,
|
||||||
|
'kyc_status' => 1,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function changePassword(ChangePasswordRequest $request): JsonResponse
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
if (! Hash::check($request->current_password, $user->password)) {
|
||||||
|
return $this->errorResponse(__('messages.incorrect_current_password'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->update([
|
||||||
|
'password' => Hash::make($request->new_password),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
17
backend/app/User/Controllers/ProvinceController.php
Executable file
17
backend/app/User/Controllers/ProvinceController.php
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Province;
|
||||||
|
use App\Traits\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
class ProvinceController extends Controller
|
||||||
|
{
|
||||||
|
use ApiResponse;
|
||||||
|
public function list(): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->successResponse(Province::all(['id', 'name']));
|
||||||
|
}
|
||||||
|
}
|
||||||
23
backend/app/User/Events/LoginEmailEvent.php
Executable file
23
backend/app/User/Events/LoginEmailEvent.php
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Events;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Broadcasting\Channel;
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class LoginEmailEvent
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*/
|
||||||
|
public function __construct(public User $user)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/User/Listeners/SendEmailListener.php
Executable file
31
backend/app/User/Listeners/SendEmailListener.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Listeners;
|
||||||
|
|
||||||
|
use App\Mail\LoginNotificationMail;
|
||||||
|
use App\User\Events\LoginEmailEvent;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
|
class SendEmailListener implements ShouldQueue{
|
||||||
|
public string $queue = 'emails';
|
||||||
|
/**
|
||||||
|
* Create the event listener.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*/
|
||||||
|
public function handle(LoginEmailEvent $event): void
|
||||||
|
{
|
||||||
|
$user = $event->user;
|
||||||
|
|
||||||
|
Mail::to($user->email)->send(
|
||||||
|
new LoginNotificationMail($user)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/app/User/Requests/Auth/LoginRequest.php
Executable file
30
backend/app/User/Requests/Auth/LoginRequest.php
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Requests\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class LoginRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'login' => 'required|string',
|
||||||
|
'password' => 'required|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/User/Requests/Auth/RegisterRequest.php
Executable file
31
backend/app/User/Requests/Auth/RegisterRequest.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Requests\Auth;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class RegisterRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'username' => 'required|unique:users,username',
|
||||||
|
'email' => 'required|email|unique:users,email',
|
||||||
|
'password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:6|confirmed',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/User/Requests/Documentation/EditRequest.php
Executable file
31
backend/app/User/Requests/Documentation/EditRequest.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Requests\Documentation;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class EditRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'documents' => 'required|array',
|
||||||
|
'documents.*.file' => 'required|file|mimes:pdf,jpg,jpeg,png|max:2048',
|
||||||
|
'documents.*.title' => 'required|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
31
backend/app/User/Requests/Documentation/UploadRequest.php
Executable file
31
backend/app/User/Requests/Documentation/UploadRequest.php
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Requests\Documentation;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UploadRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'documents' => 'required|array',
|
||||||
|
'documents.*.file' => 'required|file|mimes:pdf,jpg,jpeg,png|max:2048',
|
||||||
|
'documents.*.title' => 'required|string',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
37
backend/app/User/Requests/Gateway/StoreRequest.php
Normal file
37
backend/app/User/Requests/Gateway/StoreRequest.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Requests\Gateway;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class StoreRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return Auth::guard('web')->user()->kyc_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|max:255',
|
||||||
|
'domain' => 'required|string|max:255',
|
||||||
|
'tax_id' => 'required|string',
|
||||||
|
'bank_name' => 'required|string|max:255',
|
||||||
|
'account_holder' => 'required|string',
|
||||||
|
'iban' => 'required|string|max:255',
|
||||||
|
'logo' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048',
|
||||||
|
'business_type_id' => 'required|string|exists:business_types,id',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
33
backend/app/User/Requests/Gateway/UpdateRequest.php
Normal file
33
backend/app/User/Requests/Gateway/UpdateRequest.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\User\Requests\Gateway;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class UpdateRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return Auth::guard('web')->user()->kyc_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, ValidationRule|array|string>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'required|string|max:255',
|
||||||
|
'domain' => 'required|string|max:255',
|
||||||
|
'business_type_id' => 'required|string|exists:business_types,id',
|
||||||
|
'logo' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user