Merge branch 'feature/CallSystem' into 'develop'

create controller model,migration,factory,seeder,request, resource ,web for 4 item...

See merge request witel-back-end/crm!5
This commit is contained in:
2025-04-30 06:11:27 +00:00
41 changed files with 1902 additions and 1 deletions

View File

@@ -32,6 +32,8 @@ SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
SESSION_SAME_SITE=none
SESSION_SECURE_COOKIE=false
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
@@ -63,3 +65,5 @@ AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
TRUSTED_IP="127.0.0.1"

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Enums;
enum CallEvents: int
{
case CALL_CREATED = 1;
case OPERATOR_IS_OFFLINE = 2;
case OPERATOR_COULD_NOT_CONNECT = 3;
case OPERATOR_STORED_CALL_DATA = 4;
case NOTIFICATION_SERVER_NOT_RESPONDING = 5;
}

View File

@@ -0,0 +1,129 @@
<?php
namespace App\Http\Controllers;
use App\Enums\CallEvents;
use App\Http\Requests\Call\ListRequest;
use App\Http\Requests\Call\StoreRequest;
use App\Http\Requests\Call\UpdateRequest;
use App\Http\Resources\Call\CallResource;
use app\Http\Traits\ApiResponse;
use App\Models\Call;
use App\Models\CallHistory;
use App\Models\Category;
use App\Models\Event;
use App\Models\User;
use App\Services\Notification\Exceptions\NotificationServerNotRespondingException;
use App\Services\Notification\Exceptions\OperatorNotConnectedException;
use App\Services\Notification\Exceptions\OperatorOfflineException;
use App\Services\Notification\NotificationService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class CallController extends Controller
{
use ApiResponse;
public function store(StoreRequest $request,NotificationService $notificationService): JsonResponse
{
try
{
$call = DB::transaction(function () use ($request)
{
$operator = User::query()->where('telephone_id', $request->telephone_id)->first();
$call = Call::query()->create([
'telephone_id' => $request->telephone_id,
'caller_phone_number' => $request->caller_phone_number,
'operator_id' => $operator->id,
'operator_username' => $operator->username,
'operator_full_name' => $operator->full_name
]);
CallHistory::recordHistory($call, CallEvents::CALL_CREATED);
return $call;
});
$data = [
'telephone_id' => $call->telephone_id,
'phone_number' => $call->caller_phone_number,
'call_id' => $call->id,
];
$notificationService->deliverDataToNotificationServer($data);
return $this->successResponse();
}
catch (NotificationServerNotRespondingException $exception)
{
CallHistory::recordHistory($call, CallEvents::NOTIFICATION_SERVER_NOT_RESPONDING);
throw $exception;
}
catch (OperatorOfflineException $exception)
{
CallHistory::recordHistory($call, CallEvents::OPERATOR_IS_OFFLINE);
throw $exception;
}
catch (OperatorNotConnectedException $exception)
{
CallHistory::recordHistory($call, CallEvents::OPERATOR_COULD_NOT_CONNECT);
throw $exception;
}
}
public function update(UpdateRequest $request, Call $call): JsonResponse
{
DB::transaction(function () use ($request, $call) {
$operator = User::query()->where('telephone_id', $call->telephone_id)->first();
$category = Category::query()->where([
['category_id', $request->category_id],
['subcategory_id', $request->subcategory_id]
])->first();
$call->update([
'province_id' => $operator->province_id,
'province_fa' => $operator->province_fa,
'operator_id' => $operator->id,
'operator_username' => $operator->username,
'operator_full_name' => $operator->full_name,
'category_id' => $request->category_id,
'category_name' => $category->category_name,
'subcategory_id' => $request->subcategory_id,
'subcategory_name' => $category->subcategory_name,
'description' => $request->description,
]);
$event_id = CallEvents::OPERATOR_STORED_CALL_DATA;
$event_name = Event::query()->find($event_id)->first()->name;
CallHistory::create([
'call_id' => $call->id,
'telephone_id' => $call->telephone_id,
'caller_phone_number' => $call->caller_phone_number,
'event_id' => $event_id,
'event_name' => $event_name,
]);
});
return $this->successResponse();
}
public function list(ListRequest $request): JsonResponse
{
$phone_number = $request->phone_number;
$size = $request->size ?? config('global_variables.MAX_RECORDS_COUNT');
$calls_data = Call::query()
->when($phone_number, function ($query) use ($phone_number) {
return $query->where('caller_phone_number', $phone_number);
})->orderBy('created_at', 'DESC')
->limit($size)
->get();
return $this->successResponse(CallResource::collection($calls_data));
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers;
use app\Http\Traits\ApiResponse;
use App\Models\Category;
use Illuminate\Http\JsonResponse;
class CategoryController extends Controller
{
use ApiResponse;
public function list(): JsonResponse
{
$data = Category::all('category_id', 'category_name', 'subcategory_id', 'subcategory_name');
return $this->successResponse($data);
}
}

View File

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

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Call;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
class ListRequest 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 [
'phone_number' => 'regex:/^09\d{9}$/',
'size' => 'integer'
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Call;
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 [
'telephone_id' => 'required|string|exists:users,telephone_id',
'caller_phone_number' => 'required|numeric|regex:/^09\d{9}$/',
];
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace App\Http\Requests\Call;
use App\Models\Category;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
class UpdateRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
$operator_telephone_id = auth()->user()->telephone_id;
if ($operator_telephone_id == $this->call->telephone_id) {
return true;
}
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'category_id' => 'required|integer',
'subcategory_id' => 'required|integer',
'description' => 'string',
];
}
public function after(): array
{
return [
function (Validator $validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add(
'category',
__('messages.combination_of_category_and_subcategory_does_not_exist')
);
}
}
];
}
private function somethingElseIsInvalid(): bool
{
$category_id = $this->category_id;
$subcategory_id = $this->subcategory_id;
if ($category_id && $subcategory_id) {
return !Category::query()->where([
['category_id', $category_id],
['subcategory_id', $subcategory_id]
])->exists();
}
return false;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Resources\Call;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class CallResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'operator_id' => $this->operator_id,
'operator_full_name' => $this->operator_full_name,
'operator_username' => $this->operator_username,
'telephone_id' => $this->telephone_id,
'caller_phone_number' => $this->caller_phone_number,
'description' => $this->description,
'category_id' => $this->category_id,
'category_name' => $this->category_name,
'subcategory_id' => $this->subcategory_id,
'subcategory_name' => $this->subcategory_name,
'created_at' => $this->created_at,
];
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Call extends Model
{
use HasFactory;
protected $guarded = [
'call_id',
'created_at',
'updated_at'
];
public function histories(): HasMany
{
return $this->hasMany(CallHistory::class);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class CallHistory extends Model
{
/** @use HasFactory<\Database\Factories\CallHistoryFactory> */
use HasFactory;
protected $guarded = ['id'];
public static function recordHistory(Call $call, $event_id): void
{
$event = Event::query()->where('id', $event_id)->first();
self::create([
'call_id' => $call->id,
'telephone_id' => $call->telephone_id,
'caller_phone_number' => $call->caller_phone_number,
'event_id' => $event->id,
'event_name' => $event->name
]);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
/** @use HasFactory<\Database\Factories\CategoryFactory> */
use HasFactory;
protected $guarded = ['id'];
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
/** @use HasFactory<\Database\Factories\EventFactory> */
use HasFactory;
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
use Laravel\Telescope\TelescopeApplicationServiceProvider;
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
Telescope::night();
$this->hideSensitiveRequestDetails();
$isLocal = $this->app->environment('local');
Telescope::filter(function (IncomingEntry $entry) use ($isLocal) {
return $isLocal ||
$entry->isReportableException() ||
$entry->isFailedRequest() ||
$entry->isFailedJob() ||
$entry->isScheduledTask() ||
$entry->hasMonitoredTag();
});
}
/**
* Prevent sensitive request details from being logged by Telescope.
*/
protected function hideSensitiveRequestDetails(): void
{
if ($this->app->environment('local')) {
return;
}
Telescope::hideRequestParameters(['_token']);
Telescope::hideRequestHeaders([
'cookie',
'x-csrf-token',
'x-xsrf-token',
]);
}
/**
* Register the Telescope gate.
*
* This gate determines who can access Telescope in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewTelescope', function ($user) {
return in_array($user->email, [
//
]);
});
}
}

View File

@@ -4,4 +4,5 @@ return [
App\Providers\AppServiceProvider::class,
App\Providers\DataTableServiceProvider::class,
App\Providers\FileServiceProvider::class,
App\Providers\TelescopeServiceProvider::class,
];

View File

@@ -11,7 +11,9 @@
"require": {
"php": "^8.2",
"laravel/framework": "^12.0",
"laravel/pulse": "^1.4",
"laravel/sanctum": "^4.0",
"laravel/telescope": "^5.7",
"laravel/tinker": "^2.10.1",
"spatie/laravel-permission": "^6.17"
},

289
laravel/composer.lock generated
View File

@@ -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": "c6435e4e604560a7d58c57b5d1bd2d63",
"content-hash": "8eb5ac276d904be6e4f6bd9ca7aa7b2f",
"packages": [
{
"name": "brick/math",
@@ -378,6 +378,61 @@
],
"time": "2024-02-05T11:56:58+00:00"
},
{
"name": "doctrine/sql-formatter",
"version": "1.5.2",
"source": {
"type": "git",
"url": "https://github.com/doctrine/sql-formatter.git",
"reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/d6d00aba6fd2957fe5216fe2b7673e9985db20c8",
"reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"doctrine/coding-standard": "^12",
"ergebnis/phpunit-slow-test-detector": "^2.14",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.5"
},
"bin": [
"bin/sql-formatter"
],
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\SqlFormatter\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jeremy Dorn",
"email": "jeremy@jeremydorn.com",
"homepage": "https://jeremydorn.com/"
}
],
"description": "a PHP SQL highlighting library",
"homepage": "https://github.com/doctrine/sql-formatter/",
"keywords": [
"highlight",
"sql"
],
"support": {
"issues": "https://github.com/doctrine/sql-formatter/issues",
"source": "https://github.com/doctrine/sql-formatter/tree/1.5.2"
},
"time": "2025-01-24T11:45:48+00:00"
},
{
"name": "dragonmantank/cron-expression",
"version": "v3.4.0",
@@ -1328,6 +1383,93 @@
},
"time": "2025-02-11T13:34:40+00:00"
},
{
"name": "laravel/pulse",
"version": "v1.4.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pulse.git",
"reference": "b3cf86e88fa78ea8e6aeb86a7d9ea25ba2c1d31f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/pulse/zipball/b3cf86e88fa78ea8e6aeb86a7d9ea25ba2c1d31f",
"reference": "b3cf86e88fa78ea8e6aeb86a7d9ea25ba2c1d31f",
"shasum": ""
},
"require": {
"doctrine/sql-formatter": "^1.4.1",
"guzzlehttp/promises": "^1.0|^2.0",
"illuminate/auth": "^10.48.4|^11.0.8|^12.0",
"illuminate/cache": "^10.48.4|^11.0.8|^12.0",
"illuminate/config": "^10.48.4|^11.0.8|^12.0",
"illuminate/console": "^10.48.4|^11.0.8|^12.0",
"illuminate/contracts": "^10.48.4|^11.0.8|^12.0",
"illuminate/database": "^10.48.4|^11.0.8|^12.0",
"illuminate/events": "^10.48.4|^11.0.8|^12.0",
"illuminate/http": "^10.48.4|^11.0.8|^12.0",
"illuminate/queue": "^10.48.4|^11.0.8|^12.0",
"illuminate/redis": "^10.48.4|^11.0.8|^12.0",
"illuminate/routing": "^10.48.4|^11.0.8|^12.0",
"illuminate/support": "^10.48.4|^11.0.8|^12.0",
"illuminate/view": "^10.48.4|^11.0.8|^12.0",
"livewire/livewire": "^3.4.9",
"nesbot/carbon": "^2.67|^3.0",
"php": "^8.1",
"symfony/console": "^6.0|^7.0"
},
"conflict": {
"nunomaduro/collision": "<7.7.0"
},
"require-dev": {
"guzzlehttp/guzzle": "^7.7",
"mockery/mockery": "^1.0",
"orchestra/testbench": "^8.23.1|^9.0|^10.0",
"pestphp/pest": "^2.0",
"pestphp/pest-plugin-laravel": "^2.2",
"phpstan/phpstan": "^1.12.21",
"predis/predis": "^1.0|^2.0"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Pulse": "Laravel\\Pulse\\Facades\\Pulse"
},
"providers": [
"Laravel\\Pulse\\PulseServiceProvider"
]
},
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Laravel\\Pulse\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.",
"homepage": "https://github.com/laravel/pulse",
"keywords": [
"laravel"
],
"support": {
"issues": "https://github.com/laravel/pulse/issues",
"source": "https://github.com/laravel/pulse"
},
"time": "2025-03-30T16:25:37+00:00"
},
{
"name": "laravel/sanctum",
"version": "v4.1.0",
@@ -1453,6 +1595,75 @@
},
"time": "2025-03-19T13:51:03+00:00"
},
{
"name": "laravel/telescope",
"version": "v5.7.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/telescope.git",
"reference": "440908cb856cfbef9323244f7978ad4bf8cd2daa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/telescope/zipball/440908cb856cfbef9323244f7978ad4bf8cd2daa",
"reference": "440908cb856cfbef9323244f7978ad4bf8cd2daa",
"shasum": ""
},
"require": {
"ext-json": "*",
"laravel/framework": "^8.37|^9.0|^10.0|^11.0|^12.0",
"php": "^8.0",
"symfony/console": "^5.3|^6.0|^7.0",
"symfony/var-dumper": "^5.0|^6.0|^7.0"
},
"require-dev": {
"ext-gd": "*",
"guzzlehttp/guzzle": "^6.0|^7.0",
"laravel/octane": "^1.4|^2.0|dev-develop",
"orchestra/testbench": "^6.40|^7.37|^8.17|^9.0|^10.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.0|^10.5|^11.5"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Telescope\\TelescopeServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Telescope\\": "src/",
"Laravel\\Telescope\\Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
},
{
"name": "Mohamed Said",
"email": "mohamed@laravel.com"
}
],
"description": "An elegant debug assistant for the Laravel framework.",
"keywords": [
"debugging",
"laravel",
"monitoring"
],
"support": {
"issues": "https://github.com/laravel/telescope/issues",
"source": "https://github.com/laravel/telescope/tree/v5.7.0"
},
"time": "2025-03-27T17:25:52+00:00"
},
{
"name": "laravel/tinker",
"version": "v2.10.1",
@@ -2070,6 +2281,82 @@
],
"time": "2024-12-08T08:18:47+00:00"
},
{
"name": "livewire/livewire",
"version": "v3.6.3",
"source": {
"type": "git",
"url": "https://github.com/livewire/livewire.git",
"reference": "56aa1bb63a46e06181c56fa64717a7287e19115e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/livewire/livewire/zipball/56aa1bb63a46e06181c56fa64717a7287e19115e",
"reference": "56aa1bb63a46e06181c56fa64717a7287e19115e",
"shasum": ""
},
"require": {
"illuminate/database": "^10.0|^11.0|^12.0",
"illuminate/routing": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/validation": "^10.0|^11.0|^12.0",
"laravel/prompts": "^0.1.24|^0.2|^0.3",
"league/mime-type-detection": "^1.9",
"php": "^8.1",
"symfony/console": "^6.0|^7.0",
"symfony/http-kernel": "^6.2|^7.0"
},
"require-dev": {
"calebporzio/sushi": "^2.1",
"laravel/framework": "^10.15.0|^11.0|^12.0",
"mockery/mockery": "^1.3.1",
"orchestra/testbench": "^8.21.0|^9.0|^10.0",
"orchestra/testbench-dusk": "^8.24|^9.1|^10.0",
"phpunit/phpunit": "^10.4|^11.5",
"psy/psysh": "^0.11.22|^0.12"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Livewire": "Livewire\\Livewire"
},
"providers": [
"Livewire\\LivewireServiceProvider"
]
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Livewire\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Caleb Porzio",
"email": "calebporzio@gmail.com"
}
],
"description": "A front-end framework for Laravel.",
"support": {
"issues": "https://github.com/livewire/livewire/issues",
"source": "https://github.com/livewire/livewire/tree/v3.6.3"
},
"funding": [
{
"url": "https://github.com/livewire",
"type": "github"
}
],
"time": "2025-04-12T22:26:52+00:00"
},
{
"name": "monolog/monolog",
"version": "3.9.0",

View File

@@ -0,0 +1,5 @@
<?php
return [
'TRUSTED_IP' => explode(',', env("TRUSTED_IP", '127.0.0.1')),
];

236
laravel/config/pulse.php Normal file
View File

@@ -0,0 +1,236 @@
<?php
use Laravel\Pulse\Http\Middleware\Authorize;
use Laravel\Pulse\Pulse;
use Laravel\Pulse\Recorders;
return [
/*
|--------------------------------------------------------------------------
| Pulse Domain
|--------------------------------------------------------------------------
|
| This is the subdomain which the Pulse dashboard will be accessible from.
| When set to null, the dashboard will reside under the same domain as
| the application. Remember to configure your DNS entries correctly.
|
*/
'domain' => env('PULSE_DOMAIN'),
/*
|--------------------------------------------------------------------------
| Pulse Path
|--------------------------------------------------------------------------
|
| This is the path which the Pulse dashboard will be accessible from. Feel
| free to change this path to anything you'd like. Note that this won't
| affect the path of the internal API that is never exposed to users.
|
*/
'path' => env('PULSE_PATH', 'pulse'),
/*
|--------------------------------------------------------------------------
| Pulse Master Switch
|--------------------------------------------------------------------------
|
| This configuration option may be used to completely disable all Pulse
| data recorders regardless of their individual configurations. This
| provides a single option to quickly disable all Pulse recording.
|
*/
'enabled' => env('PULSE_ENABLED', true),
/*
|--------------------------------------------------------------------------
| Pulse Storage Driver
|--------------------------------------------------------------------------
|
| This configuration option determines which storage driver will be used
| while storing entries from Pulse's recorders. In addition, you also
| may provide any options to configure the selected storage driver.
|
*/
'storage' => [
'driver' => env('PULSE_STORAGE_DRIVER', 'database'),
'trim' => [
'keep' => env('PULSE_STORAGE_KEEP', '7 days'),
],
'database' => [
'connection' => env('PULSE_DB_CONNECTION'),
'chunk' => 1000,
],
],
/*
|--------------------------------------------------------------------------
| Pulse Ingest Driver
|--------------------------------------------------------------------------
|
| This configuration options determines the ingest driver that will be used
| to capture entries from Pulse's recorders. Ingest drivers are great to
| free up your request workers quickly by offloading the data storage.
|
*/
'ingest' => [
'driver' => env('PULSE_INGEST_DRIVER', 'storage'),
'buffer' => env('PULSE_INGEST_BUFFER', 5_000),
'trim' => [
'lottery' => [1, 1_000],
'keep' => env('PULSE_INGEST_KEEP', '7 days'),
],
'redis' => [
'connection' => env('PULSE_REDIS_CONNECTION'),
'chunk' => 1000,
],
],
/*
|--------------------------------------------------------------------------
| Pulse Cache Driver
|--------------------------------------------------------------------------
|
| This configuration option determines the cache driver that will be used
| for various tasks, including caching dashboard results, establishing
| locks for events that should only occur on one server and signals.
|
*/
'cache' => env('PULSE_CACHE_DRIVER'),
/*
|--------------------------------------------------------------------------
| Pulse Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will be assigned to every Pulse route, giving you the
| chance to add your own middleware to this list or change any of the
| existing middleware. Of course, reasonable defaults are provided.
|
*/
'middleware' => [
'web',
\App\Http\Middleware\ValidateIP::class
],
/*
|--------------------------------------------------------------------------
| Pulse Recorders
|--------------------------------------------------------------------------
|
| The following array lists the "recorders" that will be registered with
| Pulse, along with their configuration. Recorders gather application
| event data from requests and tasks to pass to your ingest driver.
|
*/
'recorders' => [
Recorders\CacheInteractions::class => [
'enabled' => env('PULSE_CACHE_INTERACTIONS_ENABLED', true),
'sample_rate' => env('PULSE_CACHE_INTERACTIONS_SAMPLE_RATE', 1),
'ignore' => [
...Pulse::defaultVendorCacheKeys(),
],
'groups' => [
'/^job-exceptions:.*/' => 'job-exceptions:*',
// '/:\d+/' => ':*',
],
],
Recorders\Exceptions::class => [
'enabled' => env('PULSE_EXCEPTIONS_ENABLED', true),
'sample_rate' => env('PULSE_EXCEPTIONS_SAMPLE_RATE', 1),
'location' => env('PULSE_EXCEPTIONS_LOCATION', true),
'ignore' => [
// '/^Package\\\\Exceptions\\\\/',
],
],
Recorders\Queues::class => [
'enabled' => env('PULSE_QUEUES_ENABLED', true),
'sample_rate' => env('PULSE_QUEUES_SAMPLE_RATE', 1),
'ignore' => [
// '/^Package\\\\Jobs\\\\/',
],
],
Recorders\Servers::class => [
'server_name' => env('PULSE_SERVER_NAME', gethostname()),
'directories' => explode(':', env('PULSE_SERVER_DIRECTORIES', '/')),
],
Recorders\SlowJobs::class => [
'enabled' => env('PULSE_SLOW_JOBS_ENABLED', true),
'sample_rate' => env('PULSE_SLOW_JOBS_SAMPLE_RATE', 1),
'threshold' => env('PULSE_SLOW_JOBS_THRESHOLD', 1000),
'ignore' => [
// '/^Package\\\\Jobs\\\\/',
],
],
Recorders\SlowOutgoingRequests::class => [
'enabled' => env('PULSE_SLOW_OUTGOING_REQUESTS_ENABLED', true),
'sample_rate' => env('PULSE_SLOW_OUTGOING_REQUESTS_SAMPLE_RATE', 1),
'threshold' => env('PULSE_SLOW_OUTGOING_REQUESTS_THRESHOLD', 1000),
'ignore' => [
// '#^http://127\.0\.0\.1:13714#', // Inertia SSR...
],
'groups' => [
// '#^https://api\.github\.com/repos/.*$#' => 'api.github.com/repos/*',
// '#^https?://([^/]*).*$#' => '\1',
// '#/\d+#' => '/*',
],
],
Recorders\SlowQueries::class => [
'enabled' => env('PULSE_SLOW_QUERIES_ENABLED', true),
'sample_rate' => env('PULSE_SLOW_QUERIES_SAMPLE_RATE', 1),
'threshold' => env('PULSE_SLOW_QUERIES_THRESHOLD', 1000),
'location' => env('PULSE_SLOW_QUERIES_LOCATION', true),
'max_query_length' => env('PULSE_SLOW_QUERIES_MAX_QUERY_LENGTH'),
'ignore' => [
'/(["`])pulse_[\w]+?\1/', // Pulse tables...
'/(["`])telescope_[\w]+?\1/', // Telescope tables...
],
],
Recorders\SlowRequests::class => [
'enabled' => env('PULSE_SLOW_REQUESTS_ENABLED', true),
'sample_rate' => env('PULSE_SLOW_REQUESTS_SAMPLE_RATE', 1),
'threshold' => env('PULSE_SLOW_REQUESTS_THRESHOLD', 1000),
'ignore' => [
'#^/'.env('PULSE_PATH', 'pulse').'$#', // Pulse dashboard...
'#^/telescope#', // Telescope dashboard...
],
],
Recorders\UserJobs::class => [
'enabled' => env('PULSE_USER_JOBS_ENABLED', true),
'sample_rate' => env('PULSE_USER_JOBS_SAMPLE_RATE', 1),
'ignore' => [
// '/^Package\\\\Jobs\\\\/',
],
],
Recorders\UserRequests::class => [
'enabled' => env('PULSE_USER_REQUESTS_ENABLED', true),
'sample_rate' => env('PULSE_USER_REQUESTS_SAMPLE_RATE', 1),
'ignore' => [
'#^/'.env('PULSE_PATH', 'pulse').'$#', // Pulse dashboard...
'#^/telescope#', // Telescope dashboard...
],
],
],
];

View File

@@ -0,0 +1,206 @@
<?php
use Laravel\Telescope\Http\Middleware\Authorize;
use Laravel\Telescope\Watchers;
return [
/*
|--------------------------------------------------------------------------
| Telescope Master Switch
|--------------------------------------------------------------------------
|
| This option may be used to disable all Telescope watchers regardless
| of their individual configuration, which simply provides a single
| and convenient way to enable or disable Telescope data storage.
|
*/
'enabled' => env('TELESCOPE_ENABLED', true),
/*
|--------------------------------------------------------------------------
| Telescope Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where Telescope will be accessible from. If the
| setting is null, Telescope will reside under the same domain as the
| application. Otherwise, this value will be used as the subdomain.
|
*/
'domain' => env('TELESCOPE_DOMAIN'),
/*
|--------------------------------------------------------------------------
| Telescope Path
|--------------------------------------------------------------------------
|
| This is the URI path where Telescope will be accessible from. Feel free
| to change this path to anything you like. Note that the URI will not
| affect the paths of its internal API that aren't exposed to users.
|
*/
'path' => env('TELESCOPE_PATH', 'telescope'),
/*
|--------------------------------------------------------------------------
| Telescope Storage Driver
|--------------------------------------------------------------------------
|
| This configuration options determines the storage driver that will
| be used to store Telescope's data. In addition, you may set any
| custom options as needed by the particular driver you choose.
|
*/
'driver' => env('TELESCOPE_DRIVER', 'database'),
'storage' => [
'database' => [
'connection' => env('DB_CONNECTION', 'mysql'),
'chunk' => 1000,
],
],
/*
|--------------------------------------------------------------------------
| Telescope Queue
|--------------------------------------------------------------------------
|
| This configuration options determines the queue connection and queue
| which will be used to process ProcessPendingUpdate jobs. This can
| be changed if you would prefer to use a non-default connection.
|
*/
'queue' => [
'connection' => env('TELESCOPE_QUEUE_CONNECTION', null),
'queue' => env('TELESCOPE_QUEUE', null),
'delay' => env('TELESCOPE_QUEUE_DELAY', 10),
],
/*
|--------------------------------------------------------------------------
| Telescope Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will be assigned to every Telescope route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => [
'web',
\App\Http\Middleware\ValidateIP::class,
],
/*
|--------------------------------------------------------------------------
| Allowed / Ignored Paths & Commands
|--------------------------------------------------------------------------
|
| The following array lists the URI paths and Artisan commands that will
| not be watched by Telescope. In addition to this list, some Laravel
| commands, like migrations and queue commands, are always ignored.
|
*/
'only_paths' => [
// 'api/*'
],
'ignore_paths' => [
'livewire*',
'nova-api*',
'pulse*',
],
'ignore_commands' => [
//
],
/*
|--------------------------------------------------------------------------
| Telescope Watchers
|--------------------------------------------------------------------------
|
| The following array lists the "watchers" that will be registered with
| Telescope. The watchers gather the application's profile data when
| a request or task is executed. Feel free to customize this list.
|
*/
'watchers' => [
Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true),
Watchers\CacheWatcher::class => [
'enabled' => env('TELESCOPE_CACHE_WATCHER', true),
'hidden' => [],
],
Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true),
Watchers\CommandWatcher::class => [
'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
'ignore' => [],
],
Watchers\DumpWatcher::class => [
'enabled' => env('TELESCOPE_DUMP_WATCHER', true),
'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false),
],
Watchers\EventWatcher::class => [
'enabled' => env('TELESCOPE_EVENT_WATCHER', true),
'ignore' => [],
],
Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
Watchers\GateWatcher::class => [
'enabled' => env('TELESCOPE_GATE_WATCHER', true),
'ignore_abilities' => [],
'ignore_packages' => true,
'ignore_paths' => [],
],
Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
Watchers\LogWatcher::class => [
'enabled' => env('TELESCOPE_LOG_WATCHER', true),
'level' => 'error',
],
Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
Watchers\ModelWatcher::class => [
'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
'events' => ['eloquent.*'],
'hydrations' => true,
],
Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
Watchers\QueryWatcher::class => [
'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
'ignore_packages' => true,
'ignore_paths' => [],
'slow' => 100,
],
Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
Watchers\RequestWatcher::class => [
'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
'ignore_http_methods' => [],
'ignore_status_codes' => [],
],
Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true),
],
];

View File

@@ -0,0 +1,44 @@
<?php
namespace Database\Factories;
use App\Models\Category;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<\App\Models\Call>
*/
class CallFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'telephone_id' => $this->faker->numerify('tel-####'),
'caller_phone_number' => '09' . $this->faker->unique()->randomNumber(9, true),
'operator_id' => User::factory(),
'operator_username' => function (array $attributes) {
return User::find($attributes['operator_id'])->username;
},
'operator_full_name' => function (array $attributes) {
return User::find($attributes['operator_id'])->full_name;
},
'description' => $this->faker->text,
'category_id' => Category::factory(),
'category_name' => function (array $attributes) {
return Category::find($attributes['category_id'])->category_name;
},
'subcategory_id' => function (array $attributes) {
return Category::find($attributes['category_id'])->subcategory_id;
},
'subcategory_name' => function (array $attributes) {
return Category::find($attributes['category_id'])->subcategory_name;
},
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Database\Factories;
use App\Models\Call;
use App\Models\Event;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\CallHistory>
*/
class CallHistoryFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'call_id' => Call::factory(),
'telephone_id' => $this->faker->numerify('tel-####'),
'caller_phone_number' => '09' . $this->faker->randomNumber(9, true),
'event_id' => Event::factory(),
'event_name' => function (array $attributes) {
return Event::query()->find($attributes['event_id'])->name;
}
];
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Category>
*/
class CategoryFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'category_id' => $this->faker->randomNumber(3, true),
'category_name' => $this->faker->words(3, true),
'subcategory_id' => $this->faker->randomNumber(4, true),
'subcategory_name' => $this->faker->words(3, true)
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Event>
*/
class EventFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => $this->faker->sentence,
];
}
}

View File

@@ -0,0 +1,49 @@
<?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('calls', function (Blueprint $table) {
$table->id();
$table->string('telephone_id');
$table->string('caller_phone_number');
$table->foreignId('province_id')
->nullable()
->constrained();
$table->string('province_fa')->nullable();
$table->foreignId('operator_id')
->nullable()
->constrained('users');
$table->string('operator_username')->nullable();
$table->string('operator_full_name')->nullable();
$table->unsignedSmallInteger('category_id')->nullable();
$table->string('category_name')->nullable();
$table->unsignedSmallInteger('subcategory_id')->nullable();
$table->string('subcategory_name')->nullable();
$table->text('description')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('calls');
}
};

View File

@@ -0,0 +1,33 @@
<?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('categories', function (Blueprint $table) {
$table->id();
$table->unsignedSmallInteger('category_id');
$table->string('category_name');
$table->unsignedSmallInteger('subcategory_id')->nullable();
$table->string('subcategory_name')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('categories');
}
};

View File

@@ -0,0 +1,37 @@
<?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('call_histories', function (Blueprint $table) {
$table->id();
$table->foreignId('call_id')
->constrained('calls');
$table->string('telephone_id');
$table->string('caller_phone_number');
$table->foreignId('event_id')
->constrained();
$table->string('event_name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('call_histories');
}
};

View File

@@ -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('events', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('events');
}
};

View File

@@ -0,0 +1,70 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Get the migration connection name.
*/
public function getConnection(): ?string
{
return config('telescope.storage.database.connection');
}
/**
* Run the migrations.
*/
public function up(): void
{
$schema = Schema::connection($this->getConnection());
$schema->create('telescope_entries', function (Blueprint $table) {
$table->bigIncrements('sequence');
$table->uuid('uuid');
$table->uuid('batch_id');
$table->string('family_hash')->nullable();
$table->boolean('should_display_on_index')->default(true);
$table->string('type', 20);
$table->longText('content');
$table->dateTime('created_at')->nullable();
$table->unique('uuid');
$table->index('batch_id');
$table->index('family_hash');
$table->index('created_at');
$table->index(['type', 'should_display_on_index']);
});
$schema->create('telescope_entries_tags', function (Blueprint $table) {
$table->uuid('entry_uuid');
$table->string('tag');
$table->primary(['entry_uuid', 'tag']);
$table->index('tag');
$table->foreign('entry_uuid')
->references('uuid')
->on('telescope_entries')
->onDelete('cascade');
});
$schema->create('telescope_monitoring', function (Blueprint $table) {
$table->string('tag')->primary();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
$schema = Schema::connection($this->getConnection());
$schema->dropIfExists('telescope_entries_tags');
$schema->dropIfExists('telescope_entries');
$schema->dropIfExists('telescope_monitoring');
}
};

View File

@@ -0,0 +1,84 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Laravel\Pulse\Support\PulseMigration;
return new class extends PulseMigration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (! $this->shouldRun()) {
return;
}
Schema::create('pulse_values', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('timestamp');
$table->string('type');
$table->mediumText('key');
match ($this->driver()) {
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
'sqlite' => $table->string('key_hash'),
};
$table->mediumText('value');
$table->index('timestamp'); // For trimming...
$table->index('type'); // For fast lookups and purging...
$table->unique(['type', 'key_hash']); // For data integrity and upserts...
});
Schema::create('pulse_entries', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('timestamp');
$table->string('type');
$table->mediumText('key');
match ($this->driver()) {
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
'sqlite' => $table->string('key_hash'),
};
$table->bigInteger('value')->nullable();
$table->index('timestamp'); // For trimming...
$table->index('type'); // For purging...
$table->index('key_hash'); // For mapping...
$table->index(['timestamp', 'type', 'key_hash', 'value']); // For aggregate queries...
});
Schema::create('pulse_aggregates', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('bucket');
$table->unsignedMediumInteger('period');
$table->string('type');
$table->mediumText('key');
match ($this->driver()) {
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
'sqlite' => $table->string('key_hash'),
};
$table->string('aggregate');
$table->decimal('value', 20, 2);
$table->unsignedInteger('count')->nullable();
$table->unique(['bucket', 'period', 'type', 'aggregate', 'key_hash']); // Force "on duplicate update"...
$table->index(['period', 'bucket']); // For trimming...
$table->index('type'); // For purging...
$table->index(['period', 'type', 'aggregate', 'bucket']); // For aggregate queries...
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('pulse_values');
Schema::dropIfExists('pulse_entries');
Schema::dropIfExists('pulse_aggregates');
}
};

View File

@@ -0,0 +1,17 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class CallHistorySeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class CallSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
}
}

View File

@@ -0,0 +1,117 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class CategorySeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$data = [
[
'category_id' => 1,
'category_name' => 'اطلاعات راه',
'subcategory_id' => 1,
'subcategory_name' => 'اطلاعات باز و بسته',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 1,
'category_name' => 'اطلاعات راه',
'subcategory_id' => 2,
'subcategory_name' => 'پرس و جو دلیل ترافیک',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 1,
'category_name' => 'اطلاعات راه',
'subcategory_id' => 3,
'subcategory_name' => 'آب و هوا',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 1,
'category_name' => 'اطلاعات راه',
'subcategory_id' => 4,
'subcategory_name' => 'یک طرفه دو طرفه',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 1,
'category_name' => 'اطلاعات راه',
'subcategory_id' => 5,
'subcategory_name' => 'مسیر مسافت',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 2,
'category_name' => 'شکایت',
'subcategory_id' => 1,
'subcategory_name' => 'شکایت از راه',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 2,
'category_name' => 'شکایت',
'subcategory_id' => 2,
'subcategory_name' => 'شکایت از اتوبوس',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 2,
'category_name' => 'شکایت',
'subcategory_id' => 3,
'subcategory_name' => 'شکایت از حمل و نقل عمومی',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 2,
'category_name' => 'شکایت',
'subcategory_id' => 4,
'subcategory_name' => 'نیاز به برف روبی',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 3,
'category_name' => 'سایر',
'subcategory_id' => 1,
'subcategory_name' => 'اشتباه',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 3,
'category_name' => 'سایر',
'subcategory_id' => 2,
'subcategory_name' => 'مزاحم',
'created_at' => now(),
'updated_at'=> now()
],
[
'category_id' => 3,
'category_name' => 'سایر',
'subcategory_id' => 3,
'subcategory_name' => 'اختلال در ارتباط',
'created_at' => now(),
'updated_at'=> now()
],
];
DB::table('categories')->insert($data);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class EventSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
DB::table('events')->insert([
[
'id' => 1,
'name' => 'تماس ساخته شد',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 2,
'name' => 'اپراتور آفلاین بود',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 3,
'name' => 'مشکل در ارتباط با اپراتور (نقص فنی)',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 4,
'name' => 'اپراتور اطلاعات تماس را ثبت کرد',
'created_at' => now(),
'updated_at' => now()
],
[
'id' => 5,
'name' => 'سرور پیام رسان قطع میباشد',
'created_at' => now(),
'updated_at' => now()
],
]);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,5 @@
{
"/app.js": "/app.js?id=99e99836705c54c9dc04352a9907bc7f",
"/app-dark.css": "/app-dark.css?id=1ea407db56c5163ae29311f1f38eb7b9",
"/app.css": "/app.css?id=de4c978567bfd90b38d186937dee5ccf"
}

View File

@@ -0,0 +1,19 @@
<x-pulse>
<livewire:pulse.servers cols="full" />
<livewire:pulse.usage cols="4" rows="2" />
<livewire:pulse.queues cols="4" />
<livewire:pulse.cache cols="4" />
<livewire:pulse.slow-queries cols="8" />
<livewire:pulse.exceptions cols="6" />
<livewire:pulse.slow-requests cols="6" />
<livewire:pulse.slow-jobs cols="6" />
<livewire:pulse.slow-outgoing-requests cols="6" />
</x-pulse>

View File

@@ -2,6 +2,7 @@
use App\Http\Controllers\Admin\UserManagementController;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\CallController;
use App\Http\Controllers\ProfileController;
use App\Http\Middleware\SuperAdminCheck;
use Illuminate\Support\Facades\Route;
@@ -35,3 +36,16 @@ Route::prefix('users')
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::middleware('auth')->get('/categories', [CategoryController::class, 'list'])->name('categories.list');