mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Fix FLEXIAPI-359 Add CardDav servers support in the spaces
This commit is contained in:
parent
9a9b8ab34e
commit
60df61d508
103 changed files with 2453 additions and 1137 deletions
|
|
@ -4,6 +4,7 @@ v2.1
|
||||||
----
|
----
|
||||||
- Fix FLEXIAPI-282 Migrate to Laravel 11 and PHP 8.2+
|
- Fix FLEXIAPI-282 Migrate to Laravel 11 and PHP 8.2+
|
||||||
- Fix FLEXIAPI-371 Add documentation for the Wizard page
|
- Fix FLEXIAPI-371 Add documentation for the Wizard page
|
||||||
|
- Fix FLEXIAPI-359 Add CardDav servers support in the spaces
|
||||||
|
|
||||||
v2.0
|
v2.0
|
||||||
----
|
----
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
|
||||||
use Awobaz\Compoships\Compoships;
|
use Awobaz\Compoships\Compoships;
|
||||||
|
|
@ -36,7 +37,7 @@ class Account extends Authenticatable
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
use Compoships;
|
use Compoships;
|
||||||
|
|
||||||
protected $with = ['passwords', 'emailChangeCode', 'types', 'actions', 'dictionaryEntries'];
|
protected $with = ['passwords', 'emailChangeCode', 'types', 'actions', 'dictionaryEntries', 'carddavServers'];
|
||||||
protected $hidden = ['expire_time', 'pivot', 'currentProvisioningToken', 'currentRecoveryCode', 'dictionaryEntries'];
|
protected $hidden = ['expire_time', 'pivot', 'currentProvisioningToken', 'currentRecoveryCode', 'dictionaryEntries'];
|
||||||
protected $appends = ['realm', 'provisioning_token', 'provisioning_token_expire_at', 'dictionary'];
|
protected $appends = ['realm', 'provisioning_token', 'provisioning_token_expire_at', 'dictionary'];
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
|
@ -149,6 +150,12 @@ class Account extends Authenticatable
|
||||||
return $this->hasMany(AccountDictionaryEntry::class);
|
return $this->hasMany(AccountDictionaryEntry::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function carddavServers()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(SpaceCardDavServer::class, 'account_carddav_credentials', 'account_id', 'space_carddav_server_id')
|
||||||
|
->withPivot('username', 'domain', 'algorithm', 'password');
|
||||||
|
}
|
||||||
|
|
||||||
public function getDictionaryAttribute()
|
public function getDictionaryAttribute()
|
||||||
{
|
{
|
||||||
if ($this->dictionaryEntries->isEmpty()) return new stdClass;
|
if ($this->dictionaryEntries->isEmpty()) return new stdClass;
|
||||||
|
|
@ -309,6 +316,15 @@ class Account extends Authenticatable
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRemainingCardDavCredentialsCreatableAttribute(): Collection
|
||||||
|
{
|
||||||
|
return $this->space->carddavServers()->whereNotIn('id', function ($query) {
|
||||||
|
$query->select('space_carddav_server_id')
|
||||||
|
->from('account_carddav_credentials')
|
||||||
|
->where('account_id', $this->id);
|
||||||
|
})->get();
|
||||||
|
}
|
||||||
|
|
||||||
public function getIdentifierAttribute(): string
|
public function getIdentifierAttribute(): string
|
||||||
{
|
{
|
||||||
return $this->attributes['username'] . '@' . $this->attributes['domain'];
|
return $this->attributes['username'] . '@' . $this->attributes['domain'];
|
||||||
|
|
|
||||||
20
flexiapi/app/AccountCardDavCredentials.php
Normal file
20
flexiapi/app/AccountCardDavCredentials.php
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class AccountCardDavCredentials extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'account_carddav_credentials';
|
||||||
|
|
||||||
|
public function cardDavServer()
|
||||||
|
{
|
||||||
|
return $this->hasOne(SpaceCardDavServer::class, 'id', 'space_carddav_server_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdentifierAttribute()
|
||||||
|
{
|
||||||
|
return $this->username . '@' . $this->domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,11 +28,9 @@ use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
|
||||||
use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
|
use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
$hostSpace = null;
|
|
||||||
|
|
||||||
function space(): ?Space
|
function space(): ?Space
|
||||||
{
|
{
|
||||||
return request()->space;
|
return is_object(request()->space) ? request()->space :null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function passwordAlgorithms(): array
|
function passwordAlgorithms(): array
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,44 @@ class ProvisioningController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$remoteContactDirectoryCounter = 0;
|
||||||
|
$authInfoIndex = 0;
|
||||||
|
|
||||||
|
// CardDav servers
|
||||||
|
|
||||||
|
if ($request->space?->carddavServers) {
|
||||||
|
foreach ($request->space->carddavServers as $carddavServer) {
|
||||||
|
$carddavServer->getProvisioningSection($config, $remoteContactDirectoryCounter);
|
||||||
|
$remoteContactDirectoryCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($account) {
|
||||||
|
foreach ($account->carddavServers as $carddavServer) {
|
||||||
|
$section = $dom->createElement('section');
|
||||||
|
$section->setAttribute('name', 'auth_info_' . $authInfoIndex);
|
||||||
|
$config->appendChild($section);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $carddavServer->pivot->username);
|
||||||
|
$entry->setAttribute('name', 'username');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $carddavServer->pivot->domain);
|
||||||
|
$entry->setAttribute('name', 'domain');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $carddavServer->pivot->password);
|
||||||
|
$entry->setAttribute('name', 'ha1');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $carddavServer->pivot->algorithm);
|
||||||
|
$entry->setAttribute('name', 'algorithm');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$authInfoIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Password reset
|
// Password reset
|
||||||
if ($account && $request->has('reset_password')) {
|
if ($account && $request->has('reset_password')) {
|
||||||
$account->updatePassword(Str::random(10));
|
$account->updatePassword(Str::random(10));
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -26,7 +26,7 @@ use Illuminate\Support\Facades\Log;
|
||||||
use App\Account;
|
use App\Account;
|
||||||
use App\AccountType;
|
use App\AccountType;
|
||||||
|
|
||||||
class AccountAccountTypeController extends Controller
|
class AccountTypeController extends Controller
|
||||||
{
|
{
|
||||||
public function create(int $id)
|
public function create(int $id)
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -27,7 +27,7 @@ use App\Account;
|
||||||
use App\AccountAction;
|
use App\AccountAction;
|
||||||
use App\Rules\NoUppercase;
|
use App\Rules\NoUppercase;
|
||||||
|
|
||||||
class AccountActionController extends Controller
|
class ActionController extends Controller
|
||||||
{
|
{
|
||||||
public function create(int $accountId)
|
public function create(int $accountId)
|
||||||
{
|
{
|
||||||
|
|
@ -17,13 +17,13 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
use App\Account;
|
use App\Account;
|
||||||
|
|
||||||
class AccountActivityController extends Controller
|
class ActivityController extends Controller
|
||||||
{
|
{
|
||||||
public function index(int $accountId)
|
public function index(int $accountId)
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?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\Account;
|
||||||
|
|
||||||
|
use App\Account;
|
||||||
|
use App\AccountCardDavCredentials;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Database\Query\Builder;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use App\Http\Requests\Account\CardDavCredentials;
|
||||||
|
|
||||||
|
class CardDavCredentialsController extends Controller
|
||||||
|
{
|
||||||
|
public function create(int $accountId)
|
||||||
|
{
|
||||||
|
$account = Account::findOrFail($accountId);
|
||||||
|
$this->checkFeatureEnabled($account);
|
||||||
|
|
||||||
|
return view('admin.account.carddav.create', [
|
||||||
|
'account' => $account,
|
||||||
|
'carddavServers' => $account->remainingCardDavCredentialsCreatable
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CardDavCredentials $request, int $accountId)
|
||||||
|
{
|
||||||
|
$account = Account::findOrFail($accountId);
|
||||||
|
$this->checkFeatureEnabled($account);
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'carddav_id' => ['required', Rule::exists('space_carddav_servers', 'id')->where(function (Builder $query) use ($account) {
|
||||||
|
return $query->where('space_id', $account->space->id);
|
||||||
|
})]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$accountCarddavCredentials = new AccountCardDavCredentials;
|
||||||
|
$accountCarddavCredentials->space_carddav_server_id = $request->get('carddav_id');
|
||||||
|
$accountCarddavCredentials->account_id = $account->id;
|
||||||
|
$accountCarddavCredentials->username = $request->get('username');
|
||||||
|
$accountCarddavCredentials->domain = $request->get('domain');
|
||||||
|
$accountCarddavCredentials->password = bchash(
|
||||||
|
$request->get('username'),
|
||||||
|
$request->get('domain'),
|
||||||
|
$request->get('password'),
|
||||||
|
$request->get('algorithm')
|
||||||
|
);
|
||||||
|
$accountCarddavCredentials->algorithm = $request->get('algorithm');
|
||||||
|
$accountCarddavCredentials->save();
|
||||||
|
|
||||||
|
return redirect()->route('admin.account.show', $account);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(int $accountId, int $cardDavId)
|
||||||
|
{
|
||||||
|
$account = Account::findOrFail($accountId);
|
||||||
|
$this->checkFeatureEnabled($account);
|
||||||
|
|
||||||
|
$accountCarddavCredentials = AccountCardDavCredentials::where('space_carddav_server_id', $cardDavId)
|
||||||
|
->where('account_id', $account->id)
|
||||||
|
->firstOrFail();
|
||||||
|
|
||||||
|
return view('admin.account.carddav.delete', [
|
||||||
|
'account' => $account,
|
||||||
|
'carddavCredentials' => $accountCarddavCredentials,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Request $request, int $accountId)
|
||||||
|
{
|
||||||
|
$account = Account::findOrFail($accountId);
|
||||||
|
$this->checkFeatureEnabled($account);
|
||||||
|
|
||||||
|
$accountCarddavCredentials = AccountCardDavCredentials::where('space_carddav_server_id', $request->carddav_id)
|
||||||
|
->where('account_id', $account->id)
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
return redirect()->route('admin.account.show', $account);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkFeatureEnabled(Account $account)
|
||||||
|
{
|
||||||
|
if (!$account->space->carddav_user_credentials) {
|
||||||
|
abort(403, 'CardDav Credentials features disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -26,7 +26,7 @@ use Illuminate\Support\Facades\Log;
|
||||||
use App\Account;
|
use App\Account;
|
||||||
use App\ContactsList;
|
use App\ContactsList;
|
||||||
|
|
||||||
class AccountContactController extends Controller
|
class ContactController extends Controller
|
||||||
{
|
{
|
||||||
public function index(int $accountId)
|
public function index(int $accountId)
|
||||||
{
|
{
|
||||||
|
|
@ -17,14 +17,14 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Account;
|
use App\Account;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Libraries\FlexisipRedisConnector;
|
use App\Libraries\FlexisipRedisConnector;
|
||||||
|
|
||||||
class AccountDeviceController extends Controller
|
class DeviceController extends Controller
|
||||||
{
|
{
|
||||||
public function index(int $accountId)
|
public function index(int $accountId)
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -25,7 +25,7 @@ use Illuminate\Http\Request;
|
||||||
use App\Account;
|
use App\Account;
|
||||||
use App\AccountDictionaryEntry;
|
use App\AccountDictionaryEntry;
|
||||||
|
|
||||||
class AccountDictionaryController extends Controller
|
class DictionaryController extends Controller
|
||||||
{
|
{
|
||||||
public function create(int $accountId)
|
public function create(int $accountId)
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Account;
|
use App\Account;
|
||||||
use App\ExternalAccount;
|
use App\ExternalAccount;
|
||||||
|
|
@ -31,7 +31,7 @@ use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Validation\Rules\File;
|
use Illuminate\Validation\Rules\File;
|
||||||
use Propaganistas\LaravelPhone\PhoneNumber;
|
use Propaganistas\LaravelPhone\PhoneNumber;
|
||||||
|
|
||||||
class AccountImportController extends Controller
|
class ImportController extends Controller
|
||||||
{
|
{
|
||||||
private Collection $errors;
|
private Collection $errors;
|
||||||
private string $importDirectory = 'imported_csv';
|
private string $importDirectory = 'imported_csv';
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Account;
|
use App\Account;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
|
@ -26,7 +26,7 @@ use App\StatisticsCall;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class AccountStatisticsController extends Controller
|
class StatisticsController extends Controller
|
||||||
{
|
{
|
||||||
public function edit(Request $request, int $accountId)
|
public function edit(Request $request, int $accountId)
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Admin;
|
namespace App\Http\Controllers\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -27,7 +27,7 @@ use Illuminate\Validation\Rule;
|
||||||
use App\AccountType;
|
use App\AccountType;
|
||||||
use App\Rules\NoUppercase;
|
use App\Rules\NoUppercase;
|
||||||
|
|
||||||
class AccountTypeController extends Controller
|
class TypeController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin\Space;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Space\CardDavServer;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use App\Space;
|
||||||
|
use App\SpaceCardDavServer;
|
||||||
|
|
||||||
|
class CardDavServerController extends Controller
|
||||||
|
{
|
||||||
|
public function create(Space $space)
|
||||||
|
{
|
||||||
|
return view('admin.space.carddav_server.create_edit', [
|
||||||
|
'space' => $space,
|
||||||
|
'carddavServer' => new SpaceCardDavServer
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CardDavServer $request)
|
||||||
|
{
|
||||||
|
$carddavServer = new SpaceCardDavServer;
|
||||||
|
$carddavServer->space_id = $request->space->id;
|
||||||
|
$carddavServer->fill($request->validated());
|
||||||
|
$carddavServer->enabled = getRequestBoolean($request, 'enabled');
|
||||||
|
$carddavServer->use_exact_match_policy = getRequestBoolean($request, 'use_exact_match_policy');
|
||||||
|
$carddavServer->save();
|
||||||
|
|
||||||
|
return redirect()->route('admin.spaces.integration', $request->space);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit(Space $space, int $carddavServerId)
|
||||||
|
{
|
||||||
|
return view('admin.space.carddav_server.create_edit', [
|
||||||
|
'space' => $space,
|
||||||
|
'carddavServer' => $space->carddavServers()->findOrFail($carddavServerId)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(CardDavServer $request, Space $space, int $carddavServerId)
|
||||||
|
{
|
||||||
|
$carddavServer = $space->carddavServers()->findOrFail($carddavServerId);
|
||||||
|
$carddavServer->fill($request->validated());
|
||||||
|
$carddavServer->enabled = getRequestBoolean($request, 'enabled');
|
||||||
|
$carddavServer->use_exact_match_policy = getRequestBoolean($request, 'use_exact_match_policy');
|
||||||
|
$carddavServer->save();
|
||||||
|
|
||||||
|
return redirect()->route('admin.spaces.integration', $request->space);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Space $space, int $carddavServerId)
|
||||||
|
{
|
||||||
|
return view('admin.space.carddav_server.delete', [
|
||||||
|
'space' => $space,
|
||||||
|
'carddavServer' => $space->carddavServers()->findOrFail($carddavServerId)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Space $space, int $carddavServerId)
|
||||||
|
{
|
||||||
|
$carddavServer = $space->carddavServers()->findOrFail($carddavServerId);
|
||||||
|
$carddavServer->delete();
|
||||||
|
|
||||||
|
return redirect()->route('admin.spaces.integration', $space->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -146,6 +146,7 @@ class SpaceController extends Controller
|
||||||
$space->expire_at = $request->get('expire_at');
|
$space->expire_at = $request->get('expire_at');
|
||||||
$space->custom_theme = getRequestBoolean($request, 'custom_theme');
|
$space->custom_theme = getRequestBoolean($request, 'custom_theme');
|
||||||
$space->web_panel = getRequestBoolean($request, 'web_panel');
|
$space->web_panel = getRequestBoolean($request, 'web_panel');
|
||||||
|
$space->carddav_user_credentials = getRequestBoolean($request, 'carddav_user_credentials');
|
||||||
$space->save();
|
$space->save();
|
||||||
|
|
||||||
return redirect()->route('admin.spaces.show', $space);
|
return redirect()->route('admin.spaces.show', $space);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\Admin;
|
namespace App\Http\Controllers\Api\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -26,7 +26,7 @@ use App\Account;
|
||||||
use App\AccountAction;
|
use App\AccountAction;
|
||||||
use App\Rules\NoUppercase;
|
use App\Rules\NoUppercase;
|
||||||
|
|
||||||
class AccountActionController extends Controller
|
class ActionController extends Controller
|
||||||
{
|
{
|
||||||
public function index(int $id)
|
public function index(int $id)
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\Admin\Account;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use App\Account;
|
||||||
|
use App\Space;
|
||||||
|
use App\AccountCardDavCredentials;
|
||||||
|
use App\SpaceCardDavServer;
|
||||||
|
use App\Http\Requests\Account\CardDavCredentials;
|
||||||
|
|
||||||
|
class CardDavCredentialsController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request, int $accountId)
|
||||||
|
{
|
||||||
|
$account = $request->space->accounts()->findOrFail($accountId);
|
||||||
|
$cardDavServers = $account->carddavServers;
|
||||||
|
|
||||||
|
if ($cardDavServers->isEmpty()) return new \stdClass;
|
||||||
|
|
||||||
|
return $cardDavServers->map(function ($cardDavServer) {
|
||||||
|
return $this->extractCardDavServer($cardDavServer);
|
||||||
|
})->keyBy('carddav_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Request $request, int $accountId, int $cardDavServerId)
|
||||||
|
{
|
||||||
|
$account = $request->space->accounts()->findOrFail($accountId);
|
||||||
|
$cardDavServer = $account->cardDavServers()->findOrFail($cardDavServerId);
|
||||||
|
|
||||||
|
return $this->extractCardDavServer($cardDavServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(CardDavCredentials $request, int $accountId, int $cardDavServerId)
|
||||||
|
{
|
||||||
|
$account = $request->space->accounts()->findOrFail($accountId);
|
||||||
|
$cardDavServer = $request->space->cardDavServers()->findOrFail($cardDavServerId);
|
||||||
|
|
||||||
|
$accountCarddavCredentials = AccountCardDavCredentials::where('account_id', $account->id)
|
||||||
|
->where('space_carddav_server_id', $cardDavServer->id)
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
$accountCarddavCredentials = new AccountCardDavCredentials;
|
||||||
|
$accountCarddavCredentials->space_carddav_server_id = $cardDavServer->id;
|
||||||
|
$accountCarddavCredentials->account_id = $account->id;
|
||||||
|
$accountCarddavCredentials->username = $request->get('username');
|
||||||
|
$accountCarddavCredentials->domain = $request->get('domain');
|
||||||
|
$accountCarddavCredentials->password = bchash(
|
||||||
|
$request->get('username'),
|
||||||
|
$request->get('domain'),
|
||||||
|
$request->get('password'),
|
||||||
|
$request->get('algorithm')
|
||||||
|
);
|
||||||
|
$accountCarddavCredentials->algorithm = $request->get('algorithm');
|
||||||
|
return $accountCarddavCredentials->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Request $request, int $accountId, int $cardDavServerId)
|
||||||
|
{
|
||||||
|
$account = $request->space->accounts()->findOrFail($accountId);
|
||||||
|
$cardDavServer = $account->cardDavServers()->findOrFail($cardDavServerId);
|
||||||
|
|
||||||
|
return $cardDavServer->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractCardDavServer(SpaceCardDavServer $cardDavServer)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'carddav_id' => $cardDavServer->id,
|
||||||
|
'username' => $cardDavServer->pivot->username,
|
||||||
|
'domain' => $cardDavServer->pivot->domain,
|
||||||
|
'algorithm' => $cardDavServer->pivot->algorithm,
|
||||||
|
'password' => $cardDavServer->pivot->password,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,13 +17,13 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\Admin;
|
namespace App\Http\Controllers\Api\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
use App\Account;
|
use App\Account;
|
||||||
|
|
||||||
class AccountContactController extends Controller
|
class ContactController extends Controller
|
||||||
{
|
{
|
||||||
public function index(int $id)
|
public function index(int $id)
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\Admin;
|
namespace App\Http\Controllers\Api\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -26,7 +26,7 @@ use Illuminate\Support\Str;
|
||||||
use App\AccountCreationToken;
|
use App\AccountCreationToken;
|
||||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||||
|
|
||||||
class AccountCreationTokenController extends Controller
|
class CreationTokenController extends Controller
|
||||||
{
|
{
|
||||||
public function create(Request $request)
|
public function create(Request $request)
|
||||||
{
|
{
|
||||||
|
|
@ -17,14 +17,14 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\Admin;
|
namespace App\Http\Controllers\Api\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Account;
|
use App\Account;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class AccountDictionaryController extends Controller
|
class DictionaryController extends Controller
|
||||||
{
|
{
|
||||||
public function index(int $accountId)
|
public function index(int $accountId)
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\Admin;
|
namespace App\Http\Controllers\Api\Admin\Account;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Rules\NoUppercase;
|
use App\Rules\NoUppercase;
|
||||||
|
|
@ -25,7 +25,7 @@ use Illuminate\Http\Request;
|
||||||
|
|
||||||
use App\AccountType;
|
use App\AccountType;
|
||||||
|
|
||||||
class AccountTypeController extends Controller
|
class TypeController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\Admin\Space;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Space\CardDavServer;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use App\Space;
|
||||||
|
use App\SpaceCardDavServer;
|
||||||
|
|
||||||
|
class CardDavServerController extends Controller
|
||||||
|
{
|
||||||
|
public function index(string $host)
|
||||||
|
{
|
||||||
|
return Space::where('host', $host)->firstOrFail()->carddavServers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(string $host, int $carddavServerId)
|
||||||
|
{
|
||||||
|
return Space::where('host', $host)->firstOrFail()->carddavServers()->findOrFail($carddavServerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(CardDavServer $request, string $host)
|
||||||
|
{
|
||||||
|
$space = Space::where('host', $host)->firstOrFail();
|
||||||
|
|
||||||
|
$carddavServer = new SpaceCardDavServer;
|
||||||
|
$carddavServer->space_id = $space->id;
|
||||||
|
$carddavServer->fill($request->validated());
|
||||||
|
$carddavServer->enabled = $request->has('enabled') && (bool)$request->get('enabled');
|
||||||
|
$carddavServer->use_exact_match_policy = $request->has('use_exact_match_policy') && (bool)$request->get('use_exact_match_policy');
|
||||||
|
|
||||||
|
return $carddavServer->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(CardDavServer $request, string $host, int $carddavServerId)
|
||||||
|
{
|
||||||
|
$space = Space::where('host', $host)->firstOrFail();
|
||||||
|
|
||||||
|
$carddavServer = $space->carddavServers()->findOrFail($carddavServerId);
|
||||||
|
$carddavServer->fill($request->validated());
|
||||||
|
$carddavServer->enabled = $request->has('enabled') && (bool)$request->get('enabled');
|
||||||
|
$carddavServer->use_exact_match_policy = $request->has('use_exact_match_policy') && (bool)$request->get('use_exact_match_policy');
|
||||||
|
|
||||||
|
return $carddavServer->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(string $host, int $carddavServerId)
|
||||||
|
{
|
||||||
|
$space = Space::where('host', $host)->firstOrFail();
|
||||||
|
|
||||||
|
$carddavServer = $space->carddavServers()->findOrFail($carddavServerId);
|
||||||
|
return $carddavServer->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api\Admin;
|
namespace App\Http\Controllers\Api\Admin\Space;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\EmailServer\CreateUpdate;
|
use App\Http\Requests\EmailServer\CreateUpdate;
|
||||||
|
|
@ -45,38 +45,37 @@ class SpaceController extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$space = new Space;
|
$space = new Space;
|
||||||
$space->name = $request->get('name');
|
|
||||||
$space->domain = $request->get('domain');
|
|
||||||
$space->host = $request->get('host');
|
|
||||||
$this->setRequestBoolean($request, $space, 'super');
|
|
||||||
$this->setRequestBoolean($request, $space, 'disable_chat_feature');
|
|
||||||
$this->setRequestBoolean($request, $space, 'disable_meetings_feature');
|
|
||||||
$this->setRequestBoolean($request, $space, 'disable_broadcast_feature');
|
|
||||||
$this->setRequestBoolean($request, $space, 'hide_settings');
|
|
||||||
$this->setRequestBoolean($request, $space, 'hide_account_settings');
|
|
||||||
$this->setRequestBoolean($request, $space, 'disable_call_recordings_feature');
|
|
||||||
$this->setRequestBoolean($request, $space, 'only_display_sip_uri_username');
|
|
||||||
$this->setRequestBoolean($request, $space, 'assistant_hide_create_account');
|
|
||||||
$this->setRequestBoolean($request, $space, 'assistant_disable_qr_code');
|
|
||||||
$this->setRequestBoolean($request, $space, 'assistant_hide_third_party_account');
|
|
||||||
$space->max_account = $request->get('max_account', 0);
|
|
||||||
$space->max_accounts = $request->get('max_accounts', 0);
|
|
||||||
$space->expire_at = $request->get('expire_at');
|
|
||||||
|
|
||||||
$space->copyright_text = $request->get('copyright_text');
|
|
||||||
$space->intro_registration_text = $request->get('intro_registration_text');
|
|
||||||
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
|
||||||
$space->account_proxy_registrar_address = $request->get('account_proxy_registrar_address');
|
$space->account_proxy_registrar_address = $request->get('account_proxy_registrar_address');
|
||||||
$space->account_realm = $request->get('account_realm');
|
$space->account_realm = $request->get('account_realm');
|
||||||
|
$space->copyright_text = $request->get('copyright_text');
|
||||||
$space->custom_provisioning_entries = $request->get('custom_provisioning_entries');
|
$space->custom_provisioning_entries = $request->get('custom_provisioning_entries');
|
||||||
|
$space->domain = $request->get('domain');
|
||||||
|
$space->expire_at = $request->get('expire_at');
|
||||||
|
$space->host = $request->get('host');
|
||||||
|
$space->intro_registration_text = $request->get('intro_registration_text');
|
||||||
|
$space->max_account = $request->get('max_account', 0);
|
||||||
|
$space->max_accounts = $request->get('max_accounts', 0);
|
||||||
|
$space->name = $request->get('name');
|
||||||
|
$space->newsletter_registration_address = $request->get('newsletter_registration_address');
|
||||||
|
$this->setRequestBoolean($request, $space, 'assistant_disable_qr_code');
|
||||||
|
$this->setRequestBoolean($request, $space, 'assistant_hide_create_account');
|
||||||
|
$this->setRequestBoolean($request, $space, 'assistant_hide_third_party_account');
|
||||||
|
$this->setRequestBoolean($request, $space, 'carddav_user_credentials');
|
||||||
$this->setRequestBoolean($request, $space, 'custom_provisioning_overwrite_all');
|
$this->setRequestBoolean($request, $space, 'custom_provisioning_overwrite_all');
|
||||||
$this->setRequestBoolean($request, $space, 'provisioning_use_linphone_provisioning_header');
|
|
||||||
$this->setRequestBoolean($request, $space, 'custom_theme');
|
$this->setRequestBoolean($request, $space, 'custom_theme');
|
||||||
$this->setRequestBoolean($request, $space, 'web_panel');
|
$this->setRequestBoolean($request, $space, 'disable_broadcast_feature');
|
||||||
$this->setRequestBoolean($request, $space, 'public_registration');
|
$this->setRequestBoolean($request, $space, 'disable_call_recordings_feature');
|
||||||
$this->setRequestBoolean($request, $space, 'phone_registration');
|
$this->setRequestBoolean($request, $space, 'disable_chat_feature');
|
||||||
|
$this->setRequestBoolean($request, $space, 'disable_meetings_feature');
|
||||||
|
$this->setRequestBoolean($request, $space, 'hide_account_settings');
|
||||||
|
$this->setRequestBoolean($request, $space, 'hide_settings');
|
||||||
$this->setRequestBoolean($request, $space, 'intercom_features');
|
$this->setRequestBoolean($request, $space, 'intercom_features');
|
||||||
|
$this->setRequestBoolean($request, $space, 'only_display_sip_uri_username');
|
||||||
|
$this->setRequestBoolean($request, $space, 'phone_registration');
|
||||||
|
$this->setRequestBoolean($request, $space, 'provisioning_use_linphone_provisioning_header');
|
||||||
|
$this->setRequestBoolean($request, $space, 'public_registration');
|
||||||
|
$this->setRequestBoolean($request, $space, 'super');
|
||||||
|
$this->setRequestBoolean($request, $space, 'web_panel');
|
||||||
$space->save();
|
$space->save();
|
||||||
|
|
||||||
return $space->refresh();
|
return $space->refresh();
|
||||||
|
|
@ -90,30 +89,30 @@ class SpaceController extends Controller
|
||||||
public function update(Request $request, string $domain)
|
public function update(Request $request, string $domain)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$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',
|
|
||||||
'max_accounts' => 'required|integer',
|
|
||||||
'expire_at' => 'nullable|date|after_or_equal:today',
|
|
||||||
'account_realm' => ['nullable', new Domain()],
|
'account_realm' => ['nullable', new Domain()],
|
||||||
|
'assistant_disable_qr_code' => 'required|boolean',
|
||||||
|
'assistant_hide_create_account' => 'required|boolean',
|
||||||
|
'assistant_hide_third_party_account' => 'required|boolean',
|
||||||
|
'carddav_user_credentials' => 'required|boolean',
|
||||||
'custom_provisioning_entries' => ['nullable', new Ini(Space::FORBIDDEN_KEYS)],
|
'custom_provisioning_entries' => ['nullable', new Ini(Space::FORBIDDEN_KEYS)],
|
||||||
'custom_provisioning_overwrite_all' => 'required|boolean',
|
'custom_provisioning_overwrite_all' => 'required|boolean',
|
||||||
'provisioning_use_linphone_provisioning_header' => 'required|boolean',
|
|
||||||
'custom_theme' => 'required|boolean',
|
'custom_theme' => 'required|boolean',
|
||||||
'web_panel' => 'required|boolean',
|
'disable_broadcast_feature' => 'required|boolean',
|
||||||
'public_registration' => 'required|boolean',
|
'disable_call_recordings_feature' => 'required|boolean',
|
||||||
'phone_registration' => 'required|boolean',
|
'disable_chat_feature' => 'required|boolean',
|
||||||
|
'disable_meetings_feature' => 'required|boolean',
|
||||||
|
'expire_at' => 'nullable|date|after_or_equal:today',
|
||||||
|
'hide_account_settings' => 'required|boolean',
|
||||||
|
'hide_settings' => 'required|boolean',
|
||||||
'intercom_features' => 'required|boolean',
|
'intercom_features' => 'required|boolean',
|
||||||
|
'max_account' => 'required|integer',
|
||||||
|
'max_accounts' => 'required|integer',
|
||||||
|
'only_display_sip_uri_username' => 'required|boolean',
|
||||||
|
'phone_registration' => 'required|boolean',
|
||||||
|
'provisioning_use_linphone_provisioning_header' => 'required|boolean',
|
||||||
|
'public_registration' => 'required|boolean',
|
||||||
|
'super' => 'required|boolean',
|
||||||
|
'web_panel' => 'required|boolean',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$space = Space::where('domain', $domain)->firstOrFail();
|
$space = Space::where('domain', $domain)->firstOrFail();
|
||||||
|
|
|
||||||
|
|
@ -72,30 +72,31 @@ class Kernel extends HttpKernel
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $middlewareAliases = [
|
protected $middlewareAliases = [
|
||||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
|
||||||
'auth.admin' => \App\Http\Middleware\AuthenticateAdmin::class,
|
'auth.admin' => \App\Http\Middleware\AuthenticateAdmin::class,
|
||||||
'auth.super_admin' => \App\Http\Middleware\AuthenticateSuperAdmin::class,
|
|
||||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||||
|
'auth.check_blocked' => \App\Http\Middleware\CheckBlocked::class,
|
||||||
'auth.digest_or_key' => \App\Http\Middleware\AuthenticateDigestOrKey::class,
|
'auth.digest_or_key' => \App\Http\Middleware\AuthenticateDigestOrKey::class,
|
||||||
'auth.jwt' => \App\Http\Middleware\AuthenticateJWT::class,
|
'auth.jwt' => \App\Http\Middleware\AuthenticateJWT::class,
|
||||||
'auth.check_blocked' => \App\Http\Middleware\CheckBlocked::class,
|
'auth.super_admin' => \App\Http\Middleware\AuthenticateSuperAdmin::class,
|
||||||
'validate_json' => \App\Http\Middleware\ValidateJSON::class,
|
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||||
'web_panel_enabled' => \App\Http\Middleware\IsWebPanelEnabled::class,
|
|
||||||
'public_registration' => \App\Http\Middleware\IsPublicRegistration::class,
|
|
||||||
'phone_registration' => \App\Http\Middleware\IsPhoneRegistration::class,
|
|
||||||
'intercom_features' => \App\Http\Middleware\IsIntercomFeatures::class,
|
|
||||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||||
'cookie' => \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
|
||||||
'cookie.encrypt' => \App\Http\Middleware\EncryptCookies::class,
|
'cookie.encrypt' => \App\Http\Middleware\EncryptCookies::class,
|
||||||
|
'cookie' => \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||||
|
'feature.carddav_user_credentials' => \App\Http\Middleware\IsCardDavCredentialsEnabled::class,
|
||||||
|
'feature.intercom' => \App\Http\Middleware\IsIntercomFeatures::class,
|
||||||
|
'feature.phone_registration' => \App\Http\Middleware\IsPhoneRegistration::class,
|
||||||
|
'feature.public_registration' => \App\Http\Middleware\IsPublicRegistration::class,
|
||||||
|
'feature.web_panel_enabled' => \App\Http\Middleware\IsWebPanelEnabled::class,
|
||||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||||
|
'localization' => \App\Http\Middleware\Localization::class,
|
||||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||||
'space.check' => \App\Http\Middleware\SpaceCheck::class,
|
'space.check' => \App\Http\Middleware\SpaceCheck::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
|
'validate_json' => \App\Http\Middleware\ValidateJSON::class,
|
||||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||||
'localization' => \App\Http\Middleware\Localization::class,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class AuthenticateAdmin
|
||||||
return redirect()->route('account.login');
|
return redirect()->route('account.login');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$request->user()->admin) {
|
if (!$request->user()->admin || $request->user()->domain != $request->space->domain) {
|
||||||
return abort(403, 'Unauthorized area');
|
return abort(403, 'Unauthorized area');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
19
flexiapi/app/Http/Middleware/IsCardDavCredentialsEnabled.php
Normal file
19
flexiapi/app/Http/Middleware/IsCardDavCredentialsEnabled.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class IsCardDavCredentialsEnabled
|
||||||
|
{
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if ($request->space->carddav_user_credentials) {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return abort(403, 'CardDav Credentials features disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
39
flexiapi/app/Http/Requests/Account/CardDavCredentials.php
Normal file
39
flexiapi/app/Http/Requests/Account/CardDavCredentials.php
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?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\Requests\Account;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
use App\Rules\Domain;
|
||||||
|
use App\Rules\PasswordAlgorithm;
|
||||||
|
|
||||||
|
class CardDavCredentials extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'username' => 'required|min:3',
|
||||||
|
'password' => 'required',
|
||||||
|
'algorithm' => ['required', new PasswordAlgorithm],
|
||||||
|
'domain' => ['required', new Domain],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
42
flexiapi/app/Http/Requests/Space/CardDavServer.php
Normal file
42
flexiapi/app/Http/Requests/Space/CardDavServer.php
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?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\Requests\Space;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
use App\EmailServer;
|
||||||
|
use App\Rules\CommaList;
|
||||||
|
|
||||||
|
class CardDavServer extends FormRequest
|
||||||
|
{
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'uri' => 'required|url',
|
||||||
|
'min_characters' => 'integer|min:1',
|
||||||
|
'results_limit' => 'integer|min:0',
|
||||||
|
'timeout' => 'integer|min:1',
|
||||||
|
'delay' => 'integer|min:100',
|
||||||
|
'fields_for_user_input' => [new CommaList],
|
||||||
|
'fields_for_domain' => [new CommaList],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
21
flexiapi/app/Rules/CommaList.php
Normal file
21
flexiapi/app/Rules/CommaList.php
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Rules;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\Rule;
|
||||||
|
use Respect\Validation\Validator;
|
||||||
|
|
||||||
|
class CommaList implements Rule
|
||||||
|
{
|
||||||
|
public function passes($attribute, $value)
|
||||||
|
{
|
||||||
|
preg_match('/^(\w+),(\w)*/', $value, $matches);
|
||||||
|
|
||||||
|
return $value == null || (!empty($matches) && $matches[0] == $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function message()
|
||||||
|
{
|
||||||
|
return 'The :attribute should be null or contain a list of words separated by commas';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,11 +23,6 @@ use Illuminate\Contracts\Validation\Rule;
|
||||||
|
|
||||||
class WithoutSpaces implements Rule
|
class WithoutSpaces implements Rule
|
||||||
{
|
{
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
public function passes($attribute, $value)
|
public function passes($attribute, $value)
|
||||||
{
|
{
|
||||||
return preg_match('/^\S*$/u', $value);
|
return preg_match('/^\S*$/u', $value);
|
||||||
|
|
|
||||||
|
|
@ -21,52 +21,67 @@ namespace App;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class Space extends Model
|
class Space extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $with = ['emailServer'];
|
protected $with = ['emailServer', 'carddavServers'];
|
||||||
|
|
||||||
public const FORBIDDEN_KEYS = [
|
public const FORBIDDEN_KEYS = [
|
||||||
'disable_chat_feature',
|
'account_proxy_registrar_address',
|
||||||
'disable_meetings_feature',
|
'account_realm',
|
||||||
'disable_broadcast_feature',
|
|
||||||
'max_account',
|
|
||||||
'hide_settings',
|
|
||||||
'hide_account_settings',
|
|
||||||
'disable_call_recordings_feature',
|
|
||||||
'only_display_sip_uri_username',
|
|
||||||
'assistant_hide_create_account',
|
|
||||||
'assistant_disable_qr_code',
|
'assistant_disable_qr_code',
|
||||||
|
'assistant_hide_create_account',
|
||||||
'assistant_hide_third_party_account',
|
'assistant_hide_third_party_account',
|
||||||
'copyright_text',
|
'copyright_text',
|
||||||
|
'disable_broadcast_feature',
|
||||||
|
'disable_call_recordings_feature',
|
||||||
|
'disable_chat_feature',
|
||||||
|
'disable_meetings_feature',
|
||||||
|
'hide_account_settings',
|
||||||
|
'hide_settings',
|
||||||
'intro_registration_text',
|
'intro_registration_text',
|
||||||
|
'max_account',
|
||||||
'newsletter_registration_address',
|
'newsletter_registration_address',
|
||||||
'account_proxy_registrar_address',
|
'only_display_sip_uri_username',
|
||||||
'account_realm'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = ['id'];
|
protected $hidden = ['id'];
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'super' => 'boolean',
|
'assistant_disable_qr_code' => 'boolean',
|
||||||
|
'assistant_hide_create_account' => 'boolean',
|
||||||
|
'assistant_hide_third_party_account' => 'boolean',
|
||||||
|
'carddav_user_credentials' => 'boolean',
|
||||||
|
'disable_broadcast_feature' => 'boolean',
|
||||||
|
'disable_call_recordings_feature' => 'boolean',
|
||||||
'disable_chat_feature' => 'boolean',
|
'disable_chat_feature' => 'boolean',
|
||||||
'disable_meetings_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',
|
|
||||||
'expire_at' => 'date',
|
'expire_at' => 'date',
|
||||||
|
'hide_account_settings' => 'boolean',
|
||||||
|
'hide_settings' => 'boolean',
|
||||||
|
'only_display_sip_uri_username' => 'boolean',
|
||||||
|
'super' => 'boolean',
|
||||||
];
|
];
|
||||||
|
|
||||||
public const HOST_REGEX = '[\w\-]+';
|
public const HOST_REGEX = '[\w\-]+';
|
||||||
public const DOMAIN_REGEX = '(?=^.{4,253}$)(^((?!-)[a-z0-9-]{1,63}(?<!-)\.)+[a-z]{2,63}$)';
|
public const DOMAIN_REGEX = '(?=^.{4,253}$)(^((?!-)[a-z0-9-]{1,63}(?<!-)\.)+[a-z]{2,63}$)';
|
||||||
|
|
||||||
|
protected static function booted()
|
||||||
|
{
|
||||||
|
static::addGlobalScope('domain', function (Builder $builder) {
|
||||||
|
if (!Auth::hasUser()) return;
|
||||||
|
|
||||||
|
if (Auth::hasUser() || Auth::user()->superAdmin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder->where('domain', Auth::user()->domain);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public function accounts()
|
public function accounts()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Account::class, 'domain', 'domain');
|
return $this->hasMany(Account::class, 'domain', 'domain');
|
||||||
|
|
@ -82,6 +97,11 @@ class Space extends Model
|
||||||
return $this->hasOne(SpaceEmailServer::class);
|
return $this->hasOne(SpaceEmailServer::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function carddavServers()
|
||||||
|
{
|
||||||
|
return $this->hasMany(SpaceCardDavServer::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function scopeNotFull(Builder $query)
|
public function scopeNotFull(Builder $query)
|
||||||
{
|
{
|
||||||
return $query->where('max_accounts', 0)
|
return $query->where('max_accounts', 0)
|
||||||
|
|
|
||||||
82
flexiapi/app/SpaceCardDavServer.php
Normal file
82
flexiapi/app/SpaceCardDavServer.php
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class SpaceCardDavServer extends Model
|
||||||
|
{
|
||||||
|
protected $hidden = ['space_id'];
|
||||||
|
protected $table = 'space_carddav_servers';
|
||||||
|
protected $fillable = ['uri', 'enabled', 'min_characters', 'results_limist', 'use_exact_match_policy', 'timeout', 'delay', 'fields_for_user_input', 'fields_for_domain'];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'enabled' => 'boolean',
|
||||||
|
'use_exact_match_policy' => 'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function space()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Space::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function accounts()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Account::class, 'account_carddav_credentials', 'space_carddav_server_id', 'account_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNameAttribute()
|
||||||
|
{
|
||||||
|
return __('CardDav Server') . ' ' . $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProvisioningSection($config, int $remoteContactDirectoryCounter)
|
||||||
|
{
|
||||||
|
$dom = $config->ownerDocument;
|
||||||
|
|
||||||
|
$section = $dom->createElement('section');
|
||||||
|
$section->setAttribute('name', 'remote_contact_directory_' . $remoteContactDirectoryCounter);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->enabled ? '1': '0');
|
||||||
|
$entry->setAttribute('name', 'enabled');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', 'carddav');
|
||||||
|
$entry->setAttribute('name', 'type');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->uri);
|
||||||
|
$entry->setAttribute('name', 'uri');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->min_characters);
|
||||||
|
$entry->setAttribute('name', 'min_characters');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->results_limit);
|
||||||
|
$entry->setAttribute('name', 'results_limit');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->timeout);
|
||||||
|
$entry->setAttribute('name', 'timeout');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->delay);
|
||||||
|
$entry->setAttribute('name', 'delay');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->fields_for_user_input);
|
||||||
|
$entry->setAttribute('name', 'carddav_fields_for_user_input');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->fields_for_domain);
|
||||||
|
$entry->setAttribute('name', 'carddav_fields_for_domain');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$entry = $dom->createElement('entry', $this->use_exact_match_policy ? '1': '0');
|
||||||
|
$entry->setAttribute('name', 'carddav_use_exact_match_policy');
|
||||||
|
$section->appendChild($entry);
|
||||||
|
|
||||||
|
$config->appendChild($section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,7 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'driver' => env('SESSION_DRIVER', 'cookie'),
|
'driver' => env('SESSION_DRIVER', 'file'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('spaces', function (Blueprint $table) {
|
||||||
|
$table->boolean('carddav_user_credentials')->default(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('space_carddav_servers', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->bigInteger('space_id')->unsigned();
|
||||||
|
$table->foreign('space_id')->references('id')
|
||||||
|
->on('spaces')->onDelete('cascade');
|
||||||
|
|
||||||
|
$table->boolean('enabled')->default(true);
|
||||||
|
$table->string('uri');
|
||||||
|
$table->integer('min_characters')->default(3);
|
||||||
|
$table->integer('results_limit')->default(0);
|
||||||
|
$table->integer('timeout')->default(5);
|
||||||
|
$table->integer('delay')->default(500);
|
||||||
|
$table->string('fields_for_user_input')->nullable();
|
||||||
|
$table->string('fields_for_domain')->nullable();
|
||||||
|
$table->boolean('use_exact_match_policy')->default(false);
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('account_carddav_credentials', function (Blueprint $table) {
|
||||||
|
$table->string('username', 64);
|
||||||
|
$table->string('password', 255);
|
||||||
|
$table->string('domain', 255);
|
||||||
|
$table->string('algorithm', 10)->default('MD5');
|
||||||
|
|
||||||
|
$table->bigInteger('space_carddav_server_id')->unsigned();
|
||||||
|
$table->foreign('space_carddav_server_id')->references('id')
|
||||||
|
->on('space_carddav_servers')->onDelete('cascade');
|
||||||
|
|
||||||
|
$table->integer('account_id')->unsigned();
|
||||||
|
$table->foreign('account_id')->references('id')
|
||||||
|
->on('accounts')->onDelete('cascade');
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['space_carddav_server_id', 'account_id'], 'account_carddav_credentials_unique');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('spaces', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('carddav_user_credentials');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::dropIfExists('account_carddav_credentials');
|
||||||
|
Schema::dropIfExists('space_carddav_servers');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -41,6 +41,9 @@
|
||||||
"Calls logs": "Journaux d'appel",
|
"Calls logs": "Journaux d'appel",
|
||||||
"Cancel": "Annuler",
|
"Cancel": "Annuler",
|
||||||
"Cannot be changed once created.": "Ne peut être changé par la suite.",
|
"Cannot be changed once created.": "Ne peut être changé par la suite.",
|
||||||
|
"CardDav credentials": "Identification CardDav",
|
||||||
|
"CardDav Server": "Serveur CardDav",
|
||||||
|
"CardDav Servers": "Serveurs CardDav",
|
||||||
"Change your email": "Changer votre email",
|
"Change your email": "Changer votre email",
|
||||||
"Change your phone number": "Changer votre numéro de téléphone",
|
"Change your phone number": "Changer votre numéro de téléphone",
|
||||||
"Check the README.md documentation": "Voir la documentation dans README.md",
|
"Check the README.md documentation": "Voir la documentation dans README.md",
|
||||||
|
|
@ -71,6 +74,7 @@
|
||||||
"Day": "Jour",
|
"Day": "Jour",
|
||||||
"Deactivate All": "Tout désactiver",
|
"Deactivate All": "Tout désactiver",
|
||||||
"Deactivated": "Désactivé",
|
"Deactivated": "Désactivé",
|
||||||
|
"Delay in milliseconds before submiting the request": "Temps en millisecondes avant d'envoyer la requête",
|
||||||
"Delete": "Supprimer",
|
"Delete": "Supprimer",
|
||||||
"Description": "Description",
|
"Description": "Description",
|
||||||
"Devices": "Appareils",
|
"Devices": "Appareils",
|
||||||
|
|
@ -84,6 +88,7 @@
|
||||||
"Email": "Email",
|
"Email": "Email",
|
||||||
"Empty": "Vide",
|
"Empty": "Vide",
|
||||||
"Enable the web interface": "Activer l'interface web",
|
"Enable the web interface": "Activer l'interface web",
|
||||||
|
"Enable user credentials for CardDav servers": "Activer les identifiants utilisateur pour les serveurs CardDav",
|
||||||
"Enabled": "Activé",
|
"Enabled": "Activé",
|
||||||
"Encrypted": "Chiffré",
|
"Encrypted": "Chiffré",
|
||||||
"Enter the code you received below": "Saisissez le code reçu ci-dessous",
|
"Enter the code you received below": "Saisissez le code reçu ci-dessous",
|
||||||
|
|
@ -118,6 +123,9 @@
|
||||||
"Key": "Clef",
|
"Key": "Clef",
|
||||||
"Last used": "Dernière utilisation",
|
"Last used": "Dernière utilisation",
|
||||||
"Leave empty to create a root Space.": "Laisser vide si vous souhaitez créer un Espace à la racine",
|
"Leave empty to create a root Space.": "Laisser vide si vous souhaitez créer un Espace à la racine",
|
||||||
|
"Limit the number of results": "Limiter le nomber de résultats",
|
||||||
|
"List of vcard fields to match for SIP domain": "Liste des champs vcard à matcher pour le domaine SIP",
|
||||||
|
"List of vcard fields to match with user input": "Liste des champs vcard à matcher avec les entrées utilisateur",
|
||||||
"Login to my account":"Connexion à mon compte",
|
"Login to my account":"Connexion à mon compte",
|
||||||
"Login using a QRCode": "S'authentifier avec un QRCode",
|
"Login using a QRCode": "S'authentifier avec un QRCode",
|
||||||
"Login": "Authentification",
|
"Login": "Authentification",
|
||||||
|
|
@ -125,6 +133,7 @@
|
||||||
"Markdown text": "Texte Markdown",
|
"Markdown text": "Texte Markdown",
|
||||||
"Max accounts": "Maximum de comptes",
|
"Max accounts": "Maximum de comptes",
|
||||||
"Meeting": "Réunions",
|
"Meeting": "Réunions",
|
||||||
|
"Min characters to search": "Nombre minimum de caractères pour chercher",
|
||||||
"Month": "Mois",
|
"Month": "Mois",
|
||||||
"My Account": "Mon Compte",
|
"My Account": "Mon Compte",
|
||||||
"My Space": "Mon Espace",
|
"My Space": "Mon Espace",
|
||||||
|
|
@ -168,6 +177,7 @@
|
||||||
"Remote provisioning": "Configuration distante",
|
"Remote provisioning": "Configuration distante",
|
||||||
"Remove": "Remove",
|
"Remove": "Remove",
|
||||||
"Renew": "Renouveller",
|
"Renew": "Renouveller",
|
||||||
|
"Request timeout in seconds": "Expiration de la requête en secondes",
|
||||||
"Requests": "Requêtes",
|
"Requests": "Requêtes",
|
||||||
"Resend": "Renvoyer",
|
"Resend": "Renvoyer",
|
||||||
"Reset my password":"Réinitialiser mon mot de passe",
|
"Reset my password":"Réinitialiser mon mot de passe",
|
||||||
|
|
@ -185,6 +195,7 @@
|
||||||
"Send an email to the user to reset the password": "Envoyer un email à l'utilisateur pour réinitialiser son mot de passe",
|
"Send an email to the user to reset the password": "Envoyer un email à l'utilisateur pour réinitialiser son mot de passe",
|
||||||
"Send an email to the user with provisioning information": "Envoyer un email à l'utilisateur avec les informations de déploiement",
|
"Send an email to the user with provisioning information": "Envoyer un email à l'utilisateur avec les informations de déploiement",
|
||||||
"Send": "Envoyer",
|
"Send": "Envoyer",
|
||||||
|
"Separated by commas": "Séparé par des virgules",
|
||||||
"Settings": "Paramètres",
|
"Settings": "Paramètres",
|
||||||
"Show usernames only": "Afficher uniquement les noms d'utilisateur",
|
"Show usernames only": "Afficher uniquement les noms d'utilisateur",
|
||||||
"SIP address":"Adresse SIP",
|
"SIP address":"Adresse SIP",
|
||||||
|
|
@ -224,6 +235,7 @@
|
||||||
"Updated on": "Mis à jour le",
|
"Updated on": "Mis à jour le",
|
||||||
"Updated": "Mise à jour",
|
"Updated": "Mise à jour",
|
||||||
"Use ; to comment, key=\"value\" to declare a complex string.": "Utilisez ; pour commenter, clef=\"valeur\" pour déclarer une chaine complexe.",
|
"Use ; to comment, key=\"value\" to declare a complex string.": "Utilisez ; pour commenter, clef=\"valeur\" pour déclarer une chaine complexe.",
|
||||||
|
"Use exact match policy": "Utiliser la rêgle de recherche exacte",
|
||||||
"Use the mobile app to recover your account using your phone number": "Utilisez l'application mobile pour récupérer votre compte avec votre numéro de téléphone",
|
"Use the mobile app to recover your account using your phone number": "Utilisez l'application mobile pour récupérer votre compte avec votre numéro de téléphone",
|
||||||
"Used on": "Utilisé le",
|
"Used on": "Utilisé le",
|
||||||
"User": "Utilisateur",
|
"User": "Utilisateur",
|
||||||
|
|
@ -243,6 +255,7 @@
|
||||||
"Welcome on :app_name": "Bienvenue sur :app_name",
|
"Welcome on :app_name": "Bienvenue sur :app_name",
|
||||||
"Welcome to :space: Start using your account today": "Bienvenue sur :space : commencez à utiliser votre compte dès maintenant",
|
"Welcome to :space: Start using your account today": "Bienvenue sur :space : commencez à utiliser votre compte dès maintenant",
|
||||||
"Welcome to :space":"Bienvenue sur :space",
|
"Welcome to :space":"Bienvenue sur :space",
|
||||||
|
"Whether match must be exact or approximate (ignoring case, accents…)": "Est-ce que la recherche doit être exacte ou approximative (ignorer les majuscules, les accents…)",
|
||||||
"Year": "Année",
|
"Year": "Année",
|
||||||
"You already have an account?": "Vous avez déjà un compte ?",
|
"You already have an account?": "Vous avez déjà un compte ?",
|
||||||
"You are going to permanently delete the following element. Please confirm your action.": "Vous allez supprimer l'élément suivant. Veuillez confirmer votre action.",
|
"You are going to permanently delete the following element. Please confirm your action.": "Vous allez supprimer l'élément suivant. Veuillez confirmer votre action.",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">
|
<li class="breadcrumb-item active" aria-current="page">
|
||||||
{{ __('Types') }}
|
{{ __('Types') }}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">
|
<li class="breadcrumb-item active" aria-current="page">
|
||||||
{{ __('Actions') }}
|
{{ __('Actions') }}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active">
|
<li class="breadcrumb-item active">
|
||||||
{{ __('Actions') }}
|
{{ __('Actions') }}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">Activity</li>
|
<li class="breadcrumb-item active" aria-current="page">Activity</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
@extends('layouts.main')
|
||||||
|
|
||||||
|
@section('breadcrumb')
|
||||||
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">
|
||||||
|
{{ __('CardDav credentials') }}
|
||||||
|
</li>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<h1><i class="ph ph-plus"></i> {{ __('CardDav credentials') }}</h1>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('admin.account.carddavs.store', $account->id) }}" accept-charset="UTF-8">
|
||||||
|
@csrf
|
||||||
|
<div class="select large">
|
||||||
|
<select name="carddav_id">
|
||||||
|
@foreach ($carddavServers as $carddavServer)
|
||||||
|
<option value="{{ $carddavServer->id }}">{{ $carddavServer->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<label for="carddav_id">{{ __('CardDav Server') }}</label>
|
||||||
|
@include('parts.errors', ['name' => 'carddav_id'])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input placeholder="Username" name="username" type="text" value="{{ old('username') }}" required>
|
||||||
|
<label for="username">{{ __('Username') }}</label>
|
||||||
|
@include('parts.errors', ['name' => 'username'])
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input placeholder="Username" name="domain" type="text" value="{{ old('domain') }}" required>
|
||||||
|
<label for="domain">{{ __('Domain') }}</label>
|
||||||
|
@include('parts.errors', ['name' => 'domain'])
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input placeholder="Password" name="password" type="password" required>
|
||||||
|
<label for="password">{{ __('Password') }}</label>
|
||||||
|
@include('parts.errors', ['name' => 'password'])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="select">
|
||||||
|
<select name="algorithm">
|
||||||
|
@foreach (passwordAlgorithms() as $value => $key)
|
||||||
|
<option value="{{ $value }}">{{ $value }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
<label for="algorithm">{{ __('Algorithm') }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input class="btn btn-success" type="submit" value="{{ __('Add') }}">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
@endsection
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
@extends('layouts.main')
|
||||||
|
|
||||||
|
@section('breadcrumb')
|
||||||
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
|
<li class="breadcrumb-item active">
|
||||||
|
{{ __('CardDav credentials') }}
|
||||||
|
</li>
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<h1><i class="ph ph-trash"></i> {{ __('CardDav credentials') }}</h1>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('admin.account.carddavs.destroy', [$account, $carddavCredentials->cardDavServer]) }}"
|
||||||
|
accept-charset="UTF-8">
|
||||||
|
@csrf
|
||||||
|
@method('delete')
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>{{ __('You are going to permanently delete the following element. Please confirm your action.') }}</p>
|
||||||
|
<p><b>{{ $carddavCredentials->identifier }}</b></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input name="account_id" type="hidden" value="{{ $account->id }}">
|
||||||
|
<input name="carddav_id" type="hidden" value="{{ $carddavCredentials->cardDavServer->id }}">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input class="btn" type="submit" value="{{ __('Delete') }}">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
@endsection
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Add contact') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Add contact') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active">
|
<li class="breadcrumb-item active">
|
||||||
{{ __('Contacts') }}
|
{{ __('Contacts') }}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Contacts') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Contacts') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.index')
|
||||||
@if ($account->id)
|
@if ($account->id)
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
<li class="breadcrumb-item">
|
||||||
|
<a href="{{ route('admin.account.show', $account->id) }}">{{ $account->identifier }}</a>
|
||||||
|
</li>
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Edit') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Edit') }}</li>
|
||||||
@else
|
@else
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Create') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Create') }}</li>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<h2>{{ __('Delete') }}</h2>
|
<h1><i class="ph ph-trash"></i> {{ __('Delete') }}</h1>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p>{{ __('You are going to permanently delete the following element. Please confirm your action.') }}</p>
|
<p>{{ __('You are going to permanently delete the following element. Please confirm your action.') }}</p>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Dictionary') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Dictionary') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
@if ($entry->id)
|
<h1><i class="ph @if ($entry->id)ph-pencil @else ph-plus @endif"></i> {{ __('Dictionary') }}</h1>
|
||||||
<h2>{{ __('Edit') }}</h2>
|
|
||||||
@else
|
|
||||||
<h2>{{ __('Create') }}</h2>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
action="{{ $entry->id ? route('admin.account.dictionary.update', [$entry->account, $entry]) : route('admin.account.dictionary.store', $account) }}"
|
action="{{ $entry->id ? route('admin.account.dictionary.update', [$entry->account, $entry]) : route('admin.account.dictionary.store', $account) }}"
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Dictionary') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Dictionary') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<h2>{{ __('Delete') }}</h2>
|
<h1><i class="ph ph-trash"></i> {{ __('Delete') }}</h1>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p>{{ __('You are going to permanently delete the following element. Please confirm your action.') }}</p>
|
<p>{{ __('You are going to permanently delete the following element. Please confirm your action.') }}</p>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item"><a href="{{ route('admin.account.external.show', ['account' => $account]) }}">{{ __('External Account') }}</a></li>
|
<li class="breadcrumb-item"><a href="{{ route('admin.account.external.show', ['account' => $account]) }}">{{ __('External Account') }}</a></li>
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active">{{ __('External Account') }}</li>
|
<li class="breadcrumb-item active">{{ __('External Account') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.index')
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Import') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Import') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.index')
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Import') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Import') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Provisioning') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Provisioning') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Reset password') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Reset password') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
@ -81,7 +80,7 @@
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<a class="btn small oppose" href="{{ route('admin.account.external.show', $account) }}">
|
<a class="btn small oppose" href="{{ route('admin.account.external.show', $account) }}">
|
||||||
<i class="ph ph-pencil"></i>
|
<i class="ph ph-plus"></i>
|
||||||
@if ($account->external){{ __('Edit') }}@else{{ __('Create') }}@endif
|
@if ($account->external){{ __('Edit') }}@else{{ __('Create') }}@endif
|
||||||
</a>
|
</a>
|
||||||
<h3>
|
<h3>
|
||||||
|
|
@ -130,6 +129,53 @@
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if ($account->space->carddav_user_credentials)
|
||||||
|
<div class="card large" id="carddavs">
|
||||||
|
@if ($account->remainingCardDavCredentialsCreatable->count() > 0)
|
||||||
|
<a class="btn small oppose" href="{{ route('admin.account.carddavs.create', $account) }}">
|
||||||
|
<i class="ph ph-plus"></i>
|
||||||
|
{{ __('Add') }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
<h3>
|
||||||
|
{{ __('CardDav credentials') }}
|
||||||
|
</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ __('CardDav Server') }}</th>
|
||||||
|
<th>{{ __('Username') }}</th>
|
||||||
|
<th>{{ __('Domain') }}</th>
|
||||||
|
<th>{{ __('Algorithm') }}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@if ($account->carddavServers->isEmpty())
|
||||||
|
<tr class="empty">
|
||||||
|
<td colspan="5">{{ __('Empty') }}</td>
|
||||||
|
</tr>
|
||||||
|
@else
|
||||||
|
@foreach ($account->carddavServers as $carddavServer)
|
||||||
|
<tr>
|
||||||
|
<td class="line">{{ $carddavServer->name }}</td>
|
||||||
|
<td class="line">{{ $carddavServer->pivot->username }}</td>
|
||||||
|
<td class="line">{{ $carddavServer->pivot->domain }}</td>
|
||||||
|
<td class="line">{{ $carddavServer->pivot->algorithm }}</td>
|
||||||
|
<td class="actions">
|
||||||
|
<a type="button" class="btn small tertiary" href="{{ route('admin.account.carddavs.delete', [$account, $carddavServer]) }}">
|
||||||
|
<i class="ph ph-trash"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="card large">
|
<div class="card large">
|
||||||
<h3>
|
<h3>
|
||||||
{{ __('Devices') }}
|
{{ __('Devices') }}
|
||||||
|
|
@ -144,7 +190,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
@if ($devices->isEmpty())
|
@if ($devices->isEmpty())
|
||||||
<tr class="empty">
|
<tr class="empty">
|
||||||
<td colspan="3">{{ __('Empty') }}</td>
|
<td colspan="2">{{ __('Empty') }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@else
|
@else
|
||||||
@foreach ($devices as $device)
|
@foreach ($devices as $device)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Statistics') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Statistics') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.show', ['account' => $account])
|
||||||
@include('admin.account.parts.breadcrumb_accounts_show', ['account' => $account])
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Calls logs') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Calls logs') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.index')
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{{ route('admin.account.type.index') }}">{{ __('Types') }}</a>
|
<a href="{{ route('admin.account.type.index') }}">{{ __('Types') }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.index')
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{{ route('admin.account.type.index') }}">{{ __('Types') }}</a>
|
<a href="{{ route('admin.account.type.index') }}">{{ __('Types') }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
@include('admin.parts.breadcrumb.accounts.index')
|
||||||
<li class="breadcrumb-item" aria-current="page">
|
<li class="breadcrumb-item" aria-current="page">
|
||||||
<a href="{{ route('admin.account.type.index') }}">{{ __('Types') }}</a>
|
<a href="{{ route('admin.account.type.index') }}">{{ __('Types') }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
@include('admin.parts.breadcrumb.accounts.index')
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{{ route('admin.account.show', $account->id) }}">{{ $account->identifier }}</a>
|
<a href="{{ route('admin.account.show', $account->id) }}">{{ $account->identifier }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
@if (auth()->user()->superAdmin)
|
||||||
|
<li class="breadcrumb-item">
|
||||||
|
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
@include('admin.parts.breadcrumb.spaces.show')
|
||||||
|
<li class="breadcrumb-item">
|
||||||
|
<a href="{{ route('admin.spaces.integration', $space) }}">{{ __('Integration') }}</a>
|
||||||
|
</li>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
@include('admin.parts.breadcrumb.spaces.index')
|
||||||
|
<li class="breadcrumb-item">
|
||||||
|
@if (auth()->user()->superAdmin)
|
||||||
|
<a href="{{ route('admin.spaces.show', $space) }}">{{ $space->name }}</a>
|
||||||
|
@else
|
||||||
|
{{ $space->name }}
|
||||||
|
@endif
|
||||||
|
</li>
|
||||||
|
|
@ -1,14 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.show')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.spaces.show', $space->id) }}">
|
|
||||||
{{ $space->name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Administration') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Administration') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
@ -48,6 +41,12 @@
|
||||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'super', 'label' => __('Super Space'), 'supporting' => __('All the admins will be super admins')])
|
@include('parts.form.toggle', ['object' => $space, 'key' => 'super', 'label' => __('Super Space'), 'supporting' => __('All the admins will be super admins')])
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3 class="large">{{ __('Integration') }}</h3>
|
||||||
|
|
||||||
|
<div class="large">
|
||||||
|
@include('parts.form.toggle', ['object' => $space, 'key' => 'carddav_user_credentials', 'label' => __('Enable user credentials for CardDav servers')])
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3 class="large">Interface</h3>
|
<h3 class="large">Interface</h3>
|
||||||
<div>
|
<div>
|
||||||
@include('parts.form.toggle', ['object' => $space, 'key' => 'custom_theme', 'label' => __('Allow a custom CSS theme'), 'supporting' => __('Check the README.md documentation')])
|
@include('parts.form.toggle', ['object' => $space, 'key' => 'custom_theme', 'label' => __('Allow a custom CSS theme'), 'supporting' => __('Check the README.md documentation')])
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
@extends('layouts.main')
|
||||||
|
|
||||||
|
@section('breadcrumb')
|
||||||
|
@include('admin.parts.breadcrumb.spaces.integration')
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">{{ __('CardDav Server') }}</li>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<header>
|
||||||
|
<h1>
|
||||||
|
<i class="ph ph-users"></i> {{ __('CardDav Server') }} -
|
||||||
|
@if ($carddavServer->id)
|
||||||
|
{{ __('Edit') }}
|
||||||
|
@else
|
||||||
|
{{ __('Create') }}
|
||||||
|
@endif
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<form method="POST"
|
||||||
|
action="{{ $carddavServer->id ? route('admin.spaces.carddavs.update', [$space->id, $carddavServer->id]) : route('admin.spaces.carddavs.store', $space->id) }}"
|
||||||
|
id="create_edit" accept-charset="UTF-8">
|
||||||
|
@csrf
|
||||||
|
@method($carddavServer->id ? 'put' : 'post')
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input placeholder="https://..." required="required" name="uri" type="url"
|
||||||
|
value="@if($carddavServer->uri){{ $carddavServer->uri }}@else{{ old('uri') }}@endif">
|
||||||
|
<label for="uri">Uri</label>
|
||||||
|
@include('parts.errors', ['name' => 'uri'])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include('parts.form.toggle', ['object' => $carddavServer, 'key' => 'enabled', 'label' => __('Enabled')])
|
||||||
|
|
||||||
|
<hr class="large" />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input placeholder="3" min="1" required="required" name="min_characters" type="number" value="@if($carddavServer->min_characters){{ $carddavServer->min_characters }}@else{{ old('min_characters') ?? 3 }}@endif">
|
||||||
|
<label for="min_characters">{{ __('Min characters to search') }}</label>
|
||||||
|
@include('parts.errors', ['name' => 'min_characters'])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input placeholder="0" min="0" required="required" name="results_limit" type="number" value="@if($carddavServer->results_limit){{ $carddavServer->results_limit }}@else{{ old('results_limit') ?? 0 }}@endif">
|
||||||
|
<label for="results_limit">{{ __('Limit the number of results') }}</label>
|
||||||
|
<span class="supporting">{{ __('Unlimited if set to 0') }}</span>
|
||||||
|
@include('parts.errors', ['name' => 'results_limit'])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include('parts.form.toggle', ['object' => $carddavServer, 'key' => 'use_exact_match_policy', 'label' => __('Use exact match policy'), 'supporting' => __('Whether match must be exact or approximate (ignoring case, accents…)')])
|
||||||
|
|
||||||
|
<details class="large" @if ($errors->isNotEmpty())open @endif>
|
||||||
|
<summary>
|
||||||
|
<h3 class="large">
|
||||||
|
{{ __('Other information') }}
|
||||||
|
</h3>
|
||||||
|
</summary>
|
||||||
|
<section>
|
||||||
|
<div>
|
||||||
|
<input placeholder="5" min="1" required="required" name="timeout" type="number" value="@if($carddavServer->timeout){{ $carddavServer->timeout }}@else{{ old('timeout') ?? 3 }}@endif">
|
||||||
|
<label for="timeout">{{ __('Request timeout in seconds') }}</label>
|
||||||
|
@include('parts.errors', ['name' => 'timeout'])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input placeholder="500" min="100" required="required" name="delay" type="number" value="@if($carddavServer->delay){{ $carddavServer->delay }}@else{{ old('delay') ?? 500 }}@endif">
|
||||||
|
<label for="delay">{{ __('Delay in milliseconds before submiting the request') }}</label>
|
||||||
|
@include('parts.errors', ['name' => 'delay'])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input placeholder="username,domain..." name="fields_for_user_input" type="text"
|
||||||
|
value="{{ $carddavServer->fields_for_user_input ?? old('fields_for_user_input') }}">
|
||||||
|
<label for="fields_for_user_input">{{ __('List of vcard fields to match with user input') }}</label>
|
||||||
|
<span class="supporting">{{ __('Separated by commas') }}</span>
|
||||||
|
@include('parts.errors', ['name' => 'fields_for_user_input'])
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input placeholder="username,domain..." name="fields_for_domain" type="text"
|
||||||
|
value="{{ $carddavServer->fields_for_domain ?? old('fields_for_domain') }}">
|
||||||
|
<label for="fields_for_domain">{{ __('List of vcard fields to match for SIP domain') }}</label>
|
||||||
|
<span class="supporting">{{ __('Separated by commas') }}</span>
|
||||||
|
@include('parts.errors', ['name' => 'fields_for_domain'])
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<div class="large">
|
||||||
|
@if ($carddavServer->id)
|
||||||
|
<input class="btn" type="submit" value="{{ __('Update') }}">
|
||||||
|
@else
|
||||||
|
<input form="create_edit" class="btn" type="submit" value="{{ __('Create') }}">
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
@endsection
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
@extends('layouts.main')
|
||||||
|
|
||||||
|
@section('breadcrumb')
|
||||||
|
@include('admin.parts.breadcrumb.spaces.integration')
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">{{ __('CardDav Server') }} - {{ __('Delete' ) }}</li>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<header>
|
||||||
|
<h1><i class="ph ph-trash"></i> {{ __('CardDav Server') }} - {{ __('Delete') }}</h1>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.spaces.integration', ['space' => $space]) }}" class="btn secondary oppose">{{ __('Cancel') }}</a>
|
||||||
|
<input form="delete" class="btn" type="submit" value="{{ __('Delete') }}">
|
||||||
|
</header>
|
||||||
|
<form id="delete" method="POST" action="{{ route('admin.spaces.carddavs.destroy', [$carddavServer->space_id, $carddavServer->id]) }}" accept-charset="UTF-8">
|
||||||
|
@csrf
|
||||||
|
@method('delete')
|
||||||
|
|
||||||
|
<div class="large">
|
||||||
|
<p>{{ __('You are going to permanently delete the following element. Please confirm your action.') }}<br />
|
||||||
|
<b><i class="ph ph-identification-card"></i> {{ $carddavServer->uri }}</b>
|
||||||
|
</p>
|
||||||
|
<input name="account_id" type="hidden" value="{{ $carddavServer->space_id }}">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
@endsection
|
||||||
|
|
@ -2,14 +2,7 @@
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@if (auth()->user()->superAdmin)
|
@if (auth()->user()->superAdmin)
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.show')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.spaces.show', $space->id) }}">
|
|
||||||
{{ $space->name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
@else
|
@else
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{{ route('admin.spaces.me') }}">
|
<a href="{{ route('admin.spaces.me') }}">
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.index')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Create') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Create') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.show')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Delete') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.show')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.spaces.show', $space->id) }}">
|
|
||||||
{{ $space->name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('App Configuration') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('App Configuration') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,13 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.integration')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.spaces.show', $space) }}">
|
|
||||||
{{ $space->name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.spaces.integration', $space) }}">{{ __('Integration') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Email Server') }} - {{ __('Delete' ) }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Email Server') }} - {{ __('Delete' ) }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<header>
|
<header>
|
||||||
<h1><i class="ph ph-trash"></i> {{ __('Delete') }}</h1>
|
<h1><i class="ph ph-trash"></i> {{ __('Email Server') }} - {{ __('Delete') }}</h1>
|
||||||
|
|
||||||
<a href="{{ route('admin.spaces.integration', ['space' => $space]) }}" class="btn secondary oppose">{{ __('Cancel') }}</a>
|
<a href="{{ route('admin.spaces.integration', ['space' => $space]) }}" class="btn secondary oppose">{{ __('Cancel') }}</a>
|
||||||
<input form="delete" class="btn" type="submit" value="{{ __('Delete') }}">
|
<input form="delete" class="btn" type="submit" value="{{ __('Delete') }}">
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.integration')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.spaces.show', $space) }}">
|
|
||||||
{{ $space->name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.spaces.integration', $space) }}">{{ __('Integration') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Email Server') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Email Server') }}</li>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
|
@ -20,7 +10,6 @@
|
||||||
<h1><i class="ph ph-envelope"></i> {{ $space->name }}</h1>
|
<h1><i class="ph ph-envelope"></i> {{ $space->name }}</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
action="{{ route('admin.spaces.email.store', $space->id) }}"
|
action="{{ route('admin.spaces.email.store', $space->id) }}"
|
||||||
id="show" accept-charset="UTF-8">
|
id="show" accept-charset="UTF-8">
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,7 @@
|
||||||
@extends('layouts.main')
|
@extends('layouts.main')
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.integration')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.spaces.show', $space->id) }}">
|
|
||||||
{{ $space->name }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Integration') }}</li>
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
@ -36,4 +28,29 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<a class="btn small oppose" href="{{ route('admin.spaces.carddavs.create', $space) }}">
|
||||||
|
<i class="ph ph-plus"></i>
|
||||||
|
{{ __('Create') }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<h3>{{ __('CardDav Servers') }}</h3>
|
||||||
|
|
||||||
|
<div class="grid third">
|
||||||
|
@foreach ($space->carddavServers as $carddavServer)
|
||||||
|
<div class="card">
|
||||||
|
<small class="oppose"><i class="ph ph-users"></i> {{ $carddavServer->accounts()->count() }}</small>
|
||||||
|
<span class="icon"><i class="ph ph-identification-card"></i></span>
|
||||||
|
<h3>{{ $carddavServer->name }}</h3>
|
||||||
|
<p>
|
||||||
|
{{ $carddavServer->uri}}<br />
|
||||||
|
<br />
|
||||||
|
<a class="btn oppose" href="{{ route('admin.spaces.carddavs.edit', [$space, $carddavServer]) }}">{{ __('Edit') }}</a>
|
||||||
|
<a class="btn oppose tertiary" href="{{ route('admin.spaces.carddavs.delete', [$space, $carddavServer]) }}">{{ __('Delete') }}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
@section('breadcrumb')
|
@section('breadcrumb')
|
||||||
@if (auth()->user()->superAdmin)
|
@if (auth()->user()->superAdmin)
|
||||||
<li class="breadcrumb-item">
|
@include('admin.parts.breadcrumb.spaces.index')
|
||||||
<a href="{{ route('admin.spaces.index') }}">{{ __('Spaces') }}</a>
|
|
||||||
</li>
|
|
||||||
@endif
|
@endif
|
||||||
<li class="breadcrumb-item">{{ $space->name }}</li>
|
<li class="breadcrumb-item">{{ $space->name }}</li>
|
||||||
<li class="breadcrumb-item active" aria-current="page">{{ __('Information') }}</li>
|
<li class="breadcrumb-item active" aria-current="page">{{ __('Information') }}</li>
|
||||||
|
|
|
||||||
115
flexiapi/resources/views/api/documentation/about_auth.blade.php
Normal file
115
flexiapi/resources/views/api/documentation/about_auth.blade.php
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
# About & Auth.
|
||||||
|
|
||||||
|
An API to deal with the Flexisip server.
|
||||||
|
|
||||||
|
The API is available under `/api`
|
||||||
|
|
||||||
|
A `content-type` and `accept` HTTP headers are REQUIRED to use the API properly
|
||||||
|
|
||||||
|
```
|
||||||
|
> GET /api/{endpoint}
|
||||||
|
> content-type: application/json
|
||||||
|
> accept: application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
|
||||||
|
Restricted endpoints are protected using a DIGEST authentication or an API Key mechanisms.
|
||||||
|
|
||||||
|
### Access model
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
### Space expiration
|
||||||
|
|
||||||
|
<span class="badge badge-error">Super Admin</span> can configure and expiration date on Spaces (`expire_at`). If the Space is expired all the authenticated endpoint of the API will return `403`.
|
||||||
|
|
||||||
|
### Localization
|
||||||
|
|
||||||
|
You can add an [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) header to your request to translate the responses, and especially errors messages, in a specific language.
|
||||||
|
|
||||||
|
Currently supported languages: @php
|
||||||
|
echo implode(', ', config('app.authorized_locales'))
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
```
|
||||||
|
> GET /api/{endpoint}
|
||||||
|
> Accept-Language: fr
|
||||||
|
> …
|
||||||
|
|
||||||
|
< HTTP 422
|
||||||
|
< {
|
||||||
|
< "message": "Le champ pseudo est obligatoire.",
|
||||||
|
< "errors": {
|
||||||
|
< "username": [
|
||||||
|
< 0 => "Le champ pseudo est obligatoire."
|
||||||
|
< ]
|
||||||
|
< }
|
||||||
|
< }
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using the API Key
|
||||||
|
|
||||||
|
You can retrieve an API Key from your account panel or using <a href="#get-accountsmeapikey">the dedicated API endpoint</a>.
|
||||||
|
|
||||||
|
**When generated by a User account the generated API Key will be restricted to the IP that generates it and will be destroyed if not used after some times.**
|
||||||
|
|
||||||
|
**If you want a stable API Key, to integrate with another server component for example, you can generate one in the Administration Panel.**
|
||||||
|
|
||||||
|
You can then use your freshly generated key by adding a new `x-api-key` header to your API requests:
|
||||||
|
|
||||||
|
```
|
||||||
|
> GET /api/{endpoint}
|
||||||
|
> x-api-key: {your-api-key}
|
||||||
|
> …
|
||||||
|
```
|
||||||
|
|
||||||
|
Or using a cookie:
|
||||||
|
|
||||||
|
```
|
||||||
|
> GET /api/{endpoint}
|
||||||
|
> Cookie: x-api-key={your-api-key}
|
||||||
|
> …
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using a JWT token
|
||||||
|
|
||||||
|
You can use a <a href="https://jwt.io/">JWT</a> token to authenticate on the API.
|
||||||
|
|
||||||
|
To do so you MUST inject it as an `Authorization: Bearer` header and configure the API with the public key of the token emitter.
|
||||||
|
|
||||||
|
```
|
||||||
|
> GET /api/{endpoint}
|
||||||
|
> Authorization: Bearer {your-jwt-token}
|
||||||
|
> …
|
||||||
|
```
|
||||||
|
|
||||||
|
The API will then check if the token was signed properly, is still valid and authenticate a user that is actually available in the system.
|
||||||
|
|
||||||
|
### Using DIGEST
|
||||||
|
|
||||||
|
To discover the available hashing algorythm you MUST send an unauthenticated request to one of the restricted endpoints.<br />
|
||||||
|
Only DIGEST-MD5 and DIGEST-SHA-256 are supported through the authentication layer.
|
||||||
|
|
||||||
|
A `from` (consisting of the user SIP address, prefixed with `sip:`) header is required to initiate the DIGEST flow.
|
||||||
|
|
||||||
|
```
|
||||||
|
> GET /api/{restricted-endpoint}
|
||||||
|
> from: sip:foobar@sip.example.org
|
||||||
|
> …
|
||||||
|
|
||||||
|
< HTTP 401
|
||||||
|
< content-type: application/json
|
||||||
|
< www-authenticate: Digest realm=test,qop=auth,algorithm=MD5,nonce="{nonce}",opaque="{opaque}"
|
||||||
|
< www-authenticate: Digest realm=test,qop=auth,algorithm=SHA-256,nonce="{nonce}",opaque="{opaque}"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find more documentation on the related [IETF RFC-7616](https://tools.ietf.org/html/rfc7616).
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
## Account Creation Request Tokens
|
||||||
|
|
||||||
|
An `account_creation_request_token` is a unique token that can be validated and then used to generate a valid `account_creation_token`.
|
||||||
|
|
||||||
|
### `POST /account_creation_request_tokens`
|
||||||
|
<span class="badge badge-success">Public</span>
|
||||||
|
|
||||||
|
Create and return an `account_creation_request_token` that should then be validated to be used.
|
||||||
|
|
||||||
|
## Account Creation Tokens
|
||||||
|
|
||||||
|
An `account_creation_token` is a unique token that allow the creation or the validation of a unique account.
|
||||||
|
|
||||||
|
### `POST /account_creation_tokens/send-by-push`
|
||||||
|
<span class="badge badge-success">Public</span>
|
||||||
|
|
||||||
|
Create and send an `account_creation_token` using a push notification to the device.
|
||||||
|
Return `403` if a token was already sent, or if the tokens limit is reached for this device.
|
||||||
|
Return `503` if the token was not successfully sent.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `pn_provider` **required**, the push notification provider, must be in apns.dev, apns or fcm
|
||||||
|
* `pn_param` the push notification parameter, can be null or contain only alphanumeric and underscore characters
|
||||||
|
* `pn_prid` the push notification unique id, can be null or contain only alphanumeric, dashes, underscore and colon characters
|
||||||
|
|
||||||
|
### `POST /account_creation_tokens/using-account-creation-request-token`
|
||||||
|
<span class="badge badge-success">Public</span>
|
||||||
|
|
||||||
|
Create an `account_creation_token` using an `account_creation_request_token`.
|
||||||
|
Return an `account_creation_token`.
|
||||||
|
Return `404` if the `account_creation_request_token` provided is not valid or expired otherwise.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `account_creation_request_token` **required**
|
||||||
|
|
||||||
|
### `POST /account_creation_tokens/consume`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Consume an `account_creation_token` and link it to the authenticated account.
|
||||||
|
Return an `account_creation_token`.
|
||||||
|
|
||||||
|
Return `404` if the `account_creation_token` provided is not valid.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `account_creation_token` **required**
|
||||||
|
|
||||||
|
### `POST /account_creation_tokens`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Create and return an `account_creation_token`.
|
||||||
|
|
||||||
|
## Account Recovery Tokens
|
||||||
|
|
||||||
|
An `account_recovery_token` is a unique token that allow the recovery of an account.
|
||||||
|
|
||||||
|
It can be used on the following page that also accepts a `phone` optional parameter to prefil the recovery form:
|
||||||
|
|
||||||
|
{{ route('account.recovery.show.phone', ['account_recovery_token' => '_the_token_']) }}
|
||||||
|
{{ route('account.recovery.show.phone', ['account_recovery_token' => '_the_token_', 'phone' => '+3312341234']) }}
|
||||||
|
|
||||||
|
### `POST /account_recovery_tokens/send-by-push`
|
||||||
|
<span class="badge badge-success">Public</span>
|
||||||
|
|
||||||
|
Create and send an `account_recovery_token` using a push notification to the device.
|
||||||
|
Return `403` if a token was already sent, or if the tokens limit is reached for this device.
|
||||||
|
Return `503` if the token was not successfully sent.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `pn_provider` **required**, the push notification provider, must be in apns.dev, apns or fcm
|
||||||
|
* `pn_param` the push notification parameter, can be null or contain only alphanumeric and underscore characters
|
||||||
|
* `pn_prid` the push notification unique id, can be null or contain only alphanumeric, dashes, underscore and colon characters
|
||||||
|
|
||||||
|
## Auth Tokens
|
||||||
|
|
||||||
|
### `POST /accounts/auth_token`
|
||||||
|
<span class="badge badge-success">Public</span>
|
||||||
|
|
||||||
|
Generate an `auth_token`. To attach the generated token to an account see [`auth_token` attachement endpoint](#get-accountsauthtokenauthtokenattach).
|
||||||
|
|
||||||
|
Return the `auth_token` object.
|
||||||
|
|
||||||
|
### `GET /accounts/auth_token/{auth_token}/attach`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Attach a publicly generated authentication token to the currently authenticated account.
|
||||||
|
|
||||||
|
Return `404` if the token is non existing or invalid.
|
||||||
176
flexiapi/resources/views/api/documentation/accounts.blade.php
Normal file
176
flexiapi/resources/views/api/documentation/accounts.blade.php
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
## Accounts
|
||||||
|
|
||||||
|
### `POST /accounts/with-account-creation-token`
|
||||||
|
<span class="badge badge-success">Public</span>
|
||||||
|
|
||||||
|
Create an account using an `account_creation_token`.
|
||||||
|
|
||||||
|
Return `422` if the parameters are invalid or if the token is expired.
|
||||||
|
|
||||||
|
Return `403` if the `max_accounts` limit of the corresponding Space is reached.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `username` unique username, minimum 6 characters
|
||||||
|
* `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`
|
||||||
|
|
||||||
|
### `GET /accounts/{sip}/info`
|
||||||
|
<span class="badge badge-success">Public</span>
|
||||||
|
|
||||||
|
Retrieve public information about the account.
|
||||||
|
Return `404` if the account doesn't exists.
|
||||||
|
|
||||||
|
### `GET /accounts/me/api_key/{auth_token}`
|
||||||
|
<span class="badge badge-success">Public</span>
|
||||||
|
|
||||||
|
Generate and retrieve a fresh API Key from an `auth_token`. The `auth_token` must be attached to an existing account, see [`auth_token` attachement endpoint](#get-accountsauthtokenauthtokenattach) to do so.
|
||||||
|
|
||||||
|
Return `404` if the token is invalid or not attached.
|
||||||
|
|
||||||
|
This endpoint is also setting the API Key as a Cookie.
|
||||||
|
|
||||||
|
### `GET /accounts/me/api_key`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Generate and retrieve a fresh API Key.
|
||||||
|
This endpoint is also setting the API Key as a Cookie.
|
||||||
|
|
||||||
|
### `GET /accounts/me`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Retrieve the account information.
|
||||||
|
|
||||||
|
### `GET /accounts/me/services/turn`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
If configured, returns valid TURN credentials following the [draft-uberti-behave-turn-rest-00 IEFT Draft](https://datatracker.ietf.org/doc/html/draft-uberti-behave-turn-rest-00).
|
||||||
|
|
||||||
|
### `GET /accounts/me/provision`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Provision the account by generating a fresh `provisioning_token`.
|
||||||
|
|
||||||
|
Return the account object.
|
||||||
|
|
||||||
|
### `DELETE /accounts/me`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Delete the account.
|
||||||
|
|
||||||
|
### `POST /accounts/me/password`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
### `POST /accounts`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
To create an account directly from the API.
|
||||||
|
|
||||||
|
Return `403` if the `max_accounts` limit of the corresponding Space is reached.
|
||||||
|
|
||||||
|
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**, must exist in one of the configured Spaces. Only configurable if the admin is a super admin. Otherwise the SIP domain of the corresponding space is used.
|
||||||
|
* `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`
|
||||||
|
* `admin` optional, a boolean, set to `false` by default, create an admin account
|
||||||
|
* `phone` optional, a valid phone number, set a phone number to the account
|
||||||
|
* `dtmf_protocol` optional, values must be `sipinfo`, `sipmessage` or `rfc2833`
|
||||||
|
* `dictionary` optional, an associative array attached to the account, <a href="#dictionary">see also the related endpoints</a>.
|
||||||
|
|
||||||
|
### `PUT /accounts/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Update an existing account. Ensure to resend all the parameters to not reset them.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `username` unique username, minimum 6 characters
|
||||||
|
* `domain` **not configurable by default**, must exist in one of the configured Spaces. Only configurable if the admin is a super admin. Otherwise the SIP domain of the corresponding space is used.
|
||||||
|
* `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
|
||||||
|
* `phone` optional, a valid phone number, set a phone number to the account
|
||||||
|
* `dtmf_protocol` optional, values must be `sipinfo`, `sipmessage` or `rfc2833`
|
||||||
|
|
||||||
|
Using this endpoint you can also set a fresh dictionnary if the parameter is set. The existing dictionary entries will be destroyed.
|
||||||
|
|
||||||
|
* `dictionary` optional, an associative array attached to the account, <a href="#dictionary">see also the related endpoints</a>.
|
||||||
|
|
||||||
|
This endpoint also return the current `phone_change_code` and `email_change_code` if they are available.
|
||||||
|
|
||||||
|
### `GET /accounts`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Retrieve all the accounts, paginated.
|
||||||
|
|
||||||
|
### `GET /accounts/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Retrieve a specific account.
|
||||||
|
|
||||||
|
### `GET /accounts/{sip}/search`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Search for a specific account by sip address.
|
||||||
|
|
||||||
|
### `GET /accounts/{email}/search-by-email`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Search for a specific account by email.
|
||||||
|
|
||||||
|
### `DELETE /accounts/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Delete a specific account and its related information.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/activate`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Activate an account.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/deactivate`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Deactivate an account.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/block`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Block an account.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/unblock`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Unblock an account.
|
||||||
|
|
||||||
|
### `GET /accounts/{id}/provision`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Provision an account by generating a fresh `provisioning_token`.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/send_provisioning_email`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Send a provisioning email to the account.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/send_reset_password_email`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Send a password reset email to the account.
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
## Account actions
|
||||||
|
|
||||||
|
The following endpoints will return `403 Forbidden` if the requested account doesn't have a DTMF protocol configured.
|
||||||
|
|
||||||
|
### `GET /accounts/{id}/actions`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Show an account related actions.
|
||||||
|
|
||||||
|
### `GET /accounts/{id}/actions/{action_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Show an account related action.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/actions/`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Create an account action.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `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>
|
||||||
|
|
||||||
|
Create an account action.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `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>
|
||||||
|
|
||||||
|
Delete an account related action.
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
## Account CardDav credentials
|
||||||
|
|
||||||
|
The following endpoints will return `403 Forbidden` if the requested account doesn't have a DTMF protocol configured.
|
||||||
|
|
||||||
|
### `GET /accounts/{id}/carddavs`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Show an account CardDav servers credentials.
|
||||||
|
|
||||||
|
### `GET /accounts/{id}/carddavs/{carddav_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Show an account CardDav server credentials.
|
||||||
|
|
||||||
|
### `PUT /accounts/{id}/carddavs/{carddav_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Create an account CardDav server credentials.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `username` **required** the username
|
||||||
|
* `password` **required** the password in plain text
|
||||||
|
* `algorithm` **required**, values can be `SHA-256` or `MD5`
|
||||||
|
* `domain` **required** the domain
|
||||||
|
|
||||||
|
### `DELETE /accounts/{id}/carddavs/{carddav_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Delete an account related action.
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
## Account contacts
|
||||||
|
|
||||||
|
### `GET /accounts/{id/me}/contacts`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Return the user contacts.
|
||||||
|
|
||||||
|
### `GET /accounts/me/contacts/{sip}`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Return a user contact.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/contacts/{contact_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Add a contact to the list.
|
||||||
|
|
||||||
|
### `DELETE /accounts/{id}/contacts/{contact_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Remove a contact from the list.
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
## Contacts Lists
|
||||||
|
|
||||||
|
### `GET /contacts_lists`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Show all the contacts lists.
|
||||||
|
|
||||||
|
### `GET /contacts_lists/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Show a contacts list.
|
||||||
|
|
||||||
|
### `POST /contacts_lists`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Create a contacts list.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `title` **required**
|
||||||
|
* `description` **required**
|
||||||
|
|
||||||
|
### `PUT /contacts_lists/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Update a contacts list.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `title` **required**
|
||||||
|
* `description` **required**
|
||||||
|
|
||||||
|
### `DELETE /contacts_lists/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Delete a contacts list.
|
||||||
|
|
||||||
|
### `POST /contacts_lists/{contacts_list_id}/contacts/{contact_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Add a contact to the contacts list.
|
||||||
|
|
||||||
|
### `DELETE /contacts_lists/{contacts_list_id}/contacts/{contact_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Remove a contact from the contacts list.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/contacts_lists/{contacts_list_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Add a contacts list to the account.
|
||||||
|
|
||||||
|
### `DELETE /accounts/{id}/contacts_lists/{contacts_list_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Remove a contacts list from the account.
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
## Account dictionary
|
||||||
|
|
||||||
|
### `GET /accounts/{id}/dictionary`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Get all the account dictionary entries.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/dictionary/{key}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Add or update a new entry to the dictionary
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `value` **required**, the entry value
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
## Accounts email
|
||||||
|
|
||||||
|
### `POST /accounts/me/email/request`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Request to change the account email. An email will be sent to the new email address to confirm the operation.
|
||||||
|
|
||||||
|
Will return `403` if the account doesn't have a validated <a href='#account-creation-tokens'>Account Creation Token</a> attached to it.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `email` the new email address, must be unique if `ACCOUNT_EMAIL_UNIQUE` is set to `true`
|
||||||
|
|
||||||
|
### `POST /accounts/me/email`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Confirm the code received and change the email.
|
||||||
|
Activate the account.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `code` the code received by email
|
||||||
|
|
||||||
|
Return the updated account.
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
## Account external Account
|
||||||
|
|
||||||
|
### `GET /accounts/{id}/external`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Get the external account.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/external`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Create or update the external account.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `username` **required**
|
||||||
|
* `domain` **required**
|
||||||
|
* `password` **required**
|
||||||
|
* `realm` must be different than `domain`
|
||||||
|
* `registrar` must be different than `domain`
|
||||||
|
* `outbound_proxy` must be different than `domain`
|
||||||
|
* `protocol` **required**, must be `UDP`, `TCP` or `TLS`
|
||||||
|
|
||||||
|
### `DELETE /accounts/{id}/external`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Delete the external account.
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
## Account phone number
|
||||||
|
|
||||||
|
### `POST /accounts/me/phone/request`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Request a specific code by SMS to change the phone number.
|
||||||
|
|
||||||
|
Will return `403` if the account doesn't have a validated <a href='#account-creation-tokens'>Account Creation Token</a> attached to it.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `phone` the phone number to send the SMS
|
||||||
|
|
||||||
|
### `POST /accounts/me/phone`
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Confirm the code received and change the phone number.
|
||||||
|
Activate the account.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `code` the received SMS code
|
||||||
|
|
||||||
|
Return the updated account.
|
||||||
|
|
||||||
|
## Accounts devices
|
||||||
|
|
||||||
|
### `GET /accounts/{id/me}/devices`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Return the user registered devices.
|
||||||
|
|
||||||
|
### `DELETE /accounts/{id/me}/devices/{uuid}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Remove one of the user registered devices.
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
## Account Types
|
||||||
|
|
||||||
|
### `GET /account_types`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Show all the account types.
|
||||||
|
|
||||||
|
### `GET /account_types/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Show an account type.
|
||||||
|
|
||||||
|
### `POST /account_types`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Create an account type.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `key` **required**, alpha numeric with dashes, lowercase
|
||||||
|
|
||||||
|
### `PUT /account_types/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Update an account type.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `key` **required**, alpha numeric with dashes, lowercase
|
||||||
|
|
||||||
|
### `DELETE /account_types/{id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Delete an account type.
|
||||||
|
|
||||||
|
### `POST /accounts/{id}/types/{type_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Add a type to the account.
|
||||||
|
|
||||||
|
### `DELETE /accounts/{id}/contacts/{type_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Remove a type from the account.
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
## Account vCards storage
|
||||||
|
|
||||||
|
### `POST /accounts/{id/me}/vcards-storage`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Store a vCard.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `vcard`, mandatory, a valid vCard having a mandatory `UID` parameter that is uniquelly identifying it. This `UID` parameter will then be used to manipulate the vcard through the following endpoints as `uuid`.
|
||||||
|
|
||||||
|
### `PUT /accounts/{id/me}/vcards-storage/{uuid}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Update a vCard.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `vcard`, mandatory, a valid vCard having a mandatory `UID` parameter that is uniquelly identifying it and is the same as the `uuid` parameter.
|
||||||
|
|
||||||
|
### `GET /accounts/{id/me}/vcards-storage`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Return the list of stored vCards
|
||||||
|
|
||||||
|
### `GET /accounts/{id/me}/vcards-storage/{uuid}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Return a stored vCard
|
||||||
|
|
||||||
|
### `DELETE /accounts/{id/me}/vcards-storage/{uuid}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
<span class="badge badge-info">User</span>
|
||||||
|
|
||||||
|
Delete a stored vCard
|
||||||
95
flexiapi/resources/views/api/documentation/spaces.blade.php
Normal file
95
flexiapi/resources/views/api/documentation/spaces.blade.php
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
|
||||||
|
## Spaces
|
||||||
|
|
||||||
|
Manage the list of allowed `spaces`. The admin accounts declared with a `domain` that is a `super` `sip_domain` will become <span class="badge badge-error">Super Admin</span>.
|
||||||
|
|
||||||
|
### `GET /spaces`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Get the list of declared Spaces.
|
||||||
|
|
||||||
|
### `GET /spaces/{domain}`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Get a Space.
|
||||||
|
|
||||||
|
### `POST /spaces`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Create a new `space`.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `name` **required**, the space name
|
||||||
|
* `domain` **required**, the SIP domain to use, must be unique
|
||||||
|
* `host` **required**, the space host
|
||||||
|
* `account_proxy_registrar_address`, the account proxy registrar address
|
||||||
|
* `account_realm`, the default realm for the accounts, fallback to the domain if not set
|
||||||
|
* `assistant_disable_qr_code` boolean, disable the QR code feature in the assistant, default to `false`
|
||||||
|
* `assistant_hide_create_account` boolean, disable the account creation assistant, default to `false`
|
||||||
|
* `assistant_hide_third_party_account` boolean, disable the call recording feature, default to `false`
|
||||||
|
* `carddav_user_credentials` boolean, enable credentials for CardDav servers
|
||||||
|
* `copyright_text` text, the copyright text
|
||||||
|
* `custom_provisioning_entries` text, the custom configuration used for the provisioning
|
||||||
|
* `custom_provisioning_overwrite_all` boolean, allow the custom configuration to overwrite the default one
|
||||||
|
* `custom_theme` boolean, allow a custom CSS file to be loaded
|
||||||
|
* `disable_broadcast_feature` boolean, disable the broadcast feature, default to `true`
|
||||||
|
* `disable_call_recordings_feature` boolean, disable the call recording feature, default to `false`
|
||||||
|
* `disable_chat_feature` boolean, disable the chat feature, default to `false`
|
||||||
|
* `disable_meetings_feature` boolean, disable the meeting feature, default to `false`
|
||||||
|
* `expire_at` date, the moment the space is expiring, default to `null` (never expire)
|
||||||
|
* `hide_account_settings` boolean, disable the account settings, default to `false`
|
||||||
|
* `hide_settings` boolean, hide the app settings, default to `false`
|
||||||
|
* `intercom_features` boolean, the intercom features switch
|
||||||
|
* `intro_registration_text` Markdown text, the main registration page text
|
||||||
|
* `max_account` integer, the maximum number of accounts configurable in the app, default to `0` (infinite)
|
||||||
|
* `max_accounts` integer, the maximum number of accounts that can be created in the space, default to `0` (infinite), cannot be less than the actual amount of accounts
|
||||||
|
* `newsletter_registration_address`, the newsletter registration email address
|
||||||
|
* `only_display_sip_uri_username` boolean, hide the SIP uris in the app, default to `false`
|
||||||
|
* `phone_registration` boolean, the phone registration switch
|
||||||
|
* `provisioning_use_linphone_provisioning_header` boolean
|
||||||
|
* `public_registration` boolean, the public registration switch
|
||||||
|
* `super` boolean, set the domain as a Super Domain
|
||||||
|
* `web_panel` boolean, the web panel switch
|
||||||
|
|
||||||
|
### `PUT /spaces/{domain}`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Update an existing `sip_domain`.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `account_proxy_registrar_address`, **required**, the account proxy registrar address
|
||||||
|
* `account_realm`, **required**, the default realm for the accounts, fallback to the domain if not set
|
||||||
|
* `assistant_disable_qr_code` **required**, boolean
|
||||||
|
* `assistant_hide_create_account` **required**, boolean
|
||||||
|
* `assistant_hide_third_party_account` **required**, boolean
|
||||||
|
* `carddav_user_credentials` **required** boolean, enable credentials for CardDav servers
|
||||||
|
* `copyright_text` **required**, text, the copyright text
|
||||||
|
* `custom_provisioning_entries` **required**, text, the custom configuration used for the provisioning
|
||||||
|
* `custom_provisioning_overwrite_all` **required**, boolean, allow the custom configuration to overwrite the default one
|
||||||
|
* `custom_theme` **required**, boolean, allow a custom CSS file to be loaded
|
||||||
|
* `disable_broadcast_feature` **required**, boolean
|
||||||
|
* `disable_call_recordings_feature` **required**, boolean
|
||||||
|
* `disable_chat_feature` **required**, boolean
|
||||||
|
* `disable_meetings_feature` **required**, boolean
|
||||||
|
* `expire_at` **required**, date, the moment the space is expiring, set to `null` to never expire
|
||||||
|
* `hide_account_settings` **required**, boolean
|
||||||
|
* `hide_settings` **required**, boolean
|
||||||
|
* `intercom_features` **required**, boolean, the intercom features switch
|
||||||
|
* `intro_registration_text` **required**, Markdown text, the main registration page text
|
||||||
|
* `max_account` **required**, integer
|
||||||
|
* `max_accounts` **required**,integer, the maximum number of accounts that can be created in the space, default to `0` (infinite), cannot be less than the actual amount of accounts
|
||||||
|
* `name` **required**, the space name
|
||||||
|
* `newsletter_registration_address`, **required**, the newsletter registration email address
|
||||||
|
* `only_display_sip_uri_username` **required**, boolean
|
||||||
|
* `phone_registration` **required**, boolean, the phone registration switch
|
||||||
|
* `provisioning_use_linphone_provisioning_header` **required**, boolean
|
||||||
|
* `public_registration` **required**, boolean, the public registration switch
|
||||||
|
* `super` **required**, boolean, set the domain as a Super Domain
|
||||||
|
* `web_panel` **required**, boolean, the web panel switch
|
||||||
|
|
||||||
|
### `DELETE /spaces/{domain}`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Delete a domain, **be careful, all the related accounts will also be destroyed**.
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
## Spaces CardDav Servers
|
||||||
|
|
||||||
|
### `GET /spaces/{domain}/carddavs`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
List current CardDavs servers.
|
||||||
|
|
||||||
|
### `GET /spaces/{domain}/carddavs/{id}`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Get a specific CardDav server.
|
||||||
|
|
||||||
|
### `POST /spaces/{domain}/carddavs`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Create a CardDav server configuration.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `uri` **required**, HTTP address of the server
|
||||||
|
* `port` **required**, integer, the port
|
||||||
|
* `enabled`, boolean
|
||||||
|
* `use_exact_match_policy`, boolean, whether match must be exact or approximate
|
||||||
|
* `min_characters`, integer, min characters to search
|
||||||
|
* `results_limit`, integer, limit the number of results, 0 to infinite
|
||||||
|
* `timeout`, integer, request timeout in seconds
|
||||||
|
* `delay`, integer, delay in milliseconds before submiting the request
|
||||||
|
* `fields_for_user_input`, comma separated list of vcard fields to match with user input
|
||||||
|
* `fields_for_domain`, comma separated list of vcard fields to match for SIP domain
|
||||||
|
|
||||||
|
### `PUT /spaces/{domain}/carddavs/{id}`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Update a CardDav server configuration.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `uri` **required**, HTTP address of the server
|
||||||
|
* `port` **required**, integer, the port
|
||||||
|
* `enabled`, boolean
|
||||||
|
* `use_exact_match_policy`, boolean, whether match must be exact or approximate
|
||||||
|
* `min_characters`, integer, min characters to search
|
||||||
|
* `results_limit`, integer, limit the number of results, 0 to infinite
|
||||||
|
* `timeout`, integer, request timeout in seconds
|
||||||
|
* `delay`, integer, delay in milliseconds before submiting the request
|
||||||
|
* `fields_for_user_input`, comma separated list of vcard fields to match with user input
|
||||||
|
* `fields_for_domain`, comma separated list of vcard fields to match for SIP domain
|
||||||
|
|
||||||
|
### `DELETE /spaces/{domain}/carddavs/{id}`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Delete a specific CardDav server configuration.
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
## Spaces Email Server
|
||||||
|
|
||||||
|
### `GET /spaces/{domain}/email`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Get a space email server configuration
|
||||||
|
|
||||||
|
### `POST /spaces/{domain}/email`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Update an existing a space email server configuration.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `host` **required**, the email server hostname
|
||||||
|
* `port` **required**, integer, the port
|
||||||
|
* `username`, the username
|
||||||
|
* `password`, the password
|
||||||
|
* `from_address`, email address, the sender email address
|
||||||
|
* `from_name`, the sender name
|
||||||
|
* `signature`, a text that will end every emails sent
|
||||||
|
|
||||||
|
### `DELETE /spaces/{domain}/email`
|
||||||
|
<span class="badge badge-error">Super Admin</span>
|
||||||
|
|
||||||
|
Delete the a space email server configuration.
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
## Statistics
|
||||||
|
|
||||||
|
FlexiAPI can record logs generated by the FlexiSIP server and compile them into statistics.
|
||||||
|
|
||||||
|
### `POST /statistics/messages`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
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
|
||||||
|
* `conference_id` string
|
||||||
|
|
||||||
|
### `PATCH /statistics/messages/{message_id}/to/{to}/devices/{device_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
### `POST /statistics/calls`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
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
|
||||||
|
* `ended_at` string, format ISO8601, when the call finished
|
||||||
|
* `conference_id` string
|
||||||
|
|
||||||
|
### `PATCH /statistics/calls/{call_id}/devices/{device_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Complete a call status.
|
||||||
|
|
||||||
|
JSON parameters:
|
||||||
|
|
||||||
|
* `rang_at` format ISO8601, when the device rang
|
||||||
|
* `invite_terminated`
|
||||||
|
* `at` format ISO8601, when the invitation ended
|
||||||
|
* `state` the termination state
|
||||||
|
|
||||||
|
### `PATCH /statistics/calls/{call_id}`
|
||||||
|
<span class="badge badge-warning">Admin</span>
|
||||||
|
|
||||||
|
Update a call when ending.
|
||||||
|
|
@ -1,118 +1,4 @@
|
||||||
# About & Auth.
|
@include('api.documentation.about_auth')
|
||||||
|
|
||||||
An API to deal with the Flexisip server.
|
|
||||||
|
|
||||||
The API is available under `/api`
|
|
||||||
|
|
||||||
A `content-type` and `accept` HTTP headers are REQUIRED to use the API properly
|
|
||||||
|
|
||||||
```
|
|
||||||
> GET /api/{endpoint}
|
|
||||||
> content-type: application/json
|
|
||||||
> accept: application/json
|
|
||||||
```
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
|
|
||||||
Restricted endpoints are protected using a DIGEST authentication or an API Key mechanisms.
|
|
||||||
|
|
||||||
### Access model
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
### Space expiration
|
|
||||||
|
|
||||||
<span class="badge badge-error">Super Admin</span> can configure and expiration date on Spaces (`expire_at`). If the Space is expired all the authenticated endpoint of the API will return `403`.
|
|
||||||
|
|
||||||
### Localization
|
|
||||||
|
|
||||||
You can add an [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) header to your request to translate the responses, and especially errors messages, in a specific language.
|
|
||||||
|
|
||||||
Currently supported languages: @php
|
|
||||||
echo implode(', ', config('app.authorized_locales'))
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
```
|
|
||||||
> GET /api/{endpoint}
|
|
||||||
> Accept-Language: fr
|
|
||||||
> …
|
|
||||||
|
|
||||||
< HTTP 422
|
|
||||||
< {
|
|
||||||
< "message": "Le champ pseudo est obligatoire.",
|
|
||||||
< "errors": {
|
|
||||||
< "username": [
|
|
||||||
< 0 => "Le champ pseudo est obligatoire."
|
|
||||||
< ]
|
|
||||||
< }
|
|
||||||
< }
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using the API Key
|
|
||||||
|
|
||||||
You can retrieve an API Key from your account panel or using <a href="#get-accountsmeapikey">the dedicated API endpoint</a>.
|
|
||||||
|
|
||||||
**When generated by a User account the generated API Key will be restricted to the IP that generates it and will be destroyed if not used after some times.**
|
|
||||||
|
|
||||||
**If you want a stable API Key, to integrate with another server component for example, you can generate one in the Administration Panel.**
|
|
||||||
|
|
||||||
You can then use your freshly generated key by adding a new `x-api-key` header to your API requests:
|
|
||||||
|
|
||||||
```
|
|
||||||
> GET /api/{endpoint}
|
|
||||||
> x-api-key: {your-api-key}
|
|
||||||
> …
|
|
||||||
```
|
|
||||||
|
|
||||||
Or using a cookie:
|
|
||||||
|
|
||||||
```
|
|
||||||
> GET /api/{endpoint}
|
|
||||||
> Cookie: x-api-key={your-api-key}
|
|
||||||
> …
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using a JWT token
|
|
||||||
|
|
||||||
You can use a <a href="https://jwt.io/">JWT</a> token to authenticate on the API.
|
|
||||||
|
|
||||||
To do so you MUST inject it as an `Authorization: Bearer` header and configure the API with the public key of the token emitter.
|
|
||||||
|
|
||||||
```
|
|
||||||
> GET /api/{endpoint}
|
|
||||||
> Authorization: Bearer {your-jwt-token}
|
|
||||||
> …
|
|
||||||
```
|
|
||||||
|
|
||||||
The API will then check if the token was signed properly, is still valid and authenticate a user that is actually available in the system.
|
|
||||||
|
|
||||||
### Using DIGEST
|
|
||||||
|
|
||||||
To discover the available hashing algorythm you MUST send an unauthenticated request to one of the restricted endpoints.<br />
|
|
||||||
Only DIGEST-MD5 and DIGEST-SHA-256 are supported through the authentication layer.
|
|
||||||
|
|
||||||
A `from` (consisting of the user SIP address, prefixed with `sip:`) header is required to initiate the DIGEST flow.
|
|
||||||
|
|
||||||
```
|
|
||||||
> GET /api/{restricted-endpoint}
|
|
||||||
> from: sip:foobar@sip.example.org
|
|
||||||
> …
|
|
||||||
|
|
||||||
< HTTP 401
|
|
||||||
< content-type: application/json
|
|
||||||
< www-authenticate: Digest realm=test,qop=auth,algorithm=MD5,nonce="{nonce}",opaque="{opaque}"
|
|
||||||
< www-authenticate: Digest realm=test,qop=auth,algorithm=SHA-256,nonce="{nonce}",opaque="{opaque}"
|
|
||||||
```
|
|
||||||
|
|
||||||
You can find more documentation on the related [IETF RFC-7616](https://tools.ietf.org/html/rfc7616).
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
# Endpoints
|
# Endpoints
|
||||||
|
|
||||||
|
|
@ -123,709 +9,35 @@ You can find more documentation on the related [IETF RFC-7616](https://tools.iet
|
||||||
|
|
||||||
Returns `pong`
|
Returns `pong`
|
||||||
|
|
||||||
## Spaces
|
@include('api.documentation.spaces')
|
||||||
|
|
||||||
Manage the list of allowed `spaces`. The admin accounts declared with a `domain` that is a `super` `sip_domain` will become <span class="badge badge-error">Super Admin</span>.
|
@include('api.documentation.spaces.carddav')
|
||||||
|
|
||||||
### `GET /spaces`
|
@include('api.documentation.spaces.email')
|
||||||
<span class="badge badge-error">Super Admin</span>
|
|
||||||
|
|
||||||
Get the list of declared Spaces.
|
@include('api.documentation.account_tokens')
|
||||||
|
|
||||||
### `GET /spaces/{domain}`
|
@include('api.documentation.accounts')
|
||||||
<span class="badge badge-error">Super Admin</span>
|
|
||||||
|
|
||||||
Get a Space.
|
@include('api.documentation.accounts.actions')
|
||||||
|
|
||||||
### `POST /spaces`
|
@include('api.documentation.accounts.carddav_credentials')
|
||||||
<span class="badge badge-error">Super Admin</span>
|
|
||||||
|
|
||||||
Create a new `space`.
|
@include('api.documentation.accounts.contacts_lists')
|
||||||
|
|
||||||
JSON parameters:
|
@include('api.documentation.accounts.contacts')
|
||||||
|
|
||||||
* `name` **required**, the space name
|
@include('api.documentation.accounts.dictionary')
|
||||||
* `domain` **required**, the SIP domain to use, must be unique
|
|
||||||
* `host` **required**, the space host
|
|
||||||
* `super` 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)
|
|
||||||
* `max_accounts` integer, the maximum number of accounts that can be created in the space, default to `0` (infinite), cannot be less than the actual amount of accounts
|
|
||||||
* `expire_at` date, the moment the space is expiring, default to `null` (never expire)
|
|
||||||
* `copyright_text` text, the copyright text
|
|
||||||
* `intro_registration_text` Markdown text, the main registration page text
|
|
||||||
* `newsletter_registration_address`, the newsletter registration email address
|
|
||||||
* `account_proxy_registrar_address`, the account proxy registrar address
|
|
||||||
* `account_realm`, the default realm for the accounts, fallback to the domain if not set
|
|
||||||
* `custom_provisioning_entries` text, the custom configuration used for the provisioning
|
|
||||||
* `custom_provisioning_overwrite_all` boolean, allow the custom configuration to overwrite the default one
|
|
||||||
* `provisioning_use_linphone_provisioning_header` boolean
|
|
||||||
* `custom_theme` boolean, allow a custom CSS file to be loaded
|
|
||||||
* `web_panel` boolean, the web panel switch
|
|
||||||
* `public_registration` boolean, the public registration switch
|
|
||||||
* `phone_registration` boolean, the phone registration switch
|
|
||||||
* `intercom_features` boolean, the intercom features switch
|
|
||||||
|
|
||||||
### `PUT /spaces/{domain}`
|
@include('api.documentation.accounts.email')
|
||||||
<span class="badge badge-error">Super Admin</span>
|
|
||||||
|
|
||||||
Update an existing `sip_domain`.
|
@include('api.documentation.accounts.external_account')
|
||||||
|
|
||||||
JSON parameters:
|
@include('api.documentation.accounts.phone')
|
||||||
|
|
||||||
* `name` **required**, the space name
|
@include('api.documentation.accounts.types')
|
||||||
* `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
|
|
||||||
* `max_accounts` **required**,integer, the maximum number of accounts that can be created in the space, default to `0` (infinite), cannot be less than the actual amount of accounts
|
|
||||||
* `expire_at` **required**, date, the moment the space is expiring, set to `null` to never expire
|
|
||||||
* `copyright_text` **required**, text, the copyright text
|
|
||||||
* `intro_registration_text` **required**, Markdown text, the main registration page text
|
|
||||||
* `newsletter_registration_address`, **required**, the newsletter registration email address
|
|
||||||
* `account_proxy_registrar_address`, **required**, the account proxy registrar address
|
|
||||||
* `account_realm`, **required**, the default realm for the accounts, fallback to the domain if not set
|
|
||||||
* `custom_provisioning_entries` **required**, text, the custom configuration used for the provisioning
|
|
||||||
* `custom_provisioning_overwrite_all` **required**, boolean, allow the custom configuration to overwrite the default one
|
|
||||||
* `provisioning_use_linphone_provisioning_header` **required**, boolean
|
|
||||||
* `custom_theme` **required**, boolean, allow a custom CSS file to be loaded
|
|
||||||
* `web_panel` **required**, boolean, the web panel switch
|
|
||||||
* `public_registration` **required**, boolean, the public registration switch
|
|
||||||
* `phone_registration` **required**, boolean, the phone registration switch
|
|
||||||
* `intercom_features` **required**, boolean, the intercom features switch
|
|
||||||
|
|
||||||
### `DELETE /spaces/{domain}`
|
@include('api.documentation.accounts.vcards_storage')
|
||||||
<span class="badge badge-error">Super Admin</span>
|
|
||||||
|
|
||||||
Delete a domain, **be careful, all the related accounts will also be destroyed**.
|
|
||||||
|
|
||||||
### `GET /spaces/{domain}/email`
|
|
||||||
<span class="badge badge-error">Super Admin</span>
|
|
||||||
|
|
||||||
Get a space email server configuration
|
|
||||||
|
|
||||||
### `POST /spaces/{domain}/email`
|
|
||||||
<span class="badge badge-error">Super Admin</span>
|
|
||||||
|
|
||||||
Update an existing a space email server configuration.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `host` **required**, the email server hostname
|
|
||||||
* `port` **required**, integer, the port
|
|
||||||
* `username`, the username
|
|
||||||
* `password`, the password
|
|
||||||
* `from_address`, email address, the sender email address
|
|
||||||
* `from_name`, the sender name
|
|
||||||
* `signature`, a text that will end every emails sent
|
|
||||||
|
|
||||||
### `DELETE /spaces/{domain}/email`
|
|
||||||
<span class="badge badge-error">Super Admin</span>
|
|
||||||
|
|
||||||
Delete the a space email server configuration.
|
|
||||||
|
|
||||||
## Account Creation Request Tokens
|
|
||||||
|
|
||||||
An `account_creation_request_token` is a unique token that can be validated and then used to generate a valid `account_creation_token`.
|
|
||||||
|
|
||||||
### `POST /account_creation_request_tokens`
|
|
||||||
<span class="badge badge-success">Public</span>
|
|
||||||
|
|
||||||
Create and return an `account_creation_request_token` that should then be validated to be used.
|
|
||||||
|
|
||||||
## Account Creation Tokens
|
|
||||||
|
|
||||||
An `account_creation_token` is a unique token that allow the creation or the validation of a unique account.
|
|
||||||
|
|
||||||
### `POST /account_creation_tokens/send-by-push`
|
|
||||||
<span class="badge badge-success">Public</span>
|
|
||||||
|
|
||||||
Create and send an `account_creation_token` using a push notification to the device.
|
|
||||||
Return `403` if a token was already sent, or if the tokens limit is reached for this device.
|
|
||||||
Return `503` if the token was not successfully sent.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `pn_provider` **required**, the push notification provider, must be in apns.dev, apns or fcm
|
|
||||||
* `pn_param` the push notification parameter, can be null or contain only alphanumeric and underscore characters
|
|
||||||
* `pn_prid` the push notification unique id, can be null or contain only alphanumeric, dashes, underscore and colon characters
|
|
||||||
|
|
||||||
### `POST /account_creation_tokens/using-account-creation-request-token`
|
|
||||||
<span class="badge badge-success">Public</span>
|
|
||||||
|
|
||||||
Create an `account_creation_token` using an `account_creation_request_token`.
|
|
||||||
Return an `account_creation_token`.
|
|
||||||
Return `404` if the `account_creation_request_token` provided is not valid or expired otherwise.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `account_creation_request_token` **required**
|
|
||||||
|
|
||||||
### `POST /account_creation_tokens/consume`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Consume an `account_creation_token` and link it to the authenticated account.
|
|
||||||
Return an `account_creation_token`.
|
|
||||||
|
|
||||||
Return `404` if the `account_creation_token` provided is not valid.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `account_creation_token` **required**
|
|
||||||
|
|
||||||
### `POST /account_creation_tokens`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Create and return an `account_creation_token`.
|
|
||||||
|
|
||||||
## Account Recovery Tokens
|
|
||||||
|
|
||||||
An `account_recovery_token` is a unique token that allow the recovery of an account.
|
|
||||||
|
|
||||||
It can be used on the following page that also accepts a `phone` optional parameter to prefil the recovery form:
|
|
||||||
|
|
||||||
{{ route('account.recovery.show.phone', ['account_recovery_token' => '_the_token_']) }}
|
|
||||||
{{ route('account.recovery.show.phone', ['account_recovery_token' => '_the_token_', 'phone' => '+3312341234']) }}
|
|
||||||
|
|
||||||
### `POST /account_recovery_tokens/send-by-push`
|
|
||||||
<span class="badge badge-success">Public</span>
|
|
||||||
|
|
||||||
Create and send an `account_recovery_token` using a push notification to the device.
|
|
||||||
Return `403` if a token was already sent, or if the tokens limit is reached for this device.
|
|
||||||
Return `503` if the token was not successfully sent.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `pn_provider` **required**, the push notification provider, must be in apns.dev, apns or fcm
|
|
||||||
* `pn_param` the push notification parameter, can be null or contain only alphanumeric and underscore characters
|
|
||||||
* `pn_prid` the push notification unique id, can be null or contain only alphanumeric, dashes, underscore and colon characters
|
|
||||||
|
|
||||||
## Auth Tokens
|
|
||||||
|
|
||||||
### `POST /accounts/auth_token`
|
|
||||||
<span class="badge badge-success">Public</span>
|
|
||||||
|
|
||||||
Generate an `auth_token`. To attach the generated token to an account see [`auth_token` attachement endpoint](#get-accountsauthtokenauthtokenattach).
|
|
||||||
|
|
||||||
Return the `auth_token` object.
|
|
||||||
|
|
||||||
### `GET /accounts/auth_token/{auth_token}/attach`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Attach a publicly generated authentication token to the currently authenticated account.
|
|
||||||
|
|
||||||
Return `404` if the token is non existing or invalid.
|
|
||||||
|
|
||||||
## Accounts
|
|
||||||
|
|
||||||
### `POST /accounts/with-account-creation-token`
|
|
||||||
<span class="badge badge-success">Public</span>
|
|
||||||
|
|
||||||
Create an account using an `account_creation_token`.
|
|
||||||
|
|
||||||
Return `422` if the parameters are invalid or if the token is expired.
|
|
||||||
|
|
||||||
Return `403` if the `max_accounts` limit of the corresponding Space is reached.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `username` unique username, minimum 6 characters
|
|
||||||
* `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`
|
|
||||||
|
|
||||||
### `GET /accounts/{sip}/info`
|
|
||||||
<span class="badge badge-success">Public</span>
|
|
||||||
|
|
||||||
Retrieve public information about the account.
|
|
||||||
Return `404` if the account doesn't exists.
|
|
||||||
|
|
||||||
### `GET /accounts/me/api_key/{auth_token}`
|
|
||||||
<span class="badge badge-success">Public</span>
|
|
||||||
|
|
||||||
Generate and retrieve a fresh API Key from an `auth_token`. The `auth_token` must be attached to an existing account, see [`auth_token` attachement endpoint](#get-accountsauthtokenauthtokenattach) to do so.
|
|
||||||
|
|
||||||
Return `404` if the token is invalid or not attached.
|
|
||||||
|
|
||||||
This endpoint is also setting the API Key as a Cookie.
|
|
||||||
|
|
||||||
### `GET /accounts/me/api_key`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Generate and retrieve a fresh API Key.
|
|
||||||
This endpoint is also setting the API Key as a Cookie.
|
|
||||||
|
|
||||||
### `GET /accounts/me`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Retrieve the account information.
|
|
||||||
|
|
||||||
### `GET /accounts/me/services/turn`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
If configured, returns valid TURN credentials following the [draft-uberti-behave-turn-rest-00 IEFT Draft](https://datatracker.ietf.org/doc/html/draft-uberti-behave-turn-rest-00).
|
|
||||||
|
|
||||||
### `GET /accounts/me/provision`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Provision the account by generating a fresh `provisioning_token`.
|
|
||||||
|
|
||||||
Return the account object.
|
|
||||||
|
|
||||||
### `DELETE /accounts/me`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Delete the account.
|
|
||||||
|
|
||||||
### `POST /accounts/me/password`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
### `POST /accounts`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
To create an account directly from the API.
|
|
||||||
|
|
||||||
Return `403` if the `max_accounts` limit of the corresponding Space is reached.
|
|
||||||
|
|
||||||
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**, must exist in one of the configured Spaces. Only configurable if the admin is a super admin. Otherwise the SIP domain of the corresponding space is used.
|
|
||||||
* `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`
|
|
||||||
* `admin` optional, a boolean, set to `false` by default, create an admin account
|
|
||||||
* `phone` optional, a valid phone number, set a phone number to the account
|
|
||||||
* `dtmf_protocol` optional, values must be `sipinfo`, `sipmessage` or `rfc2833`
|
|
||||||
* `dictionary` optional, an associative array attached to the account, <a href="#dictionary">see also the related endpoints</a>.
|
|
||||||
|
|
||||||
### `PUT /accounts/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Update an existing account. Ensure to resend all the parameters to not reset them.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `username` unique username, minimum 6 characters
|
|
||||||
* `domain` **not configurable by default**, must exist in one of the configured Spaces. Only configurable if the admin is a super admin. Otherwise the SIP domain of the corresponding space is used.
|
|
||||||
* `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
|
|
||||||
* `phone` optional, a valid phone number, set a phone number to the account
|
|
||||||
* `dtmf_protocol` optional, values must be `sipinfo`, `sipmessage` or `rfc2833`
|
|
||||||
|
|
||||||
Using this endpoint you can also set a fresh dictionnary if the parameter is set. The existing dictionary entries will be destroyed.
|
|
||||||
|
|
||||||
* `dictionary` optional, an associative array attached to the account, <a href="#dictionary">see also the related endpoints</a>.
|
|
||||||
|
|
||||||
This endpoint also return the current `phone_change_code` and `email_change_code` if they are available.
|
|
||||||
|
|
||||||
### `GET /accounts`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Retrieve all the accounts, paginated.
|
|
||||||
|
|
||||||
### `GET /accounts/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Retrieve a specific account.
|
|
||||||
|
|
||||||
### `GET /accounts/{sip}/search`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Search for a specific account by sip address.
|
|
||||||
|
|
||||||
### `GET /accounts/{email}/search-by-email`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Search for a specific account by email.
|
|
||||||
|
|
||||||
### `DELETE /accounts/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Delete a specific account and its related information.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/activate`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Activate an account.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/deactivate`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Deactivate an account.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/block`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Block an account.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/unblock`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Unblock an account.
|
|
||||||
|
|
||||||
### `GET /accounts/{id}/provision`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Provision an account by generating a fresh `provisioning_token`.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/send_provisioning_email`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Send a provisioning email to the account.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/send_reset_password_email`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Send a password reset email to the account.
|
|
||||||
|
|
||||||
## Accounts email
|
|
||||||
|
|
||||||
### `POST /accounts/me/email/request`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Request to change the account email. An email will be sent to the new email address to confirm the operation.
|
|
||||||
|
|
||||||
Will return `403` if the account doesn't have a validated <a href='#account-creation-tokens'>Account Creation Token</a> attached to it.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `email` the new email address, must be unique if `ACCOUNT_EMAIL_UNIQUE` is set to `true`
|
|
||||||
|
|
||||||
### `POST /accounts/me/email`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Confirm the code received and change the email.
|
|
||||||
Activate the account.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `code` the code received by email
|
|
||||||
|
|
||||||
Return the updated account.
|
|
||||||
|
|
||||||
## Accounts phone number
|
|
||||||
|
|
||||||
### `POST /accounts/me/phone/request`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Request a specific code by SMS to change the phone number.
|
|
||||||
|
|
||||||
Will return `403` if the account doesn't have a validated <a href='#account-creation-tokens'>Account Creation Token</a> attached to it.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `phone` the phone number to send the SMS
|
|
||||||
|
|
||||||
### `POST /accounts/me/phone`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Confirm the code received and change the phone number.
|
|
||||||
Activate the account.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `code` the received SMS code
|
|
||||||
|
|
||||||
Return the updated account.
|
|
||||||
|
|
||||||
## Accounts devices
|
|
||||||
|
|
||||||
### `GET /accounts/{id/me}/devices`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Return the user registered devices.
|
|
||||||
|
|
||||||
### `DELETE /accounts/{id/me}/devices/{uuid}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Remove one of the user registered devices.
|
|
||||||
|
|
||||||
## Account contacts
|
|
||||||
|
|
||||||
### `GET /accounts/me/contacts`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Return the user contacts.
|
|
||||||
|
|
||||||
### `GET /accounts/me/contacts/{sip}`
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Return a user contact.
|
|
||||||
|
|
||||||
## vCards storage
|
|
||||||
|
|
||||||
### `POST /accounts/{id/me}/vcards-storage`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Store a vCard.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `vcard`, mandatory, a valid vCard having a mandatory `UID` parameter that is uniquelly identifying it. This `UID` parameter will then be used to manipulate the vcard through the following endpoints as `uuid`.
|
|
||||||
|
|
||||||
### `PUT /accounts/{id/me}/vcards-storage/{uuid}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Update a vCard.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `vcard`, mandatory, a valid vCard having a mandatory `UID` parameter that is uniquelly identifying it and is the same as the `uuid` parameter.
|
|
||||||
|
|
||||||
### `GET /accounts/{id/me}/vcards-storage`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Return the list of stored vCards
|
|
||||||
|
|
||||||
### `GET /accounts/{id/me}/vcards-storage/{uuid}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Return a stored vCard
|
|
||||||
|
|
||||||
### `DELETE /accounts/{id/me}/vcards-storage/{uuid}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
<span class="badge badge-info">User</span>
|
|
||||||
|
|
||||||
Delete a stored vCard
|
|
||||||
|
|
||||||
## Contacts
|
|
||||||
|
|
||||||
### `GET /accounts/{id}/contacts`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Get all the account contacts.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/contacts/{contact_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Add a contact to the list.
|
|
||||||
|
|
||||||
### `DELETE /accounts/{id}/contacts/{contact_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Remove a contact from the list.
|
|
||||||
|
|
||||||
## Dictionary
|
|
||||||
|
|
||||||
### `GET /accounts/{id}/dictionary`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Get all the account dictionary entries.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/dictionary/{key}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Add or update a new entry to the dictionary
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `value` **required**, the entry value
|
|
||||||
|
|
||||||
## External Account
|
|
||||||
|
|
||||||
### `GET /accounts/{id}/external`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Get the external account.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/external`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Create or update the external account.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `username` **required**
|
|
||||||
* `domain` **required**
|
|
||||||
* `password` **required**
|
|
||||||
* `realm` must be different than `domain`
|
|
||||||
* `registrar` must be different than `domain`
|
|
||||||
* `outbound_proxy` must be different than `domain`
|
|
||||||
* `protocol` **required**, must be `UDP`, `TCP` or `TLS`
|
|
||||||
|
|
||||||
### `DELETE /accounts/{id}/external`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Delete the external account.
|
|
||||||
|
|
||||||
## Account Actions
|
|
||||||
|
|
||||||
The following endpoints will return `403 Forbidden` if the requested account doesn't have a DTMF protocol configured.
|
|
||||||
|
|
||||||
### `GET /accounts/{id}/actions`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Show an account related actions.
|
|
||||||
|
|
||||||
### `GET /accounts/{id}/actions/{action_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Show an account related action.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/actions/`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Create an account action.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `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>
|
|
||||||
|
|
||||||
Create an account action.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `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>
|
|
||||||
|
|
||||||
Delete an account related action.
|
|
||||||
|
|
||||||
## Contacts Lists
|
|
||||||
|
|
||||||
### `GET /contacts_lists`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Show all the contacts lists.
|
|
||||||
|
|
||||||
### `GET /contacts_lists/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Show a contacts list.
|
|
||||||
|
|
||||||
### `POST /contacts_lists`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Create a contacts list.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `title` **required**
|
|
||||||
* `description` **required**
|
|
||||||
|
|
||||||
### `PUT /contacts_lists/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Update a contacts list.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `title` **required**
|
|
||||||
* `description` **required**
|
|
||||||
|
|
||||||
### `DELETE /contacts_lists/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Delete a contacts list.
|
|
||||||
|
|
||||||
### `POST /contacts_lists/{contacts_list_id}/contacts/{contact_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Add a contact to the contacts list.
|
|
||||||
|
|
||||||
### `DELETE /contacts_lists/{contacts_list_id}/contacts/{contact_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Remove a contact from the contacts list.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/contacts_lists/{contacts_list_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Add a contacts list to the account.
|
|
||||||
|
|
||||||
### `DELETE /accounts/{id}/contacts_lists/{contacts_list_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Remove a contacts list from the account.
|
|
||||||
|
|
||||||
## Account Types
|
|
||||||
|
|
||||||
### `GET /account_types`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Show all the account types.
|
|
||||||
|
|
||||||
### `GET /account_types/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Show an account type.
|
|
||||||
|
|
||||||
### `POST /account_types`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Create an account type.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `key` **required**, alpha numeric with dashes, lowercase
|
|
||||||
|
|
||||||
### `PUT /account_types/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Update an account type.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `key` **required**, alpha numeric with dashes, lowercase
|
|
||||||
|
|
||||||
### `DELETE /account_types/{id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Delete an account type.
|
|
||||||
|
|
||||||
### `POST /accounts/{id}/types/{type_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Add a type to the account.
|
|
||||||
|
|
||||||
### `DELETE /accounts/{id}/contacts/{type_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Remove a type from the account.
|
|
||||||
|
|
||||||
## Messages
|
## Messages
|
||||||
|
|
||||||
|
|
@ -865,63 +77,8 @@ Return the list of Phone Countries and their current status.
|
||||||
|
|
||||||
If a country is deactivated all the new submitted phones submitted on the platform will be blocked.
|
If a country is deactivated all the new submitted phones submitted on the platform will be blocked.
|
||||||
|
|
||||||
## Statistics
|
|
||||||
|
|
||||||
FlexiAPI can record logs generated by the FlexiSIP server and compile them into statistics.
|
@include('api.documentation.statistics')
|
||||||
|
|
||||||
### `POST /statistics/messages`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
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
|
|
||||||
* `conference_id` string
|
|
||||||
|
|
||||||
### `PATCH /statistics/messages/{message_id}/to/{to}/devices/{device_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
### `POST /statistics/calls`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
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
|
|
||||||
* `ended_at` string, format ISO8601, when the call finished
|
|
||||||
* `conference_id` string
|
|
||||||
|
|
||||||
### `PATCH /statistics/calls/{call_id}/devices/{device_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Complete a call status.
|
|
||||||
|
|
||||||
JSON parameters:
|
|
||||||
|
|
||||||
* `rang_at` format ISO8601, when the device rang
|
|
||||||
* `invite_terminated`
|
|
||||||
* `at` format ISO8601, when the invitation ended
|
|
||||||
* `state` the termination state
|
|
||||||
|
|
||||||
### `PATCH /statistics/calls/{call_id}`
|
|
||||||
<span class="badge badge-warning">Admin</span>
|
|
||||||
|
|
||||||
Update a call when ending.
|
|
||||||
|
|
||||||
JSON parameters:
|
JSON parameters:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use App\Http\Controllers\Api\Account\VcardsStorageController;
|
use App\Http\Controllers\Api\Account\VcardsStorageController;
|
||||||
use App\Http\Controllers\Api\Admin\AccountActionController;
|
use App\Http\Controllers\Api\Admin\Account\ActionController;
|
||||||
use App\Http\Controllers\Api\Admin\AccountContactController;
|
use App\Http\Controllers\Api\Admin\Account\CardDavCredentialsController;
|
||||||
|
use App\Http\Controllers\Api\Admin\Account\ContactController;
|
||||||
|
use App\Http\Controllers\Api\Admin\Account\DictionaryController;
|
||||||
|
use App\Http\Controllers\Api\Admin\Account\TypeController;
|
||||||
use App\Http\Controllers\Api\Admin\AccountController as AdminAccountController;
|
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\ContactsListController;
|
||||||
use App\Http\Controllers\Api\Admin\ExternalAccountController;
|
use App\Http\Controllers\Api\Admin\ExternalAccountController;
|
||||||
|
use App\Http\Controllers\Api\Admin\Space\CardDavServerController;
|
||||||
|
use App\Http\Controllers\Api\Admin\Space\EmailServerController;
|
||||||
use App\Http\Controllers\Api\Admin\SpaceController;
|
use App\Http\Controllers\Api\Admin\SpaceController;
|
||||||
use App\Http\Controllers\Api\Admin\EmailServerController;
|
|
||||||
use App\Http\Controllers\Api\Admin\VcardsStorageController as AdminVcardsStorageController;
|
use App\Http\Controllers\Api\Admin\VcardsStorageController as AdminVcardsStorageController;
|
||||||
use App\Http\Controllers\Api\StatisticsMessageController;
|
|
||||||
use App\Http\Controllers\Api\StatisticsCallController;
|
use App\Http\Controllers\Api\StatisticsCallController;
|
||||||
|
use App\Http\Controllers\Api\StatisticsMessageController;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
Route::get('/', 'Api\ApiController@documentation')->name('api');
|
Route::get('/', 'Api\ApiController@documentation')->name('api');
|
||||||
|
|
@ -93,23 +95,19 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
|
||||||
|
|
||||||
// Super admin
|
// Super admin
|
||||||
Route::group(['middleware' => ['auth.super_admin']], function () {
|
Route::group(['middleware' => ['auth.super_admin']], function () {
|
||||||
Route::prefix('spaces')->controller(SpaceController::class)->group(function () {
|
Route::apiResource('spaces', SpaceController::class);
|
||||||
Route::get('/', 'index');
|
|
||||||
Route::get('{domain}', 'show');
|
|
||||||
Route::post('/', 'store');
|
|
||||||
Route::put('{domain}', 'update');
|
|
||||||
Route::delete('{domain}', 'destroy');
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::prefix('spaces/{domain}/email')->controller(EmailServerController::class)->group(function () {
|
Route::prefix('spaces/{domain}/email')->controller(EmailServerController::class)->group(function () {
|
||||||
Route::get('/', 'show');
|
Route::get('/', 'show');
|
||||||
Route::post('/', 'store');
|
Route::post('/', 'store');
|
||||||
Route::delete('/', 'destroy');
|
Route::delete('/', 'destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::apiResource('spaces/{domain}/carddavs', CardDavServerController::class);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Account creation token
|
// Account creation token
|
||||||
Route::post('account_creation_tokens', 'Api\Admin\AccountCreationTokenController@create');
|
Route::post('account_creation_tokens', 'Api\Admin\Account\CreationTokenController@create');
|
||||||
|
|
||||||
// Accounts
|
// Accounts
|
||||||
Route::prefix('accounts')->controller(AdminAccountController::class)->group(function () {
|
Route::prefix('accounts')->controller(AdminAccountController::class)->group(function () {
|
||||||
|
|
@ -140,15 +138,19 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
|
||||||
});
|
});
|
||||||
|
|
||||||
// Account contacts
|
// Account contacts
|
||||||
Route::prefix('accounts/{id}/contacts')->controller(AccountContactController::class)->group(function () {
|
Route::prefix('accounts/{id}/contacts')->controller(ContactController::class)->group(function () {
|
||||||
Route::get('/', 'index');
|
Route::get('/', 'index');
|
||||||
Route::get('{contact_id}', 'show');
|
Route::get('{contact_id}', 'show');
|
||||||
Route::post('{contact_id}', 'add');
|
Route::post('{contact_id}', 'add');
|
||||||
Route::delete('{contact_id}', 'remove');
|
Route::delete('{contact_id}', 'remove');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::apiResource('accounts/{id}/actions', AccountActionController::class);
|
Route::group(['middleware' => ['feature.carddav_user_credentials']], function () {
|
||||||
Route::apiResource('account_types', AccountTypeController::class);
|
Route::apiResource('accounts/{id}/carddavs', CardDavCredentialsController::class, ['only' => ['index', 'show', 'update', 'destroy']]);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::apiResource('accounts/{id}/actions', ActionController::class);
|
||||||
|
Route::apiResource('account_types', TypeController::class);
|
||||||
Route::apiResource('accounts/{account_id}/vcards-storage', AdminVcardsStorageController::class);
|
Route::apiResource('accounts/{account_id}/vcards-storage', AdminVcardsStorageController::class);
|
||||||
|
|
||||||
Route::apiResource('contacts_lists', ContactsListController::class);
|
Route::apiResource('contacts_lists', ContactsListController::class);
|
||||||
|
|
@ -157,7 +159,7 @@ Route::group(['middleware' => ['auth.jwt', 'auth.digest_or_key', 'auth.check_blo
|
||||||
Route::delete('{id}/contacts/{contacts_id}', 'contactRemove');
|
Route::delete('{id}/contacts/{contacts_id}', 'contactRemove');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::prefix('accounts/{id}/dictionary')->controller(AccountDictionaryController::class)->group(function () {
|
Route::prefix('accounts/{id}/dictionary')->controller(DictionaryController::class)->group(function () {
|
||||||
Route::get('/', 'index');
|
Route::get('/', 'index');
|
||||||
Route::get('{key}', 'show');
|
Route::get('{key}', 'show');
|
||||||
Route::post('{key}', 'set');
|
Route::post('{key}', 'set');
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,17 @@ use App\Http\Controllers\Account\PasswordController;
|
||||||
use App\Http\Controllers\Account\PhoneController;
|
use App\Http\Controllers\Account\PhoneController;
|
||||||
use App\Http\Controllers\Account\ProvisioningController;
|
use App\Http\Controllers\Account\ProvisioningController;
|
||||||
use App\Http\Controllers\Account\RecoveryController;
|
use App\Http\Controllers\Account\RecoveryController;
|
||||||
use App\Http\Controllers\Admin\AccountAccountTypeController;
|
|
||||||
use App\Http\Controllers\Admin\AccountActionController;
|
|
||||||
use App\Http\Controllers\Admin\AccountActivityController;
|
|
||||||
use App\Http\Controllers\Admin\AccountContactController;
|
|
||||||
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
|
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
|
||||||
use App\Http\Controllers\Admin\AccountDeviceController;
|
use App\Http\Controllers\Admin\Account\AccountTypeController;
|
||||||
use App\Http\Controllers\Admin\AccountDictionaryController;
|
use App\Http\Controllers\Admin\Account\ActionController;
|
||||||
use App\Http\Controllers\Admin\AccountImportController;
|
use App\Http\Controllers\Admin\Account\ActivityController;
|
||||||
use App\Http\Controllers\Admin\AccountStatisticsController;
|
use App\Http\Controllers\Admin\Account\CardDavCredentialsController;
|
||||||
use App\Http\Controllers\Admin\AccountTypeController;
|
use App\Http\Controllers\Admin\Account\ContactController;
|
||||||
|
use App\Http\Controllers\Admin\Account\DeviceController as AdminAccountDeviceController;
|
||||||
|
use App\Http\Controllers\Admin\Account\DictionaryController;
|
||||||
|
use App\Http\Controllers\Admin\Account\ImportController;
|
||||||
|
use App\Http\Controllers\Admin\Account\StatisticsController as AdminAccountStatisticsController;
|
||||||
|
use App\Http\Controllers\Admin\Account\TypeController;
|
||||||
use App\Http\Controllers\Admin\ApiKeyController as AdminApiKeyController;
|
use App\Http\Controllers\Admin\ApiKeyController as AdminApiKeyController;
|
||||||
use App\Http\Controllers\Admin\ContactsListContactController;
|
use App\Http\Controllers\Admin\ContactsListContactController;
|
||||||
use App\Http\Controllers\Admin\ContactsListController;
|
use App\Http\Controllers\Admin\ContactsListController;
|
||||||
|
|
@ -44,6 +45,7 @@ use App\Http\Controllers\Admin\PhoneCountryController;
|
||||||
use App\Http\Controllers\Admin\ProvisioningEmailController;
|
use App\Http\Controllers\Admin\ProvisioningEmailController;
|
||||||
use App\Http\Controllers\Admin\ResetPasswordEmailController;
|
use App\Http\Controllers\Admin\ResetPasswordEmailController;
|
||||||
use App\Http\Controllers\Admin\Space\EmailServerController;
|
use App\Http\Controllers\Admin\Space\EmailServerController;
|
||||||
|
use App\Http\Controllers\Admin\Space\CardDavServerController;
|
||||||
use App\Http\Controllers\Admin\SpaceController;
|
use App\Http\Controllers\Admin\SpaceController;
|
||||||
use App\Http\Controllers\Admin\StatisticsController;
|
use App\Http\Controllers\Admin\StatisticsController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
@ -51,7 +53,7 @@ use Illuminate\Support\Facades\Route;
|
||||||
Route::redirect('/', 'login')->name('account.home');
|
Route::redirect('/', 'login')->name('account.home');
|
||||||
Route::get('about', 'AboutController@about')->name('about');
|
Route::get('about', 'AboutController@about')->name('about');
|
||||||
|
|
||||||
Route::middleware(['web_panel_enabled'])->group(function () {
|
Route::middleware(['feature.web_panel_enabled'])->group(function () {
|
||||||
Route::get('wizard/{provisioning_token}', 'Account\ProvisioningController@wizard')->name('provisioning.wizard');
|
Route::get('wizard/{provisioning_token}', 'Account\ProvisioningController@wizard')->name('provisioning.wizard');
|
||||||
|
|
||||||
Route::get('login', 'Account\AuthenticateController@login')->name('account.login');
|
Route::get('login', 'Account\AuthenticateController@login')->name('account.login');
|
||||||
|
|
@ -88,11 +90,11 @@ Route::name('provisioning.')->prefix('provisioning')->controller(ProvisioningCon
|
||||||
Route::get('/', 'show')->name('show');
|
Route::get('/', 'show')->name('show');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['web_panel_enabled'])->group(function () {
|
Route::middleware(['feature.web_panel_enabled'])->group(function () {
|
||||||
Route::middleware(['public_registration'])->group(function () {
|
Route::middleware(['feature.public_registration'])->group(function () {
|
||||||
Route::redirect('register', 'register/email')->name('account.register');
|
Route::redirect('register', 'register/email')->name('account.register');
|
||||||
|
|
||||||
Route::middleware(['phone_registration'])->group(function () {
|
Route::middleware(['feature.phone_registration'])->group(function () {
|
||||||
Route::get('register/phone', 'Account\RegisterController@registerPhone')->name('account.register.phone');
|
Route::get('register/phone', 'Account\RegisterController@registerPhone')->name('account.register.phone');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -117,7 +119,7 @@ Route::middleware(['web_panel_enabled'])->group(function () {
|
||||||
Route::post('/', 'store')->name('email.update');
|
Route::post('/', 'store')->name('email.update');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['phone_registration'])->group(function () {
|
Route::middleware(['feature.phone_registration'])->group(function () {
|
||||||
Route::prefix('phone')->controller(PhoneController::class)->group(function () {
|
Route::prefix('phone')->controller(PhoneController::class)->group(function () {
|
||||||
Route::get('change', 'change')->name('phone.change');
|
Route::get('change', 'change')->name('phone.change');
|
||||||
Route::post('change', 'requestChange')->name('phone.request_change');
|
Route::post('change', 'requestChange')->name('phone.request_change');
|
||||||
|
|
@ -169,6 +171,8 @@ Route::middleware(['web_panel_enabled'])->group(function () {
|
||||||
Route::get('delete', 'delete')->name('delete');
|
Route::get('delete', 'delete')->name('delete');
|
||||||
Route::delete('/', 'destroy')->name('destroy');
|
Route::delete('/', 'destroy')->name('destroy');
|
||||||
});
|
});
|
||||||
|
Route::resource('{space}/carddavs', CardDavServerController::class, ['except' => ['index', 'show']]);
|
||||||
|
Route::get('{space}/carddavs/{carddav}/delete', 'Admin\Space\CardDavServerController@delete')->name('carddavs.delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('api_keys.')->prefix('api_keys')->controller(AdminApiKeyController::class)->group(function () {
|
Route::name('api_keys.')->prefix('api_keys')->controller(AdminApiKeyController::class)->group(function () {
|
||||||
|
|
@ -205,14 +209,14 @@ Route::middleware(['web_panel_enabled'])->group(function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('account.')->prefix('accounts')->group(function () {
|
Route::name('account.')->prefix('accounts')->group(function () {
|
||||||
Route::name('import.')->prefix('import')->controller(AccountImportController::class)->group(function () {
|
Route::name('import.')->prefix('import')->controller(ImportController::class)->group(function () {
|
||||||
Route::get('/', 'create')->name('create');
|
Route::get('/', 'create')->name('create');
|
||||||
Route::post('/', 'store')->name('store');
|
Route::post('/', 'store')->name('store');
|
||||||
Route::post('handle', 'handle')->name('handle');
|
Route::post('handle', 'handle')->name('handle');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['intercom_features'])->group(function () {
|
Route::middleware(['feature.intercom'])->group(function () {
|
||||||
Route::name('type.')->prefix('types')->controller(AccountTypeController::class)->group(function () {
|
Route::name('type.')->prefix('types')->controller(TypeController::class)->group(function () {
|
||||||
Route::get('/', 'index')->name('index');
|
Route::get('/', 'index')->name('index');
|
||||||
Route::get('create', 'create')->name('create');
|
Route::get('create', 'create')->name('create');
|
||||||
Route::post('/', 'store')->name('store');
|
Route::post('/', 'store')->name('store');
|
||||||
|
|
@ -222,13 +226,13 @@ Route::middleware(['web_panel_enabled'])->group(function () {
|
||||||
Route::delete('{type_id}', 'destroy')->name('destroy');
|
Route::delete('{type_id}', 'destroy')->name('destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('account_type.')->prefix('{account}/types')->controller(AccountAccountTypeController::class)->group(function () {
|
Route::name('account_type.')->prefix('{account}/types')->controller(AccountTypeController::class)->group(function () {
|
||||||
Route::get('create', 'create')->name('create');
|
Route::get('create', 'create')->name('create');
|
||||||
Route::post('/', 'store')->name('store');
|
Route::post('/', 'store')->name('store');
|
||||||
Route::delete('{type_id}', 'destroy')->name('destroy');
|
Route::delete('{type_id}', 'destroy')->name('destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('action.')->prefix('{account}/actions')->controller(AccountActionController::class)->group(function () {
|
Route::name('action.')->prefix('{account}/actions')->controller(ActionController::class)->group(function () {
|
||||||
Route::get('create', 'create')->name('create');
|
Route::get('create', 'create')->name('create');
|
||||||
Route::post('/', 'store')->name('store');
|
Route::post('/', 'store')->name('store');
|
||||||
Route::get('{action_id}/edit', 'edit')->name('edit');
|
Route::get('{action_id}/edit', 'edit')->name('edit');
|
||||||
|
|
@ -268,7 +272,7 @@ Route::middleware(['web_panel_enabled'])->group(function () {
|
||||||
Route::get('send', 'send')->name('send');
|
Route::get('send', 'send')->name('send');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('contact.')->prefix('{account}/contacts')->controller(AccountContactController::class)->group(function () {
|
Route::name('contact.')->prefix('{account}/contacts')->controller(ContactController::class)->group(function () {
|
||||||
Route::get('/', 'index')->name('index');
|
Route::get('/', 'index')->name('index');
|
||||||
Route::get('create', 'create')->name('create');
|
Route::get('create', 'create')->name('create');
|
||||||
Route::post('/', 'store')->name('store');
|
Route::post('/', 'store')->name('store');
|
||||||
|
|
@ -276,12 +280,15 @@ Route::middleware(['web_panel_enabled'])->group(function () {
|
||||||
Route::delete('/', 'destroy')->name('destroy');
|
Route::delete('/', 'destroy')->name('destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('device.')->prefix('{account}/devices')->controller(AccountDeviceController::class)->group(function () {
|
Route::name('device.')->prefix('{account}/devices')->controller(AdminAccountDeviceController::class)->group(function () {
|
||||||
Route::get('{device_id}/delete', 'delete')->name('delete');
|
Route::get('{device_id}/delete', 'delete')->name('delete');
|
||||||
Route::delete('/', 'destroy')->name('destroy');
|
Route::delete('/', 'destroy')->name('destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('dictionary.')->prefix('{account}/dictionary')->controller(AccountDictionaryController::class)->group(function () {
|
Route::resource('{account}/carddavs', CardDavCredentialsController::class, ['only' => ['create', 'store', 'destroy']]);
|
||||||
|
Route::get('{account}/carddavs/{carddav}/delete', 'Admin\Account\CardDavCredentialsController@delete')->name('carddavs.delete');
|
||||||
|
|
||||||
|
Route::name('dictionary.')->prefix('{account}/dictionary')->controller(DictionaryController::class)->group(function () {
|
||||||
Route::get('create', 'create')->name('create');
|
Route::get('create', 'create')->name('create');
|
||||||
Route::post('/', 'store')->name('store');
|
Route::post('/', 'store')->name('store');
|
||||||
Route::get('{entry}/edit', 'edit')->name('edit');
|
Route::get('{entry}/edit', 'edit')->name('edit');
|
||||||
|
|
@ -297,11 +304,11 @@ Route::middleware(['web_panel_enabled'])->group(function () {
|
||||||
Route::delete('/', 'destroy')->name('destroy');
|
Route::delete('/', 'destroy')->name('destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('activity.')->prefix('{account}/activity')->controller(AccountActivityController::class)->group(function () {
|
Route::name('activity.')->prefix('{account}/activity')->controller(ActivityController::class)->group(function () {
|
||||||
Route::get('/', 'index')->name('index');
|
Route::get('/', 'index')->name('index');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::name('statistics.')->prefix('{account}/statistics')->controller(AccountStatisticsController::class)->group(function () {
|
Route::name('statistics.')->prefix('{account}/statistics')->controller(AdminAccountStatisticsController::class)->group(function () {
|
||||||
Route::get('/', 'show')->name('show');
|
Route::get('/', 'show')->name('show');
|
||||||
Route::post('call_logs', 'editCallLogs')->name('edit_call_logs');
|
Route::post('call_logs', 'editCallLogs')->name('edit_call_logs');
|
||||||
Route::get('call_logs', 'showCallLogs')->name('show_call_logs');
|
Route::get('call_logs', 'showCallLogs')->name('show_call_logs');
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue