From 32b1db3d78fc292dfb19327a3157db17db14c9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Jaussoin?= Date: Mon, 16 Mar 2026 17:07:44 +0100 Subject: [PATCH] Fix FLEXIAPI-455 Add GET endpoints to retrieve an account call logs, documentation and tests --- .../Api/Account/StatisticsCallController.php | 32 +++++++++++++++++++ .../{ => Admin}/StatisticsCallController.php | 19 ++++++++++- flexiapi/app/StatisticsCall.php | 5 +++ flexiapi/app/StatisticsCallDevice.php | 2 +- .../api/documentation/statistics.blade.php | 6 ++++ flexiapi/routes/api.php | 13 ++++++-- flexiapi/tests/Feature/ApiStatisticsTest.php | 27 ++++++++++++++-- 7 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 flexiapi/app/Http/Controllers/Api/Account/StatisticsCallController.php rename flexiapi/app/Http/Controllers/Api/{ => Admin}/StatisticsCallController.php (85%) diff --git a/flexiapi/app/Http/Controllers/Api/Account/StatisticsCallController.php b/flexiapi/app/Http/Controllers/Api/Account/StatisticsCallController.php new file mode 100644 index 0000000..94e9e90 --- /dev/null +++ b/flexiapi/app/Http/Controllers/Api/Account/StatisticsCallController.php @@ -0,0 +1,32 @@ +. +*/ + +namespace App\Http\Controllers\Api\Account; + +use App\Http\Controllers\Controller; +use Illuminate\Http\Request; +use App\Http\Controllers\Api\Admin\StatisticsCallController as AdminStatisticsCallController; + +class StatisticsCallController extends Controller +{ + public function index(Request $request) + { + return (new AdminStatisticsCallController)->index($request, $request->user()->id); + } +} diff --git a/flexiapi/app/Http/Controllers/Api/StatisticsCallController.php b/flexiapi/app/Http/Controllers/Api/Admin/StatisticsCallController.php similarity index 85% rename from flexiapi/app/Http/Controllers/Api/StatisticsCallController.php rename to flexiapi/app/Http/Controllers/Api/Admin/StatisticsCallController.php index c38b316..63f85ef 100644 --- a/flexiapi/app/Http/Controllers/Api/StatisticsCallController.php +++ b/flexiapi/app/Http/Controllers/Api/Admin/StatisticsCallController.php @@ -17,8 +17,9 @@ along with this program. If not, see . */ -namespace App\Http\Controllers\Api; +namespace App\Http\Controllers\Api\Admin; +use App\Account; use App\Http\Controllers\Controller; use App\StatisticsCall; use App\StatisticsCallDevice; @@ -27,6 +28,22 @@ use Illuminate\Support\Facades\Log; class StatisticsCallController extends Controller { + public function index(Request $request, ?int $accountId) + { + $account = Account::findOrFail($accountId); + + $toQuery = StatisticsCall::query() + ->where('to_domain', $account->domain) + ->where('to_username', $account->username); + $calls = StatisticsCall::where('from_domain', $account->domain) + ->where('from_username', $account->username); + + return $calls->with('devices') + ->union($toQuery) + ->orderBy('initiated_at', 'desc') + ->paginate(30); + } + public function store(Request $request) { $request->validate([ diff --git a/flexiapi/app/StatisticsCall.php b/flexiapi/app/StatisticsCall.php index cb9b960..2198e66 100644 --- a/flexiapi/app/StatisticsCall.php +++ b/flexiapi/app/StatisticsCall.php @@ -34,6 +34,11 @@ class StatisticsCall extends Model protected $casts = ['initiated_at' => 'datetime', 'ended_at' => 'datetime']; protected $keyType = 'string'; + public function devices() + { + return $this->hasMany(StatisticsCallDevice::class, 'call_id', 'id'); + } + public function accountFrom() { return $this->belongsTo(Account::class, ['username', 'domain'], ['to_username', 'to_domain']); diff --git a/flexiapi/app/StatisticsCallDevice.php b/flexiapi/app/StatisticsCallDevice.php index 6717df2..8a220c0 100644 --- a/flexiapi/app/StatisticsCallDevice.php +++ b/flexiapi/app/StatisticsCallDevice.php @@ -31,6 +31,6 @@ class StatisticsCallDevice extends Model public function call() { - return $this->hasOne(StatisticsCall::class, 'id', 'call_id'); + return $this->belongsTo(StatisticsCall::class, 'id', 'call_id'); } } diff --git a/flexiapi/resources/views/api/documentation/statistics.blade.php b/flexiapi/resources/views/api/documentation/statistics.blade.php index 7e31f22..e614244 100644 --- a/flexiapi/resources/views/api/documentation/statistics.blade.php +++ b/flexiapi/resources/views/api/documentation/statistics.blade.php @@ -2,6 +2,12 @@ FlexiAPI can record logs generated by the FlexiSIP server and compile them into statistics. +### `GET /api/accounts/{id/me}/statistics/calls` +Admin +User + +Retrieve all the calls of an account, ordered by most recent first and paginated with their related `devices`. + ### `POST /statistics/messages` Admin diff --git a/flexiapi/routes/api.php b/flexiapi/routes/api.php index d95270a..5bb7fdc 100644 --- a/flexiapi/routes/api.php +++ b/flexiapi/routes/api.php @@ -41,6 +41,7 @@ use App\Http\Controllers\Api\Admin\Account\CreationTokenController as AdminCreat use App\Http\Controllers\Api\Admin\Account\DictionaryController; use App\Http\Controllers\Api\Admin\Account\TypeController; use App\Http\Controllers\Api\Admin\Account\VoicemailController as AdminVoicemailController; +use App\Http\Controllers\Api\Account\StatisticsCallController; use App\Http\Controllers\Api\Admin\AccountController as AdminAccountController; use App\Http\Controllers\Api\Admin\ExternalAccountController; use App\Http\Controllers\Api\Admin\MessageController; @@ -49,11 +50,11 @@ use App\Http\Controllers\Api\Admin\Space\CardDavServerController; use App\Http\Controllers\Api\Admin\Space\ContactsListController; use App\Http\Controllers\Api\Admin\Space\EmailServerController; use App\Http\Controllers\Api\Admin\SpaceController; +use App\Http\Controllers\Api\Admin\StatisticsCallController as AdminStatisticsCallController; use App\Http\Controllers\Api\Admin\VcardsStorageController as AdminVcardsStorageController; use App\Http\Controllers\Api\ApiController; use App\Http\Controllers\Api\PhoneCountryController; use App\Http\Controllers\Api\PingController; -use App\Http\Controllers\Api\StatisticsCallController; use App\Http\Controllers\Api\StatisticsMessageController; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Http\Request; @@ -114,6 +115,10 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo Route::apiResource('vcards-storage', VcardsStorageController::class); Route::apiResource('voicemails', VoicemailController::class, ['only' => ['index', 'show', 'store', 'destroy']]); Route::apiResource('call_forwardings', CallForwardingController::class); + + Route::prefix('statistics/calls')->controller(\App\Http\Controllers\Api\Account\StatisticsCallController::class)->group(function () { + Route::get('/', 'index'); + }); }); Route::group(['middleware' => ['auth.admin']], function () { @@ -208,12 +213,16 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo Route::delete('/', 'destroy'); }); + Route::prefix('accounts/{id}/statistics/calls')->controller(AdminStatisticsCallController::class)->group(function () { + Route::get('/', 'index'); + }); + Route::prefix('statistics/messages')->controller(StatisticsMessageController::class)->group(function () { Route::post('/', 'store'); Route::patch('{message_id}/to/{to}/devices/{device_id}', 'storeDevice'); }); - Route::prefix('statistics/calls')->controller(StatisticsCallController::class)->group(function () { + Route::prefix('statistics/calls')->controller(AdminStatisticsCallController::class)->group(function () { Route::post('/', 'store'); Route::patch('{call_id}', 'update'); Route::patch('{call_id}/devices/{device_id}', 'storeDevice'); diff --git a/flexiapi/tests/Feature/ApiStatisticsTest.php b/flexiapi/tests/Feature/ApiStatisticsTest.php index 93a0498..241daad 100644 --- a/flexiapi/tests/Feature/ApiStatisticsTest.php +++ b/flexiapi/tests/Feature/ApiStatisticsTest.php @@ -31,6 +31,7 @@ class ApiStatisticsTest extends TestCase protected $routeMessages = '/api/statistics/messages'; protected $routeCalls = '/api/statistics/calls'; + protected $routeAccountCalls = '/api/accounts/me/statistics/calls'; public function testMessages() { @@ -140,6 +141,9 @@ class ApiStatisticsTest extends TestCase 'username' => $fromUsername, 'domain' => $fromDomain, ]); + $account->generateUserApiKey(); + + $routeAdminCalls = '/api/accounts/' . $account->id . '/statistics/calls'; $this->keyAuthenticated($admin) ->json('POST', $this->routeCalls, [ @@ -150,9 +154,19 @@ class ApiStatisticsTest extends TestCase ]) ->assertStatus(200); - $this->assertDatabaseHas('statistics_calls', [ - 'id' => $id - ]); + $this->keyAuthenticated($admin) + ->get($routeAdminCalls) + ->assertStatus(200) + ->assertJsonFragment([ + 'id' => $id + ]); + + $this->keyAuthenticated($account) + ->get($this->routeAccountCalls) + ->assertStatus(200) + ->assertJsonFragment([ + 'id' => $id + ]); $this->keyAuthenticated($admin) ->json('POST', $this->routeCalls, [ @@ -207,6 +221,13 @@ class ApiStatisticsTest extends TestCase $this->assertSame(1, StatisticsCallDevice::count()); + $this->keyAuthenticated($admin) + ->get($routeAdminCalls) + ->assertStatus(200) + ->assertJsonFragment([ + 'device_id' => $device + ]); + // Update $endedAt = $this->faker->iso8601();