diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php index 91d0fa8..1821c17 100644 --- a/flexiapi/app/Account.php +++ b/flexiapi/app/Account.php @@ -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 */ diff --git a/flexiapi/app/Http/Controllers/Admin/AccountStatisticsController.php b/flexiapi/app/Http/Controllers/Admin/AccountStatisticsController.php index 6d6da30..c961147 100644 --- a/flexiapi/app/Http/Controllers/Admin/AccountStatisticsController.php +++ b/flexiapi/app/Http/Controllers/Admin/AccountStatisticsController.php @@ -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, + ]); + } } diff --git a/flexiapi/app/Http/Controllers/Admin/StatisticsController.php b/flexiapi/app/Http/Controllers/Admin/StatisticsController.php index 51e355f..e32f995 100644 --- a/flexiapi/app/Http/Controllers/Admin/StatisticsController.php +++ b/flexiapi/app/Http/Controllers/Admin/StatisticsController.php @@ -1,4 +1,21 @@ . +*/ 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, + ]); + } } diff --git a/flexiapi/app/Libraries/StatisticsGraphFactory.php b/flexiapi/app/Libraries/StatisticsGraphFactory.php index 1d036a1..1e2a14a 100644 --- a/flexiapi/app/Libraries/StatisticsGraphFactory.php +++ b/flexiapi/app/Libraries/StatisticsGraphFactory.php @@ -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); diff --git a/flexiapi/app/StatisticsCall.php b/flexiapi/app/StatisticsCall.php index 084f7b6..cb9b960 100644 --- a/flexiapi/app/StatisticsCall.php +++ b/flexiapi/app/StatisticsCall.php @@ -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'); + }); + } } diff --git a/flexiapi/app/StatisticsMessage.php b/flexiapi/app/StatisticsMessage.php index 48b31a9..393cba7 100644 --- a/flexiapi/app/StatisticsMessage.php +++ b/flexiapi/app/StatisticsMessage.php @@ -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'); + }); + } } diff --git a/flexiapi/composer.lock b/flexiapi/composer.lock index ae938b2..db4693d 100644 --- a/flexiapi/composer.lock +++ b/flexiapi/composer.lock @@ -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" } diff --git a/flexiapi/public/css/style.css b/flexiapi/public/css/style.css index fe1022a..cdaee12 100644 --- a/flexiapi/public/css/style.css +++ b/flexiapi/public/css/style.css @@ -113,6 +113,10 @@ pre { color: var(--second-7); } +b { + font-weight: bold; +} + em { font-style: italic; } diff --git a/flexiapi/resources/views/admin/account/create_edit.blade.php b/flexiapi/resources/views/admin/account/create_edit.blade.php index afa7a27..0f64307 100644 --- a/flexiapi/resources/views/admin/account/create_edit.blade.php +++ b/flexiapi/resources/views/admin/account/create_edit.blade.php @@ -19,13 +19,7 @@
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
people Create an account
diff --git a/flexiapi/resources/views/admin/account/device/index.blade.php b/flexiapi/resources/views/admin/account/device/index.blade.php
index df5428f..15cd1c9 100644
--- a/flexiapi/resources/views/admin/account/device/index.blade.php
+++ b/flexiapi/resources/views/admin/account/device/index.blade.php
@@ -17,13 +17,7 @@
Cancel
| From | +To | +Time | +
|---|---|---|
| No Calls | +||
| + @if (isset($account) && $account->identifier != $call->from) + {{ $call->from }} + @else + {{ $call->from }} + @endif + | ++ @if (isset($account) && $account->identifier != $call->to) + {{ $call->to }} + @else + {{ $call->to }} + @endif + | ++ {{ $call->initiated_at }} + @if ($call->ended_at) + ({{ $call->ended_at->diffForHumans($call->initiated_at, true) }}) + @endif + | +