Compare commits
32 Commits
feature/Mu
...
feature/Cr
| Author | SHA1 | Date | |
|---|---|---|---|
| af23df5527 | |||
| e33aac7eed | |||
| 7b0507bdda | |||
| ae8ca057fd | |||
| 32c14bd6c4 | |||
| 5596943b70 | |||
| 5831a5594a | |||
| 12736d53c5 | |||
| fda129875e | |||
| ca71547657 | |||
| 2d31eccc4a | |||
| abb92b4e22 | |||
| ea68943354 | |||
| e3831e98c9 | |||
| 9794aa1f54 | |||
| 4afcd5c81e | |||
| 74bc255d82 | |||
| ca094cff9f | |||
| c2328ec666 | |||
| e4f7b96b92 | |||
| f072bd1ee8 | |||
| f01992368e | |||
| 161fa3ae1e | |||
| b32ee444ca | |||
| cee480fff5 | |||
| 5024a242d2 | |||
| 0bba710b7d | |||
| f788f9a7ea | |||
| e74619d0ab | |||
| 5b42e23afc | |||
| 51aa3b157c | |||
| ccd2de26df |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.idea
|
||||
.env
|
||||
.env
|
||||
front
|
||||
@@ -30,7 +30,6 @@ ENV COMPOSER_ALLOW_SUPERUSER=1
|
||||
# Default command
|
||||
CMD composer install ;\
|
||||
composer dump-autoload --optimize --classmap-authoritative ;\
|
||||
php artisan key:generate ;\
|
||||
php artisan migrate ;\
|
||||
php artisan db:seed ;\
|
||||
php-fpm
|
||||
|
||||
60
backend/app/Admin/Controllers/AuthController.php
Normal file
60
backend/app/Admin/Controllers/AuthController.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\ApiResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
use ApiResponse;
|
||||
|
||||
public function register(Request $request): JsonResponse
|
||||
{
|
||||
// Expert::query()->create();
|
||||
|
||||
$request->session()->regenerate();
|
||||
|
||||
return $this->successResponse();
|
||||
}
|
||||
|
||||
public function login(Request $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();
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
return $this->successResponse([
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'email' => $user->email,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->errorResponse(__('messages.incorrect_or_username_password'));
|
||||
}
|
||||
|
||||
public function logout(Request $request): JsonResponse
|
||||
{
|
||||
Auth::logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return $this->successResponse();
|
||||
}
|
||||
}
|
||||
48
backend/app/Admin/Controllers/DocumentationController.php
Normal file
48
backend/app/Admin/Controllers/DocumentationController.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
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()->with('documents'),
|
||||
$request,
|
||||
allowedFilters: ['*'],
|
||||
allowedSortings: ['*'],
|
||||
allowedSelects: [
|
||||
'users.id', 'users.first_name', 'users.last_name', 'users.national_id',
|
||||
'users.phone_number', 'users.postal_code', 'users.city_id', 'users.province_id',
|
||||
'users.province_name', 'users.city_name', 'users.address', 'documents.title', 'documents.url'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function confirm(User $user): JsonResponse
|
||||
{
|
||||
$user->update([
|
||||
|
||||
]);
|
||||
|
||||
return $this->successResponse();
|
||||
}
|
||||
|
||||
public function reject(User $user): JsonResponse
|
||||
{
|
||||
$user->update([
|
||||
|
||||
]);
|
||||
|
||||
return $this->successResponse();
|
||||
}
|
||||
}
|
||||
114
backend/app/Admin/Controllers/ExpertManagementController.php
Normal file
114
backend/app/Admin/Controllers/ExpertManagementController.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Admin\Requests\ExpertManagement\StoreRequest;
|
||||
use App\Admin\Requests\ExpertManagement\UpdateRequest;
|
||||
use App\Admin\Resources\ExpertManagementResource;
|
||||
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(
|
||||
new ExpertManagementResource($expert)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
19
backend/app/Admin/Controllers/ProfileController.php
Normal file
19
backend/app/Admin/Controllers/ProfileController.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Controllers;
|
||||
|
||||
use App\Admin\Resources\ExpertResource;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\ApiResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
use ApiResponse;
|
||||
|
||||
public function info(): JsonResponse
|
||||
{
|
||||
return $this->successResponse(new ExpertResource(Auth::user()));
|
||||
}
|
||||
}
|
||||
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
Normal file
113
backend/app/Admin/Controllers/UserManagementController.php
Normal 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();
|
||||
}
|
||||
}
|
||||
37
backend/app/Admin/Requests/ExpertManagement/StoreRequest.php
Normal file
37
backend/app/Admin/Requests/ExpertManagement/StoreRequest.php
Normal 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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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('permission', 'name')->ignore($this->permission->id)],
|
||||
];
|
||||
}
|
||||
}
|
||||
31
backend/app/Admin/Requests/RoleManagement/StoreRequest.php
Normal file
31
backend/app/Admin/Requests/RoleManagement/StoreRequest.php
Normal 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' => 'required|array',
|
||||
'permissions.*.name' => 'required|string|exists:permissions,name',
|
||||
];
|
||||
}
|
||||
}
|
||||
35
backend/app/Admin/Requests/RoleManagement/UpdateRequest.php
Normal file
35
backend/app/Admin/Requests/RoleManagement/UpdateRequest.php
Normal 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' => ['required', 'string', 'max:255', Rule::unique('roles', 'name')->ignore($this->role->id)],
|
||||
'permissions' => 'required|array',
|
||||
'permissions.*.name' => 'required|string|exists:permissions,name',
|
||||
];
|
||||
}
|
||||
}
|
||||
40
backend/app/Admin/Requests/UserManagement/StoreRequest.php
Normal file
40
backend/app/Admin/Requests/UserManagement/StoreRequest.php
Normal 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
Normal file
49
backend/app/Admin/Requests/UserManagement/UpdateRequest.php
Normal 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',
|
||||
];
|
||||
}
|
||||
}
|
||||
41
backend/app/Admin/Resources/ExpertManagementResource.php
Normal file
41
backend/app/Admin/Resources/ExpertManagementResource.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Admin\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
/**
|
||||
* @method roles()
|
||||
* @method getAllPermissions()
|
||||
*/
|
||||
class ExpertManagementResource 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,
|
||||
'first_name' => $this->first_name,
|
||||
'last_name' => $this->last_name,
|
||||
'national_id' => $this->national_id,
|
||||
'email' => $this->email,
|
||||
'phone_number' => $this->phone_number,
|
||||
'province_name' => $this->province_name,
|
||||
'city_name' => $this->city_name,
|
||||
'roles' => $this->roles()
|
||||
->pluck('name')
|
||||
->values(),
|
||||
|
||||
'permissions' => $this->getAllPermissions()
|
||||
->pluck('name')
|
||||
->values(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
24
backend/app/Admin/Resources/ExpertResource.php
Normal file
24
backend/app/Admin/Resources/ExpertResource.php
Normal 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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
40
backend/app/Mail/LoginNotificationMail.php
Normal file
40
backend/app/Mail/LoginNotificationMail.php
Normal 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/City.php
Normal file
15
backend/app/Models/City.php
Normal 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
Normal file
30
backend/app/Models/Document.php
Normal 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
19
backend/app/Models/Expert.php
Normal file
19
backend/app/Models/Expert.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\ExpertFactory;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @method roles()
|
||||
* @method permissions()
|
||||
*/
|
||||
class Expert extends Model
|
||||
{
|
||||
/** @use HasFactory<ExpertFactory> */
|
||||
use HasFactory;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
}
|
||||
15
backend/app/Models/Province.php
Normal file
15
backend/app/Models/Province.php
Normal 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'];
|
||||
}
|
||||
20
backend/app/Models/User.php
Normal file → Executable file
20
backend/app/Models/User.php
Normal file → Executable file
@@ -4,30 +4,24 @@ namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
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 Laravel\Passport\HasApiTokens;
|
||||
|
||||
#[Fillable(['name', 'email', 'password'])]
|
||||
#[Hidden(['password', 'remember_token'])]
|
||||
#[Guarded(['id'])]
|
||||
#[Hidden(['password'])]
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<UserFactory> */
|
||||
use HasFactory, Notifiable, HasApiTokens;
|
||||
protected $guarded = ['id'];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
public function documents(): MorphToMany
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
return $this->morphToMany(Document::class, 'documentable');
|
||||
}
|
||||
}
|
||||
|
||||
2
backend/app/Providers/AppServiceProvider.php
Normal file → Executable file
2
backend/app/Providers/AppServiceProvider.php
Normal file → Executable file
@@ -4,6 +4,7 @@ namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Passport\Passport;
|
||||
use Carbon\CarbonInterval;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -21,5 +22,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
public function boot(): void
|
||||
{
|
||||
Passport::enablePasswordGrant();
|
||||
Passport::personalAccessTokensExpireIn(CarbonInterval::minutes(1));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
68
backend/app/User/Controllers/AuthController.php
Normal file
68
backend/app/User/Controllers/AuthController.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?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::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();
|
||||
|
||||
$user = Auth::user();
|
||||
|
||||
return $this->successResponse([
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'email' => $user->email,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->errorResponse(__('messages.incorrect_or_username_password'));
|
||||
}
|
||||
|
||||
public function logout(Request $request): JsonResponse
|
||||
{
|
||||
Auth::logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return $this->successResponse();
|
||||
}
|
||||
}
|
||||
14
backend/app/User/Controllers/Dashboard/ConfirmController.php
Executable file
14
backend/app/User/Controllers/Dashboard/ConfirmController.php
Executable file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Controllers\Dashboard;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ConfirmController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
24
backend/app/User/Controllers/Dashboard/DocumentationController.php
Executable file
24
backend/app/User/Controllers/Dashboard/DocumentationController.php
Executable file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Controller\Dashboard;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\ApiResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DocumentationController extends Controller
|
||||
{
|
||||
use ApiResponse;
|
||||
|
||||
public function store(StoreRequest $request): jsonResponse
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function update(UpdateRequest $request): JsonResponse
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
56
backend/app/User/Controllers/ProfileController.php
Normal file
56
backend/app/User/Controllers/ProfileController.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
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\Hash;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
use ApiResponse;
|
||||
|
||||
public function info(): JsonResponse
|
||||
{
|
||||
return $this->successResponse(new UserResource(Auth::user()));
|
||||
}
|
||||
|
||||
public function edit(EditRequest $request): JsonResponse
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
$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' => $request->province_id,
|
||||
'city_id' => $request->city_id,
|
||||
'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();
|
||||
}
|
||||
}
|
||||
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
Normal file
30
backend/app/User/Requests/Auth/LoginRequest.php
Normal 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
Normal file
31
backend/app/User/Requests/Auth/RegisterRequest.php
Normal 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',
|
||||
];
|
||||
}
|
||||
}
|
||||
30
backend/app/User/Requests/Profile/ChangePasswordRequest.php
Normal file
30
backend/app/User/Requests/Profile/ChangePasswordRequest.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\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:6',
|
||||
'new_password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:6',
|
||||
];
|
||||
}
|
||||
}
|
||||
36
backend/app/User/Requests/Profile/EditRequest.php
Normal file
36
backend/app/User/Requests/Profile/EditRequest.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Requests\Profile;
|
||||
|
||||
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 [
|
||||
'first_name' => 'required|string',
|
||||
'last_name' => 'required|string',
|
||||
'national_id' => 'required',
|
||||
'address' => 'required',
|
||||
'postal_code' => 'required',
|
||||
'phone_number' => 'required',
|
||||
'province_id' => 'required',
|
||||
'city_id' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
23
backend/app/User/Resources/UserResource.php
Normal file
23
backend/app/User/Resources/UserResource.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserResource 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,
|
||||
];
|
||||
}
|
||||
}
|
||||
13
backend/bootstrap/app.php
Normal file → Executable file
13
backend/bootstrap/app.php
Normal file → Executable file
@@ -10,10 +10,19 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
then: function () {
|
||||
Route::middleware('web')
|
||||
->prefix('expert')
|
||||
->name('expert.')
|
||||
->group(base_path('routes/expert.php'));
|
||||
},
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
//
|
||||
$middleware->web()->preventRequestForgery(['*']);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
})->create();
|
||||
})
|
||||
->withEvents(discover: [
|
||||
__DIR__.'/../app/User/Listeners',
|
||||
])->create();
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
"php": "^8.3",
|
||||
"laravel/framework": "^13.0",
|
||||
"laravel/passport": "^13.0",
|
||||
"laravel/tinker": "^3.0"
|
||||
"laravel/tinker": "^3.0",
|
||||
"spatie/laravel-permission": "^7.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
|
||||
150
backend/composer.lock
generated
150
backend/composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "7298a47753c91eab121f7ef9a163f9f2",
|
||||
"content-hash": "aaa8c08c593e524845dc3c1a83a79433",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
@@ -4218,6 +4218,154 @@
|
||||
},
|
||||
"time": "2025-12-14T04:43:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
"version": "1.93.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-package-tools.git",
|
||||
"reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/0d097bce95b2bf6802fb1d83e1e753b0f5a948e7",
|
||||
"reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "^10.0|^11.0|^12.0|^13.0",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.5",
|
||||
"orchestra/testbench": "^8.0|^9.2|^10.0|^11.0",
|
||||
"pestphp/pest": "^2.1|^3.1|^4.0",
|
||||
"phpunit/php-code-coverage": "^10.0|^11.0|^12.0",
|
||||
"phpunit/phpunit": "^10.5|^11.5|^12.5",
|
||||
"spatie/pest-plugin-test-time": "^2.2|^3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\LaravelPackageTools\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Tools for creating Laravel packages",
|
||||
"homepage": "https://github.com/spatie/laravel-package-tools",
|
||||
"keywords": [
|
||||
"laravel-package-tools",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-package-tools/issues",
|
||||
"source": "https://github.com/spatie/laravel-package-tools/tree/1.93.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-21T12:49:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-permission",
|
||||
"version": "7.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-permission.git",
|
||||
"reference": "ef42ecb781e5534d368a3853fa161e420ad51397"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-permission/zipball/ef42ecb781e5534d368a3853fa161e420ad51397",
|
||||
"reference": "ef42ecb781e5534d368a3853fa161e420ad51397",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/auth": "^12.0|^13.0",
|
||||
"illuminate/container": "^12.0|^13.0",
|
||||
"illuminate/contracts": "^12.0|^13.0",
|
||||
"illuminate/database": "^12.0|^13.0",
|
||||
"php": "^8.3",
|
||||
"spatie/laravel-package-tools": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"larastan/larastan": "^3.9",
|
||||
"laravel/passport": "^13.0",
|
||||
"laravel/pint": "^1.0",
|
||||
"orchestra/testbench": "^10.0|^11.0",
|
||||
"pestphp/pest": "^3.0|^4.0",
|
||||
"pestphp/pest-plugin-laravel": "^3.0|^4.1",
|
||||
"phpstan/phpstan": "^2.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Spatie\\Permission\\PermissionServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "7.x-dev",
|
||||
"dev-master": "7.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Spatie\\Permission\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van der Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Permission handling for Laravel 12 and up",
|
||||
"homepage": "https://github.com/spatie/laravel-permission",
|
||||
"keywords": [
|
||||
"acl",
|
||||
"laravel",
|
||||
"permission",
|
||||
"permissions",
|
||||
"rbac",
|
||||
"roles",
|
||||
"security",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-permission/issues",
|
||||
"source": "https://github.com/spatie/laravel-permission/tree/7.4.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-29T07:59:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/clock",
|
||||
"version": "v8.0.8",
|
||||
|
||||
8
backend/config/auth.php
Normal file → Executable file
8
backend/config/auth.php
Normal file → Executable file
@@ -46,6 +46,10 @@ return [
|
||||
'driver' => 'passport',
|
||||
'provider' => 'users',
|
||||
],
|
||||
'expert' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'experts',
|
||||
]
|
||||
],
|
||||
|
||||
/*
|
||||
@@ -70,6 +74,10 @@ return [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', User::class),
|
||||
],
|
||||
'experts' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', Expert::class),
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
// 'driver' => 'database',
|
||||
|
||||
34
backend/config/cors.php
Executable file
34
backend/config/cors.php
Executable file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cross-Origin Resource Sharing (CORS) Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure your settings for cross-origin resource sharing
|
||||
| or "CORS". This determines what cross-origin operations may execute
|
||||
| in web browsers. You are free to adjust these settings as needed.
|
||||
|
|
||||
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
|
|
||||
*/
|
||||
|
||||
'paths' => ['*'],
|
||||
|
||||
'allowed_methods' => ['*'],
|
||||
|
||||
'allowed_origins' => ['*'],
|
||||
|
||||
'allowed_origins_patterns' => [],
|
||||
|
||||
'allowed_headers' => ['*'],
|
||||
|
||||
'exposed_headers' => [],
|
||||
|
||||
'max_age' => 0,
|
||||
|
||||
'supports_credentials' => true,
|
||||
|
||||
];
|
||||
219
backend/config/permission.php
Normal file
219
backend/config/permission.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
use Spatie\Permission\DefaultTeamResolver;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
return [
|
||||
|
||||
'models' => [
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your permissions. Of course, it
|
||||
* is often just the "Permission" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Permission model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Permission` contract.
|
||||
*/
|
||||
|
||||
'permission' => Permission::class,
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your roles. Of course, it
|
||||
* is often just the "Role" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Role model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Role` contract.
|
||||
*/
|
||||
|
||||
'role' => Role::class,
|
||||
|
||||
/*
|
||||
* When using the "Teams" feature from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your teams. Of course, it
|
||||
* is often just the "Team" model but you may use whatever you like.
|
||||
*/
|
||||
'team' => null,
|
||||
|
||||
/*
|
||||
* When using the "HasModels" trait and passing raw IDs to syncModels,
|
||||
* attachModels, or detachModels, this model class will be used to
|
||||
* resolve those IDs. If null, defaults to the guard's model.
|
||||
*/
|
||||
'default_model' => null,
|
||||
],
|
||||
|
||||
'table_names' => [
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'roles' => 'roles',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your permissions. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'permissions' => 'permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_permissions' => 'model_has_permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models roles. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_roles' => 'model_has_roles',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'role_has_permissions' => 'role_has_permissions',
|
||||
],
|
||||
|
||||
'column_names' => [
|
||||
/*
|
||||
* Change this if you want to name the related pivots other than defaults
|
||||
*/
|
||||
'role_pivot_key' => null, // default 'role_id',
|
||||
'permission_pivot_key' => null, // default 'permission_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to name the related model primary key other than
|
||||
* `model_id`.
|
||||
*
|
||||
* For example, this would be nice if your primary keys are all UUIDs. In
|
||||
* that case, name this `model_uuid`.
|
||||
*/
|
||||
|
||||
'model_morph_key' => 'model_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to use the teams feature and your related model's
|
||||
* foreign key is other than `team_id`.
|
||||
*/
|
||||
|
||||
'team_foreign_key' => 'team_id',
|
||||
],
|
||||
|
||||
/*
|
||||
* When set to true, the method for checking permissions will be registered on the gate.
|
||||
* Set this to false if you want to implement custom logic for checking permissions.
|
||||
*/
|
||||
|
||||
'register_permission_check_method' => true,
|
||||
|
||||
/*
|
||||
* When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered
|
||||
* this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated
|
||||
* NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it.
|
||||
*/
|
||||
'register_octane_reset_listener' => false,
|
||||
|
||||
/*
|
||||
* Events will fire when a role or permission is assigned/unassigned:
|
||||
* \Spatie\Permission\Events\RoleAttachedEvent
|
||||
* \Spatie\Permission\Events\RoleDetachedEvent
|
||||
* \Spatie\Permission\Events\PermissionAttachedEvent
|
||||
* \Spatie\Permission\Events\PermissionDetachedEvent
|
||||
*
|
||||
* To enable, set to true, and then create listeners to watch these events.
|
||||
*/
|
||||
'events_enabled' => false,
|
||||
|
||||
/*
|
||||
* Teams Feature.
|
||||
* When set to true the package implements teams using the 'team_foreign_key'.
|
||||
* If you want the migrations to register the 'team_foreign_key', you must
|
||||
* set this to true before doing the migration.
|
||||
* If you already did the migration then you must make a new migration to also
|
||||
* add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions'
|
||||
* (view the latest version of this package's migration file)
|
||||
*/
|
||||
|
||||
'teams' => false,
|
||||
|
||||
/*
|
||||
* The class to use to resolve the permissions team id
|
||||
*/
|
||||
'team_resolver' => DefaultTeamResolver::class,
|
||||
|
||||
/*
|
||||
* Passport Client Credentials Grant
|
||||
* When set to true the package will use Passports Client to check permissions
|
||||
*/
|
||||
|
||||
'use_passport_client_credentials' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required permission names are added to exception messages.
|
||||
* This could be considered an information leak in some contexts, so the default
|
||||
* setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_permission_in_exception' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required role names are added to exception messages.
|
||||
* This could be considered an information leak in some contexts, so the default
|
||||
* setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_role_in_exception' => false,
|
||||
|
||||
/*
|
||||
* By default wildcard permission lookups are disabled.
|
||||
* See documentation to understand supported syntax.
|
||||
*/
|
||||
|
||||
'enable_wildcard_permission' => false,
|
||||
|
||||
/*
|
||||
* The class to use for interpreting wildcard permissions.
|
||||
* If you need to modify delimiters, override the class and specify its name here.
|
||||
*/
|
||||
// 'wildcard_permission' => Spatie\Permission\WildcardPermission::class,
|
||||
|
||||
/* Cache-specific settings */
|
||||
|
||||
'cache' => [
|
||||
|
||||
/*
|
||||
* By default all permissions are cached for 24 hours to speed up performance.
|
||||
* When permissions or roles are updated the cache is flushed automatically.
|
||||
*/
|
||||
|
||||
'expiration_time' => DateInterval::createFromDateString('24 hours'),
|
||||
|
||||
/*
|
||||
* The cache key used to store all permissions.
|
||||
*/
|
||||
|
||||
'key' => 'spatie.permission.cache',
|
||||
|
||||
/*
|
||||
* You may optionally indicate a specific cache driver to use for permission and
|
||||
* role caching using any of the `store` drivers listed in the cache.php config
|
||||
* file. Using 'default' here means to use the `default` set in cache.php.
|
||||
*/
|
||||
|
||||
'store' => 'default',
|
||||
],
|
||||
];
|
||||
0
backend/config/session.php
Normal file → Executable file
0
backend/config/session.php
Normal file → Executable file
24
backend/database/factories/CityFactory.php
Normal file
24
backend/database/factories/CityFactory.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\City;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<City>
|
||||
*/
|
||||
class CityFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
24
backend/database/factories/DocumentFactory.php
Normal file
24
backend/database/factories/DocumentFactory.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Document;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<Document>
|
||||
*/
|
||||
class DocumentFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
24
backend/database/factories/ExpertFactory.php
Normal file
24
backend/database/factories/ExpertFactory.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Expert;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<Expert>
|
||||
*/
|
||||
class ExpertFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
24
backend/database/factories/ProvinceFactory.php
Normal file
24
backend/database/factories/ProvinceFactory.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Province;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends Factory<Province>
|
||||
*/
|
||||
class ProvinceFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
2
backend/database/factories/UserFactory.php
Normal file → Executable file
2
backend/database/factories/UserFactory.php
Normal file → Executable file
@@ -25,7 +25,7 @@ class UserFactory extends Factory
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'username' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('provinces', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('provinces');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cities', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->foreignId('province_id')->constrained('provinces');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cities');
|
||||
}
|
||||
};
|
||||
24
backend/database/migrations/0001_01_01_000000_create_users_table.php
Normal file → Executable file
24
backend/database/migrations/0001_01_01_000000_create_users_table.php
Normal file → Executable file
@@ -13,20 +13,25 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('username');
|
||||
$table->string('first_name')->nullable();
|
||||
$table->string('last_name')->nullable();
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->tinyInteger('kyc_status')->default(0);
|
||||
$table->string('national_id')->nullable();
|
||||
$table->string('address')->nullable();
|
||||
$table->string('postal_code')->nullable();
|
||||
$table->string('tax_id')->nullable();
|
||||
$table->string('phone_number')->nullable();
|
||||
$table->date('birth_date')->nullable();
|
||||
$table->foreignId('province_id')->nullable()->constrained('provinces');
|
||||
$table->string('province_name')->nullable();
|
||||
$table->foreignId('city_id')->nullable()->constrained('cities');
|
||||
$table->string('city_name')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('sessions', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->foreignId('user_id')->nullable()->index();
|
||||
@@ -43,7 +48,6 @@ return new class extends Migration
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('users');
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('sessions');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$teams = config('permission.teams');
|
||||
$tableNames = config('permission.table_names');
|
||||
$columnNames = config('permission.column_names');
|
||||
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
|
||||
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
|
||||
|
||||
throw_if(empty($tableNames), 'Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
throw_if($teams && empty($columnNames['team_foreign_key'] ?? null), 'Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
|
||||
/**
|
||||
* See `docs/prerequisites.md` for suggested lengths on 'name' and 'guard_name' if "1071 Specified key was too long" errors are encountered.
|
||||
*/
|
||||
Schema::create($tableNames['permissions'], static function (Blueprint $table) {
|
||||
$table->id(); // permission id
|
||||
$table->string('name');
|
||||
$table->string('guard_name');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
/**
|
||||
* See `docs/prerequisites.md` for suggested lengths on 'name' and 'guard_name' if "1071 Specified key was too long" errors are encountered.
|
||||
*/
|
||||
Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) {
|
||||
$table->id(); // role id
|
||||
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
|
||||
}
|
||||
$table->string('name');
|
||||
$table->string('guard_name');
|
||||
$table->timestamps();
|
||||
if ($teams || config('permission.testing')) {
|
||||
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
|
||||
} else {
|
||||
$table->unique(['name', 'guard_name']);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->cascadeOnDelete();
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->cascadeOnDelete();
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->cascadeOnDelete();
|
||||
|
||||
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
throw_if(empty($tableNames), 'Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
|
||||
|
||||
Schema::dropIfExists($tableNames['role_has_permissions']);
|
||||
Schema::dropIfExists($tableNames['model_has_roles']);
|
||||
Schema::dropIfExists($tableNames['model_has_permissions']);
|
||||
Schema::dropIfExists($tableNames['roles']);
|
||||
Schema::dropIfExists($tableNames['permissions']);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('documents', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('documentable');
|
||||
$table->string('title');
|
||||
$table->string('url');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('documents');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('experts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('username');
|
||||
$table->string('first_name')->nullable();
|
||||
$table->string('last_name')->nullable();
|
||||
$table->string('email')->unique();
|
||||
$table->string('password');
|
||||
$table->string('national_id')->nullable();
|
||||
$table->string('phone_number')->nullable();
|
||||
$table->foreignId('province_id')->nullable()->constrained('provinces');
|
||||
$table->string('province_name')->nullable();
|
||||
$table->foreignId('city_id')->nullable()->constrained('cities');
|
||||
$table->string('city_name')->nullable();
|
||||
$table->tinyInteger('level')->default(1);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('experts');
|
||||
}
|
||||
};
|
||||
17
backend/database/seeders/CitySeeder.php
Normal file
17
backend/database/seeders/CitySeeder.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class CitySeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
3
backend/database/seeders/DatabaseSeeder.php
Normal file → Executable file
3
backend/database/seeders/DatabaseSeeder.php
Normal file → Executable file
@@ -18,8 +18,9 @@ class DatabaseSeeder extends Seeder
|
||||
// User::factory(10)->create();
|
||||
|
||||
User::factory()->create([
|
||||
'name' => 'Test User',
|
||||
'username' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'password' => 'password123@',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
17
backend/database/seeders/DocumentSeeder.php
Normal file
17
backend/database/seeders/DocumentSeeder.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DocumentSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
17
backend/database/seeders/ExpertSeeder.php
Normal file
17
backend/database/seeders/ExpertSeeder.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ExpertSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
17
backend/database/seeders/ProvinceSeeder.php
Normal file
17
backend/database/seeders/ProvinceSeeder.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ProvinceSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
24
backend/resources/views/emails/login-notification.blade.php
Normal file
24
backend/resources/views/emails/login-notification.blade.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Login Notification</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Hello {{ $user->username }}</h2>
|
||||
|
||||
<p>You have successfully logged in to your account.</p>
|
||||
|
||||
<p>
|
||||
Email: {{ $user->email }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If this login was not done by you, please contact support immediately.
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<p>Thank you.</p>
|
||||
</body>
|
||||
</html>
|
||||
0
backend/routes/api.php
Normal file → Executable file
0
backend/routes/api.php
Normal file → Executable file
12
backend/routes/expert.php
Executable file
12
backend/routes/expert.php
Executable file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use App\Admin\Controllers\DocumentationController;
|
||||
|
||||
Route::prefix('documents')
|
||||
->name('documents.')
|
||||
->controller(DocumentationController::class)
|
||||
->group(function () {
|
||||
Route::post('/', 'index')->name('index');
|
||||
Route::post('confirm', 'confirm')->name('confirm');
|
||||
Route::post('reject', 'reject')->name('reject');
|
||||
});
|
||||
73
backend/routes/web.php
Normal file → Executable file
73
backend/routes/web.php
Normal file → Executable file
@@ -1,7 +1,74 @@
|
||||
<?php
|
||||
|
||||
use App\Admin\Controllers\ExpertManagementController;
|
||||
use App\Admin\Controllers\PermissionManagementController;
|
||||
use App\Admin\Controllers\RoleManagementController;
|
||||
use App\Admin\Controllers\UserManagementController;
|
||||
use App\User\Controllers\AuthController;
|
||||
use App\User\Controllers\ProfileController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', function () {
|
||||
return view('welcome');
|
||||
});
|
||||
Route::prefix('auth')
|
||||
->name('Auth.')
|
||||
->controller(AuthController::class)
|
||||
->group(function () {
|
||||
Route::post('register', 'register')->name('register');
|
||||
Route::post('login', 'login')->name('login');
|
||||
Route::post('logout', 'logout')->name('logout');
|
||||
});
|
||||
|
||||
Route::prefix('profile')
|
||||
->name('profile.')
|
||||
->middleware('auth')
|
||||
->controller(ProfileController::class)
|
||||
->group(function () {
|
||||
Route::get('info', 'info')->name('info');
|
||||
Route::post('edit', 'edit')->name('edit');
|
||||
Route::post('change_password', 'changePassword')->name('changePassword');
|
||||
});
|
||||
|
||||
Route::prefix('admin')
|
||||
->name('Admin.')
|
||||
->group(function () {
|
||||
Route::prefix('user_management')
|
||||
->name('user_management.')
|
||||
->controller(UserManagementController::class)
|
||||
->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::get('/{user}', 'show')->name('show');
|
||||
Route::post('/{user}', 'update')->name('update');
|
||||
Route::delete('/{user}', 'destroy')->name('destroy');
|
||||
});
|
||||
Route::prefix('roles')
|
||||
->name('roles.')
|
||||
->controller(RoleManagementController::class)
|
||||
->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::get('/{role}', 'show')->name('show');
|
||||
Route::post('/{role}', 'update')->name('update');
|
||||
Route::delete('/{role}', 'destroy')->name('destroy');
|
||||
});
|
||||
Route::prefix('permissions')
|
||||
->name('permissions.')
|
||||
->controller(PermissionManagementController::class)
|
||||
->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::get('/{permission}', 'show')->name('show');
|
||||
Route::post('/{permission}', 'update')->name('update');
|
||||
Route::delete('/{permission}', 'destroy')->name('destroy');
|
||||
});
|
||||
Route::prefix('expert')
|
||||
->name('expert.')
|
||||
->controller(ExpertManagementController::class)
|
||||
->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::get('/{expert}', 'show')->name('show');
|
||||
Route::post('/{expert}', 'update')->name('update');
|
||||
Route::delete('/{expert}', 'destroy')->name('destroy');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user