mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 01:58:07 +00:00
Fix FLEXIAPI-182 Replace APP_SUPER_ADMINS_SIP_DOMAINS with a proper sip_domains table, API endpoints, UI panels, tests and documentation
This commit is contained in:
parent
e913b4a584
commit
2ed4f02c11
57 changed files with 1033 additions and 148 deletions
|
|
@ -10,6 +10,7 @@ v1.5
|
|||
- Fix FLEXIAPI-185 Return null if the account dictionary is empty in the API
|
||||
- Fix FLEXIAPI-184 Append phone_change_code and email_change_code to the admin /accounts/<id> endpoint if they are available
|
||||
- Fix FLEXIAPI-183 Complete the account hooks on the dictionnary actions
|
||||
- Fix FLEXIAPI-182 Replace APP_SUPER_ADMINS_SIP_DOMAINS with a proper sip_domains table, API endpoints, UI panels, console command, tests and documentation
|
||||
- Fix FLEXIAPI-181 Replace APP_ADMINS_MANAGE_MULTI_DOMAINS with APP_SUPER_ADMINS_SIP_DOMAINS
|
||||
- Fix FLEXIAPI-180 Fix the token and activation flow for the provisioning with token endpoint when the header is missing
|
||||
- Fix FLEXIAPI-179 Add Localization support as a Middleware that handles Accept-Language HTTP header
|
||||
|
|
|
|||
|
|
@ -148,6 +148,12 @@ FlexiAPI is also providing endpoints to provision Liblinphone powered devices. Y
|
|||
|
||||
FlexiAPI is shipped with several console commands that you can launch using the `artisan` executable available at the root of this project.
|
||||
|
||||
### Create or update a SIP Domain
|
||||
|
||||
Create or update a SIP Domain, required to then create accounts afterward. The `super` option enable/disable the domain as a super domain.
|
||||
|
||||
php artisan sip_domains:create-update {domain} {--super}
|
||||
|
||||
### Create an admin account
|
||||
|
||||
Create an admin account, an API Key will also be generated along the way, it might expire after a while.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ APP_KEY=
|
|||
APP_DEBUG=false
|
||||
APP_URL=http://localhost
|
||||
APP_SIP_DOMAIN=sip.example.com
|
||||
APP_SUPER_ADMINS_SIP_DOMAINS= # A comma separated list of sip domains that has their admins super admins
|
||||
|
||||
APP_LINPHONE_DAEMON_UNIX_PATH=
|
||||
APP_FLEXISIP_PUSHER_PATH=
|
||||
|
|
|
|||
|
|
@ -168,7 +168,6 @@ class Account extends Authenticatable
|
|||
return $this->hasMany(DigestNonce::class);
|
||||
}
|
||||
|
||||
|
||||
public function passwords()
|
||||
{
|
||||
return $this->hasMany(Password::class);
|
||||
|
|
@ -323,19 +322,7 @@ class Account extends Authenticatable
|
|||
|
||||
public function getSuperAdminAttribute(): bool
|
||||
{
|
||||
$domains = config('app.super_admins_sip_domains');
|
||||
|
||||
if (empty($domains)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$domains = explode(',', $domains);
|
||||
|
||||
if (empty($domains)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->admin && in_array($this->domain, $domains);
|
||||
return SipDomain::where('domain', $this->domain)->where('super', true)->exists() && $this->admin;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\ApiKey;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
use App\ApiKey;
|
||||
|
||||
class ClearApiKeys extends Command
|
||||
{
|
||||
protected $signature = 'accounts:clear-api-keys {minutes?}';
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@
|
|||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
use App\DigestNonce;
|
||||
|
||||
class ClearNonces extends Command
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\AccountTombstone;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Carbon\Carbon;
|
||||
|
||||
use App\AccountTombstone;
|
||||
|
||||
class ClearOldAccountsTombstones extends Command
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,11 +20,10 @@
|
|||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
use Carbon\Carbon;
|
||||
|
||||
use App\Account;
|
||||
use App\ApiKey;
|
||||
use Carbon\Carbon;
|
||||
use App\SipDomain;
|
||||
|
||||
class CreateAdminAccount extends Command
|
||||
{
|
||||
|
|
@ -38,6 +37,8 @@ class CreateAdminAccount extends Command
|
|||
|
||||
public function handle()
|
||||
{
|
||||
$sipDomains = SipDomain::all('domain')->pluck('domain');
|
||||
|
||||
$this->info('Your will create a new admin account in the database, existing accounts with the same credentials will be overwritten');
|
||||
|
||||
$username = $this->option('username');
|
||||
|
|
@ -49,7 +50,7 @@ class CreateAdminAccount extends Command
|
|||
}
|
||||
|
||||
if (!$this->option('domain')) {
|
||||
$domain = $this->ask('What will be the admin domain? Default: ' . config('app.sip_domain'));
|
||||
$domain = $this->ask('What will be the admin domain? Default: ' . $sipDomains->first());
|
||||
}
|
||||
|
||||
if (!$this->option('password')) {
|
||||
|
|
@ -57,9 +58,15 @@ class CreateAdminAccount extends Command
|
|||
}
|
||||
|
||||
$username = $username ?? 'admin';
|
||||
$domain = $domain ?? config('app.sip_domain');
|
||||
$domain = $domain ?? $sipDomains->first();
|
||||
$password = $password ?? 'change_me';
|
||||
|
||||
if (!$sipDomains->contains($domain)) {
|
||||
$this->error('The domain must be one of the following ones: ' . $sipDomains->implode(', '));
|
||||
$this->comment('You can create an extra domain using the dedicated console command');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// Delete the account if it already exists
|
||||
$account = Account::withoutGlobalScopes()
|
||||
->where('username', $username)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@
|
|||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Carbon\Carbon;
|
||||
|
||||
use App\Account;
|
||||
use App\ApiKey;
|
||||
use Carbon\Carbon;
|
||||
use App\SipDomain;
|
||||
|
||||
class CreateAdminAccountTest extends Command
|
||||
{
|
||||
|
|
@ -40,6 +41,11 @@ class CreateAdminAccountTest extends Command
|
|||
$username = 'admin_test';
|
||||
$domain = 'sip.example.org';
|
||||
|
||||
$this->call('sip_domains:create-update', [
|
||||
'domain' => $domain,
|
||||
'--super' => 'true'
|
||||
]);
|
||||
|
||||
$this->call('accounts:create-admin-account', [
|
||||
'--username' => $username,
|
||||
'--domain' => $domain,
|
||||
|
|
|
|||
50
flexiapi/app/Console/Commands/CreateSipDomain.php
Normal file
50
flexiapi/app/Console/Commands/CreateSipDomain.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?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\Console\Commands;
|
||||
|
||||
use App\SipDomain;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CreateSipDomain extends Command
|
||||
{
|
||||
protected $signature = 'sip_domains:create-update {domain} {--super}';
|
||||
protected $description = 'Create a SIP Domain';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->info('Your will create or update a SIP Domain in the database');
|
||||
|
||||
$sipDomain = SipDomain::where('domain', $this->argument('domain'))->firstOrNew();
|
||||
$sipDomain->domain = $this->argument('domain');
|
||||
|
||||
$sipDomain->exists
|
||||
? $this->info('The domain already exists, updating it')
|
||||
: $this->info('A new domain will be created');
|
||||
|
||||
$sipDomain->super = (bool)$this->option('super');
|
||||
$sipDomain->super
|
||||
? $this->info('Set as a super domain')
|
||||
: $this->info('Set as a normal domain');
|
||||
|
||||
$sipDomain->save();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
use App\Account;
|
||||
|
||||
class RemoveUnconfirmedAccounts extends Command
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use Carbon\Carbon;
|
|||
|
||||
class Device extends Model
|
||||
{
|
||||
protected $fillable = ['user_agent'];
|
||||
public function fromRedisContact(string $contact)
|
||||
{
|
||||
preg_match("/<(.*)>;(.*)/", $contact, $matches);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ use App\ContactsList;
|
|||
use App\Http\Requests\Account\Create\Web\AsAdminRequest;
|
||||
use App\Http\Requests\Account\Update\Web\AsAdminRequest as WebAsAdminRequest;
|
||||
use App\Services\AccountService;
|
||||
use App\SipDomain;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
|
|
@ -75,6 +76,9 @@ class AccountController extends Controller
|
|||
{
|
||||
return view('admin.account.create_edit', [
|
||||
'account' => new Account,
|
||||
'domains' => $request->user()?->superAdmin
|
||||
? SipDomain::all()
|
||||
: SipDomain::where('domain', $request->user()->domain)->get(),
|
||||
'protocols' => [null => 'None'] + Account::$dtmfProtocols
|
||||
]);
|
||||
}
|
||||
|
|
@ -88,11 +92,16 @@ class AccountController extends Controller
|
|||
return redirect()->route('admin.account.edit', $account->id);
|
||||
}
|
||||
|
||||
public function edit(int $accountId)
|
||||
public function edit(Request $request, int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
|
||||
return view('admin.account.create_edit', [
|
||||
'account' => Account::findOrFail($accountId),
|
||||
'account' => $account,
|
||||
'protocols' => [null => 'None'] + Account::$dtmfProtocols,
|
||||
'domains' => $request->user()?->superAdmin
|
||||
? SipDomain::all()
|
||||
: SipDomain::where('domain', $account->domain)->get(),
|
||||
'contacts_lists' => ContactsList::whereNotIn('id', function ($query) use ($accountId) {
|
||||
$query->select('contacts_list_id')
|
||||
->from('account_contacts_list')
|
||||
|
|
|
|||
94
flexiapi/app/Http/Controllers/Admin/SipDomainController.php
Normal file
94
flexiapi/app/Http/Controllers/Admin/SipDomainController.php
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\SipDomain;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class SipDomainController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('admin.sip_domain.index', ['sip_domains' => SipDomain::withCount('accounts')->get()]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.sip_domain.create_edit', [
|
||||
'sip_domain' => new SipDomain
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'domain' => 'required|unique:sip_domains',
|
||||
]);
|
||||
|
||||
$sipDomain = new SipDomain;
|
||||
$sipDomain->domain = $request->get('domain');
|
||||
$sipDomain->super = $request->has('super') ? (bool)$request->get('super') == "true" : false;
|
||||
$sipDomain->save();
|
||||
|
||||
return redirect()->route('admin.sip_domains.index');
|
||||
}
|
||||
|
||||
public function edit(int $id)
|
||||
{
|
||||
return view('admin.sip_domain.create_edit', [
|
||||
'sip_domain' => SipDomain::findOrFail($id)
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, int $id)
|
||||
{
|
||||
$sipDomain = SipDomain::findOrFail($id);
|
||||
$sipDomain->super = $request->has('super') ? $request->get('super') == "true" : false;
|
||||
$sipDomain->save();
|
||||
|
||||
return redirect()->route('admin.sip_domains.index');
|
||||
}
|
||||
|
||||
public function delete(int $id)
|
||||
{
|
||||
return view('admin.sip_domain.delete', [
|
||||
'sip_domain' => SipDomain::findOrFail($id)
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, int $id)
|
||||
{
|
||||
$sipDomain = SipDomain::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'domain' => [
|
||||
'required',
|
||||
Rule::in(['first-zone', $sipDomain->domain]),
|
||||
]
|
||||
]);
|
||||
|
||||
$sipDomain->delete();
|
||||
|
||||
return redirect()->route('admin.sip_domains.index');
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ use App\Rules\WithoutSpaces;
|
|||
use App\Rules\PasswordAlgorithm;
|
||||
|
||||
use App\Services\AccountService;
|
||||
use App\SipDomain;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,16 +20,17 @@
|
|||
namespace App\Http\Controllers\Api\Account;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Libraries\FlexisipConnector;
|
||||
use Illuminate\Http\Request;
|
||||
use stdClass;
|
||||
|
||||
class DeviceController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$connector = new FlexisipConnector;
|
||||
$devices = (new FlexisipConnector)->getDevices($request->user()->identifier);
|
||||
|
||||
return $connector->getDevices($request->user()->identifier);
|
||||
return ($devices->isEmpty()) ? new stdClass : $devices;
|
||||
}
|
||||
|
||||
public function destroy(Request $request, string $uuid)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ use App\ContactsList;
|
|||
use App\Http\Requests\Account\Create\Api\AsAdminRequest;
|
||||
use App\Http\Requests\Account\Update\Api\AsAdminRequest as ApiAsAdminRequest;
|
||||
use App\Services\AccountService;
|
||||
use App\SipDomain;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
|
|
@ -70,13 +71,13 @@ class AccountController extends Controller
|
|||
$account = Account::findOrFail($accountId);
|
||||
|
||||
if (!$account->hasTombstone()) {
|
||||
$tombstone = new AccountTombstone;
|
||||
$tombstone = new AccountTombstone();
|
||||
$tombstone->username = $account->username;
|
||||
$tombstone->domain = $account->domain;
|
||||
$tombstone->save();
|
||||
}
|
||||
|
||||
(new AccountService)->destroy($request, $accountId);
|
||||
(new AccountService())->destroy($request, $accountId);
|
||||
|
||||
Log::channel('events')->info('API Admin: Account destroyed', ['id' => $account->identifier]);
|
||||
}
|
||||
|
|
@ -138,12 +139,21 @@ class AccountController extends Controller
|
|||
|
||||
public function store(AsAdminRequest $request)
|
||||
{
|
||||
return (new AccountService)->store($request)->makeVisible(['confirmation_key', 'provisioning_token']);
|
||||
// Create the missing SipDomain
|
||||
if ($request->user()->superAdmin
|
||||
&& $request->has('domain')
|
||||
&& !SipDomain::pluck('domain')->contains($request->get('domain'))) {
|
||||
$sipDomain = new SipDomain();
|
||||
$sipDomain->domain = $request->get('domain');
|
||||
$sipDomain->save();
|
||||
}
|
||||
|
||||
return (new AccountService())->store($request)->makeVisible(['confirmation_key', 'provisioning_token']);
|
||||
}
|
||||
|
||||
public function update(ApiAsAdminRequest $request, int $accountId)
|
||||
{
|
||||
$account = (new AccountService)->update($request, $accountId);
|
||||
$account = (new AccountService())->update($request, $accountId);
|
||||
|
||||
Log::channel('events')->info('API Admin: Account updated', ['id' => $account->identifier]);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,17 +19,18 @@
|
|||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Libraries\FlexisipConnector;
|
||||
use App\Account;
|
||||
use stdClass;
|
||||
|
||||
class DeviceController extends Controller
|
||||
{
|
||||
public function index(int $accountId)
|
||||
{
|
||||
$connector = new FlexisipConnector;
|
||||
$devices = (new FlexisipConnector)->getDevices(Account::findOrFail($accountId)->identifier);
|
||||
|
||||
return $connector->getDevices(Account::findOrFail($accountId)->identifier);
|
||||
return ($devices->isEmpty()) ? new stdClass : $devices;
|
||||
}
|
||||
|
||||
public function destroy(int $accountId, string $uuid)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\SipDomain;
|
||||
|
||||
class SipDomainController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return SipDomain::all();
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'domain' => 'required|unique:sip_domains',
|
||||
'super' => 'required|boolean',
|
||||
]);
|
||||
|
||||
$sipDomain = new SipDomain;
|
||||
$sipDomain->domain = $request->get('domain');
|
||||
$sipDomain->super = $request->has('super') ? (bool)$request->get('super') : false;
|
||||
$sipDomain->save();
|
||||
|
||||
return $sipDomain;
|
||||
}
|
||||
|
||||
public function show(string $domain)
|
||||
{
|
||||
return SipDomain::where('domain', $domain)->firstOrFail();
|
||||
}
|
||||
|
||||
public function update(Request $request, string $domain)
|
||||
{
|
||||
$request->validate([
|
||||
'super' => 'required|boolean',
|
||||
]);
|
||||
|
||||
$sipDomain = SipDomain::where('domain', $domain)->firstOrFail();
|
||||
$sipDomain->super = $request->has('super') ? (bool)$request->get('super') : false;
|
||||
$sipDomain->save();
|
||||
|
||||
return $sipDomain;
|
||||
}
|
||||
|
||||
public function destroy(string $domain)
|
||||
{
|
||||
return SipDomain::where('domain', $domain)->delete();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2023 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ class Kernel extends HttpKernel
|
|||
protected $routeMiddleware = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.admin' => \App\Http\Middleware\AuthenticateAdmin::class,
|
||||
'auth.super_admin' => \App\Http\Middleware\AuthenticateSuperAdmin::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'auth.digest_or_key' => \App\Http\Middleware\AuthenticateDigestOrKey::class,
|
||||
'auth.jwt' => \App\Http\Middleware\AuthenticateJWT::class,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
|
|
@ -6,13 +23,6 @@ use Closure;
|
|||
|
||||
class AuthenticateAdmin
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (!$request->user()) {
|
||||
|
|
|
|||
|
|
@ -31,13 +31,6 @@ use Validator;
|
|||
|
||||
class AuthenticateDigestOrKey
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($request->bearerToken() && Auth::check()) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
|
|
|
|||
34
flexiapi/app/Http/Middleware/AuthenticateSuperAdmin.php
Normal file
34
flexiapi/app/Http/Middleware/AuthenticateSuperAdmin.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class AuthenticateSuperAdmin
|
||||
{
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (!$request->user() || !$request->user()->superAdmin) {
|
||||
return abort(403, 'Unauthorized area');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ use App\Http\Requests\Api as RequestsApi;
|
|||
use App\Http\Requests\AsAdmin;
|
||||
use App\Rules\IsNotPhoneNumber;
|
||||
use App\Rules\PasswordAlgorithm;
|
||||
use App\SipDomain;
|
||||
|
||||
class AsAdminRequest extends Request
|
||||
{
|
||||
|
|
@ -29,6 +30,10 @@ class AsAdminRequest extends Request
|
|||
'nullable',
|
||||
];
|
||||
|
||||
if ($this->user()->superAdmin) {
|
||||
$rules['domain'] = '';
|
||||
}
|
||||
|
||||
if (config('app.allow_phone_number_username_admin_api') == true) {
|
||||
array_splice(
|
||||
$rules['username'],
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class Request extends FormRequest
|
|||
}),
|
||||
'filled',
|
||||
],
|
||||
'domain' => 'exists:sip_domains,domain',
|
||||
'dictionary' => [new Dictionary()],
|
||||
'password' => 'required|min:3',
|
||||
'email' => config('app.account_email_unique')
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ class Request extends FormRequest
|
|||
})->ignore($this->route('account_id'), 'id'),
|
||||
'filled',
|
||||
],
|
||||
'domain' => 'exists:sip_domains,domain',
|
||||
'email' => [
|
||||
'nullable',
|
||||
'email',
|
||||
|
|
|
|||
|
|
@ -42,8 +42,6 @@ class FlexisipConnector
|
|||
Log::error('Redis server issue: ' . $th->getMessage());
|
||||
}
|
||||
|
||||
if ($devices->isEmpty()) return new stdClass;
|
||||
|
||||
return $devices->keyBy('uuid');
|
||||
}
|
||||
|
||||
|
|
|
|||
23
flexiapi/app/SipDomain.php
Normal file
23
flexiapi/app/SipDomain.php
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class SipDomain extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $hidden = ['id'];
|
||||
protected $casts = [
|
||||
'super' => 'boolean',
|
||||
];
|
||||
|
||||
public function accounts()
|
||||
{
|
||||
return $this->hasMany(Account::class, 'domain', 'domain');
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -15,7 +15,6 @@ return [
|
|||
|
||||
'name' => env('APP_NAME', 'Account Manager'),
|
||||
'sip_domain' => env('APP_SIP_DOMAIN', 'sip.domain.com'),
|
||||
'super_admins_sip_domains' => env('APP_SUPER_ADMINS_SIP_DOMAINS', ''),
|
||||
|
||||
'project_url' => env('APP_PROJECT_URL', ''),
|
||||
'terms_of_use_url' => env('TERMS_OF_USE_URL', ''),
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use Awobaz\Compoships\Database\Eloquent\Factories\ComposhipsFactory;
|
|||
use App\Account;
|
||||
use App\AccountCreationToken;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
use App\SipDomain;
|
||||
|
||||
class AccountFactory extends Factory
|
||||
{
|
||||
|
|
@ -34,10 +35,14 @@ class AccountFactory extends Factory
|
|||
|
||||
public function definition()
|
||||
{
|
||||
$domain = SipDomain::count() == 0
|
||||
? SipDomain::factory()->create()
|
||||
: SipDomain::first();
|
||||
|
||||
return [
|
||||
'username' => $this->faker->username,
|
||||
'display_name' => $this->faker->name,
|
||||
'domain' => config('app.sip_domain'),
|
||||
'domain' => $domain->domain,
|
||||
'user_agent' => $this->faker->userAgent,
|
||||
'confirmation_key' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'ip_address' => $this->faker->ipv4,
|
||||
|
|
@ -55,6 +60,19 @@ class AccountFactory extends Factory
|
|||
]);
|
||||
}
|
||||
|
||||
public function superAdmin()
|
||||
{
|
||||
return $this->state(function (array $attributes) {
|
||||
$sipDomain = SipDomain::where('domain', $attributes['domain'])->first();
|
||||
$sipDomain->super = true;
|
||||
$sipDomain->save();
|
||||
|
||||
return [
|
||||
'admin' => true,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function deactivated()
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
|
|
|
|||
42
flexiapi/database/factories/SipDomainFactory.php
Normal file
42
flexiapi/database/factories/SipDomainFactory.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?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 Database\Factories;
|
||||
|
||||
use App\SipDomain;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class SipDomainFactory extends Factory
|
||||
{
|
||||
protected $model = SipDomain::class;
|
||||
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'domain' => config('app.sip_domain'),
|
||||
];
|
||||
}
|
||||
|
||||
public function secondDomain()
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'domain' => 'second_' . config('app.sip_domain'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2020 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use App\SipDomain;
|
||||
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::create('sip_domains', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('domain', 64)->unique()->index();
|
||||
$table->boolean('super')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
foreach (DB::table('accounts')->select('domain')->distinct()->get()->pluck('domain') as $domain) {
|
||||
$sipDomain = new SipDomain;
|
||||
$sipDomain->domain = $domain;
|
||||
$sipDomain->super = env('APP_ADMINS_MANAGE_MULTI_DOMAINS', false); // historical environnement boolean
|
||||
$sipDomain->save();
|
||||
}
|
||||
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->foreign('domain')->references('domain')
|
||||
->on('sip_domains')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->dropForeign('accounts_domain_foreign');
|
||||
});
|
||||
Schema::dropIfExists('sip_domains');
|
||||
}
|
||||
};
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
namespace Database\Seeders;
|
||||
|
||||
use App\Account;
|
||||
use App\SipDomain;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
|
|
@ -28,6 +29,7 @@ class LiblinphoneTesterAccoutSeeder extends Seeder
|
|||
{
|
||||
$accounts = [];
|
||||
$passwords = [];
|
||||
$domains = [];
|
||||
|
||||
foreach ($json as $element) {
|
||||
if ($element->type == 'account') {
|
||||
|
|
@ -43,6 +45,8 @@ class LiblinphoneTesterAccoutSeeder extends Seeder
|
|||
)
|
||||
);
|
||||
|
||||
if(!in_array($element->domain, $domains)) array_push($domains, $element->domain);
|
||||
|
||||
if (isset($element->passwords)) {
|
||||
foreach ($element->passwords as $password) {
|
||||
array_push(
|
||||
|
|
@ -76,6 +80,8 @@ class LiblinphoneTesterAccoutSeeder extends Seeder
|
|||
$this->generatePasswordArray($element->idStart + $i, 'secret', 'CLRTXT')
|
||||
);
|
||||
}
|
||||
|
||||
if(!in_array($element->domain, $domains)) array_push($domains, $element->domain);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +90,13 @@ class LiblinphoneTesterAccoutSeeder extends Seeder
|
|||
|
||||
Account::withoutGlobalScopes()->whereIn('id', $ids)->delete();
|
||||
|
||||
// Create the domains
|
||||
foreach ($domains as $domain) {
|
||||
$sipDomain = SipDomain::where('domain', $domain)->firstOrNew();
|
||||
$sipDomain->domain = $domain;
|
||||
$sipDomain->save();
|
||||
}
|
||||
|
||||
// And seed the fresh ones
|
||||
DB::table('accounts')->insert($accounts);
|
||||
DB::table('passwords')->insert($passwords);
|
||||
|
|
|
|||
|
|
@ -6,36 +6,35 @@
|
|||
|
||||
@section('content')
|
||||
|
||||
<header>
|
||||
<h1><i class="material-symbols-outlined">devices</i> Devices management</h1>
|
||||
</header>
|
||||
<header>
|
||||
<h1><i class="material-symbols-outlined">devices</i> Devices management</h1>
|
||||
</header>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User Agent</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if ($devices->isEmpty())
|
||||
<tr class="empty">
|
||||
<td colspan="3">No Devices</td>
|
||||
</tr>
|
||||
@endif
|
||||
@foreach ($devices as $device)
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ $device->user_agent }}</td>
|
||||
<td>
|
||||
<a type="button"
|
||||
class="btn"
|
||||
href="{{ route('account.device.delete', [$device->uuid]) }}">
|
||||
Delete
|
||||
</a>
|
||||
</td>
|
||||
<th>User Agent</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if ($devices->isEmpty())
|
||||
<tr class="empty">
|
||||
<td colspan="3">No Devices</td>
|
||||
</tr>
|
||||
@else
|
||||
@foreach ($devices as $device)
|
||||
<tr>
|
||||
<td>{{ $device->user_agent }}</td>
|
||||
<td>
|
||||
<a type="button" class="btn" href="{{ route('account.device.delete', [$device->uuid]) }}">
|
||||
Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@endsection
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -46,10 +46,13 @@
|
|||
<label for="username">Username</label>
|
||||
@include('parts.errors', ['name' => 'username'])
|
||||
</div>
|
||||
<div>
|
||||
<input placeholder="domain.com" @if (auth()->user()?->superAdmin) required @else disabled @endif name="domain"
|
||||
type="text" value="{{ $account->domain ?? config('app.sip_domain') }}"
|
||||
@if ($account->id) readonly @endif>
|
||||
<div class="select">
|
||||
<select name="domain" @if (auth()->user()?->superAdmin) required @else disabled @endif>
|
||||
@foreach ($domains as $sipDomain)
|
||||
<option value="{{ $sipDomain->domain }}" @if ($account->domain == $sipDomain->domain) selected="selected" @endif>
|
||||
{{ $sipDomain->domain }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<label for="domain">Domain</label>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -27,19 +27,20 @@
|
|||
<tr class="empty">
|
||||
<td colspan="3">No Devices</td>
|
||||
</tr>
|
||||
@else
|
||||
@foreach ($devices as $device)
|
||||
<tr>
|
||||
<td>{{ $device->user_agent }}</td>
|
||||
<td>
|
||||
<a type="button"
|
||||
class="btn"
|
||||
href="{{ route('admin.account.device.delete', [$account, $device->uuid]) }}">
|
||||
Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endif
|
||||
@foreach ($devices as $device)
|
||||
<tr>
|
||||
<td>{{ $device->user_agent }}</td>
|
||||
<td>
|
||||
<a type="button"
|
||||
class="btn"
|
||||
href="{{ route('admin.account.device.delete', [$account, $device->uuid]) }}">
|
||||
Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,23 +8,21 @@
|
|||
@endsection
|
||||
|
||||
@section('content')
|
||||
<h2>Delete a Contact List</h2>
|
||||
|
||||
<form method="POST" action="{{ route('admin.contacts_lists.destroy', $contacts_list->id) }}" accept-charset="UTF-8">
|
||||
<header>
|
||||
<h2><i class="material-symbols-outlined">delete</i> Delete a Contact List</h2>
|
||||
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}" class="btn btn-secondary oppose">Cancel</a>
|
||||
<input form="delete" class="btn" type="submit" value="Delete">
|
||||
</header>
|
||||
<form id="delete" method="POST" action="{{ route('admin.contacts_lists.destroy', $contacts_list->id) }}" accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method('delete')
|
||||
|
||||
<div class="large">
|
||||
<p>You are going to permanently delete the following contacts list. Please confirm your action.<br />
|
||||
<b>{{ $contacts_list->title }}</b>
|
||||
<h3>{{ $contacts_list->title }}</h3>
|
||||
</p>
|
||||
|
||||
<input name="contacts_lists_id" type="hidden" value="{{ $contacts_list->id }}">
|
||||
</div>
|
||||
<div>
|
||||
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}" class="btn btn-secondary">Cancel</a>
|
||||
<input class="btn" type="submit" value="Delete">
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.sip_domains.index') }}">SIP Domains</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Edit</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<header>
|
||||
@if ($sip_domain->id)
|
||||
<h1><i class="material-symbols-outlined">dns</i> {{ $sip_domain->domain }}</h1>
|
||||
<a href="{{ route('admin.sip_domains.index') }}" class="btn btn-secondary oppose">Cancel</a>
|
||||
<a class="btn btn-secondary" href="{{ route('admin.sip_domains.delete', $sip_domain->id) }}">
|
||||
<i class="material-symbols-outlined">delete</i>
|
||||
Delete
|
||||
</a>
|
||||
<input form="create_edit_sip_domains" class="btn" type="submit" value="Update">
|
||||
@else
|
||||
<h1><i class="material-symbols-outlined">account_box</i> Create a SIP Domain</h1>
|
||||
<a href="{{ route('admin.sip_domains.index') }}" class="btn btn-secondary oppose">Cancel</a>
|
||||
<input form="create_edit_sip_domains" class="btn" type="submit" value="Create">
|
||||
@endif
|
||||
</header>
|
||||
|
||||
<form method="POST" id="create_edit_sip_domains"
|
||||
action="{{ $sip_domain->id ? route('admin.sip_domains.update', $sip_domain->id) : route('admin.sip_domains.store') }}"
|
||||
accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method($sip_domain->id ? 'put' : 'post')
|
||||
@if (!$sip_domain->id)
|
||||
<div>
|
||||
<input placeholder="Name" required="required" name="domain" type="text"
|
||||
value="{{ $sip_domain->domain ?? old('domain') }}">
|
||||
<label for="username">Domain</label>
|
||||
@include('parts.errors', ['name' => 'domain'])
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div>
|
||||
<input name="super" value="true" type="radio" @if ($sip_domain->super) checked @endif>
|
||||
<p>Enabled</p>
|
||||
<input name="super" value="false" type="radio" @if (!$sip_domain->super) checked @endif>
|
||||
<p>Disabled</p>
|
||||
<label>Super domain</label>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@endsection
|
||||
34
flexiapi/resources/views/admin/sip_domain/delete.blade.php
Normal file
34
flexiapi/resources/views/admin/sip_domain/delete.blade.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ route('admin.sip_domains.index') }}">SIP Domains</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Delete</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<header>
|
||||
<h1><i class="material-symbols-outlined">delete</i> Delete a SIP Domain</h1>
|
||||
<a href="{{ route('admin.sip_domains.edit', $sip_domain->id) }}" class="btn btn-secondary oppose">Cancel</a>
|
||||
<input form="delete" class="btn" type="submit" value="Delete">
|
||||
</header>
|
||||
<form id="delete" method="POST" action="{{ route('admin.sip_domains.destroy', $sip_domain->id) }}" accept-charset="UTF-8">
|
||||
@csrf
|
||||
@method('delete')
|
||||
|
||||
<div class="large">
|
||||
<p>You are going to permanently delete the following domain please confirm your action.</p>
|
||||
<h3>{{ $sip_domain->domain }}</h3>
|
||||
<p>This will also destroy <b>{{ $sip_domain->accounts()->count() }} related accounts</b></p>
|
||||
|
||||
<input name="sip_domain" type="hidden" value="{{ $sip_domain->id }}">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input placeholder="domain.tld" required="required" name="domain" type="text">
|
||||
<label for="username">Please retype the domain here to confirm</label>
|
||||
@include('parts.errors', ['name' => 'domain'])
|
||||
</div>
|
||||
</form>
|
||||
@endsection
|
||||
43
flexiapi/resources/views/admin/sip_domain/index.blade.php
Normal file
43
flexiapi/resources/views/admin/sip_domain/index.blade.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
<li class="breadcrumb-item" aria-current="page">
|
||||
SIP Domains
|
||||
</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<header>
|
||||
<h1><i class="material-symbols-outlined">dns</i> SIP Domains</h1>
|
||||
<a class="btn oppose" href="{{ route('admin.sip_domains.create') }}">
|
||||
<i class="material-symbols-outlined">add_circle</i>
|
||||
New SIP Domain
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>SIP Domain</th>
|
||||
<th>Accounts</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($sip_domains as $sip_domain)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.sip_domains.edit', $sip_domain->id) }}">
|
||||
{{ $sip_domain->domain }}
|
||||
@if ($sip_domain->super) <span class="badge badge-error" title="Super domain">Super</span> @endif
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ $sip_domain->accounts_count }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@endsection
|
||||
|
|
@ -24,6 +24,7 @@ The endpoints are accessible using three different models:
|
|||
- <span class="badge badge-success">Public</span> publicly accessible
|
||||
- <span class="badge badge-info">User</span> the endpoint can only be accessed by an authenticated user
|
||||
- <span class="badge badge-warning">Admin</span> the endpoint can be only be accessed by an authenticated admin user
|
||||
- <span class="badge badge-error">Super Admin</span> the endpoint can be only be accessed by an authenticated super admin user
|
||||
|
||||
### Localization
|
||||
|
||||
|
|
@ -127,6 +128,44 @@ An `account_creation_request_token` is a unique token that can be validated and
|
|||
|
||||
Create and return an `account_creation_request_token` that should then be validated to be used.
|
||||
|
||||
## SIP Domains
|
||||
|
||||
Manage the list of allowed `sip_domains`. The admin accounts declared with a `domain` that is a `super` `sip_domain` will become <span class="badge badge-error">Super Admin</span>.
|
||||
|
||||
### `GET /sip_domains`
|
||||
<span class="badge badge-error">Super Admin</span>
|
||||
|
||||
Get the list of declared SIP Domains.
|
||||
|
||||
### `GET /sip_domains/{domain}`
|
||||
<span class="badge badge-error">Super Admin</span>
|
||||
|
||||
Get a SIP Domain.
|
||||
|
||||
### `POST /sip_domains`
|
||||
<span class="badge badge-error">Super Admin</span>
|
||||
|
||||
Create a new `sip_domain`.
|
||||
|
||||
JSON parameters:
|
||||
|
||||
* `domain` required, the domain to use, must be unique
|
||||
* `super` required, boolean, set the domain as a Super Domain
|
||||
|
||||
### `PUT /sip_domains/{domain}`
|
||||
<span class="badge badge-error">Super Admin</span>
|
||||
|
||||
Update an existing `sip_domain`.
|
||||
|
||||
JSON parameters:
|
||||
|
||||
* `super` required, boolean, set the domain as a Super Domain
|
||||
|
||||
### `DELETE /sip_domains/{domain}`
|
||||
<span class="badge badge-error">Super Admin</span>
|
||||
|
||||
Delete a domain, **be careful, all the related accounts will also be destroyed**.
|
||||
|
||||
## Account Creation Tokens
|
||||
|
||||
An `account_creation_token` is a unique token that allow the creation or the validation of a unique account.
|
||||
|
|
@ -336,7 +375,7 @@ JSON parameters:
|
|||
* `username` unique username, minimum 6 characters
|
||||
* `password` required minimum 6 characters
|
||||
* `algorithm` required, values can be `SHA-256` or `MD5`
|
||||
* `domain` **not configurable by default**. Only configurable if the admin is a super admin. Otherwise `APP_SIP_DOMAIN` is used.
|
||||
* `domain` **not configurable by default**. Only configurable if the admin is a super admin. Otherwise `APP_SIP_DOMAIN` is used. If the domain is not available in the `sip_domains` list, it will be created automatically.
|
||||
* `activated` optional, a boolean, set to `false` by default
|
||||
* `display_name` optional, string
|
||||
* `email` optional, must be an email, must be unique if `ACCOUNT_EMAIL_UNIQUE` is set to `true`
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
$items['admin.account.index'] = ['title' => 'Accounts', 'icon' => 'people'];
|
||||
$items['admin.contacts_lists.index'] = ['title' => 'Contacts Lists', 'icon' => 'account_box'];
|
||||
$items['admin.statistics.show'] = ['title' => 'Statistics', 'icon' => 'analytics'];
|
||||
|
||||
if (auth()->user()->superAdmin) {
|
||||
$items['admin.sip_domains.index'] = ['title' => 'SIP Domains', 'icon' => 'dns'];
|
||||
}
|
||||
}
|
||||
@endphp
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use App\Http\Controllers\Api\Admin\AccountController as AdminAccountController;
|
|||
use App\Http\Controllers\Api\Admin\AccountDictionaryController;
|
||||
use App\Http\Controllers\Api\Admin\AccountTypeController;
|
||||
use App\Http\Controllers\Api\Admin\ContactsListController;
|
||||
use App\Http\Controllers\Api\Admin\SipDomainController;
|
||||
use App\Http\Controllers\Api\Admin\VcardsStorageController as AdminVcardsStorageController;
|
||||
use App\Http\Controllers\Api\StatisticsMessageController;
|
||||
use App\Http\Controllers\Api\StatisticsCallController;
|
||||
|
|
@ -91,6 +92,17 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
|
|||
Route::post('messages', 'Api\Admin\MessageController@send');
|
||||
}
|
||||
|
||||
// Super admin
|
||||
Route::group(['middleware' => ['auth.super_admin']], function () {
|
||||
Route::prefix('sip_domains')->controller(SipDomainController::class)->group(function () {
|
||||
Route::get('/', 'index');
|
||||
Route::get('{domain}', 'show');
|
||||
Route::post('/', 'store');
|
||||
Route::put('{domain}', 'update');
|
||||
Route::delete('{domain}', 'destroy');
|
||||
});
|
||||
});
|
||||
|
||||
// Account creation token
|
||||
Route::post('account_creation_tokens', 'Api\Admin\AccountCreationTokenController@create');
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ use App\Http\Controllers\Admin\AccountController as AdminAccountController;
|
|||
use App\Http\Controllers\Admin\AccountStatisticsController;
|
||||
use App\Http\Controllers\Admin\ContactsListController;
|
||||
use App\Http\Controllers\Admin\ContactsListContactController;
|
||||
use App\Http\Controllers\Admin\SipDomainController;
|
||||
use App\Http\Controllers\Admin\StatisticsController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
|
|
@ -152,6 +153,12 @@ Route::group(['middleware' => 'web_panel_enabled'], function () {
|
|||
Route::get('auth_tokens/auth/{token}', 'Account\AuthTokenController@auth')->name('auth_tokens.auth');
|
||||
|
||||
Route::name('admin.')->prefix('admin')->middleware(['auth.admin', 'auth.check_blocked'])->group(function () {
|
||||
|
||||
Route::middleware(['auth.super_admin'])->group(function () {
|
||||
Route::resource('sip_domains', SipDomainController::class);
|
||||
Route::get('sip_domains/delete/{id}', 'Admin\SipDomainController@delete')->name('sip_domains.delete');
|
||||
});
|
||||
|
||||
Route::name('statistics.')->controller(StatisticsController::class)->prefix('statistics')->group(function () {
|
||||
Route::get('/', 'index')->name('index');
|
||||
Route::post('call_logs', 'editCallLogs')->name('edit_call_logs');
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Account;
|
||||
use App\Password;
|
||||
use DateTimeImmutable;
|
||||
use Lcobucci\Clock\FrozenClock;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use App\Password;
|
|||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ApiAccountContactTest extends TestCase
|
||||
class ApiAccountContactsTest extends TestCase
|
||||
{
|
||||
protected $route = '/api/accounts';
|
||||
protected $contactsListsRoute = '/api/contacts_lists';
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use App\AccountCreationToken;
|
|||
use App\AccountTombstone;
|
||||
use App\ActivationExpiration;
|
||||
use App\Password;
|
||||
use App\SipDomain;
|
||||
use Carbon\Carbon;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
|
@ -86,14 +87,13 @@ class ApiAccountTest extends TestCase
|
|||
|
||||
public function testUsernameNotPhone()
|
||||
{
|
||||
$password = Password::factory()->admin()->create();
|
||||
$password->account->generateApiKey();
|
||||
//$password->account->save();
|
||||
$account = Account::factory()->admin()->create();
|
||||
$account->generateApiKey();
|
||||
|
||||
$username = '+33612121212';
|
||||
$domain = 'example.com';
|
||||
$domain = SipDomain::first()->domain;
|
||||
|
||||
$this->keyAuthenticated($password->account)
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => $username,
|
||||
'domain' => $domain,
|
||||
|
|
@ -104,7 +104,7 @@ class ApiAccountTest extends TestCase
|
|||
|
||||
config()->set('app.allow_phone_number_username_admin_api', true);
|
||||
|
||||
$this->keyAuthenticated($password->account)
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => $username,
|
||||
'domain' => $domain,
|
||||
|
|
@ -118,10 +118,9 @@ class ApiAccountTest extends TestCase
|
|||
{
|
||||
$password = Password::factory()->admin()->create();
|
||||
$password->account->generateApiKey();
|
||||
//$password->account->save();
|
||||
|
||||
$username = 'blabla🔥';
|
||||
$domain = 'example.com';
|
||||
$domain = SipDomain::first()->domain;
|
||||
|
||||
$this->keyAuthenticated($password->account)
|
||||
->json($this->method, $this->route, [
|
||||
|
|
@ -161,7 +160,7 @@ class ApiAccountTest extends TestCase
|
|||
|
||||
$password = Password::factory()->admin()->create();
|
||||
$username = 'foobar';
|
||||
$domain = 'example.com';
|
||||
$domain = SipDomain::first()->domain;
|
||||
|
||||
config()->set('app.admins_manage_multi_domains', false);
|
||||
|
||||
|
|
@ -191,53 +190,48 @@ class ApiAccountTest extends TestCase
|
|||
{
|
||||
$configDomain = 'sip.domain.com';
|
||||
config()->set('app.sip_domain', $configDomain);
|
||||
config()->set('app.super_admins_sip_domains', $configDomain);
|
||||
|
||||
$password = Password::factory()->admin()->create();
|
||||
$password->account->generateApiKey();
|
||||
$password->account->save();
|
||||
$account = Account::factory()->superAdmin()->create();
|
||||
$account->generateApiKey();
|
||||
$account->save();
|
||||
|
||||
$username = 'foobar';
|
||||
$domain1 = 'example.com';
|
||||
$domain2 = 'foobar.com';
|
||||
$domain1 = SipDomain::first()->domain;
|
||||
$domain2 = SipDomain::factory()->secondDomain()->create()->domain;
|
||||
|
||||
$response0 = $this->keyAuthenticated($password->account)
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => $username,
|
||||
'domain' => $domain1,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
]);
|
||||
|
||||
$response0
|
||||
])
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'username' => $username,
|
||||
'domain' => $domain1
|
||||
]);
|
||||
|
||||
$response1 = $this->keyAuthenticated($password->account)
|
||||
$this->keyAuthenticated($account)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => $username,
|
||||
'domain' => $domain2,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
]);
|
||||
|
||||
$response1
|
||||
])
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'username' => $username,
|
||||
'domain' => $domain2
|
||||
]);
|
||||
|
||||
$this->keyAuthenticated($password->account)
|
||||
$this->keyAuthenticated($account)
|
||||
->get($this->route)
|
||||
->assertStatus(200)
|
||||
->assertJson(['data' => [
|
||||
[
|
||||
'username' => $password->account->username,
|
||||
'domain' => $password->account->domain
|
||||
'username' => $account->username,
|
||||
'domain' => $account->domain
|
||||
],
|
||||
[
|
||||
'username' => $username,
|
||||
|
|
@ -250,12 +244,68 @@ class ApiAccountTest extends TestCase
|
|||
]]);
|
||||
}
|
||||
|
||||
public function testCreateDomainAsAdmin()
|
||||
{
|
||||
$admin = Account::factory()->admin()->create();
|
||||
$admin->generateApiKey();
|
||||
$admin->save();
|
||||
|
||||
$username = 'foo';
|
||||
$newDomain = 'new.domain';
|
||||
|
||||
// Standard admin
|
||||
$this->keyAuthenticated($admin)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => $username,
|
||||
'domain' => $newDomain,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
])
|
||||
->assertStatus(422);
|
||||
|
||||
$this->keyAuthenticated($admin)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => $username,
|
||||
'domain' => $admin->domain,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
])
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testCreateDomainAsSuperAdmin()
|
||||
{
|
||||
$superAdmin = Account::factory()->superAdmin()->create();
|
||||
$superAdmin->generateApiKey();
|
||||
$superAdmin->save();
|
||||
|
||||
$username = 'foo';
|
||||
$newDomain = 'new.domain';
|
||||
|
||||
// Super admin
|
||||
$this->keyAuthenticated($superAdmin)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => $username,
|
||||
'domain' => $newDomain,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
])
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'username' => $username,
|
||||
'domain' => $newDomain
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('sip_domains', [
|
||||
'domain' => $newDomain
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function testDomainInTestDeployment()
|
||||
{
|
||||
$configDomain = 'testdomain.com';
|
||||
$adminDomain = 'admindomain.com';
|
||||
config()->set('app.super_admins_sip_domains', $adminDomain);
|
||||
config()->set('app.sip_domain', $adminDomain);
|
||||
config()->set('app.sip_domain', $configDomain);
|
||||
|
||||
$password = Password::factory()->admin()->create();
|
||||
$username = 'foobar';
|
||||
|
|
@ -358,11 +408,12 @@ class ApiAccountTest extends TestCase
|
|||
$entryValue = 'bar';
|
||||
$entryNewKey = 'new_key';
|
||||
$entryNewValue = 'new_value';
|
||||
$domain = SipDomain::first()->domain;
|
||||
|
||||
$result = $this->keyAuthenticated($admin)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => 'john',
|
||||
'domain' => 'lennon.com',
|
||||
'domain' => $domain,
|
||||
'password' => 'password123',
|
||||
'algorithm' => 'SHA-256',
|
||||
'dictionary' => [
|
||||
|
|
@ -381,7 +432,7 @@ class ApiAccountTest extends TestCase
|
|||
$this->keyAuthenticated($admin)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => 'john2',
|
||||
'domain' => 'lennon.com',
|
||||
'domain' => $domain,
|
||||
'password' => 'password123',
|
||||
'algorithm' => 'SHA-256',
|
||||
'dictionary' => [
|
||||
|
|
@ -392,7 +443,7 @@ class ApiAccountTest extends TestCase
|
|||
$this->keyAuthenticated($admin)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => 'john2',
|
||||
'domain' => 'lennon.com',
|
||||
'domain' => $domain,
|
||||
'password' => 'password123',
|
||||
'algorithm' => 'SHA-256',
|
||||
'dictionary' => 'hop'
|
||||
|
|
@ -479,7 +530,6 @@ class ApiAccountTest extends TestCase
|
|||
public function testActivated()
|
||||
{
|
||||
$password = Password::factory()->admin()->create();
|
||||
|
||||
$username = 'username';
|
||||
|
||||
$response0 = $this->generateFirstResponse($password);
|
||||
|
|
@ -672,13 +722,14 @@ class ApiAccountTest extends TestCase
|
|||
$password->account->generateApiKey();
|
||||
|
||||
$username = 'username';
|
||||
$domain = SipDomain::first()->domain;
|
||||
|
||||
$response = $this->generateFirstResponse($password, $this->method, $this->route);
|
||||
$this->generateSecondResponse($password, $response)
|
||||
->json($this->method, $this->route, [
|
||||
'username' => $username,
|
||||
'email' => 'email@test.com',
|
||||
'domain' => 'server.com',
|
||||
'domain' => $domain,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => 'nonascii€',
|
||||
])
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Tests\Feature;
|
|||
use App\Account;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ApiVcardsStorageTest extends TestCase
|
||||
class ApiAccountVcardsStorageTest extends TestCase
|
||||
{
|
||||
protected $route = '/api/accounts/me/vcards-storage';
|
||||
protected $method = 'POST';
|
||||
|
|
|
|||
117
flexiapi/tests/Feature/ApiSipDomainTest.php
Normal file
117
flexiapi/tests/Feature/ApiSipDomainTest.php
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
<?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 Tests\Feature;
|
||||
|
||||
use App\Account;
|
||||
use App\SipDomain;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ApiSipDomainTest extends TestCase
|
||||
{
|
||||
protected $route = '/api/sip_domains';
|
||||
|
||||
public function testBaseAdmin()
|
||||
{
|
||||
$admin = Account::factory()->admin()->create();
|
||||
$admin->generateApiKey();
|
||||
|
||||
$secondDomain = SipDomain::factory()->secondDomain()->create();
|
||||
$username = 'foo';
|
||||
|
||||
// Admin domain
|
||||
$this->keyAuthenticated($admin)
|
||||
->json('POST', '/api/accounts', [
|
||||
'username' => $username,
|
||||
'domain' => $admin->domain,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
// Second domain
|
||||
$this->keyAuthenticated($admin)
|
||||
->json('POST', '/api/accounts', [
|
||||
'username' => $username,
|
||||
// The domain is ignored there, to fallback on the admin one
|
||||
'domain' => $secondDomain->domain,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
])
|
||||
->assertJsonValidationErrors(['username']);
|
||||
|
||||
// Admin domain is now a super domain
|
||||
SipDomain::where('domain', $admin->domain)->update(['super' => true]);
|
||||
|
||||
$this->keyAuthenticated($admin)
|
||||
->json('POST', '/api/accounts', [
|
||||
'username' => $username,
|
||||
'domain' => $secondDomain->domain,
|
||||
'algorithm' => 'SHA-256',
|
||||
'password' => '123456',
|
||||
])
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testSuperAdmin()
|
||||
{
|
||||
$admin = Account::factory()->superAdmin()->create();
|
||||
$admin->generateApiKey();
|
||||
|
||||
$thirdDomain = 'third.domain';
|
||||
|
||||
$this->keyAuthenticated($admin)
|
||||
-> json('POST', $this->route, [
|
||||
'domain' => $thirdDomain,
|
||||
'super' => false
|
||||
])
|
||||
->assertStatus(201);
|
||||
|
||||
$this->keyAuthenticated($admin)
|
||||
->json('GET', $this->route)
|
||||
->assertJsonFragment([
|
||||
'domain' => $thirdDomain,
|
||||
'super' => false
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
$this->keyAuthenticated($admin)
|
||||
->json('PUT', $this->route . '/' . $thirdDomain, [
|
||||
'super' => true
|
||||
])
|
||||
->assertJsonFragment([
|
||||
'domain' => $thirdDomain,
|
||||
'super' => true
|
||||
])
|
||||
->assertStatus(200);
|
||||
|
||||
$this->keyAuthenticated($admin)
|
||||
->json('DELETE', $this->route . '/' . $thirdDomain)
|
||||
->assertStatus(200);
|
||||
|
||||
// Only the admin domain remains
|
||||
$this->keyAuthenticated($admin)
|
||||
->json('GET', $this->route)
|
||||
->assertJsonFragment([
|
||||
'domain' => $admin->domain,
|
||||
'super' => true
|
||||
])
|
||||
->assertStatus(200);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue