Add call logs browsing, general and per account

This commit is contained in:
Timothée Jaussoin 2023-10-16 09:05:45 +00:00
parent 95707c7749
commit 179c76251d
19 changed files with 466 additions and 109 deletions

View file

@ -32,6 +32,7 @@ use Awobaz\Compoships\Compoships;
use App\ApiKey;
use App\Password;
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
use Doctrine\DBAL\Query;
class Account extends Authenticatable
{
@ -91,6 +92,16 @@ class Account extends Authenticatable
return $query->where('id', '<', 0);
}
public static function subByContactsList($query, int $contactsListId)
{
return $query->from('accounts')
->whereIn('id', function ($query) use ($contactsListId) {
$query->select('contact_id')
->from('contacts_list_contact')
->where('contacts_list_id', $contactsListId);
});
}
/**
* Relations
*/

View file

@ -5,7 +5,9 @@ namespace App\Http\Controllers\Admin;
use App\Account;
use App\Http\Controllers\Controller;
use App\Libraries\StatisticsGraphFactory;
use App\StatisticsCall;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AccountStatisticsController extends Controller
{
@ -59,4 +61,41 @@ class AccountStatisticsController extends Controller
'callsToGraph' => $callsToGraph,
]);
}
public function editCallLogs(Request $request, int $accountId)
{
return redirect()->route('admin.account.statistics.show_call_logs', [
'from' => $request->get('from'),
'to' => $request->get('to'),
'account' => $accountId
]);
}
public function showCallLogs(Request $request, int $accountId)
{
$account = Account::findOrFail($accountId);
$toQuery = DB::table('statistics_calls')
->where('to_domain', $account->domain)
->where('to_username', $account->username);
$calls = StatisticsCall::where('from_domain', $account->domain)
->where('from_username', $account->username);
if ($request->get('to')) {
$toQuery = $toQuery->where('initiated_at', '<=', $request->get('to'));
$calls = $calls->where('initiated_at', '<=', $request->get('to'));
}
if ($request->get('from')) {
$toQuery = $toQuery->where('initiated_at', '>=', $request->get('from'));
$calls = $calls->where('initiated_at', '>=', $request->get('from'));
}
$calls = $calls->union($toQuery);
return view('admin.account.statistics.show_call_logs', [
'account' => $account,
'calls' => $calls->orderBy('initiated_at', 'desc')->paginate(30),
'request' => $request,
]);
}
}

View file

@ -1,4 +1,21 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Admin;
@ -32,11 +49,6 @@ class StatisticsController extends Controller
]);
}
/*public function search(Request $request)
{
return redirect()->route('admin.statistics.search', $request->except('_token', 'query'));
}*/
public function show(Request $request, string $type = 'messages')
{
$request->validate([
@ -45,7 +57,7 @@ class StatisticsController extends Controller
'by' => 'in:day,week,month,year',
]);
$graph = new StatisticsGraphFactory($request, $type, fromDomain: $request->get('domain'));
$graph = new StatisticsGraphFactory($request, type: $type, domain: $request->get('domain'));
$config = $graph->getConfig();
$domains = collect();
@ -77,4 +89,49 @@ class StatisticsController extends Controller
'request' => $request
]);
}
public function editCallLogs(Request $request)
{
return redirect()->route('admin.statistics.show_call_logs', [
'from' => $request->get('from'),
'to' => $request->get('to'),
'domain' => $request->get('domain'),
'contacts_list' => $request->get('contacts_list'),
]);
}
public function showCallLogs(Request $request)
{
$fromQuery = StatisticsCall::query();
$toQuery = StatisticsCall::query();
if ($request->get('domain')) {
$fromQuery->where('to_domain', $request->get('domain'));
$toQuery->where('from_domain', $request->get('domain'));
}
if ($request->get('to')) {
$fromQuery->where('initiated_at', '<=', $request->get('to'));
$toQuery->where('initiated_at', '<=', $request->get('to'));
}
if ($request->get('from')) {
$fromQuery->where('initiated_at', '>=', $request->get('from'));
$toQuery->where('initiated_at', '>=', $request->get('from'));
}
if ($request->has('contacts_list')) {
$fromQuery->fromByContactsList($request->get('contacts_list'));
$toQuery->toByContactsList($request->get('contacts_list'));
}
$calls = $fromQuery->union($toQuery);
return view('admin.statistics.show_call_logs', [
'calls' => $calls->orderBy('initiated_at', 'desc')->paginate(30),
'domains' => StatisticsCall::groupBy('from_domain')->pluck('from_domain'),
'contacts_lists' => ContactsList::all()->pluck('title', 'id'),
'request' => $request,
]);
}
}

View file

@ -20,7 +20,6 @@
namespace App\Libraries;
use App\Account;
use App\ContactsList;
use App\StatisticsCall;
use App\StatisticsMessage;
use Carbon\Carbon;
@ -37,6 +36,7 @@ class StatisticsGraphFactory
public function __construct(
private Request $request,
private string $type = 'messages',
public ?string $domain = null, // both from and to filter
public ?string $fromUsername = null,
public ?string $fromDomain = null,
public ?string $toUsername = null,
@ -53,58 +53,82 @@ class StatisticsGraphFactory
case 'messages':
$dateColumn = 'sent_at';
$label = 'Messages';
$this->data = StatisticsMessage::orderBy($dateColumn, 'asc');
$fromQuery = StatisticsMessage::query();
$toQuery = StatisticsMessage::query();
if (!config('app.admins_manage_multi_domains')) {
$this->data->where('from_domain', config('app.sip_domain'));
$fromQuery->where('from_domain', config('app.sip_domain'));
$toQuery->toDomain($this->domain);
} elseif ($this->domain) {
$fromQuery->where('from_domain', $this->domain);
$toQuery->toDomain($this->domain);
} elseif ($this->fromDomain) {
$this->data->where('from_domain', $this->fromDomain)->orderBy('from_domain');
$fromQuery->where('from_domain', $this->fromDomain)->orderBy('from_domain');
if ($this->fromUsername) {
$this->data->where('from_username', $this->fromUsername);
$fromQuery->where('from_username', $this->fromUsername);
}
} elseif ($this->toDomain && $this->toUsername) {
$this->data->whereIn('id', function ($query) {
$query->select('message_id')
->from('statistics_message_devices')
->where('to_username', $this->toUsername)
->where('to_domain', $this->toDomain);
});
$toQuery->toUsernameDomain($this->toUsername, $this->toDomain);
}
if ($this->request->has('contacts_list')) {
$fromQuery = $fromQuery->fromByContactsList($this->request->get('contacts_list'));
$toQuery = $toQuery->toByContactsList($this->request->get('contacts_list'));
}
$this->data = $fromQuery; //->union($toQuery);
$this->data->orderBy($dateColumn, 'asc');
break;
case 'calls':
$dateColumn = 'initiated_at';
$label = 'Calls';
$this->data = StatisticsCall::orderBy($dateColumn, 'asc');
$fromQuery = StatisticsCall::query();
$toQuery = StatisticsCall::query();
if (!config('app.admins_manage_multi_domains')) {
$this->data->where('from_domain', config('app.sip_domain'));
$fromQuery->where('from_domain', config('app.sip_domain'));
$toQuery->where('to_domain', config('app.sip_domain'));
} elseif ($this->domain) {
$fromQuery = $fromQuery->where('to_domain', $this->domain);
$toQuery = $toQuery->where('from_domain', $this->domain);
} elseif ($this->fromDomain) {
$this->data->where('from_domain', $this->fromDomain)->orderBy('from_domain');
$fromQuery->where('from_domain', $this->fromDomain)->orderBy('from_domain');
if ($this->fromUsername) {
$this->data->where('from_username', $this->fromUsername);
$fromQuery->where('from_username', $this->fromUsername);
}
} elseif ($this->toDomain) {
$this->data->where('to_domain', $this->toDomain)->orderBy('to_domain');
$toQuery->where('to_domain', $this->toDomain)->orderBy('to_domain');
if ($this->toUsername) {
$this->data->where('to_username', $this->toUsername);
$toQuery->where('to_username', $this->toUsername);
}
}
if ($this->request->has('contacts_list')) {
$fromQuery = $fromQuery->fromByContactsList($this->request->get('contacts_list'));
$toQuery = $toQuery->toByContactsList($this->request->get('contacts_list'));
}
$this->data = $fromQuery; //->union($toQuery);
$this->data->orderBy($dateColumn, 'asc');
break;
case 'accounts':
$label = 'Accounts';
$this->data = Account::orderBy($dateColumn, 'asc');
// Accounts doesn't have a from and to
$this->domain = $this->domain ?? $this->fromDomain;
if (!config('app.admins_manage_multi_domains')) {
$this->data->where('domain', config('app.sip_domain'));
} elseif ($this->fromDomain) {
$this->data->where('domain', $this->fromDomain)->orderBy('domain');
} elseif ($this->domain) {
$this->data->where('domain', $this->domain);
if ($this->fromUsername) {
$this->data->where('username', $this->fromUsername);

View file

@ -23,6 +23,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Awobaz\Compoships\Compoships;
use Illuminate\Database\Eloquent\Builder;
class StatisticsCall extends Model
{
@ -42,4 +43,36 @@ class StatisticsCall extends Model
{
return $this->belongsTo(Account::class, ['username', 'domain'], ['to_username', 'to_domain']);
}
public function getFromAttribute()
{
return $this->attributes['from_username'] . '@' . $this->attributes['from_domain'];
}
public function getToAttribute()
{
return $this->attributes['to_username'] . '@' . $this->attributes['to_domain'];
}
public function scopeToByContactsList(Builder $query, int $contactsListId)
{
return $query->whereIn('to_domain', function ($query) use ($contactsListId) {
Account::subByContactsList($query, $contactsListId)
->select('domain');
})->whereIn('to_username', function ($query) use ($contactsListId) {
Account::subByContactsList($query, $contactsListId)
->select('username');
});
}
public function scopeFromByContactsList(Builder $query, int $contactsListId)
{
return $query->whereIn('from_domain', function ($query) use ($contactsListId) {
Account::subByContactsList($query, $contactsListId)
->select('domain');
})->whereIn('from_username', function ($query) use ($contactsListId) {
Account::subByContactsList($query, $contactsListId)
->select('username');
});
}
}

View file

@ -23,6 +23,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Awobaz\Compoships\Compoships;
use Awobaz\Compoships\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class StatisticsMessage extends Model
{
@ -37,4 +38,48 @@ class StatisticsMessage extends Model
{
return $this->belongsTo(Account::class, ['username', 'domain'], ['to_username', 'to_domain']);
}
public function scopeToUsernameDomain(Builder $query, ?string $username, ?string $domain)
{
return $query->whereIn('id', function ($query) use ($username, $domain) {
$query->select('message_id')
->from('statistics_message_devices')
->where('to_username', $username)
->where('to_domain', $domain);
});
}
public function scopeToDomain(Builder $query, ?string $domain)
{
return $query->whereIn('id', function ($query) use ($domain) {
$query->select('message_id')
->from('statistics_message_devices')
->where('to_domain', $domain);
});
}
public function scopeToByContactsList(Builder $query, int $contactsListId)
{
return $query->whereIn('id', function ($query) use ($contactsListId) {
$query->select('message_id')
->from('statistics_message_devices')
->whereIn('to_domain', function ($query) use ($contactsListId) {
Account::subByContactsList($query, $contactsListId)
->select('domain');
})->whereIn('to_username', function ($query) use ($contactsListId) {
Account::subByContactsList($query, $contactsListId)
->select('username');
});
});
}
public function scopeFromByContactsList(Builder $query, int $contactsListId)
{
return $query->whereIn('from_domain', function ($query) use ($contactsListId) {
Account::subByContactsList($query, $contactsListId)
->select('domain');
})->whereIn('from_username', function ($query) use ($contactsListId) {
Account::subByContactsList($query, $contactsListId)
->select('username');
});
}
}

80
flexiapi/composer.lock generated
View file

@ -461,16 +461,16 @@
},
{
"name": "doctrine/dbal",
"version": "3.7.0",
"version": "3.7.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf"
"reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/00d03067f07482f025d41ab55e4ba0db5eca2cdf",
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/5b7bd66c9ff58c04c5474ab85edce442f8081cb2",
"reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2",
"shasum": ""
},
"require": {
@ -554,7 +554,7 @@
],
"support": {
"issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/3.7.0"
"source": "https://github.com/doctrine/dbal/tree/3.7.1"
},
"funding": [
{
@ -570,7 +570,7 @@
"type": "tidelift"
}
],
"time": "2023-09-26T20:56:55+00:00"
"time": "2023-10-06T05:06:20+00:00"
},
{
"name": "doctrine/deprecations",
@ -1320,21 +1320,21 @@
},
{
"name": "fruitcake/php-cors",
"version": "v1.2.0",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/fruitcake/php-cors.git",
"reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e"
"reference": "3d158f36e7875e2f040f37bc0573956240a5a38b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruitcake/php-cors/zipball/58571acbaa5f9f462c9c77e911700ac66f446d4e",
"reference": "58571acbaa5f9f462c9c77e911700ac66f446d4e",
"url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b",
"reference": "3d158f36e7875e2f040f37bc0573956240a5a38b",
"shasum": ""
},
"require": {
"php": "^7.4|^8.0",
"symfony/http-foundation": "^4.4|^5.4|^6"
"symfony/http-foundation": "^4.4|^5.4|^6|^7"
},
"require-dev": {
"phpstan/phpstan": "^1.4",
@ -1344,7 +1344,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.1-dev"
"dev-master": "1.2-dev"
}
},
"autoload": {
@ -1375,7 +1375,7 @@
],
"support": {
"issues": "https://github.com/fruitcake/php-cors/issues",
"source": "https://github.com/fruitcake/php-cors/tree/v1.2.0"
"source": "https://github.com/fruitcake/php-cors/tree/v1.3.0"
},
"funding": [
{
@ -1387,7 +1387,7 @@
"type": "github"
}
],
"time": "2022-02-20T15:07:15+00:00"
"time": "2023-10-12T05:21:21+00:00"
},
{
"name": "graham-campbell/result-type",
@ -1858,16 +1858,16 @@
},
{
"name": "laravel/framework",
"version": "v9.52.15",
"version": "v9.52.16",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "e3350e87a52346af9cc655a3012d2175d2d05ad7"
"reference": "082345d76fc6a55b649572efe10b11b03e279d24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/e3350e87a52346af9cc655a3012d2175d2d05ad7",
"reference": "e3350e87a52346af9cc655a3012d2175d2d05ad7",
"url": "https://api.github.com/repos/laravel/framework/zipball/082345d76fc6a55b649572efe10b11b03e279d24",
"reference": "082345d76fc6a55b649572efe10b11b03e279d24",
"shasum": ""
},
"require": {
@ -2052,7 +2052,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2023-08-08T14:28:40+00:00"
"time": "2023-10-03T13:02:30+00:00"
},
{
"name": "laravel/serializable-closure",
@ -2304,16 +2304,16 @@
},
{
"name": "league/flysystem",
"version": "3.16.0",
"version": "3.17.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729"
"reference": "bd4c9b26849d82364119c68429541f1631fba94b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fdf372ca6b63c6e281b1c01a624349ccb757729",
"reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/bd4c9b26849d82364119c68429541f1631fba94b",
"reference": "bd4c9b26849d82364119c68429541f1631fba94b",
"shasum": ""
},
"require": {
@ -2331,8 +2331,8 @@
"symfony/http-client": "<5.2"
},
"require-dev": {
"async-aws/s3": "^1.5",
"async-aws/simple-s3": "^1.1",
"async-aws/s3": "^1.5 || ^2.0",
"async-aws/simple-s3": "^1.1 || ^2.0",
"aws/aws-sdk-php": "^3.220.0",
"composer/semver": "^3.0",
"ext-fileinfo": "*",
@ -2378,7 +2378,7 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.16.0"
"source": "https://github.com/thephpleague/flysystem/tree/3.17.0"
},
"funding": [
{
@ -2390,7 +2390,7 @@
"type": "github"
}
],
"time": "2023-09-07T19:22:17+00:00"
"time": "2023-10-05T20:15:05+00:00"
},
{
"name": "league/flysystem-local",
@ -2838,16 +2838,16 @@
},
{
"name": "nette/schema",
"version": "v1.2.4",
"version": "v1.2.5",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab"
"reference": "0462f0166e823aad657c9224d0f849ecac1ba10a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/c9ff517a53903b3d4e29ec547fb20feecb05b8ab",
"reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab",
"url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a",
"reference": "0462f0166e823aad657c9224d0f849ecac1ba10a",
"shasum": ""
},
"require": {
@ -2894,9 +2894,9 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.2.4"
"source": "https://github.com/nette/schema/tree/v1.2.5"
},
"time": "2023-08-05T18:56:25+00:00"
"time": "2023-10-05T20:37:59+00:00"
},
{
"name": "nette/utils",
@ -8724,16 +8724,16 @@
},
{
"name": "composer/pcre",
"version": "3.1.0",
"version": "3.1.1",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2"
"reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2",
"reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2",
"url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9",
"reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9",
"shasum": ""
},
"require": {
@ -8775,7 +8775,7 @@
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.1.0"
"source": "https://github.com/composer/pcre/tree/3.1.1"
},
"funding": [
{
@ -8791,7 +8791,7 @@
"type": "tidelift"
}
],
"time": "2022-11-17T09:50:14+00:00"
"time": "2023-10-11T07:11:09+00:00"
},
{
"name": "composer/xdebug-handler",
@ -9666,5 +9666,5 @@
"platform-overrides": {
"php": "8.0.2"
},
"plugin-api-version": "2.6.0"
"plugin-api-version": "2.3.0"
}

View file

@ -113,6 +113,10 @@ pre {
color: var(--second-7);
}
b {
font-weight: bold;
}
em {
font-style: italic;
}

View file

@ -19,13 +19,7 @@
<input form="create_edit" class="btn" type="submit" value="Update">
</header>
<p title="{{ $account->updated_at }}">Updated on {{ $account->updated_at->format('d/m/Y') }}
@include('parts.tabs', [
'items' => [
route('admin.account.edit', $account->id) => 'Information',
route('admin.account.device.index', $account->id) => 'Devices',
route('admin.account.statistics.show', $account->id) => 'Statistics',
],
])
@include('admin.account.parts.tabs')
@else
<header>
<h1><i class="material-icons-outlined">people</i> Create an account</h1>

View file

@ -17,13 +17,7 @@
<a href="{{ route('admin.account.edit', $account->id) }}" class="btn btn-secondary oppose">Cancel</a>
</header>
@include('parts.tabs', [
'items' => [
route('admin.account.edit', $account->id) => 'Information',
route('admin.account.device.index', $account->id) => 'Devices',
route('admin.account.statistics.show', $account->id) => 'Statistics',
],
])
@include('admin.account.parts.tabs')
<table class="table">
<thead>

View file

@ -0,0 +1,8 @@
@include('parts.tabs', [
'items' => [
route('admin.account.edit', $account->id) => 'Information',
route('admin.account.statistics.show_call_logs', $account->id) => 'Call Logs',
route('admin.account.device.index', $account->id) => 'Devices',
route('admin.account.statistics.show', $account->id) => 'Statistics',
],
])

View file

@ -16,13 +16,7 @@
<h1><i class="material-icons-outlined">people</i> {{ $account->identifier }}</h1>
</header>
@include('parts.tabs', [
'items' => [
route('admin.account.edit', $account->id) => 'Information',
route('admin.account.device.index', $account->id) => 'Devices',
route('admin.account.statistics.show', $account->id) => 'Statistics',
],
])
@include('admin.account.parts.tabs')
<div>
<form class="inline" method="POST" action="{{ route('admin.account.statistics.edit', $account) }}" accept-charset="UTF-8">

View file

@ -0,0 +1,38 @@
@extends('layouts.main')
@section('breadcrumb')
<li class="breadcrumb-item">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Call Logs</li>
@endsection
@section('content')
<header>
<h1><i class="material-icons-outlined">list</i> Call Logs</h1>
</header>
@include('admin.account.parts.tabs')
<div>
<form class="inline" method="POST" action="{{ route('admin.account.statistics.edit_call_logs', $account->id) }}" accept-charset="UTF-8">
@csrf
@method('post')
<div>
<input type="date" name="from" value="{{ $request->get('from') }}" onchange="this.form.submit()">
<label for="from">From</label>
</div>
<div>
<input type="date" name="to" value="{{ $request->get('to') }}" onchange="this.form.submit()">
<label for="to">To</label>
</div>
<div class="oppose">
<a class="btn btn-secondary" href="{{ route('admin.account.statistics.show_call_logs', $account->id) }}">Reset</a>
</div>
</form>
</div>
@include('parts.call_logs.table', ['calls' => $calls])
@endsection

View file

@ -34,22 +34,20 @@
</div>
@endif
@if ($type == 'accounts')
<div class="select">
<select name="contacts_list" onchange="this.form.submit()">
<option value="">
Select a contacts list
<div class="select">
<select name="contacts_list" onchange="this.form.submit()">
<option value="">
Select a contacts list
</option>
@foreach ($contacts_lists as $key => $name)
<option value="{{ $key }}"
@if (request()->get('contacts_list', '') == $key) selected="selected" @endif>
{{ $name }}
</option>
@foreach ($contacts_lists as $key => $name)
<option value="{{ $key }}"
@if (request()->get('contacts_list', '') == $key) selected="selected" @endif>
{{ $name }}
</option>
@endforeach
</select>
<label for="contacts_list">Contacts list</label>
</div>
@endif
@endforeach
</select>
<label for="contacts_list">Contacts list</label>
</div>
<div>
<a href="{{ route('admin.statistics.show', ['by' => 'day', 'type' => $type] + $request->only(['from', 'to', 'domain', 'contacts_list'])) }}"

View file

@ -0,0 +1,8 @@
@include('parts.tabs', [
'items' => [
route('admin.statistics.show', ['type' => 'accounts']) => 'Accounts',
route('admin.statistics.show', ['type' => 'calls']) => 'Calls',
route('admin.statistics.show_call_logs') => 'Call Logs',
route('admin.statistics.show', ['type' => 'messages']) => 'Messages',
],
])

View file

@ -9,15 +9,8 @@
<h1><i class="material-icons-outlined">analytics</i> Statistics</h1>
</header>
@include('parts.tabs', [
'items' => [
route('admin.statistics.show', ['type' => 'messages']) => 'Messages',
route('admin.statistics.show', ['type' => 'accounts']) => 'Accounts',
route('admin.statistics.show', ['type' => 'calls']) => 'Calls',
],
])
@include('admin.statistics.parts.tabs')
@include('admin.statistics.parts.filters')
@include('parts.graph')
@endsection

View file

@ -0,0 +1,71 @@
@extends('layouts.main')
@section('breadcrumb')
<li class="breadcrumb-item active" aria-current="page">Statistics</li>
@endsection
@section('content')
<header>
<h1><i class="material-icons-outlined">analytics</i> Statistics</h1>
</header>
@include('admin.statistics.parts.tabs')
<div>
<form class="inline" method="POST" action="{{ route('admin.statistics.edit_call_logs') }}" accept-charset="UTF-8">
@csrf
@method('post')
<div>
<input type="date" name="from" value="{{ $request->get('from') }}" onchange="this.form.submit()">
<label for="from">From</label>
</div>
<div>
<input type="date" name="to" value="{{ $request->get('to') }}" onchange="this.form.submit()">
<label for="to">To</label>
</div>
<div class="large on_desktop"></div>
@if (config('app.admins_manage_multi_domains'))
<div class="select">
<select name="domain" onchange="this.form.submit()">
<option value="">
Select a domain
</option>
@foreach ($domains as $d)
<option value="{{ $d }}"
@if (request()->get('domain', '') == $d) selected="selected" @endif>
{{ $d }}
</option>
@endforeach
</select>
<label for="domain">Domain</label>
</div>
@endif
<div class="select">
<select name="contacts_list" onchange="this.form.submit()">
<option value="">
Select a contacts list
</option>
@foreach ($contacts_lists as $key => $name)
<option value="{{ $key }}"
@if (request()->get('contacts_list', '') == $key) selected="selected" @endif>
{{ $name }}
</option>
@endforeach
</select>
<label for="contacts_list">Contacts list</label>
</div>
<div class="on_desktop"></div>
<div class="oppose">
<a class="btn btn-secondary" href="{{ route('admin.statistics.show_call_logs') }}">Reset</a>
</div>
</form>
</div>
@include('parts.call_logs.table', ['calls' => $calls])
@endsection

View file

@ -0,0 +1,42 @@
<table class="table">
<thead>
<tr>
<th>From</th>
<th>To</th>
<th>Time</th>
</tr>
</thead>
<tbody>
@if ($calls->isEmpty())
<tr class="empty">
<td colspan="3">No Calls</td>
</tr>
@endif
@foreach ($calls as $call)
<tr>
<td class="line">
@if (isset($account) && $account->identifier != $call->from)
<b>{{ $call->from }}</b>
@else
{{ $call->from }}
@endif
</td>
<td class="line">
@if (isset($account) && $account->identifier != $call->to)
<b>{{ $call->to }}</b>
@else
{{ $call->to }}
@endif
</td>
<td class="line">
{{ $call->initiated_at }}
@if ($call->ended_at)
({{ $call->ended_at->diffForHumans($call->initiated_at, true) }})
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
{{ $calls->links('pagination::bootstrap-4') }}

View file

@ -135,6 +135,8 @@ if (config('app.web_panel')) {
Route::name('admin.')->prefix('admin')->middleware(['auth.admin'])->group(function () {
Route::name('statistics.')->controller(StatisticsController::class)->prefix('statistics')->group(function () {
Route::get('/', 'index')->name('index');
Route::post('call_logs', 'editCallLogs')->name('edit_call_logs');
Route::get('call_logs', 'showCallLogs')->name('show_call_logs');
Route::get('/{type?}', 'show')->name('show');
Route::post('/', 'edit')->name('edit');
//Route::post('search', 'search')->name('search');
@ -208,6 +210,8 @@ if (config('app.web_panel')) {
Route::name('statistics.')->prefix('{account}/statistics')->controller(AccountStatisticsController::class)->group(function () {
Route::get('/', 'show')->name('show');
Route::post('call_logs', 'editCallLogs')->name('edit_call_logs');
Route::get('call_logs', 'showCallLogs')->name('show_call_logs');
Route::post('/', 'edit')->name('edit');
});
});