Fix FLEXIAPI-203 Implement domain based Linphone configuration, add...

This commit is contained in:
Timothée Jaussoin 2024-08-12 10:14:21 +00:00
parent 4d550d04ab
commit a4e44d94a6
14 changed files with 306 additions and 67 deletions

View file

@ -4,6 +4,7 @@ v1.6
----
- Fix FLEXIAPI-192 Add DotEnv configuration to allow the expiration of tokens and codes in the app
- Fix FLEXIAPI-196 Add a phone validation system by country code with configuration panels and related tests and documentation
- Fix FLEXIAPI-203 Implement domain based Linphone configuration, add documentation, complete API endpoints, complete provisioning XML
v1.5
---

View file

@ -178,6 +178,11 @@ class Account extends Authenticatable
return $this->belongsToMany(AccountType::class);
}
public function sipDomain()
{
return $this->hasOne(SipDomain::class, 'domain', 'domain');
}
public function statisticsFromCalls()
{
return $this->hasMany(StatisticsCall::class, ['from_username', 'from_domain'], ['username', 'domain']);

View file

@ -40,6 +40,11 @@ function generateNonce(): string
return Str::random(32);
}
function getRequestBoolean(Request $request, string $key): bool
{
return $request->has($key) ? $request->get($key) == "true" : false;
}
function generateValidNonce(Account $account): string
{
$nonce = new DigestNonce();

View file

@ -201,6 +201,35 @@ class ProvisioningController extends Controller
$config->appendChild($section);
if ($account) {
$ui = $xpath->query("//section[@name='ui']")->item(0);
if ($ui == null && $account->sipDomain) {
$section = $dom->createElement('section');
$section->setAttribute('name', 'ui');
foreach ([
'super',
'disable_chat_feature',
'disable_meetings_feature',
'disable_broadcast_feature',
'hide_settings',
'hide_account_settings',
'disable_call_recordings_feature',
'only_display_sip_uri_username',
'assistant_hide_create_account',
'assistant_disable_qr_code',
'assistant_hide_third_party_account',
'max_account',
] as $key) {
// Cast the booleans into integers
$entry = $dom->createElement('entry', (int)$account->sipDomain->$key);
$entry->setAttribute('name', $key);
$section->appendChild($entry);
}
$config->appendChild($section);
}
$section = $xpath->query("//section[@name='proxy_0']")->item(0);
if ($section == null) {

View file

@ -47,7 +47,7 @@ class SipDomainController extends Controller
$sipDomain = new SipDomain;
$sipDomain->domain = $request->get('domain');
$sipDomain->super = $request->has('super') ? (bool)$request->get('super') == "true" : false;
$sipDomain = $this->setConfig($request, $sipDomain);
$sipDomain->save();
return redirect()->route('admin.sip_domains.index');
@ -62,11 +62,37 @@ class SipDomainController extends Controller
public function update(Request $request, int $id)
{
$request->validate([
'max_account' => 'required|integer',
]);
$sipDomain = SipDomain::findOrFail($id);
$sipDomain->super = $request->has('super') ? $request->get('super') == "true" : false;
$sipDomain = $this->setConfig($request, $sipDomain);
$sipDomain->save();
return redirect()->route('admin.sip_domains.index');
return redirect()->back();
}
private function setConfig(Request $request, SipDomain $sipDomain)
{
$request->validate([
'max_account' => 'required|integer',
]);
$sipDomain->super = getRequestBoolean($request, 'super');
$sipDomain->disable_chat_feature = getRequestBoolean($request, 'disable_chat_feature');
$sipDomain->disable_meetings_feature = getRequestBoolean($request, 'disable_meetings_feature');
$sipDomain->disable_broadcast_feature = getRequestBoolean($request, 'disable_broadcast_feature');
$sipDomain->hide_settings = getRequestBoolean($request, 'hide_settings');
$sipDomain->max_account = $request->get('max_account', 0);
$sipDomain->hide_account_settings = getRequestBoolean($request, 'hide_account_settings');
$sipDomain->disable_call_recordings_feature = getRequestBoolean($request, 'disable_call_recordings_feature');
$sipDomain->only_display_sip_uri_username = getRequestBoolean($request, 'only_display_sip_uri_username');
$sipDomain->assistant_hide_create_account = getRequestBoolean($request, 'assistant_hide_create_account');
$sipDomain->assistant_disable_qr_code = getRequestBoolean($request, 'assistant_disable_qr_code');
$sipDomain->assistant_hide_third_party_account = getRequestBoolean($request, 'assistant_hide_third_party_account');
return $sipDomain;
}
public function delete(int $id)

View file

@ -35,15 +35,26 @@ class SipDomainController extends Controller
{
$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;
$this->setRequestBoolean($request, $sipDomain, 'super');
$this->setRequestBoolean($request, $sipDomain, 'disable_chat_feature');
$this->setRequestBoolean($request, $sipDomain, 'disable_meetings_feature');
$this->setRequestBoolean($request, $sipDomain, 'disable_broadcast_feature');
$this->setRequestBoolean($request, $sipDomain, 'hide_settings');
$this->setRequestBoolean($request, $sipDomain, 'hide_account_settings');
$this->setRequestBoolean($request, $sipDomain, 'disable_call_recordings_feature');
$this->setRequestBoolean($request, $sipDomain, 'only_display_sip_uri_username');
$this->setRequestBoolean($request, $sipDomain, 'assistant_hide_create_account');
$this->setRequestBoolean($request, $sipDomain, 'assistant_disable_qr_code');
$this->setRequestBoolean($request, $sipDomain, 'assistant_hide_third_party_account');
$sipDomain->max_account = $request->get('max_account', 0);
$sipDomain->save();
return $sipDomain;
return $sipDomain->refresh();
}
public function show(string $domain)
@ -55,15 +66,44 @@ class SipDomainController extends Controller
{
$request->validate([
'super' => 'required|boolean',
'disable_chat_feature' => 'required|boolean',
'disable_meetings_feature' => 'required|boolean',
'disable_broadcast_feature' => 'required|boolean',
'hide_settings' => 'required|boolean',
'hide_account_settings' => 'required|boolean',
'disable_call_recordings_feature' => 'required|boolean',
'only_display_sip_uri_username' => 'required|boolean',
'assistant_hide_create_account' => 'required|boolean',
'assistant_disable_qr_code' => 'required|boolean',
'assistant_hide_third_party_account' => 'required|boolean',
'max_account' => 'required|integer',
]);
$sipDomain = SipDomain::where('domain', $domain)->firstOrFail();
$sipDomain->super = $request->has('super') ? (bool)$request->get('super') : false;
$sipDomain->super = $request->get('super');
$sipDomain->disable_chat_feature = $request->get('disable_chat_feature');
$sipDomain->disable_meetings_feature = $request->get('disable_meetings_feature');
$sipDomain->disable_broadcast_feature = $request->get('disable_broadcast_feature');
$sipDomain->hide_settings = $request->get('hide_settings');
$sipDomain->hide_account_settings = $request->get('hide_account_settings');
$sipDomain->disable_call_recordings_feature = $request->get('disable_call_recordings_feature');
$sipDomain->only_display_sip_uri_username = $request->get('only_display_sip_uri_username');
$sipDomain->assistant_hide_create_account = $request->get('assistant_hide_create_account');
$sipDomain->assistant_disable_qr_code = $request->get('assistant_disable_qr_code');
$sipDomain->assistant_hide_third_party_account = $request->get('assistant_hide_third_party_account');
$sipDomain->max_account = $request->get('max_account', 0);
$sipDomain->save();
return $sipDomain;
}
private function setRequestBoolean(Request $request, SipDomain $sipDomain, string $key)
{
if ($request->has($key)) {
$sipDomain->$key = (bool)$request->get($key);
}
}
public function destroy(string $domain)
{
return SipDomain::where('domain', $domain)->delete();

View file

@ -2,10 +2,8 @@
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
{
@ -14,6 +12,16 @@ class SipDomain extends Model
protected $hidden = ['id'];
protected $casts = [
'super' => 'boolean',
'disable_chat_feature' => 'boolean',
'disable_meetings_feature' => 'boolean',
'disable_broadcast_feature' => 'boolean',
'hide_settings' => 'boolean',
'hide_account_settings' => 'boolean',
'disable_call_recordings_feature' => 'boolean',
'only_display_sip_uri_username' => 'boolean',
'assistant_hide_create_account' => 'boolean',
'assistant_disable_qr_code' => 'boolean',
'assistant_hide_third_party_account' => 'boolean',
];
public function accounts()

View file

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::table('sip_domains', function (Blueprint $table) {
$table->boolean('disable_chat_feature')->default(false);
$table->boolean('disable_meetings_feature')->default(false);
$table->boolean('disable_broadcast_feature')->default(true);
$table->integer('max_account')->default(0);
$table->boolean('hide_settings')->default(false);
$table->boolean('hide_account_settings')->default(false);
$table->boolean('disable_call_recordings_feature')->default(false);
$table->boolean('only_display_sip_uri_username')->default(false);
$table->boolean('assistant_hide_create_account')->default(false);
$table->boolean('assistant_disable_qr_code')->default(false);
$table->boolean('assistant_hide_third_party_account')->default(false);
});
}
public function down()
{
Schema::table('sip_domains', function (Blueprint $table) {
$table->dropColumn('disable_chat_feature');
$table->dropColumn('disable_meetings_feature');
$table->dropColumn('disable_broadcast_feature');
$table->dropColumn('max_account');
$table->dropColumn('hide_settings');
$table->dropColumn('hide_account_settings');
$table->dropColumn('disable_call_recordings_feature');
$table->dropColumn('only_display_sip_uri_username');
$table->dropColumn('assistant_hide_create_account');
$table->dropColumn('assistant_disable_qr_code');
$table->dropColumn('assistant_hide_third_party_account');
});
}
};

View file

@ -94,13 +94,7 @@
<h2>Other information</h2>
<div>
<input name="activated" value="true" type="radio" @if ($account->activated) checked @endif>
<p>Enabled</p>
<input name="activated" value="false" type="radio" @if (!$account->activated) checked @endif>
<p>Disabled</p>
<label>Status</label>
</div>
@include('parts.form.toggle', ['object' => $account, 'key' => 'activated', 'label' => 'Status'])
<div>
<input name="blocked" value="false" type="radio" @if (!$account->blocked) checked @endif>

View file

@ -38,13 +38,36 @@
</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>
@include('parts.form.toggle', ['key' => 'super', 'label' => 'Super domain'])
<h3 class="large">Features</h3>
@include('parts.form.toggle', ['object' => $sip_domain, 'key' => 'disable_chat_feature', 'label' => 'Chat feature', 'reverse' => true])
@include('parts.form.toggle', ['object' => $sip_domain, 'key' => 'disable_meetings_feature', 'label' => 'Meeting feature', 'reverse' => true])
@include('parts.form.toggle', ['object' => $sip_domain, 'key' => 'disable_broadcast_feature', 'label' => 'Conference feature', 'reverse' => true])
@include('parts.form.toggle', ['object' => $sip_domain, 'key' => 'hide_settings', 'label' => 'General settings', 'reverse' => true])
@include('parts.form.toggle', ['object' => $sip_domain, 'key' => 'hide_account_settings', 'label' => 'Account settings', 'reverse' => true])
@include('parts.form.toggle', ['object' => $sip_domain, 'key' => 'disable_call_recordings_feature', 'label' => 'Record audio/video calls', 'reverse' => true])
<h3 class="large">General toggles</h3>
@include('parts.form.toggle', ['key' => 'only_display_sip_uri_username', 'label' => 'Only display usernames (hide SIP addresses)'])
<div class="select">
<select name="max_account">
@foreach ([0 => 'No limit', 1 => 'One', 2 => 'Two', 3 => 'Three', 4 => 'Four', 5 => 'Five'] as $key => $value)
<option value="{{ $key }}" @if ($sip_domain->max_account == $key) selected="selected" @endif>
{{ $value }}</option>
@endforeach
</select>
<label for="domain">Max account authorized</label>
</div>
<h3 class="large">Assistant</h3>
@include('parts.form.toggle', ['key' => 'assistant_hide_create_account', 'label' => 'Account creation panel', 'reverse' => true])
@include('parts.form.toggle', ['key' => 'assistant_disable_qr_code', 'label' => 'QR Code scanning panel', 'reverse' => true])
@include('parts.form.toggle', ['key' => 'assistant_hide_third_party_account', 'label' => 'Third party SIP panel', 'reverse' => true])
</form>
@endsection

View file

@ -149,8 +149,19 @@ 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
* `domain` **required**, the domain to use, must be unique
* `super` **required**, boolean, set the domain as a Super Domain
* `disable_chat_feature` boolean, disable the chat feature, default to `false`
* `disable_meetings_feature` boolean, disable the meeting feature, default to `false`
* `disable_broadcast_feature` boolean, disable the broadcast feature, default to `true`
* `hide_settings` boolean, hide the app settings, default to `false`
* `hide_account_settings` boolean, disable the account settings, default to `false`
* `disable_call_recordings_feature` boolean, disable the call recording feature, default to `false`
* `only_display_sip_uri_username` boolean, hide the SIP uris in the app, default to `false`
* `assistant_hide_create_account` boolean, disable the account creation assistant, default to `false`
* `assistant_disable_qr_code` boolean, disable the QR code feature in the assistant, default to `false`
* `assistant_hide_third_party_account` boolean, disable the call recording feature, default to `false`
* `max_account` integer, the maximum number of accounts configurable in the app, default to `0` (infinite)
### `PUT /sip_domains/{domain}`
<span class="badge badge-error">Super Admin</span>
@ -159,7 +170,18 @@ Update an existing `sip_domain`.
JSON parameters:
* `super` required, boolean, set the domain as a Super Domain
* `super` **required**, boolean, set the domain as a Super Domain
* `disable_chat_feature` **required**, boolean
* `disable_meetings_feature` **required**, boolean
* `disable_broadcast_feature` **required**, boolean
* `hide_settings` **required**, boolean
* `hide_account_settings` **required**, boolean
* `disable_call_recordings_feature` **required**, boolean
* `only_display_sip_uri_username` **required**, boolean
* `assistant_hide_create_account` **required**, boolean
* `assistant_disable_qr_code` **required**, boolean
* `assistant_hide_third_party_account` **required**, boolean
* `max_account` **required**, integer
### `DELETE /sip_domains/{domain}`
<span class="badge badge-error">Super Admin</span>
@ -192,7 +214,7 @@ Return `404` if the `account_creation_request_token` provided is not valid or ex
JSON parameters:
* `account_creation_request_token` required
* `account_creation_request_token` **required**
### `POST /account_creation_tokens/consume`
<span class="badge badge-info">User</span>
@ -204,7 +226,7 @@ Return `404` if the `account_creation_token` provided is not valid.
JSON parameters:
* `account_creation_token` required
* `account_creation_token` **required**
### `POST /account_creation_tokens`
<span class="badge badge-warning">Admin</span>
@ -238,12 +260,12 @@ Send an email with the activation key if `email` is set, send an SMS otherwise.
JSON parameters:
* `username` required if `phone` not set, unique username, minimum 6 characters
* `password` required minimum 6 characters
* `algorithm` required, values can be `SHA-256` or `MD5`
* `username` **required** if `phone` not set, unique username, minimum 6 characters
* `password` **required** minimum 6 characters
* `algorithm` **required**, values can be `SHA-256` or `MD5`
* `domain` if not set the value is enforced to the default registration domain set in the global configuration
* `email` optional if `phone` set, an email, set an email to the account, must be unique if `ACCOUNT_EMAIL_UNIQUE` is set to `true`
* `phone` required if `username` not set, optional if `email` set, a valid phone number, set a phone number to the account
* `phone` **required** if `username` not set, optional if `email` set, a valid phone number, set a phone number to the account
* `account_creation_token` the unique `account_creation_token`
### `POST /accounts/with-account-creation-token`
@ -255,8 +277,8 @@ Return `422` if the parameters are invalid or if the token is expired.
JSON parameters:
* `username` unique username, minimum 6 characters
* `password` required minimum 6 characters
* `algorithm` required, values can be `SHA-256` or `MD5`
* `password` **required** minimum 6 characters
* `algorithm` **required**, values can be `SHA-256` or `MD5`
* `account_creation_token` the unique `account_creation_token`
* `dtmf_protocol` optional, values must be `sipinfo`, `sipmessage` or `rfc2833`
@ -284,7 +306,7 @@ Can only be used once, a new `recover_key` need to be requested to be called aga
JSON parameters:
* `phone` required, the phone number to send the SMS to
* `phone` **required**, the phone number to send the SMS to
* `account_creation_token` the unique `account_creation_token`
### `GET /accounts/{sip}/recover/{recover_key}`
@ -361,9 +383,9 @@ Change the account password.
JSON parameters:
* `algorithm` required, values can be `SHA-256` or `MD5`
* `old_password` required if the password is already set, the old password
* `password` required, the new password
* `algorithm` **required**, values can be `SHA-256` or `MD5`
* `old_password` **required** if the password is already set, the old password
* `password` **required**, the new password
### `POST /accounts`
<span class="badge badge-warning">Admin</span>
@ -373,8 +395,8 @@ To create an account directly from the API. <span class="badge badge-message">De
JSON parameters:
* `username` unique username, minimum 6 characters
* `password` required minimum 6 characters
* `algorithm` required, values can be `SHA-256` or `MD5`
* `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. 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
@ -394,8 +416,8 @@ JSON parameters:
* `username` unique username, minimum 6 characters
* `domain` **not configurable by default**. Only configurable if the admin is a super admin. Otherwise `APP_SIP_DOMAIN` is used.
* `password` required minimum 6 characters
* `algorithm` required, values can be `SHA-256` or `MD5`
* `password` **required** minimum 6 characters
* `algorithm` **required**, values can be `SHA-256` or `MD5`
* `display_name` optional, string
* `email` optional, must be an email, must be unique if `ACCOUNT_EMAIL_UNIQUE` is set to `true`
* `admin` optional, a boolean, set to `false` by default
@ -605,7 +627,7 @@ Add or update a new entry to the dictionary
JSON parameters:
* `value` required, the entry value
* `value` **required**, the entry value
### `DELETE /accounts/{id}/dictionary/{key}`
<span class="badge badge-warning">Admin</span>
@ -633,8 +655,8 @@ Create an account action.
JSON parameters:
* `key` required, alpha numeric with dashes, lowercase
* `code` required, alpha numeric, lowercase
* `key` **required**, alpha numeric with dashes, lowercase
* `code` **required**, alpha numeric, lowercase
### `PUT /accounts/{id}/actions/{action_id}`
<span class="badge badge-warning">Admin</span>
@ -643,8 +665,8 @@ Create an account action.
JSON parameters:
* `key` required, alpha numeric with dashes, lowercase
* `code` required, alpha numeric, lowercase
* `key` **required**, alpha numeric with dashes, lowercase
* `code` **required**, alpha numeric, lowercase
### `DELETE /accounts/{id}/actions/{action_id}`
<span class="badge badge-warning">Admin</span>
@ -670,8 +692,8 @@ Create a contacts list.
JSON parameters:
* `title` required
* `description` required
* `title` **required**
* `description` **required**
### `PUT /contacts_lists/{id}`
<span class="badge badge-warning">Admin</span>
@ -680,8 +702,8 @@ Update a contacts list.
JSON parameters:
* `title` required
* `description` required
* `title` **required**
* `description` **required**
### `DELETE /contacts_lists/{id}`
<span class="badge badge-warning">Admin</span>
@ -727,7 +749,7 @@ Create an account type.
JSON parameters:
* `key` required, alpha numeric with dashes, lowercase
* `key` **required**, alpha numeric with dashes, lowercase
### `PUT /account_types/{id}`
<span class="badge badge-warning">Admin</span>
@ -736,7 +758,7 @@ Update an account type.
JSON parameters:
* `key` required, alpha numeric with dashes, lowercase
* `key` **required**, alpha numeric with dashes, lowercase
### `DELETE /account_types/{id}`
<span class="badge badge-warning">Admin</span>
@ -762,8 +784,8 @@ Send a message over SIP.
JSON parameters:
* `to` required, SIP address of the receiver
* `body` required, content of the message
* `to` **required**, SIP address of the receiver
* `body` **required**, content of the message
## Phone Countries
@ -787,10 +809,10 @@ Announce the creation of a message.
JSON parameters:
* `id` required, string
* `from` required, string the sender of the message
* `sent_at` required, string, format ISO8601, when the message was actually sent
* `encrypted` required, boolean
* `id` **required**, string
* `from` **required**, string the sender of the message
* `sent_at` **required**, string, format ISO8601, when the message was actually sent
* `encrypted` **required**, boolean
* `conference_id` string
### `PATCH /statistics/messages/{message_id}/to/{to}/devices/{device_id}`
@ -800,8 +822,8 @@ Complete a message status.
JSON parameters:
* `last_status` required, an integer containing the last status code
* `received_at` required, format ISO8601, when the message was received
* `last_status` **required**, an integer containing the last status code
* `received_at` **required**, format ISO8601, when the message was received
### `POST /statistics/calls`
<span class="badge badge-warning">Admin</span>
@ -810,10 +832,10 @@ Announce the beginning of a call.
JSON parameters:
* `id` required, string
* `from` required, string the initier of the call
* `to` required, string the destination of the call
* `initiated_at` required, string, format ISO8601, when the call was started
* `id` **required**, string
* `from` **required**, string the initier of the call
* `to` **required**, string the destination of the call
* `initiated_at` **required**, string, format ISO8601, when the call was started
* `ended_at` string, format ISO8601, when the call finished
* `conference_id` string
@ -836,7 +858,7 @@ Update a call when ending.
JSON parameters:
* `ended_at` required, string, format ISO8601, when the call finished
* `ended_at` **required**, string, format ISO8601, when the call finished
# Non-API Endpoints

View file

@ -0,0 +1,13 @@
<div>
@if (!isset($reverse) || !$reverse)
<input name="{{ $key }}" value="true" type="radio" @if ($object->$key) checked @endif>
@if (isset($reverse) && $reverse)<p>Disabled</p>@else<p>Enabled</p>@endif
@endif
<input name="{{ $key }}" value="false" type="radio" @if (!$object->$key) checked @endif>
@if (isset($reverse) && $reverse)<p>Enabled</p>@else<p>Disabled</p>@endif
<label>{{ $label }}</label>
@if (isset($reverse) && $reverse)
<input name="{{ $key }}" value="true" type="radio" @if ($object->$key) checked @endif>
@if (isset($reverse) && $reverse)<p>Disabled</p>@else<p>Enabled</p>@endif
@endif
</div>

View file

@ -23,6 +23,7 @@ use App\Account;
use App\AuthToken;
use App\Password;
use App\ProvisioningToken;
use App\SipDomain;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
@ -125,6 +126,27 @@ class AccountProvisioningTest extends TestCase
->assertSee('ha1');
}
public function testUiSectionProvisioning()
{
$secondDomain = SipDomain::factory()->create();
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->domain = $secondDomain->domain;
$password->account->save();
$this->keyAuthenticated($password->account)
->withHeaders([
'x-linphone-provisioning' => true,
])
->get($this->accountRoute)
->assertStatus(200)
->assertHeader('Content-Type', 'application/xml')
->assertSee('ha1')
->assertSee('disable_call_recordings_feature')
->assertSee('ui');
}
public function testAuthenticatedReProvisioning()
{
$password = Password::factory()->create();

View file

@ -76,7 +76,7 @@ class ApiSipDomainTest extends TestCase
$thirdDomain = 'third.domain';
$this->keyAuthenticated($admin)
$response = $this->keyAuthenticated($admin)
-> json('POST', $this->route, [
'domain' => $thirdDomain,
'super' => false
@ -95,9 +95,18 @@ class ApiSipDomainTest extends TestCase
->json('PUT', $this->route . '/' . $thirdDomain, [
'super' => true
])
->assertStatus(422);
$json = $response->json();
$json['super'] = true;
$json['hide_settings'] = true;
$this->keyAuthenticated($admin)
->json('PUT', $this->route . '/' . $thirdDomain, $json)
->assertJsonFragment([
'domain' => $thirdDomain,
'super' => true
'super' => true,
'hide_settings' => true
])
->assertStatus(200);