Compare commits

13 Commits

Author SHA1 Message Date
7950c43eed Merge pull request 'remove redundant packages' (#1) from feature/ModifyDockerfile into develop
Reviewed-on: #1
2026-02-22 05:58:17 +00:00
379f0b7daa remove redundant packages 2026-02-22 09:27:07 +03:30
de6630dfc5 Merge branch 'feature/Teleport' into 'develop'
add select

See merge request witel-back-end/crm!35
2026-02-14 12:06:18 +00:00
342cd8cb51 add select 2026-02-14 15:34:55 +03:30
530e23d1e1 Merge branch 'feature/Teleport' into 'develop'
logout

See merge request witel-back-end/crm!33
2025-08-17 12:15:25 +00:00
e90d3775e2 logout 2025-08-17 15:43:12 +03:30
d4be4f557f Merge branch 'feature/Teleport' into 'develop'
create roles and permissions

See merge request witel-back-end/crm!32
2025-08-16 12:11:20 +00:00
1b88fb0f0a create roles and permissions 2025-08-16 15:38:38 +03:30
efd93816a0 Merge branch 'feature/TokenLogin' into 'develop'
fix route names

See merge request witel-back-end/crm!31
2025-08-16 05:56:26 +00:00
3ac70b0076 fix route names 2025-08-16 09:24:50 +03:30
07a7355f7f Merge branch 'feature/TokenLogin' into 'develop'
Feature/token login

See merge request witel-back-end/crm!30
2025-08-13 13:26:20 +00:00
dd2e016ad2 debug 2025-08-13 16:47:11 +03:30
0902b4864c Merge branch 'feature/TokenLogin' into 'develop'
Feature/token login

See merge request witel-back-end/crm!29
2025-08-13 11:00:56 +00:00
17 changed files with 215 additions and 95 deletions

View File

@@ -27,13 +27,6 @@ DB_DATABASE=laravel
DB_USERNAME=root DB_USERNAME=root
DB_PASSWORD= DB_PASSWORD=
ASTERISK_DB_CONNECTION=asterisk
ASTERISK_DB_HOST=127.0.0.1
ASTERISK_DB_PORT=3306
ASTERISK_DB_DATABASE=laravel
ASTERISK_DB_USERNAME=root
ASTERISK_DB_PASSWORD=
SESSION_DRIVER=database SESSION_DRIVER=database
SESSION_LIFETIME=120 SESSION_LIFETIME=120
SESSION_ENCRYPT=false SESSION_ENCRYPT=false

View File

@@ -2,9 +2,7 @@ FROM docker.arvancloud.ir/php:8.3-fpm-alpine3.21
# Install common PHP extension dependencies # Install common PHP extension dependencies
RUN apk update && apk add --no-cache \ RUN apk update && apk add --no-cache \
git \
bash \ bash \
nano \
curl \ curl \
libpng \ libpng \
libpng-dev \ libpng-dev \
@@ -29,8 +27,8 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
ENV COMPOSER_ALLOW_SUPERUSER=1 ENV COMPOSER_ALLOW_SUPERUSER=1
# Default command # Default command
CMD composer install \ CMD composer install ;\
&& php artisan key:generate \ php artisan key:generate ;\
&& php artisan migrate \ php artisan migrate ;\
&& php artisan db:seed \ php artisan db:seed ;\
&& php-fpm php-fpm

View File

@@ -25,8 +25,8 @@ class RoleManagementController extends Controller
Role::query(), Role::query(),
$request, $request,
allowedFilters: array('id', 'name', 'name_fa'), allowedFilters: array('id', 'name', 'name_fa'),
allowedSortings: array('id', 'name', 'name_fa'), allowedRelations: array('permissions:id,name_fa'),
allowedRelations: array('permissions:id,name_fa') allowedSortings: array('id', 'name', 'name_fa')
); );
return response()->json($data); return response()->json($data);

View File

@@ -20,11 +20,13 @@ class LoginToProvinceController extends Controller
->value('ip'); ->value('ip');
$data = [ $data = [
'user_id' => auth()->user()->id, 'user_id' => auth()->user()->username,
'token' => Hash::make(config('globalVariables.LOGIN_HASH_VALUE')), 'token' => Hash::make(config('globalVariables.LOGIN_HASH_VALUE')),
'ip' => $province_ip, 'ip' => $province_ip,
]; ];
auth()->user()->currentAccessToken()->delete();
return $this->successResponse($data); return $this->successResponse($data);
} }
} }

View File

@@ -26,7 +26,7 @@ class SupervisorController extends Controller
{ {
OperatorDialogue::query()->updateOrCreate( OperatorDialogue::query()->updateOrCreate(
[ [
$request->cdr_unique_id 'cdr_unique_id' => $request->cdr_unique_id,
], ],
[ [
'cdr_unique_id' => $request->cdr_unique_id, 'cdr_unique_id' => $request->cdr_unique_id,

View File

@@ -19,10 +19,13 @@ class VerifyAuthenticationController extends Controller
return $this->errorResponse('Invalid token'); return $this->errorResponse('Invalid token');
} }
$user = User::query()->findOrFail($request->user_id); $user = User::query()->firstWhere('username', '=', $request->user_id);
Auth::login($user); $token = $user->createToken("{$user->username}", ['*'], now()->addWeek())->plainTextToken;
return $this->successResponse(); return $this->successResponse([
'message' => __('messages.successful'),
'token' => $token
]);
} }
} }

View File

@@ -1,24 +0,0 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class VerifySetadIp
{
/**
* Handle an incoming request.
*
* @param Closure(Request): (Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->ip() == config('globalVariables.SETAD_IP')) {
return $next($request);
}
abort(Response::HTTP_FORBIDDEN);
}
}

View File

@@ -25,6 +25,7 @@ class RateRequest extends FormRequest
'cdr_unique_id' => 'required|string', 'cdr_unique_id' => 'required|string',
'is_good' => 'required|in:0,1', 'is_good' => 'required|in:0,1',
'description' => 'string', 'description' => 'string',
'date' => 'required|date'
]; ];
} }
} }

View File

@@ -2,9 +2,18 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class Cdr extends Model class Cdr extends Model
{ {
protected $table = 'cdr'; protected $table = 'asteriskcdrdb.cdr';
protected function recordingfile(): Attribute
{
return Attribute::make(
get: fn($value) => $value == null ? null : url('/') . 'recordingfiles/' . $value
);
}
} }

View File

@@ -13,6 +13,10 @@ class DataTableService
{ {
$query = DB::table('asteriskcdrdb.cdr') $query = DB::table('asteriskcdrdb.cdr')
->leftJoin('roaddb.operator_dialogues', 'asteriskcdrdb.cdr.uniqueid', '=', 'roaddb.operator_dialogues.cdr_unique_id') ->leftJoin('roaddb.operator_dialogues', 'asteriskcdrdb.cdr.uniqueid', '=', 'roaddb.operator_dialogues.cdr_unique_id')
->select(
'asteriskcdrdb.cdr.*',
DB::raw("CONCAT('" . url('recordings') . "/', DATE_FORMAT(calldate, '%Y/%m/%d/'), recordingfile) AS recording_url")
)
->where('dst', '<>', '') ->where('dst', '<>', '')
->where('lastapp', '=', 'Dial') ->where('lastapp', '=', 'Dial')
->where('duration', '>', 0) ->where('duration', '>', 0)

View File

@@ -25,14 +25,14 @@ class ReportService
COUNT(CASE WHEN lastapp = 'Busy' THEN 1 END) AS dnd, 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 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_calls, 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 AVG(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' THEN billsec END) AS avg,
( (
COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END) COUNT(CASE WHEN disposition <> 'BUSY' AND dst BETWEEN 101 AND 105 THEN 1 END)
- ( - (
COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 THEN 1 END) COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'ANSWERED' AND dst BETWEEN 101 AND 104 THEN 1 END)
+ COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst BETWEEN 101 AND 104 AND duration > 14 THEN 1 END) + COUNT(CASE WHEN dcontext = 'from-internal' AND disposition = 'NO ANSWER' AND dst BETWEEN 101 AND 104 AND duration > 14 THEN 1 END)
) )
) AS fail, ) AS fail
")->groupByRaw('DATE(calldate)'); ")->groupByRaw('DATE(calldate)');
$data = DataTableFacade::run( $data = DataTableFacade::run(

View File

@@ -19,7 +19,6 @@ return Application::configure(basePath: dirname(__DIR__))
$middleware->statefulApi()->alias([ $middleware->statefulApi()->alias([
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class, 'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class, 'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
'setadIp' => \App\Http\Middleware\VerifySetadIp::class,
]); ]);
}) })
->withExceptions(function (Exceptions $exceptions) { ->withExceptions(function (Exceptions $exceptions) {

View File

@@ -4,5 +4,4 @@ return [
'TRUSTED_IP' => explode(',', env("TRUSTED_IP", '127.0.0.1')), 'TRUSTED_IP' => explode(',', env("TRUSTED_IP", '127.0.0.1')),
'NOTIFICATION_SERVER_URL' => env('NOTIFICATION_SERVER_URL', '127.0.0.1'), 'NOTIFICATION_SERVER_URL' => env('NOTIFICATION_SERVER_URL', '127.0.0.1'),
'LOGIN_HASH_VALUE' => env('LOGIN_HASH_VALUE'), 'LOGIN_HASH_VALUE' => env('LOGIN_HASH_VALUE'),
'SETAD_IP' => env('SETAD_IP'),
]; ];

View File

@@ -45,7 +45,103 @@ class PermissionSeeder extends Seeder
'guard_name' => 'api', 'guard_name' => 'api',
'created_at' => now(), 'created_at' => now(),
'updated_at' => now() 'updated_at' => now()
] ],
[
'id' => 5,
'name' => 'country_calls_report',
'name_fa' => 'تجمعی تمام مراکز',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 6,
'name' => 'country_voice_rating',
'name_fa' => 'تجمعی کیفی تمام مراکز',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 7,
'name' => 'country_message_rating',
'name_fa' => 'تجمعی پیام های مردمی',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 8,
'name' => 'country_keypress_report',
'name_fa' => 'گزارش تماس ها',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 9,
'name' => 'supervise_operator_dialogue',
'name_fa' => 'ارزیابی مکالمات اپراتور',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 10,
'name' => 'supervise_system_message',
'name_fa' => 'ارزیابی پیام های سیستمی',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 11,
'name' => 'supervise_people_message',
'name_fa' => 'ارزیابی پیام های مردمی',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 12,
'name' => 'province_reports',
'name_fa' => 'گزارشات استان',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 13,
'name' => 'province_operator_dialogue',
'name_fa' => 'مکالمات اپراتور',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 14,
'name' => 'province_system_message',
'name_fa' => 'پیام های سیستمی',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 15,
'name' => 'province_people_message',
'name_fa' => 'پیام های مردمی',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 16,
'name' => 'supervisor_performance',
'name_fa' => 'عملکرد کارشناس ستاد',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
],
]); ]);
} }
} }

View File

@@ -16,16 +16,56 @@ class RoleSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
$role = Role::query()->create([ $superAdmin = Role::query()->create([
'id' => 1, 'id' => 1,
'name' => 'super-admin', 'name' => 'super-admin',
'name_fa' => 'ادمین', 'name_fa' => 'سوپر ادمین',
'guard_name' => 'api', 'guard_name' => 'api',
'created_at' => now(), 'created_at' => now(),
'updated_at' => now() 'updated_at' => now()
]); ]);
$role->givePermissionTo(Permission::all()); $superAdmin->givePermissionTo(Permission::all());
User::query()->where('username', '=', 'witel')->first()->assignRole('super-admin'); User::query()->where('username', '=', 'witel')->first()->assignRole('super-admin');
$setadAdmin = Role::query()->create([
'id' => 2,
'name' => 'setad-admin',
'name_fa' => 'ادمین ستاد',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
]);
$setadAdmin->givePermissionTo([1, 3, 4, 5, 6, 7, 8, 16]);
$setadExpert = Role::query()->create([
'id' => 3,
'name' => 'setad-expert',
'name_fa' => 'کارشناس ستاد',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
]);
$setadExpert->givePermissionTo([3, 4, 5, 6, 7, 8]);
$provinceSupervisor = Role::query()->create([
'id' => 4,
'name' => 'province-supervisor',
'name_fa' => 'ارزیاب استان',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
]);
$provinceSupervisor->givePermissionTo([3, 4, 9, 10, 11, 12]);
$province = Role::query()->create([
'id' => 5,
'name' => 'province',
'name_fa' => 'استان',
'guard_name' => 'api',
'created_at' => now(),
'updated_at' => now()
]);
$province->givePermissionTo([3, 12, 13, 14, 15]);
} }
} }

View File

@@ -153,7 +153,7 @@ Route::middleware('auth')
->group(function () { ->group(function () {
Route::get('/', 'index')->name('index'); Route::get('/', 'index')->name('index');
Route::get('/excel', 'excel')->name('excel'); Route::get('/excel', 'excel')->name('excel');
Route::post('/rate/{operatorDialogue}', 'rate')->name('rate'); Route::post('/rate', 'rate')->name('rate');
Route::get('/{operatorDialogue}', 'show')->name('show'); Route::get('/{operatorDialogue}', 'show')->name('show');
}); });
}); });
@@ -187,7 +187,7 @@ Route::middleware('auth')
->name('peopleMessages.') ->name('peopleMessages.')
->group(function () { ->group(function () {
Route::prefix('operator') Route::prefix('operator')
->name('peopleMessages.') ->name('operator.')
->controller(\App\Http\Controllers\ProvinceDashboard\PeopleMessages\OperatorController::class) ->controller(\App\Http\Controllers\ProvinceDashboard\PeopleMessages\OperatorController::class)
->group(function () { ->group(function () {
Route::get('/', 'index')->name('index'); Route::get('/', 'index')->name('index');
@@ -197,7 +197,7 @@ Route::middleware('auth')
}); });
Route::prefix('supervisor') Route::prefix('supervisor')
->name('peopleMessages.') ->name('supervisor.')
->controller(\App\Http\Controllers\ProvinceDashboard\PeopleMessages\SupervisorController::class) ->controller(\App\Http\Controllers\ProvinceDashboard\PeopleMessages\SupervisorController::class)
->group(function () { ->group(function () {
Route::get('/', 'index')->name('index'); Route::get('/', 'index')->name('index');
@@ -214,8 +214,7 @@ Route::middleware(['auth', 'permission:teleport_to_province'])
Route::post('/', 'authenticate')->name('authenticate'); Route::post('/', 'authenticate')->name('authenticate');
}); });
Route::middleware(['auth', 'setadIp']) Route::prefix('verify_authentication')
->prefix('verify_authentication')
->name('verifyAuthentication.') ->name('verifyAuthentication.')
->controller(VerifyAuthenticationController::class) ->controller(VerifyAuthenticationController::class)
->group(function () { ->group(function () {

View File

@@ -1,36 +1,37 @@
insert into provinces (id, name, lat, lon) values insert into provinces (id, name, lat, lon, ip) values
('1','آذربایجان شرقی','38.0742000000','46.2962000000'), ('1','آذربایجان شرقی','38.0742000000','46.2962000000', '172.30.5.1'),
('2','آذربایجان غربی','37.5495000000','45.0683000000'), ('2','آذربایجان غربی','37.5495000000','45.0683000000', '172.30.5.1'),
('3','اردبیل','38.2419000000','48.2887000000'), ('3','اردبیل','38.2419000000','48.2887000000', '172.30.5.1'),
('4','اصفهان','32.6709000000','51.6650000000'), ('4','اصفهان','32.6709000000','51.6650000000', '172.30.5.1'),
('5','البرز','35.8124000000','51.0074000000'), ('5','البرز','35.8124000000','51.0074000000', '172.30.5.1'),
('6','ایرانشهر','27.2069903000','60.6882515000'), ('6','ایرانشهر','27.2069903000','60.6882515000', '172.30.5.1'),
('7','ایلام','33.6381000000','46.4203000000'), ('7','ایلام','33.6381000000','46.4203000000', '172.30.5.1'),
('8','بوشهر','28.9312000000','50.8458000000'), ('8','بوشهر','28.9312000000','50.8458000000', '172.30.5.1'),
('9','تهران','35.7065000000','51.3477000000'), ('9','تهران','35.7065000000','51.3477000000', '172.30.5.1'),
('10','چهارمحال و بختیاری','32.3259000000','50.8497000000'), ('10','چهارمحال و بختیاری','32.3259000000','50.8497000000', '172.30.5.1'),
('11','خراسان جنوبی','32.8635000000','59.2177000000'), ('11','خراسان جنوبی','32.8635000000','59.2177000000', '172.30.5.1'),
('12','خراسان رضوی','36.2977000000','59.6059000000'), ('12','خراسان رضوی','36.2977000000','59.6059000000', '172.30.5.1'),
('13','خراسان شمالی','37.4761000000','57.3320000000'), ('13','خراسان شمالی','37.4761000000','57.3320000000', '172.30.5.1'),
('14','خوزستان','31.3231000000','48.6793000000'), ('14','خوزستان','31.3231000000','48.6793000000', '172.30.5.1'),
('15','زنجان','36.6782000000','48.5079000000'), ('15','زنجان','36.6782000000','48.5079000000', '172.30.5.1'),
('16','سمنان شرق','36.4056260000','54.9670738726'), ('16','سمنان شرق','36.4056260000','54.9670738726', '172.30.5.1'),
('17','سمنان غرب','35.5834074000','53.3882906000'), ('17','سمنان غرب','35.5834074000','53.3882906000', '172.30.5.1'),
('18','سیستان و بلوچستان','29.4912000000','60.8674000000'), ('18','سیستان و بلوچستان','29.4912000000','60.8674000000', '172.30.5.1'),
('19','فارس','29.6061000000','52.5378000000'), ('19','فارس','29.6061000000','52.5378000000', '172.30.5.1'),
('20','قزوین','36.2816000000','50.0153000000'), ('20','قزوین','36.2816000000','50.0153000000', '172.30.5.1'),
('21','قم','34.6425000000','50.8801000000'), ('21','قم','34.6425000000','50.8801000000', '172.30.5.1'),
('22','کردستان','35.3128000000','46.9979000000'), ('22','کردستان','35.3128000000','46.9979000000', '172.30.5.1'),
('23','کرمان','30.2924085000','57.0645647000'), ('23','کرمان','30.2924085000','57.0645647000', '172.30.5.1'),
('24','کرمان جنوب','28.6697367000','57.7373382000'), ('24','کرمان جنوب','28.6697367000','57.7373382000', '172.30.5.1'),
('25','کرمانشاه','34.3241000000','47.0736000000'), ('25','کرمانشاه','34.3241000000','47.0736000000', '172.30.5.1'),
('26','کهگیلویه و بویراحمد','30.6678000000','51.5803000000'), ('26','کهگیلویه و بویراحمد','30.6678000000','51.5803000000', '172.30.5.1'),
('27','گلستان','36.8305000000','54.4242000000'), ('27','گلستان','36.8305000000','54.4242000000', '172.30.5.1'),
('28','گیلان','37.2795000000','49.5846000000'), ('28','گیلان','37.2795000000','49.5846000000', '172.30.5.1'),
('29','لارستان','27.6619203000','54.3229561000'), ('29','لارستان','27.6619203000','54.3229561000', '172.30.5.1'),
('30','لرستان','33.4844000000','48.3538000000'), ('30','لرستان','33.4844000000','48.3538000000', '172.30.5.1'),
('31','مازندران','36.5505000000','53.0708000000'), ('31','مازندران','36.5505000000','53.0708000000', '172.30.5.1'),
('32','مرکزی','34.0883000000','49.7132000000'), ('32','مرکزی','34.0883000000','49.7132000000', '172.30.5.1'),
('33','هرمزگان','27.1795000000','56.2781000000'), ('33','هرمزگان','27.1795000000','56.2781000000', '172.30.5.1'),
('34','همدان','34.7992000000','48.5148000000'), ('34','همدان','34.7992000000','48.5148000000', '172.30.5.1'),
('35','یزد','31.8888000000','54.3641000000'); ('35','یزد','31.8888000000','54.3641000000', '172.30.5.1'),
('36','ستاد','35.7065000000','51.3477000000', '172.30.5.1');