From 9a0758a754a676899eb3d00275ccf6d051b9913b Mon Sep 17 00:00:00 2001 From: amirghasempoor Date: Tue, 12 Aug 2025 16:44:14 +0330 Subject: [PATCH 1/2] change from session to token --- app/Http/Controllers/AuthController.php | 33 ++-- app/Models/User.php | 5 +- bootstrap/app.php | 2 +- config/auth.php | 6 +- database/seeders/DatabaseSeeder.php | 8 +- database/seeders/PermissionSeeder.php | 6 +- database/seeders/RoleSeeder.php | 2 +- routes/api.php | 223 ++++++++++++++++++++++- routes/web.php | 230 +----------------------- 9 files changed, 253 insertions(+), 262 deletions(-) diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index c566d73..64fac6e 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -4,9 +4,10 @@ namespace App\Http\Controllers; use App\Http\Requests\Auth\LoginRequest; use App\Http\Traits\ApiResponse; +use App\Models\User; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Hash; class AuthController extends Controller { @@ -14,33 +15,25 @@ class AuthController extends Controller public function login(LoginRequest $request): JsonResponse { - if ($this->attemptLogin($request)) + $user = User::query()->where('username', '=', $request->username)->first(); + + if (!Hash::check($request->password, $user->password)) { - $request->session()->regenerate(); - $this->updateUserInfo($request); - return $this->successResponse(); + return $this->errorResponse(__('messages.invalid_credentials')); } - return $this->errorResponse(__('messages.invalid_credentials')); - } + $token = $user->createToken("{$request->username}", ['*'], now()->addWeek())->plainTextToken; - protected function attemptLogin(Request $request): bool - { - return Auth::guard()->attempt($request->only('username', 'password')); - } - - protected function updateUserInfo(Request $request): void - { - Auth::user()->update([ - 'last_login' => now(), + return $this->successResponse([ + 'message' => __('messages.successful'), + 'token' => $token ]); } - public function logout(Request $request): JsonResponse + public function logout(): JsonResponse { - Auth::guard()->logout(); - $request->session()->invalidate(); - $request->session()->regenerateToken(); + auth()->user()->currentAccessToken()->delete(); + return $this->successResponse(); } } diff --git a/app/Models/User.php b/app/Models/User.php index f3f3154..f26e31c 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -7,16 +7,17 @@ use App\Facades\File\FileFacade; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; +use Laravel\Sanctum\HasApiTokens; use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { - use HasFactory, Notifiable, HasRoles; + use HasFactory, Notifiable, HasRoles, HasApiTokens; protected $guarded = []; protected $hidden = ['password', 'pivot']; - public string $guard_name = 'web'; + public string $guard_name = 'api'; public function storeFile($file, $name) { diff --git a/bootstrap/app.php b/bootstrap/app.php index 1e90ca2..5185425 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -10,7 +10,7 @@ return Application::configure(basePath: dirname(__DIR__)) api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', - apiPrefix: 'server/api', + apiPrefix: '/server', ) ->withMiddleware(function (Middleware $middleware) { $middleware->validateCsrfTokens(except: [ diff --git a/config/auth.php b/config/auth.php index 0ba5d5d..0344f08 100644 --- a/config/auth.php +++ b/config/auth.php @@ -14,7 +14,7 @@ return [ */ 'defaults' => [ - 'guard' => env('AUTH_GUARD', 'web'), + 'guard' => env('AUTH_GUARD', 'api'), 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), ], @@ -40,6 +40,10 @@ return [ 'driver' => 'session', 'provider' => 'users', ], + 'api' => [ + 'driver' => 'sanctum', + 'provider' => 'users', + ], ], /* diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d01a0ef..6054b18 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -15,9 +15,9 @@ class DatabaseSeeder extends Seeder { // User::factory(10)->create(); - User::factory()->create([ - 'name' => 'Test User', - 'email' => 'test@example.com', - ]); +// User::factory()->create([ +// 'name' => 'Test User', +// 'email' => 'test@example.com', +// ]); } } diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index cb1ca2a..738fece 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -18,7 +18,7 @@ class PermissionSeeder extends Seeder 'id' => 1, 'name' => 'manage_users', 'name_fa' => 'مدیریت کاربران', - 'guard_name' => 'web', + 'guard_name' => 'api', 'created_at' => now(), 'updated_at' => now() ], @@ -26,7 +26,7 @@ class PermissionSeeder extends Seeder 'id' => 2, 'name' => 'manage_roles', 'name_fa' => 'مدیریت نقش ها', - 'guard_name' => 'web', + 'guard_name' => 'api', 'created_at' => now(), 'updated_at' => now() ], @@ -34,7 +34,7 @@ class PermissionSeeder extends Seeder 'id' => 3, 'name' => 'manage_calls', 'name_fa' => 'مدیریت تماس ها', - 'guard_name' => 'web', + 'guard_name' => 'api', 'created_at' => now(), 'updated_at' => now() ] diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index 8aea2e5..9c96d80 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -20,7 +20,7 @@ class RoleSeeder extends Seeder 'id' => 1, 'name' => 'super-admin', 'name_fa' => 'ادمین', - 'guard_name' => 'web', + 'guard_name' => 'api', 'created_at' => now(), 'updated_at' => now() ]); diff --git a/routes/api.php b/routes/api.php index 660dc9c..0c62851 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,15 +1,234 @@ post('/', [CallController::class, 'store'])->name('store'); -Route::prefix('operator') +Route::prefix('auth') + ->name('auth.') + ->controller(AuthController::class) + ->group(function () { + 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('/change_password', 'changePassword')->name('changePassword'); + Route::post('/change_avatar', 'changeAvatar')->name('changeAvatar'); + Route::get('/permissions', 'permissions')->name('permissions'); Route::get('/online', 'online')->name('online'); Route::get('/offline', 'offline')->name('offline'); }); + +Route::prefix('users') + ->name('users.') + ->middleware(['auth', 'permission:manage_users']) + ->controller(UserManagementController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('/{user}', 'show')->middleware([SuperAdminCheck::class])->name('show'); + Route::post('/', 'store')->name('store'); + Route::post('/{user}', 'update')->middleware([SuperAdminCheck::class])->name('update'); + Route::delete('/{user}', 'destroy')->middleware([SuperAdminCheck::class])->name('destroy'); + }); + +Route::prefix('calls') + ->name('calls.') + ->controller(CallController::class) + ->group(function () { + Route::post('/', 'store')->name('store'); + Route::get('/list', 'list')->name('list')->middleware(['auth', 'permission:manage_calls']); + Route::post('/{call}', 'update')->name('update')->middleware(['auth', 'permission:manage_calls']); + }); + +Route::prefix('categories') + ->middleware('auth') + ->controller(CategoryController::class) + ->name('categories.') + ->group(function () { + Route::get('/list', 'list')->name('list'); + }); + +Route::middleware('auth') + ->prefix('permissions') + ->name('permissions.') + ->controller(PermissionManagementController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('list', 'list')->name('list'); + 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('provinces') + ->controller(ProvinceController::class) + ->name('provinces.') + ->group(function () { + Route::get('/list', 'list')->name('list'); + }); + +Route::middleware('auth') + ->prefix('roles') + ->name('roles.') + ->controller(RoleManagementController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('list', 'list')->name('list'); + Route::post('/', 'store')->name('store'); + Route::get('/{role}', 'show')->name('show'); + Route::post('/{role}', 'update')->name('update'); + Route::delete('/{role}', 'destroy')->name('destroy'); + }); + +Route::middleware('auth') + ->prefix('cumulative_stats') + ->name('cumulativeStats.') + ->controller(CumulativeCentersStatsController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + }); + +Route::middleware('auth') + ->prefix('cumulative_voice_ratings') + ->name('cumulativeVoiceRatings.') + ->controller(CumulativeVoiceRatingStatsController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + }); + +Route::middleware('auth') + ->prefix('cumulative_keypress_stats') + ->name('cumulativeKeypressStats.') + ->controller(CumulativeKeypressStatsController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + }); + +Route::middleware('auth') + ->prefix('cumulative_message_ratings') + ->name('cumulativeMessageRatings.') + ->controller(CumulativeMessageRatingStatsController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + }); + +Route::middleware('auth') + ->prefix('dialogs') + ->name('dialogs.') + ->group(function () { + Route::prefix('operator') + ->name('operator.') + ->controller(\App\Http\Controllers\ProvinceDashboard\OperatorDialogues\OperatorController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('/excel', 'excel')->name('excel'); + Route::get('/{operatorDialogue}','show')->name('show'); + }); + Route::prefix('supervisor') + ->name('supervisor.') + ->controller(\App\Http\Controllers\ProvinceDashboard\OperatorDialogues\SupervisorController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('/excel', 'excel')->name('excel'); + Route::post('/rate/{operatorDialogue}', 'rate')->name('rate'); + Route::get('/{operatorDialogue}', 'show')->name('show'); + }); + }); + +Route::middleware('auth') + ->prefix('system_messages') + ->name('systemMessages.') + ->group(function () { + Route::prefix('operator') + ->name('systemMessages.') + ->controller(\App\Http\Controllers\ProvinceDashboard\SystemMessages\OperatorController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('/excel', 'excel')->name('excel'); + Route::get('/{systemMessage}', 'show')->name('show'); + }); + + Route::prefix('supervisor') + ->name('systemMessages.') + ->controller(\App\Http\Controllers\ProvinceDashboard\SystemMessages\SupervisorController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('/excel', 'excel')->name('excel'); + Route::get('/{systemMessage}', 'show')->name('show'); + Route::post('/{systemMessage}', 'rate')->name('rate'); + }); + }); + +Route::middleware('auth') + ->prefix('people_messages') + ->name('peopleMessages.') + ->group(function () { + Route::prefix('operator') + ->name('peopleMessages.') + ->controller(\App\Http\Controllers\ProvinceDashboard\PeopleMessages\OperatorController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('/excel', 'excel')->name('excel'); + Route::post('/{peopleMessage}', 'handle')->name('handle'); + Route::get('/{peopleMessage}', 'show')->name('show'); + }); + + Route::prefix('supervisor') + ->name('peopleMessages.') + ->controller(\App\Http\Controllers\ProvinceDashboard\PeopleMessages\SupervisorController::class) + ->group(function () { + Route::get('/', 'index')->name('index'); + Route::get('/excel', 'excel')->name('excel'); + Route::get('/{peopleMessage}', 'show')->name('show'); + }); + }); + +Route::middleware(['auth', 'permission:teleport_to_province']) + ->prefix('login_to_province') + ->name('loginToProvince.') + ->controller(LoginToProvinceController::class) + ->group(function () { + Route::post('/', 'authenticate')->name('authenticate'); + }); + +Route::middleware(['auth', 'setadIp']) + ->prefix('verify_authentication') + ->name('verifyAuthentication.') + ->controller(VerifyAuthenticationController::class) + ->group(function () { + Route::post('/', 'login')->name('login'); + }); + +Route::middleware('auth') + ->prefix('report') + ->name('report.') + ->controller(ReportController::class) + ->group(function () { + Route::get('/cumulative', 'cumulative')->name('cumulative'); + Route::get('/people_messages', 'peopleMessages')->name('peopleMessages'); + Route::get('/detailed_logs', 'detailedLogs')->name('detailedLogs'); + Route::get('/operator_performance_daily', 'operatorPerformanceDaily')->name('operatorPerformanceDaily'); + Route::get('/operator_performance_total', 'operatorPerformanceTotal')->name('operatorPerformanceTotal'); + }); diff --git a/routes/web.php b/routes/web.php index a3b5c64..86a06c5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,233 +1,7 @@ group(function () { - Route::prefix('auth') - ->name('auth.') - ->controller(AuthController::class) - ->group(function () { - 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('/change_password', 'changePassword')->name('changePassword'); - Route::post('/change_avatar', 'changeAvatar')->name('changeAvatar'); - Route::get('/permissions', 'permissions')->name('permissions'); - }); - - Route::prefix('users') - ->name('users.') - ->middleware(['auth', 'permission:manage_users']) - ->controller(UserManagementController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('/{user}', 'show')->middleware([SuperAdminCheck::class])->name('show'); - Route::post('/', 'store')->name('store'); - Route::post('/{user}', 'update')->middleware([SuperAdminCheck::class])->name('update'); - Route::delete('/{user}', 'destroy')->middleware([SuperAdminCheck::class])->name('destroy'); - }); - - Route::prefix('calls') - ->name('calls.') - ->controller(CallController::class) - ->group(function () { - Route::post('/', 'store')->name('store'); - Route::get('/list', 'list')->name('list')->middleware(['auth', 'permission:manage_calls']); - Route::post('/{call}', 'update')->name('update')->middleware(['auth', 'permission:manage_calls']); - }); - - Route::prefix('categories') - ->middleware('auth') - ->controller(CategoryController::class) - ->name('categories.') - ->group(function () { - Route::get('/list', 'list')->name('list'); - }); - - Route::middleware('auth') - ->prefix('permissions') - ->name('permissions.') - ->controller(PermissionManagementController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('list', 'list')->name('list'); - 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('provinces') - ->controller(ProvinceController::class) - ->name('provinces.') - ->group(function () { - Route::get('/list', 'list')->name('list'); - }); - - Route::middleware('auth') - ->prefix('roles') - ->name('roles.') - ->controller(RoleManagementController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('list', 'list')->name('list'); - Route::post('/', 'store')->name('store'); - Route::get('/{role}', 'show')->name('show'); - Route::post('/{role}', 'update')->name('update'); - Route::delete('/{role}', 'destroy')->name('destroy'); - }); - - Route::middleware('auth') - ->prefix('cumulative_stats') - ->name('cumulativeStats.') - ->controller(CumulativeCentersStatsController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - }); - - Route::middleware('auth') - ->prefix('cumulative_voice_ratings') - ->name('cumulativeVoiceRatings.') - ->controller(CumulativeVoiceRatingStatsController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - }); - - Route::middleware('auth') - ->prefix('cumulative_keypress_stats') - ->name('cumulativeKeypressStats.') - ->controller(CumulativeKeypressStatsController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - }); - - Route::middleware('auth') - ->prefix('cumulative_message_ratings') - ->name('cumulativeMessageRatings.') - ->controller(CumulativeMessageRatingStatsController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - }); - - Route::middleware('auth') - ->prefix('dialogs') - ->name('dialogs.') - ->group(function () { - Route::prefix('operator') - ->name('operator.') - ->controller(\App\Http\Controllers\ProvinceDashboard\OperatorDialogues\OperatorController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('/excel', 'excel')->name('excel'); - Route::get('/{operatorDialogue}','show')->name('show'); - }); - Route::prefix('supervisor') - ->name('supervisor.') - ->controller(\App\Http\Controllers\ProvinceDashboard\OperatorDialogues\SupervisorController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('/excel', 'excel')->name('excel'); - Route::post('/rate/{operatorDialogue}', 'rate')->name('rate'); - Route::get('/{operatorDialogue}', 'show')->name('show'); - }); - }); - - Route::middleware('auth') - ->prefix('system_messages') - ->name('systemMessages.') - ->group(function () { - Route::prefix('operator') - ->name('systemMessages.') - ->controller(\App\Http\Controllers\ProvinceDashboard\SystemMessages\OperatorController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('/excel', 'excel')->name('excel'); - Route::get('/{systemMessage}', 'show')->name('show'); - }); - - Route::prefix('supervisor') - ->name('systemMessages.') - ->controller(\App\Http\Controllers\ProvinceDashboard\SystemMessages\SupervisorController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('/excel', 'excel')->name('excel'); - Route::get('/{systemMessage}', 'show')->name('show'); - Route::post('/{systemMessage}', 'rate')->name('rate'); - }); - }); - - Route::middleware('auth') - ->prefix('people_messages') - ->name('peopleMessages.') - ->group(function () { - Route::prefix('operator') - ->name('peopleMessages.') - ->controller(\App\Http\Controllers\ProvinceDashboard\PeopleMessages\OperatorController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('/excel', 'excel')->name('excel'); - Route::post('/{peopleMessage}', 'handle')->name('handle'); - Route::get('/{peopleMessage}', 'show')->name('show'); - }); - - Route::prefix('supervisor') - ->name('peopleMessages.') - ->controller(\App\Http\Controllers\ProvinceDashboard\PeopleMessages\SupervisorController::class) - ->group(function () { - Route::get('/', 'index')->name('index'); - Route::get('/excel', 'excel')->name('excel'); - Route::get('/{peopleMessage}', 'show')->name('show'); - }); - }); - - Route::middleware(['auth', 'permission:teleport_to_province']) - ->prefix('login_to_province') - ->name('loginToProvince.') - ->controller(LoginToProvinceController::class) - ->group(function () { - Route::post('/', 'authenticate')->name('authenticate'); - }); - - Route::middleware(['auth', 'setadIp']) - ->prefix('verify_authentication') - ->name('verifyAuthentication.') - ->controller(VerifyAuthenticationController::class) - ->group(function () { - Route::post('/', 'login')->name('login'); - }); - - Route::middleware('auth') - ->prefix('report') - ->name('report.') - ->controller(ReportController::class) - ->group(function () { - Route::get('/cumulative', 'cumulative')->name('cumulative'); - Route::get('/people_messages', 'peopleMessages')->name('peopleMessages'); - Route::get('/detailed_logs', 'detailedLogs')->name('detailedLogs'); - Route::get('/operator_performance_daily', 'operatorPerformanceDaily')->name('operatorPerformanceDaily'); - Route::get('/operator_performance_total', 'operatorPerformanceTotal')->name('operatorPerformanceTotal'); - }); +Route::get('/', function () { + return view('welcome'); }); From f77d0ee0d081aeb5bdcf2f14ac77615849b14511 Mon Sep 17 00:00:00 2001 From: amirghasempoor Date: Wed, 13 Aug 2025 14:14:28 +0330 Subject: [PATCH 2/2] fix the bugs --- Dockerfile | 4 +- .../Admin/UserManagementController.php | 4 +- app/Http/Controllers/CallController.php | 2 +- app/Http/Controllers/ProfileController.php | 2 +- .../SupervisorController.php | 22 ++-- .../OperatorDialogs/RateRequest.php | 1 + .../OperatorDialogues/DataTableService.php | 2 +- .../Dashboard/Province/ReportService.php | 102 +++++++----------- ...110555_create_operator_dialogues_table.php | 2 +- database/seeders/PermissionSeeder.php | 9 +- routes/api.php | 1 + 11 files changed, 69 insertions(+), 82 deletions(-) diff --git a/Dockerfile b/Dockerfile index f3c4890..8c14e99 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,10 +19,10 @@ RUN apk update && apk add --no-cache \ && docker-php-ext-install pdo_pgsql pdo_mysql gd zip # Set the working directory -WORKDIR /var/www/laravel +WORKDIR /var/www/crm/backend COPY . . -RUN chmod -R 777 /var/www/laravel/storage /var/www/laravel/bootstrap/cache +RUN chmod -R 777 /var/www/crm/backend/storage /var/www/crm/backend/bootstrap/cache # Install Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer diff --git a/app/Http/Controllers/Admin/UserManagementController.php b/app/Http/Controllers/Admin/UserManagementController.php index 55d639c..077cb55 100644 --- a/app/Http/Controllers/Admin/UserManagementController.php +++ b/app/Http/Controllers/Admin/UserManagementController.php @@ -27,8 +27,8 @@ class UserManagementController extends Controller User::query()->where('username', "<>", "witel"), $request, allowedFilters: array('id', 'full_name', 'username', 'province_id', 'phone_number', 'national_id', 'telephone_id'), - allowedSortings: array('id', 'full_name', 'username', 'province_id', 'phone_number', 'national_id', 'telephone_id'), - allowedRelations: array('roles:id,name_fa') + allowedRelations: array('roles:id,name_fa'), + allowedSortings: array('id', 'full_name', 'username', 'province_id', 'phone_number', 'national_id', 'telephone_id') ); return response()->json($data); diff --git a/app/Http/Controllers/CallController.php b/app/Http/Controllers/CallController.php index 6cf67ba..97580c2 100644 --- a/app/Http/Controllers/CallController.php +++ b/app/Http/Controllers/CallController.php @@ -123,7 +123,7 @@ class CallController extends Controller $size = $request->size ?? config('global_variables.MAX_RECORDS_COUNT'); $calls_data = Call::query() - ->when($phone_number, fn($query, $phone_number) => $query->where('phone_number', '=', $phone_number)) + ->when($phone_number, fn($query, $phone_number) => $query->where('caller_phone_number', '=', $phone_number)) ->orderBy('created_at', 'DESC') ->limit($size) ->get(); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 05b8c08..a2a7b75 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -52,7 +52,7 @@ class ProfileController extends Controller public function online(Request $request): JsonResponse { User::query() - ->firstWhere('telephone_id', '=', $request->telephone_id) + ->Where('telephone_id', '=', $request->telephone_id) ->update(['is_online' => true,]); return $this->successResponse(); diff --git a/app/Http/Controllers/ProvinceDashboard/OperatorDialogues/SupervisorController.php b/app/Http/Controllers/ProvinceDashboard/OperatorDialogues/SupervisorController.php index c3cdace..946bed1 100644 --- a/app/Http/Controllers/ProvinceDashboard/OperatorDialogues/SupervisorController.php +++ b/app/Http/Controllers/ProvinceDashboard/OperatorDialogues/SupervisorController.php @@ -22,14 +22,22 @@ class SupervisorController extends Controller return response()->json($dataTableService->index($request)); } - public function rate(RateRequest $request,OperatorDialogue $operatorDialogue): JsonResponse + public function rate(RateRequest $request): JsonResponse { - $operatorDialogue->update([ - 'supervisor_id' => auth()->user()->id, - 'is_good' => $request->is_good, - 'is_listen' => true, - 'description' => $request->description, - ]); + OperatorDialogue::query()->updateOrCreate( + [ + $request->cdr_unique_id + ], + [ + 'cdr_unique_id' => $request->cdr_unique_id, + 'date' => $request->date, + 'supervisor_id' => auth()->user()->id, + 'is_good' => $request->is_good, + 'is_listen' => true, + 'description' => $request->description, + ] + ); + return $this->successResponse(); } diff --git a/app/Http/Requests/ProvinceDashboard/OperatorDialogs/RateRequest.php b/app/Http/Requests/ProvinceDashboard/OperatorDialogs/RateRequest.php index f5150a1..1d7d447 100644 --- a/app/Http/Requests/ProvinceDashboard/OperatorDialogs/RateRequest.php +++ b/app/Http/Requests/ProvinceDashboard/OperatorDialogs/RateRequest.php @@ -22,6 +22,7 @@ class RateRequest extends FormRequest public function rules(): array { return [ + 'cdr_unique_id' => 'required|string', 'is_good' => 'required|in:0,1', 'description' => 'string', ]; diff --git a/app/Services/Dashboard/Province/OperatorDialogues/DataTableService.php b/app/Services/Dashboard/Province/OperatorDialogues/DataTableService.php index 4354160..d844d42 100644 --- a/app/Services/Dashboard/Province/OperatorDialogues/DataTableService.php +++ b/app/Services/Dashboard/Province/OperatorDialogues/DataTableService.php @@ -12,7 +12,7 @@ class DataTableService public function index(Request $request) { $query = DB::table('asteriskcdrdb.cdr') - ->leftJoin('crm_db.operator_dialogues', 'asteriskcdrdb.cdr.uniqueid', '=', 'crm_db.operator_dialogues.cdr_unique_id') + ->leftJoin('roaddb.operator_dialogues', 'asteriskcdrdb.cdr.uniqueid', '=', 'roaddb.operator_dialogues.cdr_unique_id') ->where('dst', '<>', '') ->where('lastapp', '=', 'Dial') ->where('duration', '>', 0) diff --git a/app/Services/Dashboard/Province/ReportService.php b/app/Services/Dashboard/Province/ReportService.php index bd804d6..bba6ddd 100644 --- a/app/Services/Dashboard/Province/ReportService.php +++ b/app/Services/Dashboard/Province/ReportService.php @@ -4,11 +4,12 @@ namespace App\Services\Dashboard\Province; use App\Facades\DataTable\DataTableFacade; use Illuminate\Http\Request; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; class ReportService { - public function cumulative(Request $request) + public function cumulative(Request $request): Collection { $query = DB::table('asteriskcdrdb.cdr') ->selectRaw(" @@ -23,13 +24,9 @@ class ReportService COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 AND billsec > 9 THEN 1 END) AS b10, COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, COUNT(CASE WHEN dst BETWEEN 502 AND 599 THEN 1 END) AS trans, - COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) AS all, + COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) AS all_calls, AVG(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' THEN billsec END) AS avg - "); -// ->whereBetween('calldate', [$from, $to]) // use Carbon or date strings -// ->groupBy(DB::raw('DATE(calldate)')) -// ->orderByDesc(DB::raw('DATE(calldate)')) -// ->get(); + ")->groupByRaw('DATE(calldate)'); $data = DataTableFacade::run( $query, @@ -38,6 +35,9 @@ class ReportService allowedSortings: ['*'], allowedGroupBy: ['d'] ); + + $data = collect($data); + $totals = [ 'd' => 'TOTAL', 'total' => $data->sum('total'), @@ -66,8 +66,6 @@ class ReportService COUNT(CASE WHEN is_listen = 1 THEN 1 END) AS l, COUNT(CASE WHEN is_listen = 0 THEN 1 END) AS nl '); -// ->whereBetween('date', [$date_from, $date_to]) -// ->first(); return DataTableFacade::run( $query, @@ -81,57 +79,33 @@ class ReportService { $query = DB::table('asteriskcdrdb.cdr') ->where('recordingfile', '<>', ''); -// ->whereBetween('calldate', ["$date_from $time_from", "$date_to $time_to"]) -// ->when($cid, function ($query, $cid) { -// return $query->where('src', 'like', "%{$cid}%"); -// }) -// ->when($c_op, function ($query, $c_op) { -// return $query->where('dst', $c_op); -// }, function ($query) { -// return $query->whereBetween('dst', [100, 110]); -// }) -// ->orderByDesc('calldate'); return DataTableFacade::run( $query, $request, allowedFilters: ['*'], allowedSortings: ['*'], + allowedSelects: ['calldate', 'src', 'dst', 'disposition', 'duration'] ); } public function operatorPerformanceDaily(Request $request) { - $query = DB::table('asteriskcdrdb.cdr') + $query = DB::table(DB::raw("(SELECT *, CAST(dst AS UNSIGNED) AS dst_num FROM asteriskcdrdb.cdr) AS cdr")) ->selectRaw(" - * - (all - (ok + nok)) AS fail - FROM ( - SELECT - DATE(calldate) AS d, - dst, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 THEN 1 END) AS ok, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst BETWEEN 101 AND 104 AND duration > 14 THEN 1 END) AS nok, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 AND billsec > 9 THEN 1 END) AS b10, - COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, - COUNT(CASE WHEN dst BETWEEN 502 AND 599 THEN 1 END) AS trans, - COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) AS all - FROM asteriskcdrdb.cdr - WHERE dst BETWEEN 101 AND 105 - GROUP BY d, dst - ORDER BY d, dst - ); - "); -// ->whereBetween('calldate', ["$date_from $time_from", "$date_to $time_to"]) -// ->when($cid, function ($query, $cid) { -// return $query->where('src', 'like', "%{$cid}%"); -// }) -// ->when($c_op, function ($query, $c_op) { -// return $query->where('dst', $c_op); -// }, function ($query) { -// return $query->whereBetween('dst', [100, 110]); -// }) -// ->orderByDesc('calldate'); + DATE(calldate) AS d, + dst, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst_num BETWEEN 1 AND 104 THEN 1 END) AS ok, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst_num BETWEEN 1 AND 104 AND duration > 14 THEN 1 END) AS nok, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst_num BETWEEN 1 AND 104 AND billsec > 9 THEN 1 END) AS b10, + COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, + COUNT(CASE WHEN dst_num BETWEEN 502 AND 599 THEN 1 END) AS trans, + COUNT(CASE WHEN disposition <> 'BUSY' AND dst_num BETWEEN 1 AND 105 THEN 1 END) AS total_calls + ") + ->whereBetween('dst_num', [1, 105]) + ->groupBy(DB::raw('DATE(calldate)'), 'dst') + ->orderBy(DB::raw('DATE(calldate)')) + ->orderBy('dst'); return DataTableFacade::run( $query, @@ -143,25 +117,21 @@ class ReportService public function operatorPerformanceTotal(Request $request) { - $query = DB::table('asteriskcdrdb.cdr') + $query = DB::table(DB::raw("(SELECT *, CAST(dst AS UNSIGNED) AS dst_num FROM asteriskcdrdb.cdr) AS cdr")) ->selectRaw(" - * - (all - (ok + nok)) AS fail - FROM ( - SELECT - DATE(calldate) AS d, - dst, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 THEN 1 END) AS ok, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst BETWEEN 101 AND 104 AND duration > 14 THEN 1 END) AS nok, - COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 AND billsec > 9 THEN 1 END) AS b10, - COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, - COUNT(CASE WHEN dst BETWEEN 502 AND 599 THEN 1 END) AS trans, - COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) AS all - FROM asteriskcdrdb.cdr - WHERE dst BETWEEN 101 AND 105 - GROUP BY dst - ORDER BY dst); - "); + DATE(calldate) AS d, + dst, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst_num BETWEEN 1 AND 104 THEN 1 END) AS ok, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst_num BETWEEN 1 AND 104 AND duration > 14 THEN 1 END) AS nok, + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst_num BETWEEN 1 AND 104 AND billsec > 9 THEN 1 END) AS b10, + COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, + COUNT(CASE WHEN dst_num BETWEEN 502 AND 599 THEN 1 END) AS trans, + COUNT(CASE WHEN disposition <> 'BUSY' AND dst_num BETWEEN 1 AND 105 THEN 1 END) AS total_calls + ") + ->whereBetween('dst_num', [1, 105]) + ->groupBy('dst') + ->orderBy(DB::raw('DATE(calldate)')) + ->orderBy('dst'); return DataTableFacade::run( $query, diff --git a/database/migrations/2025_08_02_110555_create_operator_dialogues_table.php b/database/migrations/2025_08_02_110555_create_operator_dialogues_table.php index 2a37667..61fe9ce 100644 --- a/database/migrations/2025_08_02_110555_create_operator_dialogues_table.php +++ b/database/migrations/2025_08_02_110555_create_operator_dialogues_table.php @@ -13,7 +13,7 @@ return new class extends Migration { Schema::create('operator_dialogues', function (Blueprint $table) { $table->id(); - $table->string('cdr_unique_id'); + $table->string('cdr_unique_id', 32)->collation('utf8mb4_general_ci'); $table->dateTime('date'); $table->foreignId('supervisor_id')->constrained('users'); $table->boolean('is_listen')->default(false); diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php index 738fece..0a40f64 100644 --- a/database/seeders/PermissionSeeder.php +++ b/database/seeders/PermissionSeeder.php @@ -37,8 +37,15 @@ class PermissionSeeder extends Seeder 'guard_name' => 'api', 'created_at' => now(), 'updated_at' => now() + ], + [ + 'id' => 4, + 'name' => 'teleport_to_province', + 'name_fa' => 'انتقال به استان ها', + 'guard_name' => 'api', + 'created_at' => now(), + 'updated_at' => now() ] ]); - } } diff --git a/routes/api.php b/routes/api.php index 0c62851..c68579a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -15,6 +15,7 @@ use App\Http\Controllers\ProfileController; use App\Http\Controllers\ProvinceController; use App\Http\Controllers\ProvinceDashboard\ReportController; use App\Http\Controllers\ProvinceDashboard\VerifyAuthenticationController; +use App\Http\Middleware\SuperAdminCheck; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route;