mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Redesign the account related pages
This commit is contained in:
parent
f90304d768
commit
806a77a756
28 changed files with 728 additions and 644 deletions
|
|
@ -37,12 +37,10 @@ class Account extends Authenticatable
|
|||
|
||||
protected $with = ['passwords', 'admin', 'alias', 'activationExpiration', 'emailChangeCode', 'types', 'actions'];
|
||||
protected $hidden = ['alias', 'expire_time', 'confirmation_key', 'provisioning_token', 'pivot'];
|
||||
protected $dateTimes = ['creation_time'];
|
||||
protected $appends = ['realm', 'phone', 'confirmation_key_expires'];
|
||||
protected $casts = [
|
||||
'activated' => 'boolean',
|
||||
];
|
||||
public $timestamps = false;
|
||||
|
||||
public static $dtmfProtocols = ['sipinfo' => 'SIPInfo', 'rfc2833' => 'RFC2833', 'sipmessage' => 'SIP Message'];
|
||||
|
||||
|
|
@ -309,6 +307,11 @@ class Account extends Authenticatable
|
|||
}
|
||||
}
|
||||
|
||||
public function setRole(string $role)
|
||||
{
|
||||
$this->setAdminAttribute($role == 'admin');
|
||||
}
|
||||
|
||||
public function hasTombstone()
|
||||
{
|
||||
return AccountTombstone::where('username', $this->attributes['username'])
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class CreateAdminAccountTest extends Command
|
|||
$account->ip_address = '0.0.0.0';
|
||||
|
||||
// Create an "old" account to prevent unwanted deletion on the test server
|
||||
$account->creation_time = Carbon::now()->subYears(3);
|
||||
$account->created_at = Carbon::now()->subYears(3);
|
||||
$account->save();
|
||||
|
||||
$admin = new Admin;
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class GenerateExternalAccounts extends Command
|
|||
$account->ip_address = '127.0.0.1';
|
||||
$account->user_agent = 'External Account Generator';
|
||||
$account->group = $this->argument('group');
|
||||
$account->creation_time = Carbon::now();
|
||||
$account->created_at = Carbon::now();
|
||||
$i++;
|
||||
|
||||
$account->push($account->toArray());
|
||||
|
|
@ -80,7 +80,7 @@ class GenerateExternalAccounts extends Command
|
|||
Account::insert($accounts->toArray());
|
||||
|
||||
$insertedAccounts = Account::where('group', $this->argument('group'))
|
||||
->orderBy('creation_time', 'desc')
|
||||
->latest()
|
||||
->take($this->argument('amount'))
|
||||
->get();
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ use App\Admin;
|
|||
use App\Alias;
|
||||
use App\ApiKey;
|
||||
use App\DigestNonce;
|
||||
use App\EmailChanged;
|
||||
use App\Password;
|
||||
use App\PhoneChangeCode;
|
||||
|
||||
|
|
@ -106,7 +105,7 @@ class ImportDatabase extends Command
|
|||
// Fix bad creation_time
|
||||
$creationTime = strtotime($element->creation_time);
|
||||
if ($creationTime == false || $creationTime < 0) {
|
||||
$element->creation_time = gmdate('Y-m-d H:i:s', 1);
|
||||
$element->created_at = gmdate('Y-m-d H:i:s', 1);
|
||||
}
|
||||
return (array)$element;
|
||||
})
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class RemoveUnconfirmedAccounts extends Command
|
|||
public function handle()
|
||||
{
|
||||
$accounts = Account::where(
|
||||
'creation_time',
|
||||
'created_at',
|
||||
'<',
|
||||
Carbon::now()->subDays($this->argument('days'))->toDateTimeString()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,27 +26,38 @@ use Carbon\Carbon;
|
|||
|
||||
use App\Account;
|
||||
use App\Admin;
|
||||
use App\Alias;
|
||||
use App\ExternalAccount;
|
||||
use App\Http\Requests\CreateAccountRequest;
|
||||
use App\Http\Requests\UpdateAccountRequest;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
public function index(Request $request, $search = '')
|
||||
public function index(Request $request)
|
||||
{
|
||||
$accounts = Account::orderBy('creation_time', 'desc')->with('externalAccount');
|
||||
$accounts = Account::orderBy('updated_at', $request->get('updated_at_order', 'desc'))
|
||||
->with('externalAccount');
|
||||
|
||||
if (!empty($search)) {
|
||||
$accounts = $accounts->where('username', 'like', '%'.$search.'%');
|
||||
if ($request->has('search')) {
|
||||
$accounts = $accounts->where('username', 'like', '%' . $request->get('search') . '%');
|
||||
}
|
||||
|
||||
if ($request->has('updated_date')) {
|
||||
$accounts->whereDate('updated_at', $request->get('updated_date'));
|
||||
}
|
||||
|
||||
return view('admin.account.index', [
|
||||
'search' => $search,
|
||||
'accounts' => $accounts->paginate(30)->appends($request->query())
|
||||
'search' => $request->get('search'),
|
||||
'updated_date' => $request->get('updated_date'),
|
||||
'accounts' => $accounts->paginate(20)->appends($request->query()),
|
||||
'updated_at_order' => $request->get('updated_at_order') == 'desc' ? 'asc' : 'desc'
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(Request $request)
|
||||
{
|
||||
return redirect()->route('admin.account.index', $request->except('_token'));
|
||||
}
|
||||
|
||||
public function show(int $id)
|
||||
{
|
||||
return view('admin.account.show', [
|
||||
|
|
@ -71,9 +82,10 @@ class AccountController extends Controller
|
|||
$account->display_name = $request->get('display_name');
|
||||
$account->domain = resolveDomain($request);
|
||||
$account->ip_address = $request->ip();
|
||||
$account->creation_time = Carbon::now();
|
||||
$account->created_at = Carbon::now();
|
||||
$account->user_agent = config('app.name');
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->activated = $request->has('activated');
|
||||
$account->save();
|
||||
|
||||
$account->phone = $request->get('phone');
|
||||
|
|
@ -94,26 +106,28 @@ class AccountController extends Controller
|
|||
|
||||
public function update(UpdateAccountRequest $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'password' => 'confirmed',
|
||||
]);
|
||||
|
||||
$account = Account::findOrFail($id);
|
||||
$account->username = $request->get('username');
|
||||
$account->email = $request->get('email');
|
||||
$account->display_name = $request->get('display_name');
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->activated = $request->has('activated');
|
||||
$account->save();
|
||||
|
||||
$account->phone = $request->get('phone');
|
||||
$account->fillPassword($request);
|
||||
|
||||
$account->setRole($request->get('role'));
|
||||
|
||||
Log::channel('events')->info('Web Admin: Account updated', ['id' => $account->identifier]);
|
||||
|
||||
return redirect()->route('admin.account.show', $id);
|
||||
}
|
||||
|
||||
public function search(Request $request)
|
||||
{
|
||||
return redirect()->route('admin.account.index', $request->get('search'));
|
||||
}
|
||||
|
||||
public function attachExternalAccount(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
|
|
@ -124,28 +138,6 @@ class AccountController extends Controller
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function activate(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
$account->activated = true;
|
||||
$account->save();
|
||||
|
||||
Log::channel('events')->info('Web Admin: Account activated', ['id' => $account->identifier]);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function deactivate(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
$account->activated = false;
|
||||
$account->save();
|
||||
|
||||
Log::channel('events')->info('Web Admin: Account deactivated', ['id' => $account->identifier]);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function provision(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
|
|
@ -157,33 +149,6 @@ class AccountController extends Controller
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function admin(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
|
||||
$admin = new Admin;
|
||||
$admin->account_id = $account->id;
|
||||
$admin->save();
|
||||
|
||||
Log::channel('events')->info('Web Admin: Account set as admin', ['id' => $account->identifier]);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function unadmin(Request $request, $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
|
||||
// An admin cannot remove it's own permission
|
||||
if ($account->id == $request->user()->id) abort(403);
|
||||
|
||||
if ($account->admin) $account->admin->delete();
|
||||
|
||||
Log::channel('events')->info('Web Admin: Account unset as admin', ['id' => $account->identifier]);
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function delete(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ class AccountController extends Controller
|
|||
? $request->get('domain')
|
||||
: config('app.sip_domain');
|
||||
$account->ip_address = $request->ip();
|
||||
$account->creation_time = Carbon::now();
|
||||
$account->created_at = Carbon::now();
|
||||
$account->user_agent = $request->header('User-Agent') ?? config('app.name');
|
||||
$account->provision();
|
||||
$account->save();
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class AccountController extends Controller
|
|||
$account->activated = $request->has('activated') ? (bool)$request->get('activated') : false;
|
||||
$account->ip_address = $request->ip();
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->creation_time = Carbon::now();
|
||||
$account->created_at = Carbon::now();
|
||||
$account->domain = resolveDomain($request);
|
||||
$account->user_agent = $request->header('User-Agent') ?? config('app.name');
|
||||
|
||||
|
|
|
|||
|
|
@ -29,23 +29,24 @@ class UpdateAccountRequest extends FormRequest
|
|||
new BlacklistedUsername,
|
||||
new SIPUsername,
|
||||
Rule::unique('accounts', 'username')->where(function ($query) {
|
||||
$query->where('domain', config('app.sip_domain'));
|
||||
})->ignore($this->route('id'), 'id'),
|
||||
$query->where('domain', resolveDomain($this));
|
||||
})->ignore($this->route('account_id'), 'id'),
|
||||
'filled',
|
||||
],
|
||||
'email' => [
|
||||
'nullable',
|
||||
'email',
|
||||
config('app.account_email_unique') ? Rule::unique('accounts', 'email')->ignore($this->route('id')) : null
|
||||
config('app.account_email_unique') ? Rule::unique('accounts', 'email')->ignore($this->route('account_id')) : null
|
||||
],
|
||||
'role' => 'in:admin,end_user',
|
||||
'password_sha256' => 'nullable|min:3',
|
||||
'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(),
|
||||
'phone' => [
|
||||
'nullable',
|
||||
Rule::unique('accounts', 'username')->where(function ($query) {
|
||||
$query->where('domain', config('app.sip_domain'));
|
||||
})->ignore($this->route('id'), 'id'),
|
||||
Rule::unique('aliases', 'alias')->ignore($this->route('id'), 'account_id'),
|
||||
})->ignore($this->route('account_id'), 'id'),
|
||||
Rule::unique('aliases', 'alias')->ignore($this->route('account_id'), 'account_id'),
|
||||
new WithoutSpaces, 'starts_with:+'
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class StatisticsCruncher
|
|||
{
|
||||
$data = self::getAccountFrom(Carbon::now()->subMonth())
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -43,14 +43,14 @@ class StatisticsCruncher
|
|||
->from('aliases');
|
||||
})
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
$dataActivated = self::getAccountFrom(Carbon::now()->subMonth())
|
||||
->where('activated', true)
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ class StatisticsCruncher
|
|||
->from('aliases');
|
||||
})
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ class StatisticsCruncher
|
|||
{
|
||||
$data = self::getAccountFrom(Carbon::now()->subWeek())
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -88,14 +88,14 @@ class StatisticsCruncher
|
|||
->from('aliases');
|
||||
})
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
$dataActivated = self::getAccountFrom(Carbon::now()->subWeek())
|
||||
->where('activated', true)
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ class StatisticsCruncher
|
|||
->from('aliases');
|
||||
})
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ class StatisticsCruncher
|
|||
{
|
||||
$data = self::getAccountFrom(Carbon::now()->subDay())
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d %H') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d %H') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -133,14 +133,14 @@ class StatisticsCruncher
|
|||
->from('aliases');
|
||||
})
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d %H') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d %H') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
$dataActivated = self::getAccountFrom(Carbon::now()->subDay())
|
||||
->where('activated', true)
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d %H') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d %H') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ class StatisticsCruncher
|
|||
->from('aliases');
|
||||
})
|
||||
->get(array(
|
||||
DB::raw("date_format(creation_time,'%Y-%m-%d %H') as moment"),
|
||||
DB::raw("date_format(created_at,'%Y-%m-%d %H') as moment"),
|
||||
DB::raw('COUNT(*) as "count"')
|
||||
))->each->setAppends([])->pluck('count', 'moment');
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ class StatisticsCruncher
|
|||
|
||||
private static function getAccountFrom($date)
|
||||
{
|
||||
return Account::where('creation_time', '>=', $date)
|
||||
return Account::where('created_at', '>=', $date)
|
||||
->groupBy('moment')
|
||||
->orderBy('moment', 'DESC')
|
||||
->setEagerLoads([]);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class AccountService
|
|||
$account->activated = false;
|
||||
$account->domain = config('app.sip_domain');
|
||||
$account->ip_address = $request->ip();
|
||||
$account->creation_time = Carbon::now();
|
||||
$account->created_at = Carbon::now();
|
||||
$account->user_agent = config('app.name');
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->confirmation_key = generatePin();
|
||||
|
|
|
|||
74
flexiapi/composer.lock
generated
74
flexiapi/composer.lock
generated
|
|
@ -650,28 +650,28 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/inflector",
|
||||
"version": "2.0.6",
|
||||
"version": "2.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/inflector.git",
|
||||
"reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024"
|
||||
"reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/inflector/zipball/d9d313a36c872fd6ee06d9a6cbcf713eaa40f024",
|
||||
"reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024",
|
||||
"url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff",
|
||||
"reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^10",
|
||||
"doctrine/coding-standard": "^11.0",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.3",
|
||||
"phpunit/phpunit": "^8.5 || ^9.5",
|
||||
"vimeo/psalm": "^4.25"
|
||||
"vimeo/psalm": "^4.25 || ^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -721,7 +721,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/inflector/issues",
|
||||
"source": "https://github.com/doctrine/inflector/tree/2.0.6"
|
||||
"source": "https://github.com/doctrine/inflector/tree/2.0.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -737,7 +737,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-10-20T09:10:12+00:00"
|
||||
"time": "2023-06-16T13:40:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
|
|
@ -1119,16 +1119,16 @@
|
|||
},
|
||||
{
|
||||
"name": "fakerphp/faker",
|
||||
"version": "v1.22.0",
|
||||
"version": "v1.23.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FakerPHP/Faker.git",
|
||||
"reference": "f85772abd508bd04e20bb4b1bbe260a68d0066d2"
|
||||
"reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FakerPHP/Faker/zipball/f85772abd508bd04e20bb4b1bbe260a68d0066d2",
|
||||
"reference": "f85772abd508bd04e20bb4b1bbe260a68d0066d2",
|
||||
"url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e3daa170d00fde61ea7719ef47bb09bb8f1d9b01",
|
||||
"reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1181,9 +1181,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/FakerPHP/Faker/issues",
|
||||
"source": "https://github.com/FakerPHP/Faker/tree/v1.22.0"
|
||||
"source": "https://github.com/FakerPHP/Faker/tree/v1.23.0"
|
||||
},
|
||||
"time": "2023-05-14T12:31:37+00:00"
|
||||
"time": "2023-06-12T08:44:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fruitcake/php-cors",
|
||||
|
|
@ -1729,16 +1729,16 @@
|
|||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v9.52.8",
|
||||
"version": "v9.52.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "d4c62cc12544b8acc8d89fcb510f4aefb12e6dea"
|
||||
"reference": "c512ece7b1ee393eac5893f37cb2b029a5413b97"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/d4c62cc12544b8acc8d89fcb510f4aefb12e6dea",
|
||||
"reference": "d4c62cc12544b8acc8d89fcb510f4aefb12e6dea",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/c512ece7b1ee393eac5893f37cb2b029a5413b97",
|
||||
"reference": "c512ece7b1ee393eac5893f37cb2b029a5413b97",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1923,7 +1923,7 @@
|
|||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2023-05-30T14:45:57+00:00"
|
||||
"time": "2023-06-08T20:06:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
|
|
@ -4149,16 +4149,16 @@
|
|||
},
|
||||
{
|
||||
"name": "react/stream",
|
||||
"version": "v1.2.0",
|
||||
"version": "v1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/stream.git",
|
||||
"reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9"
|
||||
"reference": "6fbc9672905c7d5a885f2da2fc696f65840f4a66"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/stream/zipball/7a423506ee1903e89f1e08ec5f0ed430ff784ae9",
|
||||
"reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9",
|
||||
"url": "https://api.github.com/repos/reactphp/stream/zipball/6fbc9672905c7d5a885f2da2fc696f65840f4a66",
|
||||
"reference": "6fbc9672905c7d5a885f2da2fc696f65840f4a66",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4168,12 +4168,12 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"clue/stream-filter": "~1.2",
|
||||
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
|
||||
"phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"React\\Stream\\": "src"
|
||||
"React\\Stream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
|
@ -4215,19 +4215,15 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/reactphp/stream/issues",
|
||||
"source": "https://github.com/reactphp/stream/tree/v1.2.0"
|
||||
"source": "https://github.com/reactphp/stream/tree/v1.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/WyriHaximus",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/clue",
|
||||
"type": "github"
|
||||
"url": "https://opencollective.com/reactphp",
|
||||
"type": "open_collective"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-11T12:37:55+00:00"
|
||||
"time": "2023-06-16T10:52:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "respect/stringifier",
|
||||
|
|
@ -8207,16 +8203,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.6.8",
|
||||
"version": "9.6.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e"
|
||||
"reference": "a9aceaf20a682aeacf28d582654a1670d8826778"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e",
|
||||
"reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a9aceaf20a682aeacf28d582654a1670d8826778",
|
||||
"reference": "a9aceaf20a682aeacf28d582654a1670d8826778",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8290,7 +8286,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.8"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.9"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8306,7 +8302,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-11T05:14:45+00:00"
|
||||
"time": "2023-06-11T06:13:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class AccountFactory extends Factory
|
|||
'confirmation_key' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'provisioning_token' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'ip_address' => $this->faker->ipv4,
|
||||
'creation_time' => $this->faker->dateTime,
|
||||
'created_at' => $this->faker->dateTime,
|
||||
'dtmf_protocol' => array_rand(Account::$dtmfProtocols),
|
||||
'activated' => true
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function(Blueprint $table) {
|
||||
$table->renameColumn('creation_time', 'created_at');
|
||||
});
|
||||
|
||||
// Two different migrations to handle SQLite
|
||||
Schema::table('accounts', function(Blueprint $table) {
|
||||
$table->dateTime('updated_at')->nullable();
|
||||
});
|
||||
|
||||
DB::statement('update accounts set updated_at = created_at');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function(Blueprint $table) {
|
||||
$table->renameColumn('created_at', 'creation_time');
|
||||
$table->dropColumn('updated_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -115,7 +115,7 @@ class LiblinphoneTesterAccoutSeeder extends Seeder
|
|||
'ip_address' => '',
|
||||
'confirmation_key' => $confirmationKey,
|
||||
'user_agent' => 'FlexiAPI Seeder',
|
||||
'creation_time' => '2010-01-03 04:30:43'
|
||||
'created_at' => '2010-01-03 04:30:43'
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
359
flexiapi/public/css/far.css
vendored
359
flexiapi/public/css/far.css
vendored
|
|
@ -90,6 +90,11 @@ body {
|
|||
--danger-9: rgba(104, 26, 54, 1);
|
||||
}
|
||||
|
||||
body.show_menu {
|
||||
max-height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
p,
|
||||
a {
|
||||
font-size: 1.5rem;
|
||||
|
|
@ -104,6 +109,11 @@ p b {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
p i {
|
||||
vertical-align: middle;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
p>a:not(.btn),
|
||||
label>a {
|
||||
text-decoration: underline;
|
||||
|
|
@ -186,12 +196,54 @@ header nav a i {
|
|||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
header nav a:first-child {
|
||||
@media screen and (max-width: 800px) {
|
||||
header nav {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
header nav a {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
header nav a i {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
header nav a#logo {
|
||||
font-weight: 700;
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
header nav a:first-child::before {
|
||||
header nav a#menu {
|
||||
color: var(--main-5);
|
||||
}
|
||||
|
||||
header nav a#menu:after {
|
||||
display: block;
|
||||
font-family: 'Material Icons';
|
||||
content: "\e5d2";
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
body.show_menu header nav a#menu:after {
|
||||
content: "\e5cd";
|
||||
}
|
||||
|
||||
header nav a#logo span {
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
header nav a#logo {
|
||||
position: absolute;
|
||||
left: calc(50% - 1.5rem);
|
||||
top: 0.75rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
header nav a#logo::before {
|
||||
content: '';
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
|
|
@ -202,17 +254,16 @@ header nav a:first-child::before {
|
|||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
margin-right: 1.5rem;
|
||||
border-radius: 1rem;
|
||||
box-shadow: 0 0 2rem rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
header nav a:nth-child(2) {
|
||||
header nav a.oppose {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
header nav a:last-child {
|
||||
padding-right: 2rem;
|
||||
header nav a.oppose ~ a.oppose {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/** Section **/
|
||||
|
|
@ -224,9 +275,13 @@ content section {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
content nav + section {
|
||||
min-width: calc(80% - 20rem);
|
||||
}
|
||||
|
||||
/** Sidenav **/
|
||||
|
||||
content nav {
|
||||
content > nav {
|
||||
background-color: var(--main-5);
|
||||
width: 20rem;
|
||||
margin-left: 0;
|
||||
|
|
@ -239,9 +294,11 @@ content nav {
|
|||
background-position: bottom center;
|
||||
background-repeat: repeat-x;
|
||||
background-image: url('/img/footer.svg');
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
content nav a {
|
||||
content > nav a {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 1.75rem;
|
||||
|
|
@ -254,14 +311,34 @@ content nav a {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
content nav a.current {
|
||||
@media screen and (max-width: 800px) {
|
||||
content > nav {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
min-height: 100vh;
|
||||
max-height: 100%;
|
||||
overflow-y: scroll;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0;
|
||||
padding-top: 2rem;
|
||||
|
||||
transition: transform 0.5s ease-in-out;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
body.show_menu content > nav {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
content > nav a.current {
|
||||
background-color: white;
|
||||
border-radius: 4rem;
|
||||
color: var(--main-5);
|
||||
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
content nav a.current:before {
|
||||
content > nav a.current:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 1rem;
|
||||
|
|
@ -274,7 +351,7 @@ content nav a.current:before {
|
|||
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
content nav a i {
|
||||
content > nav a i {
|
||||
margin: 0 1rem;
|
||||
margin-left: 2rem;
|
||||
font-size: 2rem;
|
||||
|
|
@ -312,199 +389,18 @@ h1 i {
|
|||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
/** Forms **/
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background-color: var(--main-5);
|
||||
font-weight: 600;
|
||||
border: 1px solid var(--main-5);
|
||||
border-radius: 3rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
padding: 1rem 2rem;
|
||||
color: white;
|
||||
margin: 0 1rem;
|
||||
h2 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 800;
|
||||
padding: 1rem 0;
|
||||
color: var(--second-7);
|
||||
}
|
||||
|
||||
.btn i {
|
||||
margin-right: 0.5rem;
|
||||
margin-left: -0.5rem;
|
||||
h2 i {
|
||||
font-size: 2rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.oppose {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.btn[disabled] {
|
||||
color: var(--main-5);
|
||||
border-color: var(--main-5);
|
||||
background-color: var(--main-1);
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: var(--main-6);
|
||||
border-color: var(--main-6);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
background-color: var(--main-7);
|
||||
border-color: var(--main-7);
|
||||
}
|
||||
|
||||
.btn.btn-secondary {
|
||||
background-color: transparent;
|
||||
color: var(--main-5);
|
||||
}
|
||||
|
||||
.btn.btn-secondary:hover {
|
||||
background-color: var(--main-1);
|
||||
}
|
||||
|
||||
.btn.btn-secondary:active {
|
||||
background-color: var(--main-5);
|
||||
border-color: var(--main-5);
|
||||
color: white;
|
||||
}
|
||||
|
||||
form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1.5rem 0.5rem;
|
||||
}
|
||||
|
||||
form div {
|
||||
position: relative;
|
||||
min-height: 4rem;
|
||||
}
|
||||
|
||||
form .large {
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
form div {
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
}
|
||||
|
||||
form small {
|
||||
display: block;
|
||||
font-weight: 300;
|
||||
color: var(--second-6);
|
||||
font-size: 1.25rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
form label {
|
||||
color: var(--second-6);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
form input[required]+label:after {
|
||||
content: '*';
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
form input:not([type=checkbox])+label,
|
||||
form select+label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
form div .btn {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
form div .btn.oppose {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
form div input,
|
||||
form div select {
|
||||
padding: 1rem 2rem;
|
||||
background-color: var(--grey-1);
|
||||
border-radius: 3rem;
|
||||
border: 1px solid var(--grey-2);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
form div select {
|
||||
appearance: none;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
form div.checkbox {
|
||||
min-height: 2rem;
|
||||
}
|
||||
|
||||
form div.select:after {
|
||||
font-family: 'Material Icons';
|
||||
content: "\e5cf";
|
||||
display: block;
|
||||
font-size: 3rem;
|
||||
color: var(--second-6);
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 0rem;
|
||||
pointer-events: none;
|
||||
line-height: 4rem;
|
||||
}
|
||||
|
||||
form div input[disabled] {
|
||||
border-color: var(--grey-4);
|
||||
color: var(--grey-4);
|
||||
background-color: var(--grey-2);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
form div input[type=checkbox] {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
form div input:not([type=checkbox]):not(.btn),
|
||||
form div select {
|
||||
margin-top: 2.5rem;
|
||||
box-sizing: border-box;
|
||||
min-width: 65%;
|
||||
}
|
||||
|
||||
form div input:autofill {
|
||||
background: var(--grey-1);
|
||||
}
|
||||
|
||||
form div input:hover,
|
||||
form div select:hover {
|
||||
border-color: var(--second-4);
|
||||
}
|
||||
|
||||
form div input:focus-visible, form div input:active {
|
||||
color: var(--main-5);
|
||||
border-color: var(--main-5);
|
||||
}
|
||||
|
||||
form div input:focus-visible+label, form div input:active+label {
|
||||
color: var(--main-5);
|
||||
}
|
||||
|
||||
form div input:invalid {
|
||||
border-color: var(--danger-6);
|
||||
color: var(--danger-5);
|
||||
}
|
||||
|
||||
form div input:invalid+label {
|
||||
color: var(--danger-5);
|
||||
}
|
||||
|
||||
/** Badge **/
|
||||
|
||||
.badge {
|
||||
|
|
@ -524,23 +420,30 @@ table {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
table tr th {
|
||||
table tr td,
|
||||
table tr th{
|
||||
line-height: 4rem;
|
||||
padding: 0 2rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
table tr th,
|
||||
table tr th a {
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: var(--second-4);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table tr th a i {
|
||||
font-size: 3rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table thead {
|
||||
border-bottom: 1px solid var(--second-4);
|
||||
}
|
||||
|
||||
table tr td,
|
||||
table tr th {
|
||||
line-height: 4rem;
|
||||
padding: 0 2rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
table tr:nth-child(2n) {
|
||||
background-color: var(--grey-1);
|
||||
|
|
@ -556,7 +459,7 @@ table tr:nth-child(2n) {
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
@media screen and (max-width: 800px) {
|
||||
|
||||
.on_mobile,
|
||||
.on_mobile_after:after {
|
||||
|
|
@ -571,4 +474,46 @@ table tr:nth-child(2n) {
|
|||
.on_desktop {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Pagination **/
|
||||
|
||||
ul.pagination {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
ul.pagination li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
ul.pagination li .page-link {
|
||||
font-size: 1.6rem;
|
||||
padding: 0.5rem;
|
||||
line-height: 2rem;
|
||||
border-radius: 2rem;
|
||||
margin: 0 0.5rem;
|
||||
text-align: center;
|
||||
min-width: 2rem;
|
||||
display: block;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
ul.pagination li:not(.disabled).active .page-link {
|
||||
color: white;
|
||||
background-color: var(--main-5);
|
||||
}
|
||||
|
||||
ul.pagination li:not(.disabled) .page-link {
|
||||
color: var(--main-5);
|
||||
}
|
||||
ul.pagination li:not(.disabled):not(.active) .page-link:hover {
|
||||
background-color: var(--main-1);
|
||||
}
|
||||
|
||||
ul.pagination li:not(.disabled) .page-link:hover {
|
||||
border-color: var(--main-5);
|
||||
}
|
||||
|
|
|
|||
216
flexiapi/public/css/form.css
vendored
Normal file
216
flexiapi/public/css/form.css
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/** Forms **/
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background-color: var(--main-5);
|
||||
font-weight: 600;
|
||||
border: 1px solid var(--main-5);
|
||||
border-radius: 3rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: 2rem;
|
||||
padding: 1rem 2rem;
|
||||
color: white;
|
||||
margin: 0 1rem;
|
||||
}
|
||||
|
||||
.btn i {
|
||||
margin-right: 0.5rem;
|
||||
margin-left: -0.5rem;
|
||||
font-size: 2rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.oppose {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.btn[disabled] {
|
||||
color: var(--main-5);
|
||||
border-color: var(--main-5);
|
||||
background-color: var(--main-1);
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: var(--main-6);
|
||||
border-color: var(--main-6);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
background-color: var(--main-7);
|
||||
border-color: var(--main-7);
|
||||
}
|
||||
|
||||
.btn.btn-secondary {
|
||||
background-color: transparent;
|
||||
color: var(--main-5);
|
||||
}
|
||||
|
||||
.btn.btn-secondary:hover {
|
||||
background-color: var(--main-1);
|
||||
}
|
||||
|
||||
.btn.btn-secondary:active {
|
||||
background-color: var(--main-5);
|
||||
border-color: var(--main-5);
|
||||
color: white;
|
||||
}
|
||||
|
||||
form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1.5rem 0.5rem;
|
||||
}
|
||||
|
||||
form.inline {
|
||||
display: block;
|
||||
}
|
||||
|
||||
form div {
|
||||
position: relative;
|
||||
min-height: 4rem;
|
||||
}
|
||||
|
||||
form.inline div {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin-right: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
form .large,
|
||||
form h2 {
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
form div {
|
||||
grid-column: 1/-1;
|
||||
}
|
||||
}
|
||||
|
||||
form small {
|
||||
display: block;
|
||||
font-weight: 300;
|
||||
color: var(--second-6);
|
||||
font-size: 1.25rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
form label {
|
||||
color: var(--second-6);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
form input[required]+label:after {
|
||||
content: '*';
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
form input:not([type=checkbox]) ~ label,
|
||||
form select ~ label {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
form:not(.inline) div .btn {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
form div .btn.oppose {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
form div input,
|
||||
form div select {
|
||||
padding: 1rem 2rem;
|
||||
background-color: var(--grey-1);
|
||||
border-radius: 3rem;
|
||||
border: 1px solid var(--grey-2);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
form div select {
|
||||
appearance: none;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
form div.checkbox {
|
||||
min-height: 2rem;
|
||||
}
|
||||
|
||||
form div.select:after {
|
||||
font-family: 'Material Icons';
|
||||
content: "\e5cf";
|
||||
display: block;
|
||||
font-size: 3rem;
|
||||
color: var(--second-6);
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
bottom: 0rem;
|
||||
pointer-events: none;
|
||||
line-height: 4rem;
|
||||
}
|
||||
|
||||
form div input[disabled] {
|
||||
border-color: var(--grey-4);
|
||||
color: var(--grey-4);
|
||||
background-color: var(--grey-2);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
form div input[type=checkbox] {
|
||||
margin-right: 1rem;
|
||||
accent-color: var(--main-5);
|
||||
}
|
||||
|
||||
form div input:not([type=checkbox]):not([type=radio]):not(.btn),
|
||||
form div select {
|
||||
margin-top: 2.5rem;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
form div input[type=radio] {
|
||||
width: auto;
|
||||
margin: 1rem;
|
||||
margin-top: 3.75rem;
|
||||
accent-color: var(--main-5);
|
||||
}
|
||||
|
||||
form div input[type=radio] + p {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
form div input:autofill {
|
||||
background: var(--grey-1);
|
||||
}
|
||||
|
||||
form div input:hover,
|
||||
form div select:hover {
|
||||
border-color: var(--second-4);
|
||||
}
|
||||
|
||||
form div input:focus-visible, form div input:active {
|
||||
color: var(--main-5);
|
||||
border-color: var(--main-5);
|
||||
}
|
||||
|
||||
form div input:focus-visible+label, form div input:active+label {
|
||||
color: var(--main-5);
|
||||
}
|
||||
|
||||
form div input:invalid {
|
||||
border-color: var(--danger-6);
|
||||
color: var(--danger-5);
|
||||
}
|
||||
|
||||
form div input:invalid+label {
|
||||
color: var(--danger-5);
|
||||
}
|
||||
|
|
@ -3,86 +3,60 @@
|
|||
@section('content')
|
||||
|
||||
<h1><i class="material-icons">dashboard</i> Dashboard</h1>
|
||||
|
||||
<div class="list-group mb-3 pt-2">
|
||||
<a href="{{ route('account.email.change') }}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Change my current account email</h5>
|
||||
</div>
|
||||
@if (!empty($account->email))
|
||||
<p class="mb-1">{{ $account->email }}</p>
|
||||
@else
|
||||
<p class="mb-1">No email yet</p>
|
||||
@endif
|
||||
</a>
|
||||
@if (config('app.devices_management') == true)
|
||||
<a href="{{ route('account.device.index') }}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Manage my devices</h5>
|
||||
</div>
|
||||
<p class="mb-1">See and delete the devices linked to your account</p>
|
||||
</a>
|
||||
<p>
|
||||
<i class="material-icons">email</i>
|
||||
@if (!empty($account->email))
|
||||
{{ $account->email }}
|
||||
@else
|
||||
No email yet
|
||||
@endif
|
||||
<a href="{{ route('account.password') }}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
@if ($account->passwords()->count() > 0)
|
||||
<h5 class="mb-1">Change my password</h5>
|
||||
@else
|
||||
<h5 class="mb-1">Set my password</h5>
|
||||
@endif
|
||||
</div>
|
||||
@if ($account->passwords()->where('algorithm', 'SHA-256')->exists())
|
||||
<p class="mb-1">SHA-256 password configured</p>
|
||||
@else
|
||||
<p class="mb-1">MD5 password only</p>
|
||||
@endif
|
||||
</a>
|
||||
<a href="{{ route('account.delete') }}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Delete my account</h5>
|
||||
</div>
|
||||
<p class="mb-1">Remove your account from our service</p>
|
||||
</a>
|
||||
</div>
|
||||
<a href="{{ route('account.email.change') }}">Change my current account email</a>
|
||||
</p>
|
||||
|
||||
@if($account->admin)
|
||||
<h3>Admin area</h3>
|
||||
<div class="list-group mb-3">
|
||||
<a href="{{ route('admin.account.index') }}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Accounts</h5>
|
||||
</div>
|
||||
<p class="mb-1">Manage the Flexisip accounts</p>
|
||||
</a>
|
||||
<a href="{{ route('admin.account.type.index') }}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Account types</h5>
|
||||
</div>
|
||||
<p class="mb-1">Manage the account types</p>
|
||||
</a>
|
||||
<a href="{{ route('admin.statistics.show.day') }}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">Statistics</h5>
|
||||
</div>
|
||||
<p class="mb-1">Show some registration statistics</p>
|
||||
</a>
|
||||
</div>
|
||||
<p>
|
||||
<i class="material-icons">call</i>
|
||||
@if (!empty($account->phone))
|
||||
{{ $account->phone }}
|
||||
@else
|
||||
No phone yet
|
||||
@endif
|
||||
<a href="{{ route('account.phone.change') }}">Change my current account phone</a>
|
||||
</p>
|
||||
@if (config('app.devices_management') == true)
|
||||
<p>
|
||||
<i class="material-icons">laptop</i>
|
||||
<a href="{{ route('account.device.index') }}">Manage my devices</a>
|
||||
</p>
|
||||
@endif
|
||||
<p>
|
||||
<i class="material-icons">lock</i>
|
||||
<a href="{{ route('account.password') }}" >
|
||||
@if ($account->passwords()->count() > 0)
|
||||
Change my password
|
||||
@else
|
||||
Set my password
|
||||
@endif
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
<h3 class="mt-3">Account information</h3>
|
||||
<p>
|
||||
<i class="material-icons">delete</i>
|
||||
<a href="{{ route('account.delete') }}">Delete my account</a>
|
||||
</p>
|
||||
|
||||
<h2><i class="material-icons">person</i> Account information</h2>
|
||||
|
||||
<p><i class="material-icons">alternate_email</i> SIP address: sip:{{ $account->identifier }}</p>
|
||||
<p><i class="material-icons">person</i> Username: {{ $account->username }}</p>
|
||||
<p><i class="material-icons">dns</i> Domain: {{ $account->domain }}</p>
|
||||
|
||||
<div class="list-group">
|
||||
<b>SIP address:</b> sip:{{ $account->identifier }}<br />
|
||||
<b>Username:</b> {{ $account->username }}<br />
|
||||
<b>Domain:</b> {{ $account->domain }}<br />
|
||||
<br />
|
||||
@if (!empty(config('app.proxy_registrar_address')))
|
||||
<b>Proxy/registrar address: </b> sip:{{ config('app.proxy_registrar_address') }}<br />
|
||||
<p><i class="material-icons">lan</i> Proxy/registrar address: sip:{{ config('app.proxy_registrar_address') }}</p>
|
||||
@endif
|
||||
@if (!empty(config('app.transport_protocol_text')))
|
||||
<b>Transport: </b> {{ config('app.transport_protocol_text') }} <br />
|
||||
<p><i class="material-icons">settings_ethernet</i> Transport: {{ config('app.transport_protocol_text') }} </p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!--<h3 class="mt-3">Automatic authentication</h3>
|
||||
|
||||
|
|
@ -97,23 +71,22 @@ Once generated the QR Code stays valid for a few minutes.</p>
|
|||
<button type="submit" class="btn btn-primary">Generate</button>
|
||||
{!! Form::close() !!}-->
|
||||
|
||||
<h3 class="mt-3">API Key</h3>
|
||||
<h2><i class="material-icons">key</i>API Key</h2>
|
||||
|
||||
<p>You can generate an API key and use it to request the different API endpoints, <a href="{{ route('api') }}">check the related API documentation</a> to know how to use that key.</p>
|
||||
|
||||
{!! Form::open(['route' => 'account.api_key.generate']) !!}
|
||||
<div class="form-row">
|
||||
<div class="col-8">
|
||||
<input readonly class="form-control" placeholder="No key yet, press Generate"
|
||||
@if ($account->apiKey)
|
||||
value="{{ $account->apiKey->key }}"
|
||||
@endif
|
||||
>
|
||||
<div>
|
||||
<input readonly class="form-control" placeholder="No key yet, press Generate"
|
||||
@if ($account->apiKey)
|
||||
value="{{ $account->apiKey->key }}"
|
||||
@endif
|
||||
>
|
||||
<label>Key</label>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary">Generate</button>
|
||||
</div>
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
|
||||
@include('parts.account_variables', ['account' => $account])
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
@section('content')
|
||||
<section>
|
||||
<h1>
|
||||
<i class="material-icons">mail</i>
|
||||
<i class="material-icons">call</i>
|
||||
@if ($account->phone)
|
||||
Change your phone number
|
||||
@else
|
||||
|
|
|
|||
|
|
@ -1,86 +1,95 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
<li class="breadcrumb-item" aria-current="page">
|
||||
<a href="{{ route('admin.account.index') }}">Accounts</a>
|
||||
</li>
|
||||
@if ($account->id)
|
||||
<li class="breadcrumb-item" aria-current="page">
|
||||
<a href="{{ route('admin.account.show', $account->id) }}">{{ $account->identifier }}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">
|
||||
Edit
|
||||
</li>
|
||||
@else
|
||||
<li class="breadcrumb-item active" aria-current="page">
|
||||
Create
|
||||
</li>
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
@if ($account->id)
|
||||
<h1>Edit an account</h1>
|
||||
@else
|
||||
<h1>Create an account</h1>
|
||||
@endif
|
||||
|
||||
{!! Form::model($account, [
|
||||
'route' => $account->id
|
||||
? ['admin.account.update', $account->id]
|
||||
: ['admin.account.store'],
|
||||
'method' => $account->id
|
||||
? 'put'
|
||||
: 'post'
|
||||
]) !!}
|
||||
<div>
|
||||
{!! Form::text('username', $account->username, ['placeholder' => 'Username', 'required' => 'required']); !!}
|
||||
{!! Form::label('username', 'Username') !!}
|
||||
</div>
|
||||
<div>
|
||||
@if (config('app.admins_manage_multi_domains'))
|
||||
{!! Form::text('domain', $account->domain ?? config('app.sip_domain'), ['placeholder' => 'domain.com', 'required' => 'required']); !!}
|
||||
<a class="btn oppose btn-secondary" href="{{ route('admin.account.delete', $account->id) }}">
|
||||
<i class="material-icons">delete</i>
|
||||
Delete
|
||||
</a>
|
||||
@if ($account->id)
|
||||
<h1><i class="material-icons">people</i> Edit an account</h1>
|
||||
<p title="{{ $account->updated_at }}">Updated on {{ $account->updated_at->format('d/m/Y')}}
|
||||
@else
|
||||
{!! Form::text('domain', $account->domain ?? config('app.sip_domain'), ['placeholder' => 'domain.com', 'disabled']); !!}
|
||||
<h1><i class="material-icons">people</i> Create an account</h1>
|
||||
@endif
|
||||
{!! Form::label('domain', 'Domain') !!}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{!! Form::password('password', ['placeholder' => 'Password', 'required']); !!}
|
||||
{!! Form::label('password', ($account->id) ? 'Password (fill to change)' : 'Password') !!}
|
||||
</div>
|
||||
<div>
|
||||
{!! Form::checkbox('password_sha256', 'checked', $account->sha256Password) !!}
|
||||
{!! Form::label('password_sha256', 'Use a SHA-256 encrypted password') !!}
|
||||
</div>
|
||||
<form method="POST"
|
||||
action="{{ $account->id ? route('admin.account.update', $account->id) : route('admin.account.store') }}"
|
||||
accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method($account->id ? 'put' : 'post')
|
||||
<h2>Connexion</h2>
|
||||
<div>
|
||||
<input placeholder="Username" required="required" name="username" type="text" value="{{ $account->username }}">
|
||||
<label for="username">Username</label>
|
||||
@include('parts.errors', ['name' => 'username'])
|
||||
</div>
|
||||
<div>
|
||||
<input placeholder="domain.com" @if (config('app.admins_manage_multi_domains')) required @else disabled @endif name="domain" type="text" value="{{ $account->domain ?? config('app.sip_domain') }}">
|
||||
<label for="domain">Domain</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{!! Form::email('email', $account->email, ['placeholder' => 'Email']); !!}
|
||||
{!! Form::label('email', 'Email') !!}
|
||||
</div>
|
||||
<div>
|
||||
<input placeholder="John Doe" name="display_name" type="text" value="{{ $account->display_name }}">
|
||||
<label for="display_name">Display Name</label>
|
||||
@include('parts.errors', ['name' => 'display_name'])
|
||||
</div>
|
||||
<div></div>
|
||||
|
||||
<div>
|
||||
{!! Form::text('display_name', $account->display_name, ['placeholder' => 'John Doe']); !!}
|
||||
{!! Form::label('display_name', 'Display Name') !!}
|
||||
</div>
|
||||
<div>
|
||||
<input placeholder="Password" name="password" type="password" value="">
|
||||
<label for="password">{{ $account->id ? 'Password (fill to change)' : 'Password' }}</label>
|
||||
@include('parts.errors', ['name' => 'password'])
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{!! Form::text('phone', $account->phone, ['placeholder' => '+12123123']); !!}
|
||||
{!! Form::label('phone', 'Phone') !!}
|
||||
</div>
|
||||
<div>
|
||||
<input placeholder="Password" name="password_confirmation" type="password" value="">
|
||||
<label for="password_confirmation">Confirm password</label>
|
||||
@include('parts.errors', ['name' => 'password_confirmation'])
|
||||
</div>
|
||||
|
||||
<div class="select">
|
||||
{!! Form::select('dtmf_protocol', $protocols, $account->dtmf_protocol); !!}
|
||||
{!! Form::label('dtmf_protocol', 'DTMF Protocol') !!}
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div>
|
||||
{!! Form::submit(($account->id) ? 'Update' : 'Create', ['class' => 'btn oppose']) !!}
|
||||
</div>
|
||||
<div>
|
||||
<input placeholder="Email" name="email" type="email" value="{{ $account->email }}">
|
||||
<label for="email">Email</label>
|
||||
@include('parts.errors', ['name' => 'email'])
|
||||
</div>
|
||||
|
||||
{!! Form::close() !!}
|
||||
<div>
|
||||
<input placeholder="+12123123" name="phone" type="text" value="{{ $account->phone }}">
|
||||
<label for="phone">Phone</label>
|
||||
@include('parts.errors', ['name' => 'phone'])
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
<h2>Other information</h2>
|
||||
|
||||
<div>
|
||||
<input name="activated" type="checkbox" @if ($account->activated)checked @endif>
|
||||
<label>Activated</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input name="role" value="admin" type="radio" @if ($account->admin)checked @endif>
|
||||
<p>Admin</p>
|
||||
<input name="role" value="end_user" type="radio" @if (!$account->admin)checked @endif>
|
||||
<p>End user</p>
|
||||
<label>Role</label>
|
||||
</div>
|
||||
|
||||
<div class="select">
|
||||
<select name="dtmf_protocol">
|
||||
@foreach ($protocols as $value => $name)
|
||||
<option value="{{ $value }}" @if( $account->dtmf_protocol == $value )selected="selected"@endif>{{ $name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<label for="dtmf_protocol">DTMF Protocol</label>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="large">
|
||||
<input class="btn oppose" type="submit" value="{{ $account->id ? 'Update' : 'Create' }}">
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -1,17 +1,5 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
<li class="breadcrumb-item" aria-current="page">
|
||||
<a href="{{ route('admin.account.index') }}">Accounts</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item" aria-current="page">
|
||||
<a href="{{ route('admin.account.show', $account->id) }}">{{ $account->identifier }}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Delete</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<h2>Delete an account</h2>
|
||||
|
||||
{!! Form::open(['route' => 'admin.account.destroy', 'method' => 'delete']) !!}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
<li class="breadcrumb-item active" aria-current="page">Accounts</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<div>
|
||||
|
|
@ -14,15 +10,21 @@
|
|||
<h1><i class="material-icons">people</i> Account</h1>
|
||||
</div>
|
||||
<div>
|
||||
{!! Form::open(['route' => 'admin.account.search']) !!}
|
||||
<form class="inline" method="POST" action="{{ route('admin.account.search')}}" accept-charset="UTF-8">
|
||||
@csrf
|
||||
<div>
|
||||
{!! Form::text('search', $search, ['placeholder' => 'Search by username: +1234, foo_bar…']) !!}
|
||||
{!! Form::label('search', 'Search') !!}
|
||||
<input placeholder="Search by username: +1234, foo_bar…" name="search" type="text" value="{{ $search }}">
|
||||
<label for="search">Search</label>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="btn oppose">Search</button>
|
||||
<input name="updated_date" type="date" value="{{ $updated_date }}">
|
||||
<label for="updated_date">Updated Date</label>
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
<div>
|
||||
<a href="{{ route('admin.account.index')}}" type="reset" class="btn btn-secondary">Reset</a>
|
||||
<button type="submit" class="btn">Search</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
|
@ -32,14 +34,23 @@
|
|||
<tr>
|
||||
<th scope="col">Identifier (email)</th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col">Created</th>
|
||||
<th scope="col">
|
||||
<a href="{{ route('admin.account.index', ['updated_at_order' => $updated_at_order]) }}">
|
||||
Updated
|
||||
@if ($updated_at_order == 'desc')
|
||||
<i class="material-icons">expand_more</i>
|
||||
@else
|
||||
<i class="material-icons">expand_less</i>
|
||||
@endif
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($accounts as $account)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.account.show', $account->id) }}">
|
||||
<a href="{{ route('admin.account.edit', $account->id) }}">
|
||||
{{ $account->identifier }}
|
||||
</a>
|
||||
</td>
|
||||
|
|
@ -60,7 +71,7 @@
|
|||
<span class="badge badge-info">SHA256</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $account->creation_time}}</td>
|
||||
<td>{{ $account->created_at}}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -32,20 +32,6 @@
|
|||
|
||||
<br />
|
||||
|
||||
@if ($account->activated)
|
||||
<span class="badge badge-success">Activated</span> <a href="{{ route('admin.account.deactivate', $account->id) }}">Deactivate</a>
|
||||
@else
|
||||
<span class="badge badge-danger">Unactivated</span> <a href="{{ route('admin.account.activate', $account->id) }}">Activate</a>
|
||||
@endif
|
||||
|
||||
<br />
|
||||
|
||||
@if ($account->admin)
|
||||
<span class="badge badge-success">Admin</span> <a href="{{ route('admin.account.unadmin', $account->id) }}">Remove admin role</a>
|
||||
@else
|
||||
<span class="badge badge-danger">Not Admin</span> <a href="{{ route('admin.account.admin', $account->id) }}">Add admin role</a>
|
||||
@endif
|
||||
|
||||
<h3 class="mt-3">External Account</h3>
|
||||
|
||||
@if ($account->externalAccount)
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
@extends('layouts.base')
|
||||
|
||||
@section('header')
|
||||
<nav>
|
||||
<a href="{{ route('account.dashboard') }}">{{ config('app.name') }}</a>
|
||||
@if (Auth::check())
|
||||
<a href="{{ route('account.logout') }}">Logout</a>
|
||||
@endif
|
||||
</div>
|
||||
</nav>
|
||||
@endsection
|
||||
|
||||
@section('body')
|
||||
<div class="container pt-4">
|
||||
@include('parts.errors')
|
||||
@include('parts.breadcrumb')
|
||||
@yield('content')
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>{{ config('app.name') }}</title>
|
||||
<!--<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">-->
|
||||
|
||||
@if (config('instance.custom_theme'))
|
||||
@if (file_exists(public_path('css/' . config('app.env') . '.style.css')))
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/' . config('app.env') . '.style.css') }}">
|
||||
@else
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/far.css') }}">
|
||||
@endif
|
||||
<!--<link rel="stylesheet" type="text/css" href="{{ asset('css/charts.css') }}" >-->
|
||||
@endif
|
||||
</head>
|
||||
|
||||
<body class="@yield('classes')">
|
||||
<header>
|
||||
@yield('header')
|
||||
</header>
|
||||
@yield('body')
|
||||
<!--
|
||||
<footer class="text-center mt-2">
|
||||
|
||||
@if (config('instance.copyright'))
|
||||
{{ config('instance.copyright') }} |
|
||||
@endif
|
||||
<a href="{{ route('account.documentation') }}">Documentation</a> |
|
||||
<a href="{{ route('api') }}">API</a>
|
||||
</footer>-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -12,8 +12,9 @@
|
|||
@if (file_exists(public_path('css/' . config('app.env') . '.style.css')))
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/' . config('app.env') . '.style.css') }}">
|
||||
@else
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/far.css') }}">
|
||||
@endif
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/far.css') }}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('css/form.css') }}">
|
||||
<!--<link rel="stylesheet" type="text/css" href="{{ asset('css/charts.css') }}" >-->
|
||||
@endif
|
||||
</head>
|
||||
|
|
@ -22,17 +23,22 @@
|
|||
<header>
|
||||
@if (config('app.web_panel'))
|
||||
<nav>
|
||||
<a href="{{ route('account.home') }}">{{ config('app.name') }}</a>
|
||||
<a id="logo" href="{{ route('account.home') }}"><span class="on_desktop">{{ config('app.name') }}</span></a>
|
||||
|
||||
@if (!isset($welcome) || $welcome == false)
|
||||
<a id="menu" class="on_mobile" href="#" onclick="document.body.classList.toggle('show_menu')"></a>
|
||||
@endif
|
||||
|
||||
@if (auth()->user())
|
||||
<a href="{{ route('account.dashboard') }}">
|
||||
<i class="material-icons">person</i>My Account
|
||||
<a class="oppose" href="{{ route('account.dashboard') }}">
|
||||
<i class="material-icons">account_circle</i><span class="on_desktop">{{ auth()->user()->identifier }}</span>
|
||||
</a>
|
||||
<a href="{{ route('account.logout') }}">
|
||||
<a class="oppose" href="{{ route('account.logout') }}">
|
||||
<i class="material-icons">logout</i>
|
||||
</a>
|
||||
@else
|
||||
<a href="{{ route('account.login') }}">
|
||||
<i class="material-icons">info</i> Login
|
||||
<a class="oppose" href="{{ route('account.login') }}">
|
||||
<i class="material-icons">info</i><span class="on_desktop">Login</span>
|
||||
</a>
|
||||
@endif
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
<nav>
|
||||
@foreach ([
|
||||
'account.dashboard' => ['title' => 'Dashboard', 'icon' => 'dashboard'],
|
||||
'admin.account.index' => ['title' => 'Accounts', 'icon' => 'people'],
|
||||
'admin.statistics.show.day' => ['title' => 'Statistics', 'icon' => 'analytics'],
|
||||
] as $route => $value)
|
||||
@php
|
||||
$items = [
|
||||
'account.dashboard' => ['title' => 'Dashboard', 'icon' => 'dashboard'],
|
||||
];
|
||||
|
||||
if (auth()->user() && auth()->user()->admin) {
|
||||
$items['admin.account.index'] = ['title' => 'Accounts', 'icon' => 'people'];
|
||||
$items['admin.statistics.show.day'] = ['title' => 'Statistics', 'icon' => 'analytics'];
|
||||
}
|
||||
@endphp
|
||||
|
||||
@foreach ($items as $route => $value)
|
||||
<a @if (str_starts_with(url()->current(), route($route)))class="current"@endif href="{{ route($route) }}">
|
||||
<i class="material-icons">{{ $value['icon'] }}</i>
|
||||
{{ $value['title'] }}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ use App\Http\Controllers\Account\PasswordController;
|
|||
use App\Http\Controllers\Account\PhoneController;
|
||||
use App\Http\Controllers\Account\ProvisioningController;
|
||||
use App\Http\Controllers\Account\RecoveryController;
|
||||
use App\Http\Controllers\Admin\AccountAccountTypeController;
|
||||
use App\Http\Controllers\Admin\AccountActionController;
|
||||
use App\Http\Controllers\Admin\AccountContactController;
|
||||
use App\Http\Controllers\Admin\AccountTypeController;
|
||||
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
|
@ -50,10 +55,10 @@ Route::group(['middleware' => 'auth.digest_or_key'], function () {
|
|||
Route::get('contacts/vcard', 'Account\ContactVcardController@index')->name('account.contacts.vcard.index');
|
||||
});
|
||||
|
||||
Route::prefix('provisioning')->controller(ProvisioningController::class)->group(function () {
|
||||
Route::get('auth_token/{auth_token}', 'authToken')->name('provisioning.auth_token');
|
||||
Route::get('qrcode/{provisioning_token}', 'qrcode')->name('provisioning.qrcode');
|
||||
Route::get('{provisioning_token?}', 'show')->name('provisioning.show');
|
||||
Route::name('provisioning.')->prefix('provisioning')->controller(ProvisioningController::class)->group(function () {
|
||||
Route::get('auth_token/{auth_token}', 'authToken')->name('auth_token');
|
||||
Route::get('qrcode/{provisioning_token}', 'qrcode')->name('qrcode');
|
||||
Route::get('{provisioning_token?}', 'show')->name('show');
|
||||
});
|
||||
|
||||
if (publicRegistrationEnabled()) {
|
||||
|
|
@ -129,57 +134,57 @@ if (config('app.web_panel')) {
|
|||
Route::get('statistics/month', 'Admin\StatisticsController@showMonth')->name('statistics.show.month');
|
||||
|
||||
Route::prefix('accounts')->group(function () {
|
||||
// Account types
|
||||
Route::get('types', 'Admin\AccountTypeController@index')->name('account.type.index');
|
||||
Route::get('types/create', 'Admin\AccountTypeController@create')->name('account.type.create');
|
||||
Route::post('types', 'Admin\AccountTypeController@store')->name('account.type.store');
|
||||
Route::get('types/{type_id}/edit', 'Admin\AccountTypeController@edit')->name('account.type.edit');
|
||||
Route::put('types/{type_id}', 'Admin\AccountTypeController@update')->name('account.type.update');
|
||||
Route::get('types/{type_id}/delete', 'Admin\AccountTypeController@delete')->name('account.type.delete');
|
||||
Route::delete('types/{type_id}', 'Admin\AccountTypeController@destroy')->name('account.type.destroy');
|
||||
Route::name('account.type.')->prefix('types')->controller(AccountTypeController::class)->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::get('create', 'create')->name('create');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::get('{type_id}/edit', 'edit')->name('edit');
|
||||
Route::put('{type_id}', 'update')->name('update');
|
||||
Route::get('{type_id}/delete', 'delete')->name('delete');
|
||||
Route::delete('{type_id}', 'destroy')->name('destroy');
|
||||
});
|
||||
|
||||
Route::get('{account}/types/create', 'Admin\AccountAccountTypeController@create')->name('account.account_type.create');
|
||||
Route::post('{account}/types', 'Admin\AccountAccountTypeController@store')->name('account.account_type.store');
|
||||
Route::delete('{account}/types/{type_id}', 'Admin\AccountAccountTypeController@destroy')->name('account.account_type.destroy');
|
||||
Route::name('account.account_type.')->prefix('{account}/types')->controller(AccountAccountTypeController::class)->group(function () {
|
||||
Route::get('create', 'create')->name('create');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::delete('{type_id}', 'destroy')->name('destroy');
|
||||
});
|
||||
|
||||
// Contacts
|
||||
Route::get('{account}/contacts/create', 'Admin\AccountContactController@create')->name('account.contact.create');
|
||||
Route::post('{account}/contacts', 'Admin\AccountContactController@store')->name('account.contact.store');
|
||||
Route::get('{account}/contacts/{contact_id}/delete', 'Admin\AccountContactController@delete')->name('account.contact.delete');
|
||||
Route::delete('{account}/contacts', 'Admin\AccountContactController@destroy')->name('account.contact.destroy');
|
||||
Route::name('account.contact.')->prefix('{account}/contacts')->controller(AccountContactController::class)->group(function () {
|
||||
Route::get('create', 'create')->name('create');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::get('{contact_id}/delete', 'delete')->name('delete');
|
||||
Route::delete('/', 'destroy')->name('destroy');
|
||||
});
|
||||
|
||||
// Accounts
|
||||
Route::get('{account}/show', 'Admin\AccountController@show')->name('account.show');
|
||||
Route::name('account.')->controller(AdminAccountController::class)->group(function () {
|
||||
Route::get('{account_id}/show', 'show')->name('show');
|
||||
|
||||
Route::get('{account}/activate', 'Admin\AccountController@activate')->name('account.activate');
|
||||
Route::get('{account}/deactivate', 'Admin\AccountController@deactivate')->name('account.deactivate');
|
||||
Route::get('{account_id}/external_account/attach', 'attachExternalAccount')->name('external_account.attach');
|
||||
|
||||
Route::get('{account}/external_account/attach', 'Admin\AccountController@attachExternalAccount')->name('account.external_account.attach');
|
||||
Route::get('{account_id}/provision', 'provision')->name('provision');
|
||||
|
||||
Route::get('{account}/admin', 'Admin\AccountController@admin')->name('account.admin');
|
||||
Route::get('{id}/unadmin', 'Admin\AccountController@unadmin')->name('account.unadmin');
|
||||
Route::get('create', 'create')->name('create');
|
||||
Route::post('accounts', 'store')->name('store');
|
||||
|
||||
Route::get('{account}/provision', 'Admin\AccountController@provision')->name('account.provision');
|
||||
Route::get('{account_id}/edit', 'edit')->name('edit');
|
||||
Route::put('{account_id}', 'update')->name('update');
|
||||
|
||||
Route::get('create', 'Admin\AccountController@create')->name('account.create');
|
||||
Route::post('accounts', 'Admin\AccountController@store')->name('account.store');
|
||||
Route::get('{account_id}/delete', 'delete')->name('delete');
|
||||
Route::delete('/', 'destroy')->name('destroy');
|
||||
|
||||
Route::get('{account}/edit', 'Admin\AccountController@edit')->name('account.edit');
|
||||
Route::put('{id}', 'Admin\AccountController@update')->name('account.update');
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::post('search', 'search')->name('search');
|
||||
});
|
||||
|
||||
Route::get('{account}/delete', 'Admin\AccountController@delete')->name('account.delete');
|
||||
Route::delete('accounts', 'Admin\AccountController@destroy')->name('account.destroy');
|
||||
|
||||
Route::get('{search?}', 'Admin\AccountController@index')->name('account.index');
|
||||
Route::post('search', 'Admin\AccountController@search')->name('account.search');
|
||||
|
||||
// Account actions
|
||||
Route::get('{account}/actions/create', 'Admin\AccountActionController@create')->name('account.action.create');
|
||||
Route::post('{account}/actions', 'Admin\AccountActionController@store')->name('account.action.store');
|
||||
Route::get('{account}/actions/{action_id}/edit', 'Admin\AccountActionController@edit')->name('account.action.edit');
|
||||
Route::put('{account}/actions/{action_id}', 'Admin\AccountActionController@update')->name('account.action.update');
|
||||
Route::get('{account}/actions/{action_id}/delete', 'Admin\AccountActionController@delete')->name('account.action.delete');
|
||||
Route::delete('{account}/actions/{action_id}', 'Admin\AccountActionController@destroy')->name('account.action.destroy');
|
||||
Route::name('account.action.')->prefix('{account}/actions')->controller(AccountActionController::class)->group(function () {
|
||||
Route::get('create', 'create')->name('create');
|
||||
Route::post('/', 'store')->name('store');
|
||||
Route::get('{action_id}/edit', 'edit')->name('edit');
|
||||
Route::put('{action_id}', 'update')->name('update');
|
||||
Route::get('{action_id}/delete', 'delete')->name('delete');
|
||||
Route::delete('{action_id}', 'destroy')->name('destroy');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue