mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 01:58:07 +00:00
Add Account statistics
This commit is contained in:
parent
e516ae788c
commit
7feb7fd184
25 changed files with 864 additions and 366 deletions
|
|
@ -23,17 +23,20 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Carbon\Carbon;
|
||||
|
||||
use Awobaz\Compoships\Compoships;
|
||||
|
||||
use App\ApiKey;
|
||||
use App\Password;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
|
||||
class Account extends Authenticatable
|
||||
{
|
||||
use HasFactory;
|
||||
use Compoships;
|
||||
|
||||
protected $with = ['passwords', 'admin', 'alias', 'activationExpiration', 'emailChangeCode', 'types', 'actions'];
|
||||
protected $hidden = ['alias', 'expire_time', 'confirmation_key', 'provisioning_token', 'pivot'];
|
||||
|
|
@ -180,6 +183,26 @@ class Account extends Authenticatable
|
|||
return $this->belongsToMany(AccountType::class);
|
||||
}
|
||||
|
||||
public function statisticsFromCalls()
|
||||
{
|
||||
return $this->hasMany(StatisticsCall::class, ['from_username', 'from_domain'], ['username', 'domain']);
|
||||
}
|
||||
|
||||
public function statisticsToCalls()
|
||||
{
|
||||
return $this->hasMany(StatisticsCall::class, ['to_username', 'to_domain'], ['username', 'domain']);
|
||||
}
|
||||
|
||||
public function statisticsFromMessages()
|
||||
{
|
||||
return $this->hasMany(StatisticsMessage::class, ['from_username', 'from_domain'], ['username', 'domain']);
|
||||
}
|
||||
|
||||
public function statisticsToMessageDevices()
|
||||
{
|
||||
return $this->hasMany(StatisticsMessageDevice::class, ['to_username', 'to_domain'], ['username', 'domain']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Libraries\StatisticsGraphFactory;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AccountStatisticsController extends Controller
|
||||
{
|
||||
public function edit(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
|
||||
return redirect()->route('admin.account.statistics.show', [
|
||||
'account' => $account,
|
||||
'from' => $request->get('from'),
|
||||
'to' => $request->get('to'),
|
||||
'by' => $request->get('by'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request, int $accountId)
|
||||
{
|
||||
$request->validate([
|
||||
'from' => 'date_format:Y-m-d|before:to',
|
||||
'to' => 'date_format:Y-m-d|after:from',
|
||||
'by' => 'in:day,week,month,year',
|
||||
]);
|
||||
|
||||
$account = Account::findOrFail($accountId);
|
||||
|
||||
$messagesFromGraph = view('parts.graph', [
|
||||
'jsonConfig' => json_encode((new StatisticsGraphFactory($request, 'messages', fromUsername: $account->username, fromDomain: $account->domain))->getConfig()),
|
||||
'request' => $request
|
||||
])->render();
|
||||
|
||||
$messagesToGraph = view('parts.graph', [
|
||||
'jsonConfig' => json_encode((new StatisticsGraphFactory($request, 'messages', toUsername: $account->username, toDomain: $account->domain))->getConfig()),
|
||||
'request' => $request
|
||||
])->render();
|
||||
|
||||
$callsFromGraph = view('parts.graph', [
|
||||
'jsonConfig' => json_encode((new StatisticsGraphFactory($request, 'calls', fromUsername: $account->username, fromDomain: $account->domain))->getConfig()),
|
||||
'request' => $request
|
||||
])->render();
|
||||
|
||||
$callsToGraph = view('parts.graph', [
|
||||
'jsonConfig' => json_encode((new StatisticsGraphFactory($request, 'calls', toUsername: $account->username, toDomain: $account->domain))->getConfig()),
|
||||
'request' => $request
|
||||
])->render();
|
||||
|
||||
return view('admin.account.statistics.show', [
|
||||
'account' => $account,
|
||||
'messagesFromGraph' => $messagesFromGraph,
|
||||
'messagesToGraph' => $messagesToGraph,
|
||||
'callsFromGraph' => $callsFromGraph,
|
||||
'callsToGraph' => $callsToGraph,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,16 +3,13 @@
|
|||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Account;
|
||||
use App\ContactsList;
|
||||
use App\StatisticsMessage;
|
||||
use App\StatisticsCall;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Libraries\StatisticsGraphFactory;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonInterval;
|
||||
use Carbon\CarbonPeriod;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StatisticsController extends Controller
|
||||
{
|
||||
|
|
@ -27,12 +24,19 @@ class StatisticsController extends Controller
|
|||
{
|
||||
return redirect()->route('admin.statistics.show', [
|
||||
'from' => $request->get('from'),
|
||||
'type' => $request->get('type'),
|
||||
'to' => $request->get('to'),
|
||||
'by' => $request->get('by'),
|
||||
'type' => $request->get('type'),
|
||||
'domain' => $request->get('domain'),
|
||||
'contacts_list' => $request->get('contacts_list'),
|
||||
]);
|
||||
}
|
||||
|
||||
/*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([
|
||||
|
|
@ -41,186 +45,36 @@ class StatisticsController extends Controller
|
|||
'by' => 'in:day,week,month,year',
|
||||
]);
|
||||
|
||||
$dateColumn = 'created_at';
|
||||
$label = 'Label';
|
||||
|
||||
switch ($type) {
|
||||
case 'messages':
|
||||
$dateColumn = 'sent_at';
|
||||
$label = 'Messages';
|
||||
$data = StatisticsMessage::orderBy($dateColumn, 'asc');
|
||||
break;
|
||||
|
||||
case 'calls':
|
||||
$dateColumn = 'initiated_at';
|
||||
$label = 'Calls';
|
||||
$data = StatisticsCall::orderBy($dateColumn, 'asc');
|
||||
break;
|
||||
|
||||
case 'accounts':
|
||||
$label = 'Accounts';
|
||||
$data = Account::orderBy($dateColumn, 'asc');
|
||||
break;
|
||||
}
|
||||
|
||||
$data = $data->groupBy('moment')
|
||||
->orderBy('moment', 'desc')
|
||||
->setEagerLoads([]);
|
||||
|
||||
if ($request->get('to')) {
|
||||
$data = $data->where($dateColumn, '<=', $request->get('to'));
|
||||
}
|
||||
|
||||
$by = $request->get('by', 'day');
|
||||
|
||||
switch ($by) {
|
||||
case 'day':
|
||||
$data = $data->where($dateColumn, '>=', $request->get('from', Carbon::now()->subDay()->format('Y-m-d H:i:s')))
|
||||
->get([
|
||||
DB::raw("date_format(" . $dateColumn . ",'%Y-%m-%d %H') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
]);
|
||||
break;
|
||||
case 'week':
|
||||
$data = $data->where($dateColumn, '>=', $request->get('from', Carbon::now()->subWeek()->format('Y-m-d H:i:s')))
|
||||
->get([
|
||||
DB::raw("date_format(" . $dateColumn . ",'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
]);
|
||||
break;
|
||||
case 'month':
|
||||
$data = $data->where($dateColumn, '>=', $request->get('from', Carbon::now()->subMonth()->format('Y-m-d H:i:s')))
|
||||
->get([
|
||||
DB::raw("date_format(" . $dateColumn . ",'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
]);
|
||||
break;
|
||||
case 'year':
|
||||
$data = $data->where($dateColumn, '>=', $request->get('from', Carbon::now()->subYear()->format('Y-m-d H:i:s')))
|
||||
->get([
|
||||
DB::raw("date_format(" . $dateColumn . ",'%Y-%m') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
$data = $data->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
$data = $this->compileStatistics(
|
||||
$by,
|
||||
$request->get('from'),
|
||||
$request->get('to'),
|
||||
$data
|
||||
);
|
||||
$graph = new StatisticsGraphFactory($request, $type, fromDomain: $request->get('domain'));
|
||||
$config = $graph->getConfig();
|
||||
$domains = collect();
|
||||
|
||||
if ($request->get('export', false)) {
|
||||
$file = fopen('php://output', 'w');
|
||||
|
||||
$callback = function () use ($data, $file) {
|
||||
foreach ($data as $key => $value) {
|
||||
fputcsv($file, [$key, $value]);
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
};
|
||||
|
||||
return response()->stream($callback, 200, [
|
||||
"Content-type" => "text/csv",
|
||||
"Content-Disposition" => "attachment; filename=export.csv",
|
||||
"Pragma" => "no-cache",
|
||||
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
|
||||
"Expires" => "0"
|
||||
]);
|
||||
return $graph->export();
|
||||
}
|
||||
|
||||
$config = [
|
||||
'type' => 'bar',
|
||||
'data' => [
|
||||
'labels' => $data->keys()->toArray(),
|
||||
'datasets' => [[
|
||||
'label' => $label,
|
||||
'borderColor' => 'rgba(108, 122, 135, 1)',
|
||||
'backgroundColor' => 'rgba(108, 122, 135, 1)',
|
||||
'data' => $data->values()->toArray(),
|
||||
'order' => 1
|
||||
]]
|
||||
],
|
||||
'options' => [
|
||||
'maintainAspectRatio' => false,
|
||||
'spanGaps' => true,
|
||||
'legend' => [
|
||||
'position' => 'right'
|
||||
],
|
||||
'scales' => [
|
||||
'y' => [
|
||||
'stacked' => true,
|
||||
'title' => [
|
||||
'display' => true,
|
||||
'text' => $label
|
||||
]
|
||||
],
|
||||
'x' => [
|
||||
'stacked' => true,
|
||||
]
|
||||
],
|
||||
'interaction' => [
|
||||
'mode' => 'nearest',
|
||||
'axis' => 'x',
|
||||
'intersect' => false
|
||||
],
|
||||
]
|
||||
];
|
||||
if (config('app.admins_manage_multi_domains')) {
|
||||
switch ($type) {
|
||||
case 'messages':
|
||||
$domains = StatisticsMessage::groupBy('from_domain')->pluck('from_domain');
|
||||
break;
|
||||
|
||||
case 'calls':
|
||||
$domains = StatisticsCall::groupBy('from_domain')->pluck('from_domain');
|
||||
break;
|
||||
|
||||
case 'accounts':
|
||||
$domains = Account::groupBy('domain')->pluck('domain');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return view('admin.statistics.show', [
|
||||
'domains' => $domains,
|
||||
'contacts_lists' => ContactsList::all()->pluck('title', 'id'),
|
||||
'jsonConfig' => json_encode($config),
|
||||
'by' => $by,
|
||||
'type' => $type,
|
||||
'request' => $request
|
||||
]);
|
||||
}
|
||||
|
||||
private static function compileStatistics(string $by, $from, $to, $data): Collection
|
||||
{
|
||||
$stats = [];
|
||||
|
||||
switch ($by) {
|
||||
case 'day':
|
||||
$period = collect(CarbonInterval::hour()->toPeriod(
|
||||
$from ?? Carbon::now()->subDay()->format('Y-m-d H:i:s'),
|
||||
$to ?? Carbon::now()->format('Y-m-d H:i:s')
|
||||
))->map->format('Y-m-d H');
|
||||
break;
|
||||
|
||||
case 'week':
|
||||
$period = collect(CarbonPeriod::create(
|
||||
$from ?? Carbon::now()->subWeek(),
|
||||
$to ?? Carbon::now()
|
||||
))->map->format('Y-m-d');
|
||||
break;
|
||||
|
||||
case 'month':
|
||||
$period = collect(
|
||||
CarbonPeriod::create(
|
||||
$from ?? Carbon::now()->subMonth(),
|
||||
$to ?? Carbon::now()
|
||||
)
|
||||
)->map->format('Y-m-d');
|
||||
break;
|
||||
|
||||
case 'year':
|
||||
$period = collect(
|
||||
CarbonPeriod::create(
|
||||
$from ?? Carbon::now()->subYear(),
|
||||
$to ?? Carbon::now()
|
||||
)
|
||||
)->map->format('Y-m');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($period as $moment) {
|
||||
$stats[$moment] = $data[$moment] ?? 0;
|
||||
}
|
||||
|
||||
return collect($stats);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
282
flexiapi/app/Libraries/StatisticsGraphFactory.php
Normal file
282
flexiapi/app/Libraries/StatisticsGraphFactory.php
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
<?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\Libraries;
|
||||
|
||||
use App\Account;
|
||||
use App\ContactsList;
|
||||
use App\StatisticsCall;
|
||||
use App\StatisticsMessage;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonInterval;
|
||||
use Carbon\CarbonPeriod;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class StatisticsGraphFactory
|
||||
{
|
||||
private $data = null;
|
||||
|
||||
public function __construct(
|
||||
private Request $request,
|
||||
private string $type = 'messages',
|
||||
public ?string $fromUsername = null,
|
||||
public ?string $fromDomain = null,
|
||||
public ?string $toUsername = null,
|
||||
public ?string $toDomain = null
|
||||
) {
|
||||
}
|
||||
|
||||
public function getConfig()
|
||||
{
|
||||
$dateColumn = 'created_at';
|
||||
$label = 'Label';
|
||||
|
||||
switch ($this->type) {
|
||||
case 'messages':
|
||||
$dateColumn = 'sent_at';
|
||||
$label = 'Messages';
|
||||
$this->data = StatisticsMessage::orderBy($dateColumn, 'asc');
|
||||
|
||||
if (!config('app.admins_manage_multi_domains')) {
|
||||
$this->data->where('from_domain', config('app.sip_domain'));
|
||||
} elseif ($this->fromDomain) {
|
||||
$this->data->where('from_domain', $this->fromDomain)->orderBy('from_domain');
|
||||
|
||||
if ($this->fromUsername) {
|
||||
$this->data->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);
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'calls':
|
||||
$dateColumn = 'initiated_at';
|
||||
$label = 'Calls';
|
||||
$this->data = StatisticsCall::orderBy($dateColumn, 'asc');
|
||||
|
||||
if (!config('app.admins_manage_multi_domains')) {
|
||||
$this->data->where('from_domain', config('app.sip_domain'));
|
||||
} elseif ($this->fromDomain) {
|
||||
$this->data->where('from_domain', $this->fromDomain)->orderBy('from_domain');
|
||||
|
||||
if ($this->fromUsername) {
|
||||
$this->data->where('from_username', $this->fromUsername);
|
||||
}
|
||||
} elseif ($this->toDomain) {
|
||||
$this->data->where('to_domain', $this->toDomain)->orderBy('to_domain');
|
||||
|
||||
if ($this->toUsername) {
|
||||
$this->data->where('to_username', $this->toUsername);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'accounts':
|
||||
$label = 'Accounts';
|
||||
$this->data = Account::orderBy($dateColumn, 'asc');
|
||||
|
||||
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');
|
||||
|
||||
if ($this->fromUsername) {
|
||||
$this->data->where('username', $this->fromUsername);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->request->has('contacts_list')) {
|
||||
$this->data->whereIn('id', function ($query) {
|
||||
$query->select('contact_id')
|
||||
->from('contacts_list_contact')
|
||||
->where('contacts_list_id', $this->request->get('contacts_list'));
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$this->data = $this->data->groupBy('moment')
|
||||
->orderBy('moment', 'desc')
|
||||
->setEagerLoads([]);
|
||||
|
||||
if ($this->request->get('to')) {
|
||||
$this->data = $this->data->where($dateColumn, '<=', $this->request->get('to'));
|
||||
}
|
||||
|
||||
$by = $this->request->get('by', 'day');
|
||||
|
||||
switch ($by) {
|
||||
case 'day':
|
||||
$this->data = $this->data->where($dateColumn, '>=', $this->request->get('from', Carbon::now()->subDay()->format('Y-m-d H:i:s')))
|
||||
->get([
|
||||
DB::raw("date_format(" . $dateColumn . ",'%Y-%m-%d %H') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
]);
|
||||
break;
|
||||
case 'week':
|
||||
$this->data = $this->data->where($dateColumn, '>=', $this->request->get('from', Carbon::now()->subWeek()->format('Y-m-d H:i:s')))
|
||||
->get([
|
||||
DB::raw("date_format(" . $dateColumn . ",'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
]);
|
||||
break;
|
||||
case 'month':
|
||||
$this->data = $this->data->where($dateColumn, '>=', $this->request->get('from', Carbon::now()->subMonth()->format('Y-m-d H:i:s')))
|
||||
->get([
|
||||
DB::raw("date_format(" . $dateColumn . ",'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
]);
|
||||
break;
|
||||
case 'year':
|
||||
$this->data = $this->data->where($dateColumn, '>=', $this->request->get('from', Carbon::now()->subYear()->format('Y-m-d H:i:s')))
|
||||
->get([
|
||||
DB::raw("date_format(" . $dateColumn . ",'%Y-%m') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->data = $this->data->each->setAppends([])->pluck('count', 'moment');
|
||||
$this->data = $this->compileStatistics(
|
||||
$by,
|
||||
$this->request->get('from'),
|
||||
$this->request->get('to'),
|
||||
$this->data
|
||||
);
|
||||
|
||||
return [
|
||||
'type' => 'bar',
|
||||
'data' => [
|
||||
'labels' => $this->data->keys()->toArray(),
|
||||
'datasets' => [[
|
||||
'label' => $label,
|
||||
'borderColor' => 'rgba(108, 122, 135, 1)',
|
||||
'backgroundColor' => 'rgba(108, 122, 135, 1)',
|
||||
'data' => $this->data->values()->toArray(),
|
||||
'order' => 1
|
||||
]]
|
||||
],
|
||||
'options' => [
|
||||
'maintainAspectRatio' => false,
|
||||
'spanGaps' => true,
|
||||
'legend' => [
|
||||
'position' => 'right'
|
||||
],
|
||||
'scales' => [
|
||||
'y' => [
|
||||
'stacked' => true,
|
||||
'title' => [
|
||||
'display' => true,
|
||||
'text' => $label
|
||||
]
|
||||
],
|
||||
'x' => [
|
||||
'stacked' => true,
|
||||
]
|
||||
],
|
||||
'interaction' => [
|
||||
'mode' => 'nearest',
|
||||
'axis' => 'x',
|
||||
'intersect' => false
|
||||
],
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function export()
|
||||
{
|
||||
$file = fopen('php://output', 'w');
|
||||
|
||||
if ($this->data == null) {
|
||||
$this->getConfig();
|
||||
}
|
||||
|
||||
$callback = function () use ($file) {
|
||||
foreach ($this->data as $key => $value) {
|
||||
fputcsv($file, [$key, $value]);
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
};
|
||||
|
||||
return response()->stream($callback, 200, [
|
||||
"Content-type" => "text/csv",
|
||||
"Content-Disposition" => "attachment; filename=export.csv",
|
||||
"Pragma" => "no-cache",
|
||||
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
|
||||
"Expires" => "0"
|
||||
]);
|
||||
}
|
||||
|
||||
private function compileStatistics(string $by, $from, $to, $data): Collection
|
||||
{
|
||||
$stats = [];
|
||||
|
||||
switch ($by) {
|
||||
case 'day':
|
||||
$period = collect(CarbonInterval::hour()->toPeriod(
|
||||
$from ?? Carbon::now()->subDay()->format('Y-m-d H:i:s'),
|
||||
$to ?? Carbon::now()->format('Y-m-d H:i:s')
|
||||
))->map->format('Y-m-d H');
|
||||
break;
|
||||
|
||||
case 'week':
|
||||
$period = collect(CarbonPeriod::create(
|
||||
$from ?? Carbon::now()->subWeek(),
|
||||
$to ?? Carbon::now()
|
||||
))->map->format('Y-m-d');
|
||||
break;
|
||||
|
||||
case 'month':
|
||||
$period = collect(
|
||||
CarbonPeriod::create(
|
||||
$from ?? Carbon::now()->subMonth(),
|
||||
$to ?? Carbon::now()
|
||||
)
|
||||
)->map->format('Y-m-d');
|
||||
break;
|
||||
|
||||
case 'year':
|
||||
$period = collect(
|
||||
CarbonPeriod::create(
|
||||
$from ?? Carbon::now()->subYear(),
|
||||
$to ?? Carbon::now()
|
||||
)
|
||||
)->map->format('Y-m');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($period as $moment) {
|
||||
$stats[$moment] = $data[$moment] ?? 0;
|
||||
}
|
||||
|
||||
return collect($stats);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,11 +22,24 @@ namespace App;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use Awobaz\Compoships\Compoships;
|
||||
|
||||
class StatisticsCall extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Compoships;
|
||||
|
||||
public $incrementing = false;
|
||||
protected $casts = ['initiated_at' => 'datetime', 'ended_at' => 'datetime'];
|
||||
protected $keyType = 'string';
|
||||
|
||||
public function accountFrom()
|
||||
{
|
||||
return $this->belongsTo(Account::class, ['username', 'domain'], ['to_username', 'to_domain']);
|
||||
}
|
||||
|
||||
public function accountTo()
|
||||
{
|
||||
return $this->belongsTo(Account::class, ['username', 'domain'], ['to_username', 'to_domain']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,13 +20,21 @@
|
|||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use Awobaz\Compoships\Compoships;
|
||||
use Awobaz\Compoships\Database\Eloquent\Model;
|
||||
|
||||
class StatisticsMessage extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Compoships;
|
||||
|
||||
public $incrementing = false;
|
||||
protected $casts = ['sent_at' => 'datetime'];
|
||||
protected $keyType = 'string';
|
||||
|
||||
public function accountFrom()
|
||||
{
|
||||
return $this->belongsTo(Account::class, ['username', 'domain'], ['to_username', 'to_domain']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@
|
|||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use Awobaz\Compoships\Database\Eloquent\Model;
|
||||
|
||||
class StatisticsMessageDevice extends Model
|
||||
{
|
||||
|
|
@ -33,4 +34,9 @@ class StatisticsMessageDevice extends Model
|
|||
{
|
||||
return $this->hasOne(StatisticsMessage::class, 'id', 'message_id');
|
||||
}
|
||||
|
||||
public function accountTo()
|
||||
{
|
||||
return $this->belongsTo(Account::class, ['username', 'domain'], ['to_username', 'to_domain']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
"require": {
|
||||
"php": ">=8.0.2",
|
||||
"anhskohbo/no-captcha": "^3.5",
|
||||
"awobaz/compoships": "^2.2",
|
||||
"doctrine/dbal": "^3.6.6",
|
||||
"endroid/qr-code": "^4.8.2",
|
||||
"fakerphp/faker": "^1.23",
|
||||
|
|
|
|||
236
flexiapi/composer.lock
generated
236
flexiapi/composer.lock
generated
|
|
@ -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": "1c0a59db2fada52615ad6f31e0599291",
|
||||
"content-hash": "b6a450b1e7adf4c259121350856f83a6",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anhskohbo/no-captcha",
|
||||
|
|
@ -70,6 +70,68 @@
|
|||
},
|
||||
"time": "2023-02-15T16:07:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "awobaz/compoships",
|
||||
"version": "2.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/topclaudy/compoships.git",
|
||||
"reference": "404901e2ebd6794f70d2710a56edd4b0c500ce1f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/topclaudy/compoships/zipball/404901e2ebd6794f70d2710a56edd4b0c500ce1f",
|
||||
"reference": "404901e2ebd6794f70d2710a56edd4b0c500ce1f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"fakerphp/faker": "^1.18",
|
||||
"illuminate/database": ">=5.6 <11.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-sqlite3": "*",
|
||||
"phpunit/phpunit": "^6.0|^8.0|^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"awobaz/blade-active": "Blade directives for the Laravel 'Active' package",
|
||||
"awobaz/eloquent-auto-append": "Automatically append accessors to model serialization",
|
||||
"awobaz/eloquent-mutators": "Reusable mutators (getters/setters) for Laravel 5's Eloquent",
|
||||
"awobaz/syntactic": "Syntactic sugar for named and indexed parameters call."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Awobaz\\Compoships\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Claudin J. Daniel",
|
||||
"email": "cdaniel@awobaz.com"
|
||||
}
|
||||
],
|
||||
"description": "Laravel relationships with support for composite/multiple keys",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"laravel composite keys",
|
||||
"laravel relationships"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/topclaudy/compoships/issues",
|
||||
"source": "https://github.com/topclaudy/compoships/tree/2.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://paypal.me/awobaz",
|
||||
"type": "custom"
|
||||
}
|
||||
],
|
||||
"time": "2023-02-22T16:52:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
"version": "2.0.8",
|
||||
|
|
@ -399,16 +461,16 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "3.6.6",
|
||||
"version": "3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "63646ffd71d1676d2f747f871be31b7e921c7864"
|
||||
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/63646ffd71d1676d2f747f871be31b7e921c7864",
|
||||
"reference": "63646ffd71d1676d2f747f871be31b7e921c7864",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/00d03067f07482f025d41ab55e4ba0db5eca2cdf",
|
||||
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -424,9 +486,9 @@
|
|||
"doctrine/coding-standard": "12.0.0",
|
||||
"fig/log-test": "^1",
|
||||
"jetbrains/phpstorm-stubs": "2023.1",
|
||||
"phpstan/phpstan": "1.10.29",
|
||||
"phpstan/phpstan": "1.10.35",
|
||||
"phpstan/phpstan-strict-rules": "^1.5",
|
||||
"phpunit/phpunit": "9.6.9",
|
||||
"phpunit/phpunit": "9.6.13",
|
||||
"psalm/plugin-phpunit": "0.18.4",
|
||||
"slevomat/coding-standard": "8.13.1",
|
||||
"squizlabs/php_codesniffer": "3.7.2",
|
||||
|
|
@ -492,7 +554,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/dbal/issues",
|
||||
"source": "https://github.com/doctrine/dbal/tree/3.6.6"
|
||||
"source": "https://github.com/doctrine/dbal/tree/3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -508,20 +570,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-17T05:38:17+00:00"
|
||||
"time": "2023-09-26T20:56:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
"version": "v1.1.1",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/deprecations.git",
|
||||
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3"
|
||||
"reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
|
||||
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
|
||||
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
|
||||
"reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -553,9 +615,9 @@
|
|||
"homepage": "https://www.doctrine-project.org/",
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/deprecations/issues",
|
||||
"source": "https://github.com/doctrine/deprecations/tree/v1.1.1"
|
||||
"source": "https://github.com/doctrine/deprecations/tree/1.1.2"
|
||||
},
|
||||
"time": "2023-06-03T09:27:29+00:00"
|
||||
"time": "2023-09-27T20:04:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/event-manager",
|
||||
|
|
@ -2054,16 +2116,16 @@
|
|||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/commonmark.git",
|
||||
"reference": "d44a24690f16b8c1808bf13b1bd54ae4c63ea048"
|
||||
"reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d44a24690f16b8c1808bf13b1bd54ae4c63ea048",
|
||||
"reference": "d44a24690f16b8c1808bf13b1bd54ae4c63ea048",
|
||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/3669d6d5f7a47a93c08ddff335e6d945481a1dd5",
|
||||
"reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2156,7 +2218,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-24T15:16:10+00:00"
|
||||
"time": "2023-08-30T16:55:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/config",
|
||||
|
|
@ -2242,16 +2304,16 @@
|
|||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
"version": "3.15.1",
|
||||
"version": "3.16.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/flysystem.git",
|
||||
"reference": "a141d430414fcb8bf797a18716b09f759a385bed"
|
||||
"reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a141d430414fcb8bf797a18716b09f759a385bed",
|
||||
"reference": "a141d430414fcb8bf797a18716b09f759a385bed",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fdf372ca6b63c6e281b1c01a624349ccb757729",
|
||||
"reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2260,6 +2322,8 @@
|
|||
"php": "^8.0.2"
|
||||
},
|
||||
"conflict": {
|
||||
"async-aws/core": "<1.19.0",
|
||||
"async-aws/s3": "<1.14.0",
|
||||
"aws/aws-sdk-php": "3.209.31 || 3.210.0",
|
||||
"guzzlehttp/guzzle": "<7.0",
|
||||
"guzzlehttp/ringphp": "<1.1.1",
|
||||
|
|
@ -2279,7 +2343,7 @@
|
|||
"microsoft/azure-storage-blob": "^1.1",
|
||||
"phpseclib/phpseclib": "^3.0.14",
|
||||
"phpstan/phpstan": "^0.12.26",
|
||||
"phpunit/phpunit": "^9.5.11",
|
||||
"phpunit/phpunit": "^9.5.11|^10.0",
|
||||
"sabre/dav": "^4.3.1"
|
||||
},
|
||||
"type": "library",
|
||||
|
|
@ -2314,7 +2378,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/flysystem/issues",
|
||||
"source": "https://github.com/thephpleague/flysystem/tree/3.15.1"
|
||||
"source": "https://github.com/thephpleague/flysystem/tree/3.16.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2326,20 +2390,20 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-04T09:04:26+00:00"
|
||||
"time": "2023-09-07T19:22:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem-local",
|
||||
"version": "3.15.0",
|
||||
"version": "3.16.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/flysystem-local.git",
|
||||
"reference": "543f64c397fefdf9cfeac443ffb6beff602796b3"
|
||||
"reference": "ec7383f25642e6fd4bb0c9554fc2311245391781"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/543f64c397fefdf9cfeac443ffb6beff602796b3",
|
||||
"reference": "543f64c397fefdf9cfeac443ffb6beff602796b3",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ec7383f25642e6fd4bb0c9554fc2311245391781",
|
||||
"reference": "ec7383f25642e6fd4bb0c9554fc2311245391781",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2374,7 +2438,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/thephpleague/flysystem-local/issues",
|
||||
"source": "https://github.com/thephpleague/flysystem-local/tree/3.15.0"
|
||||
"source": "https://github.com/thephpleague/flysystem-local/tree/3.16.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2386,7 +2450,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-02T20:02:14+00:00"
|
||||
"time": "2023-08-30T10:23:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/mime-type-detection",
|
||||
|
|
@ -2668,16 +2732,16 @@
|
|||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
"version": "2.69.0",
|
||||
"version": "2.71.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/briannesbitt/Carbon.git",
|
||||
"reference": "4308217830e4ca445583a37d1bf4aff4153fa81c"
|
||||
"reference": "98276233188583f2ff845a0f992a235472d9466a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4308217830e4ca445583a37d1bf4aff4153fa81c",
|
||||
"reference": "4308217830e4ca445583a37d1bf4aff4153fa81c",
|
||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/98276233188583f2ff845a0f992a235472d9466a",
|
||||
"reference": "98276233188583f2ff845a0f992a235472d9466a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2770,7 +2834,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-03T09:00:52+00:00"
|
||||
"time": "2023-09-25T11:31:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/schema",
|
||||
|
|
@ -2836,16 +2900,16 @@
|
|||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v4.0.1",
|
||||
"version": "v4.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "9124157137da01b1f5a5a22d6486cb975f26db7e"
|
||||
"reference": "cead6637226456b35e1175cc53797dd585d85545"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/9124157137da01b1f5a5a22d6486cb975f26db7e",
|
||||
"reference": "9124157137da01b1f5a5a22d6486cb975f26db7e",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/cead6637226456b35e1175cc53797dd585d85545",
|
||||
"reference": "cead6637226456b35e1175cc53797dd585d85545",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2867,8 +2931,7 @@
|
|||
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
|
||||
"ext-json": "to use Nette\\Utils\\Json",
|
||||
"ext-mbstring": "to use Strings::lower() etc...",
|
||||
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
|
||||
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
|
||||
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
|
@ -2917,9 +2980,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.0.1"
|
||||
"source": "https://github.com/nette/utils/tree/v4.0.2"
|
||||
},
|
||||
"time": "2023-07-30T15:42:21+00:00"
|
||||
"time": "2023-09-19T11:58:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
|
|
@ -3362,16 +3425,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.27",
|
||||
"version": "9.2.29",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1"
|
||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1",
|
||||
"reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3428,7 +3491,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -3436,7 +3499,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-07-26T13:44:30+00:00"
|
||||
"time": "2023-09-19T04:57:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
|
@ -3681,16 +3744,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.6.11",
|
||||
"version": "9.6.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "810500e92855eba8a7a5319ae913be2da6f957b0"
|
||||
"reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/810500e92855eba8a7a5319ae913be2da6f957b0",
|
||||
"reference": "810500e92855eba8a7a5319ae913be2da6f957b0",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be",
|
||||
"reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3705,7 +3768,7 @@
|
|||
"phar-io/manifest": "^2.0.3",
|
||||
"phar-io/version": "^3.0.2",
|
||||
"php": ">=7.3",
|
||||
"phpunit/php-code-coverage": "^9.2.13",
|
||||
"phpunit/php-code-coverage": "^9.2.28",
|
||||
"phpunit/php-file-iterator": "^3.0.5",
|
||||
"phpunit/php-invoker": "^3.1.1",
|
||||
"phpunit/php-text-template": "^2.0.3",
|
||||
|
|
@ -3764,7 +3827,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.11"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -3780,7 +3843,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-19T07:10:56+00:00"
|
||||
"time": "2023-09-19T05:39:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
|
|
@ -3984,16 +4047,16 @@
|
|||
},
|
||||
{
|
||||
"name": "psr/http-client",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-client.git",
|
||||
"reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31"
|
||||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31",
|
||||
"reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31",
|
||||
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
||||
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4030,9 +4093,9 @@
|
|||
"psr-18"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-client/tree/1.0.2"
|
||||
"source": "https://github.com/php-fig/http-client"
|
||||
},
|
||||
"time": "2023-04-10T20:12:12+00:00"
|
||||
"time": "2023-09-23T14:17:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
|
|
@ -8920,16 +8983,16 @@
|
|||
},
|
||||
{
|
||||
"name": "maximebf/debugbar",
|
||||
"version": "v1.18.2",
|
||||
"version": "v1.19.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/maximebf/php-debugbar.git",
|
||||
"reference": "17dcf3f6ed112bb85a37cf13538fd8de49f5c274"
|
||||
"reference": "30f65f18f7ac086255a77a079f8e0dcdd35e828e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/17dcf3f6ed112bb85a37cf13538fd8de49f5c274",
|
||||
"reference": "17dcf3f6ed112bb85a37cf13538fd8de49f5c274",
|
||||
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/30f65f18f7ac086255a77a079f8e0dcdd35e828e",
|
||||
"reference": "30f65f18f7ac086255a77a079f8e0dcdd35e828e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8980,9 +9043,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/maximebf/php-debugbar/issues",
|
||||
"source": "https://github.com/maximebf/php-debugbar/tree/v1.18.2"
|
||||
"source": "https://github.com/maximebf/php-debugbar/tree/v1.19.0"
|
||||
},
|
||||
"time": "2023-02-04T15:27:00+00:00"
|
||||
"time": "2023-09-19T19:53:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mockery/mockery",
|
||||
|
|
@ -9159,16 +9222,16 @@
|
|||
},
|
||||
{
|
||||
"name": "pdepend/pdepend",
|
||||
"version": "2.14.0",
|
||||
"version": "2.15.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pdepend/pdepend.git",
|
||||
"reference": "1121d4b04af06e33e9659bac3a6741b91cab1de1"
|
||||
"reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/1121d4b04af06e33e9659bac3a6741b91cab1de1",
|
||||
"reference": "1121d4b04af06e33e9659bac3a6741b91cab1de1",
|
||||
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/d12f25bcdfb7754bea458a4a5cb159d55e9950d0",
|
||||
"reference": "d12f25bcdfb7754bea458a4a5cb159d55e9950d0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -9210,7 +9273,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/pdepend/pdepend/issues",
|
||||
"source": "https://github.com/pdepend/pdepend/tree/2.14.0"
|
||||
"source": "https://github.com/pdepend/pdepend/tree/2.15.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -9218,26 +9281,26 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-26T13:15:18+00:00"
|
||||
"time": "2023-09-28T12:00:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpmd/phpmd",
|
||||
"version": "2.13.0",
|
||||
"version": "2.14.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpmd/phpmd.git",
|
||||
"reference": "dad0228156856b3ad959992f9748514fa943f3e3"
|
||||
"reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpmd/phpmd/zipball/dad0228156856b3ad959992f9748514fa943f3e3",
|
||||
"reference": "dad0228156856b3ad959992f9748514fa943f3e3",
|
||||
"url": "https://api.github.com/repos/phpmd/phpmd/zipball/442fc2c34edcd5198b442d8647c7f0aec3afabe8",
|
||||
"reference": "442fc2c34edcd5198b442d8647c7f0aec3afabe8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0",
|
||||
"ext-xml": "*",
|
||||
"pdepend/pdepend": "^2.12.1",
|
||||
"pdepend/pdepend": "^2.15.1",
|
||||
"php": ">=5.3.9"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -9247,7 +9310,7 @@
|
|||
"gregwar/rst": "^1.0",
|
||||
"mikey179/vfsstream": "^1.6.8",
|
||||
"phpunit/phpunit": "^4.8.36 || ^5.7.27",
|
||||
"squizlabs/php_codesniffer": "^2.0"
|
||||
"squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2"
|
||||
},
|
||||
"bin": [
|
||||
"src/bin/phpmd"
|
||||
|
|
@ -9284,6 +9347,7 @@
|
|||
"description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.",
|
||||
"homepage": "https://phpmd.org/",
|
||||
"keywords": [
|
||||
"dev",
|
||||
"mess detection",
|
||||
"mess detector",
|
||||
"pdepend",
|
||||
|
|
@ -9293,7 +9357,7 @@
|
|||
"support": {
|
||||
"irc": "irc://irc.freenode.org/phpmd",
|
||||
"issues": "https://github.com/phpmd/phpmd/issues",
|
||||
"source": "https://github.com/phpmd/phpmd/tree/2.13.0"
|
||||
"source": "https://github.com/phpmd/phpmd/tree/2.14.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -9301,7 +9365,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-09-10T08:44:15+00:00"
|
||||
"time": "2023-09-28T13:07:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
|
|
@ -9602,5 +9666,5 @@
|
|||
"platform-overrides": {
|
||||
"php": "8.0.2"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,17 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Awobaz\Compoships\Database\Eloquent\Factories\ComposhipsFactory;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
|
||||
class AccountFactory extends Factory
|
||||
{
|
||||
protected $model = Account::class;
|
||||
use ComposhipsFactory;
|
||||
|
||||
public function definition()
|
||||
{
|
||||
|
|
@ -39,7 +42,7 @@ class AccountFactory extends Factory
|
|||
'confirmation_key' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'provisioning_token' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'ip_address' => $this->faker->ipv4,
|
||||
'created_at' => $this->faker->dateTime,
|
||||
'created_at' => $this->faker->dateTimeBetween('-1 year'),
|
||||
'dtmf_protocol' => array_rand(Account::$dtmfProtocols),
|
||||
'activated' => true
|
||||
];
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ namespace Database\Factories;
|
|||
use App\Admin;
|
||||
use App\Password;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class AdminFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\StatisticsMessage;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Awobaz\Compoships\Database\Eloquent\Factories\ComposhipsFactory;
|
||||
|
||||
class StatisticsMessageDeviceFactory extends Factory
|
||||
{
|
||||
use ComposhipsFactory;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$message = StatisticsMessage::factory()->create();
|
||||
|
||||
return [
|
||||
'message_id' => $message->id,
|
||||
'to_username' => $this->faker->userName(),
|
||||
'to_domain' => $this->faker->domainName(),
|
||||
'device_id' => $this->faker->uuid(),
|
||||
'received_at' => $this->faker->dateTimeBetween('-1 year'),
|
||||
'last_status' => 200,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,12 @@
|
|||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Awobaz\Compoships\Database\Eloquent\Factories\ComposhipsFactory;
|
||||
|
||||
class StatisticsMessageFactory extends Factory
|
||||
{
|
||||
use ComposhipsFactory;
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::table('statistics_calls', function (Blueprint $table) {
|
||||
$table->index('from_domain');
|
||||
$table->index('from_username');
|
||||
$table->index('to_domain');
|
||||
$table->index('to_username');
|
||||
});
|
||||
|
||||
Schema::table('statistics_messages', function (Blueprint $table) {
|
||||
$table->index('from_domain');
|
||||
$table->index('from_username');
|
||||
});
|
||||
|
||||
Schema::table('statistics_message_devices', function (Blueprint $table) {
|
||||
$table->index('to_domain');
|
||||
$table->index('to_username');
|
||||
});
|
||||
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->index('domain');
|
||||
$table->index('username');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('statistics_calls', function (Blueprint $table) {
|
||||
$table->dropIndex('statistics_calls_from_domain_index');
|
||||
$table->dropIndex('statistics_calls_from_username_index');
|
||||
$table->dropIndex('statistics_calls_to_domain_index');
|
||||
$table->dropIndex('statistics_calls_to_username_index');
|
||||
});
|
||||
|
||||
Schema::table('statistics_messages', function (Blueprint $table) {
|
||||
$table->dropIndex('statistics_messages_from_domain_index');
|
||||
$table->dropIndex('statistics_messages_from_username_index');
|
||||
});
|
||||
|
||||
Schema::table('statistics_message_devices', function (Blueprint $table) {
|
||||
$table->dropIndex('statistics_message_devices_to_domain_index');
|
||||
$table->dropIndex('statistics_message_devices_to_username_index');
|
||||
});
|
||||
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->dropIndex('accounts_domain_index');
|
||||
$table->dropIndex('accounts_username_index');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Account;
|
||||
use App\StatisticsCall;
|
||||
use App\StatisticsCallDevice;
|
||||
use App\StatisticsMessage;
|
||||
|
|
@ -39,12 +40,11 @@ class StatisticsSeeder extends Seeder
|
|||
StatisticsCall::truncate();
|
||||
Schema::enableForeignKeyConstraints();
|
||||
|
||||
StatisticsMessage::factory()
|
||||
->count(10000)
|
||||
->create();
|
||||
|
||||
StatisticsCall::factory()
|
||||
->count(10000)
|
||||
Account::factory(10)
|
||||
->hasStatisticsFromMessages(20)
|
||||
->hasStatisticsToMessageDevices(20)
|
||||
->hasStatisticsFromCalls(20)
|
||||
->hasStatisticsToCalls(20)
|
||||
->create();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
flexiapi/public/css/style.css
vendored
2
flexiapi/public/css/style.css
vendored
|
|
@ -760,7 +760,7 @@ select.list_toggle {
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
#chart {
|
||||
.chart {
|
||||
min-height: 80vh;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@
|
|||
<p title="{{ $account->updated_at }}">Updated on {{ $account->updated_at->format('d/m/Y') }}
|
||||
@include('parts.tabs', [
|
||||
'items' => [
|
||||
route('admin.account.edit', $account->id, ['type' => 'messages']) => 'Information',
|
||||
route('admin.account.device.index', $account->id, ['type' => 'accounts']) => 'Devices',
|
||||
route('admin.account.edit', $account->id) => 'Information',
|
||||
route('admin.account.device.index', $account->id) => 'Devices',
|
||||
route('admin.account.statistics.show', $account->id) => 'Statistics',
|
||||
],
|
||||
])
|
||||
@else
|
||||
|
|
@ -41,7 +42,8 @@
|
|||
<h2>Connexion</h2>
|
||||
<div>
|
||||
<input placeholder="Username" required="required" name="username" type="text"
|
||||
value="@if ($account->id){{ $account->username }}@else{{ old('username') }}@endif" @if ($account->id) readonly @endif>
|
||||
value="@if ($account->id) {{ $account->username }}@else{{ old('username') }} @endif"
|
||||
@if ($account->id) readonly @endif>
|
||||
<label for="username">Username</label>
|
||||
@include('parts.errors', ['name' => 'username'])
|
||||
</div>
|
||||
|
|
@ -53,32 +55,37 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<input placeholder="John Doe" name="display_name" type="text" value="@if ($account->id){{ $account->display_name }}@else{{ old('display_name') }}@endif">
|
||||
<input placeholder="John Doe" name="display_name" type="text"
|
||||
value="@if ($account->id) {{ $account->display_name }}@else{{ old('display_name') }} @endif">
|
||||
<label for="display_name">Display Name</label>
|
||||
@include('parts.errors', ['name' => 'display_name'])
|
||||
</div>
|
||||
<div></div>
|
||||
|
||||
<div>
|
||||
<input placeholder="Password" name="password" type="password" value="" autocomplete="new-password" @if (!$account->id)required @endif>
|
||||
<input placeholder="Password" name="password" type="password" value="" autocomplete="new-password"
|
||||
@if (!$account->id) required @endif>
|
||||
<label for="password">{{ $account->id ? 'Password (fill to change)' : 'Password' }}</label>
|
||||
@include('parts.errors', ['name' => 'password'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input placeholder="Password" name="password_confirmation" type="password" value="" autocomplete="off" @if (!$account->id)required @endif>
|
||||
<input placeholder="Password" name="password_confirmation" type="password" value="" autocomplete="off"
|
||||
@if (!$account->id) required @endif>
|
||||
<label for="password_confirmation">Confirm password</label>
|
||||
@include('parts.errors', ['name' => 'password_confirmation'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input placeholder="Email" name="email" type="email" value="@if ($account->id){{ $account->email }}@else{{ old('email') }}@endif">
|
||||
<input placeholder="Email" name="email" type="email"
|
||||
value="@if ($account->id) {{ $account->email }}@else{{ old('email') }} @endif">
|
||||
<label for="email">Email</label>
|
||||
@include('parts.errors', ['name' => 'email'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input placeholder="+12123123" name="phone" type="text" value="@if ($account->id){{ $account->phone }}@else{{ old('phone') }}@endif">
|
||||
<input placeholder="+12123123" name="phone" type="text"
|
||||
value="@if ($account->id) {{ $account->phone }}@else{{ old('phone') }} @endif">
|
||||
<label for="phone">Phone</label>
|
||||
@include('parts.errors', ['name' => 'phone'])
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@
|
|||
|
||||
@include('parts.tabs', [
|
||||
'items' => [
|
||||
route('admin.account.edit', $account->id, ['type' => 'messages']) => 'Information',
|
||||
route('admin.account.device.index', $account->id, ['type' => 'accounts']) => 'Devices',
|
||||
route('admin.account.edit', $account->id) => 'Information',
|
||||
route('admin.account.device.index', $account->id) => 'Devices',
|
||||
route('admin.account.statistics.show', $account->id) => 'Statistics',
|
||||
],
|
||||
])
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.account.index') }}">Accounts</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.account.edit', $account) }}">{{ $account->identifier }}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Statistics</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<header>
|
||||
<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',
|
||||
],
|
||||
])
|
||||
|
||||
<div>
|
||||
<form class="inline" method="POST" action="{{ route('admin.account.statistics.edit', $account) }}" accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method('post')
|
||||
|
||||
<input type="hidden" name="by" value="{{ request()->get('by', 'day') }}">
|
||||
|
||||
<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>
|
||||
<a href="{{ route('admin.account.statistics.show', ['account' => $account, 'by' => 'day'] + request()->only(['from', 'to', 'domain'])) }}"
|
||||
class="chip @if (request()->get('by', 'day') == 'day') selected @endif">Day</a>
|
||||
<a href="{{ route('admin.account.statistics.show', ['account' => $account, 'by' => 'week'] + request()->only(['from', 'to', 'domain'])) }}"
|
||||
class="chip @if (request()->get('by', 'day') == 'week') selected @endif">Week</a>
|
||||
<a href="{{ route('admin.account.statistics.show', ['account' => $account, 'by' => 'month'] + request()->only(['from', 'to', 'domain'])) }}"
|
||||
class="chip @if (request()->get('by', 'day') == 'month') selected @endif">Month</a>
|
||||
<a href="{{ route('admin.account.statistics.show', ['account' => $account, 'by' => 'year'] + request()->only(['from', 'to', 'domain'])) }}"
|
||||
class="chip @if (request()->get('by', 'day') == 'year') selected @endif">Year</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<h2><i class="material-icons-outlined">message</i> Messages from the account</h2>
|
||||
|
||||
{!! $messagesFromGraph !!}
|
||||
|
||||
<h2><i class="material-icons-outlined">message</i> Messages to the account</h2>
|
||||
|
||||
{!! $messagesToGraph !!}
|
||||
|
||||
<h2><i class="material-icons-outlined">call</i> Calls from the account</h2>
|
||||
|
||||
{!! $callsFromGraph !!}
|
||||
|
||||
<h2><i class="material-icons-outlined">call</i> Calls to the account</h2>
|
||||
|
||||
{!! $callsToGraph !!}
|
||||
|
||||
@endsection
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<div class="bar first" style="flex-basis: {{ percent($slice['phone'] - $slice['activated_phone'], $max) }}%"
|
||||
data-value="{{ $slice['phone'] - $slice['activated_phone'] }}"
|
||||
title="Unactivated phone: {{ $slice['phone'] - $slice['activated_phone'] }}"></div>
|
||||
<div class="bar first activated" style="flex-basis: {{ percent($slice['activated_phone'], $max) }}%"
|
||||
data-value="{{ $slice['activated_phone'] }}"
|
||||
title="Activated phone: {{ $slice['activated_phone'] }}"></div>
|
||||
<div class="bar second" style="flex-basis: {{ percent($slice['email'] - $slice['activated_email'], $max) }}%"
|
||||
data-value="{{ $slice['email'] - $slice['activated_email'] }}"
|
||||
title="Unactivated email: {{ $slice['email'] - $slice['activated_email'] }}"></div>
|
||||
<div class="bar second activated" style="flex-basis: {{ percent($slice['activated_email'], $max) }}%"
|
||||
data-value="{{ $slice['activated_email'] }}"
|
||||
title="Activated email: {{ $slice['activated_email'] }}"></div>
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<div>
|
||||
<form class="inline" method="POST" action="{{ route('admin.statistics.edit') }}" accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method('post')
|
||||
|
||||
<input type="hidden" name="by" value="{{ $request->get('by', 'day') }}">
|
||||
<input type="hidden" name="type" value="{{ $type }}">
|
||||
|
||||
<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
|
||||
|
||||
@if ($type == 'accounts')
|
||||
<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>
|
||||
@endif
|
||||
|
||||
<div>
|
||||
<a href="{{ route('admin.statistics.show', ['by' => 'day', 'type' => $type] + $request->only(['from', 'to', 'domain', 'contacts_list'])) }}"
|
||||
class="chip @if ($request->get('by', 'day') == 'day') selected @endif">Day</a>
|
||||
<a href="{{ route('admin.statistics.show', ['by' => 'week', 'type' => $type] + $request->only(['from', 'to', 'domain', 'contacts_list'])) }}"
|
||||
class="chip @if ($request->get('by', 'day') == 'week') selected @endif">Week</a>
|
||||
<a href="{{ route('admin.statistics.show', ['by' => 'month', 'type' => $type] + $request->only(['from', 'to', 'domain', 'contacts_list'])) }}"
|
||||
class="chip @if ($request->get('by', 'day') == 'month') selected @endif">Month</a>
|
||||
<a href="{{ route('admin.statistics.show', ['by' => 'year', 'type' => $type] + $request->only(['from', 'to', 'domain', 'contacts_list'])) }}"
|
||||
class="chip @if ($request->get('by', 'day') == 'year') selected @endif">Year</a>
|
||||
</div>
|
||||
|
||||
<div class="oppose">
|
||||
<a class="btn btn-secondary" href="{{ route('admin.statistics.show') }}">Reset</a>
|
||||
<a class="btn btn-tertiary"
|
||||
href="{{ route('admin.statistics.show', ['by' => $request->get('by', 'day'), 'type' => $type, 'export' => true] + $request->only(['from', 'to', 'domain'])) }}">
|
||||
<i class="material-icons-outlined">download</i> Export
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<div class="legend">
|
||||
<div class="first">Unactivated phones</div>
|
||||
<div class="first activated">Activated phones</div>
|
||||
<div class="second">Unactivated emails</div>
|
||||
<div class="second activated">Activated emails</div>
|
||||
</div>
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
@endsection
|
||||
|
||||
@section('content')
|
||||
<header>
|
||||
<h1><i class="material-icons-outlined">analytics</i> Statistics</h1>
|
||||
</header>
|
||||
<header>
|
||||
<h1><i class="material-icons-outlined">analytics</i> Statistics</h1>
|
||||
</header>
|
||||
|
||||
@include('parts.tabs', [
|
||||
'items' => [
|
||||
|
|
@ -17,43 +17,7 @@
|
|||
],
|
||||
])
|
||||
|
||||
<div>
|
||||
<form class="inline" method="POST" action="{{ route('admin.statistics.edit') }}" accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method('post')
|
||||
|
||||
<input type="hidden" name="by" value="{{ $by }}">
|
||||
<input type="hidden" name="type" value="{{ $type }}">
|
||||
|
||||
<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>
|
||||
<a href="{{ route('admin.statistics.show', ['by' => 'day', 'type' => $type] + $request->only(['from', 'to'])) }}"
|
||||
class="chip @if ($by == 'day') selected @endif">Day</a>
|
||||
<a href="{{ route('admin.statistics.show', ['by' => 'week', 'type' => $type] + $request->only(['from', 'to'])) }}"
|
||||
class="chip @if ($by == 'week') selected @endif">Week</a>
|
||||
<a href="{{ route('admin.statistics.show', ['by' => 'month', 'type' => $type] + $request->only(['from', 'to'])) }}"
|
||||
class="chip @if ($by == 'month') selected @endif">Month</a>
|
||||
<a href="{{ route('admin.statistics.show', ['by' => 'year', 'type' => $type] + $request->only(['from', 'to'])) }}"
|
||||
class="chip @if ($by == 'year') selected @endif">Year</a>
|
||||
</div>
|
||||
|
||||
<div class="oppose">
|
||||
<a class="btn btn-secondary" href="{{ route('admin.statistics.show') }}">Reset</a>
|
||||
<a class="btn btn-tertiary"
|
||||
href="{{ route('admin.statistics.show', ['by' => $by, 'type' => $type, 'export' => true] + $request->only(['from', 'to'])) }}">
|
||||
<i class="material-icons-outlined">download</i> Export
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@include('admin.statistics.parts.filters')
|
||||
|
||||
@include('parts.graph')
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -1,27 +1,17 @@
|
|||
<div id="chart" @if (isset($style))style="{{ $style }}" @endif></div>
|
||||
@php($id = generatePin())
|
||||
|
||||
<div id="chart-{{ $id }}" class="chart"></div>
|
||||
|
||||
<script>
|
||||
const config = {!! $jsonConfig !!};
|
||||
|
||||
chart = document.getElementById('chart');
|
||||
chart = document.getElementById('chart-' + {{ $id }});
|
||||
chart.innerHTML = '';
|
||||
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.id = 'myChart';
|
||||
canvas.id = 'myChart-' + {{ $id }};
|
||||
chart.appendChild(canvas);
|
||||
|
||||
@if (isset($withDataLabel) && $withDataLabel)
|
||||
config.plugins = [ChartDataLabels];
|
||||
@endif
|
||||
|
||||
@if (isset($showLabel) && $showLabel)
|
||||
config.options.plugins.datalabels.formatter = function(value, context) {
|
||||
return value + ' ' + context.dataset.label;
|
||||
}
|
||||
@endif
|
||||
|
||||
new Chart(
|
||||
document.getElementById('myChart'),
|
||||
config
|
||||
document.getElementById('myChart-' + {{ $id }}),
|
||||
{!! $jsonConfig !!}
|
||||
);
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ use App\Http\Controllers\Admin\AccountDeviceController;
|
|||
use App\Http\Controllers\Admin\AccountTypeController;
|
||||
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
|
||||
use App\Http\Controllers\Admin\AccountImportController;
|
||||
use App\Http\Controllers\Admin\AccountStatisticsController;
|
||||
use App\Http\Controllers\Admin\ContactsListController;
|
||||
use App\Http\Controllers\Admin\ContactsListContactController;
|
||||
use App\Http\Controllers\Admin\StatisticsController;
|
||||
|
|
@ -132,6 +133,7 @@ if (config('app.web_panel')) {
|
|||
Route::get('/', 'index')->name('index');
|
||||
Route::get('/{type?}', 'show')->name('show');
|
||||
Route::post('/', 'edit')->name('edit');
|
||||
//Route::post('search', 'search')->name('search');
|
||||
});
|
||||
|
||||
Route::name('account.')->prefix('accounts')->group(function () {
|
||||
|
|
@ -191,6 +193,11 @@ if (config('app.web_panel')) {
|
|||
Route::delete('/', 'destroy')->name('destroy');
|
||||
});
|
||||
|
||||
Route::name('statistics.')->prefix('{account}/statistics')->controller(AccountStatisticsController::class)->group(function () {
|
||||
Route::get('/', 'show')->name('show');
|
||||
Route::post('/', 'edit')->name('edit');
|
||||
});
|
||||
|
||||
Route::name('action.')->prefix('{account}/actions')->controller(AccountActionController::class)->group(function () {
|
||||
Route::get('create', 'create')->name('create');
|
||||
Route::post('/', 'store')->name('store');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue