Complete the authenticated account contacts tests and fix the related documentation

Cleanup the returned Vcard 4.0 formats
Implement the recently introducted REST endpoints in the admin panels
Add account actions logs to the new Controllers
This commit is contained in:
Timothée Jaussoin 2021-10-26 15:08:31 +02:00
parent 917ab3d123
commit 48323477cf
28 changed files with 930 additions and 123 deletions

View file

@ -9,6 +9,18 @@ class AccountAction extends Model
{
use HasFactory;
public static $protocols = ['sipinfo' => 'SIPInfo', 'rfc2833' => 'RFC2833'];
public static function protocolsRule()
{
return implode(',', array_keys(self::$protocols));
}
public function getResolvedProtocolAttribute()
{
return self::$protocols[$this->attributes['protocol']];
}
public function account()
{
return $this->belongsTo('App\Account');

View file

@ -0,0 +1,67 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2021 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Account;
use App\AccountType;
class AccountAccountTypeController extends Controller
{
public function create(Account $account)
{
return view('admin.account.account_type.create', [
'account' => $account,
'account_types' => AccountType::whereNotIn('id', function($query) use ($account) {
$query->select('account_type_id')
->from('account_account_type')
->where('account_id', $account->id);
})->pluck('key', 'id')
]);
}
public function store(Request $request, Account $account)
{
$request->validate([
'account_type_id' => ['required', 'exists:account_types,id'],
]);
$account->types()->detach($request->get('account_type_id'));
$account->types()->attach($request->get('account_type_id'));
$request->session()->flash('success', 'Type successfully added');
Log::channel('events')->info('Web Admin: Account type attached', ['id' => $account->identifier, 'type_id' => $request->get('account_type_id')]);
return redirect()->route('admin.account.show', $account);
}
public function destroy(Request $request, Account $account, int $typeId)
{
$account->types()->detach($typeId);
$request->session()->flash('success', 'Type successfully removed');
Log::channel('events')->info('Web Admin: Account type detached', ['id' => $account->identifier, 'type_id' => $request->get('account_type_id')]);
return redirect()->route('admin.account.show', $account);
}
}

View file

@ -0,0 +1,119 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2021 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Account;
use App\AccountAction;
use App\Rules\NoUppercase;
class AccountActionController extends Controller
{
public function create(Account $account)
{
return view('admin.account.action.create_edit', [
'action' => new AccountAction,
'account' => $account,
'protocols' => AccountAction::$protocols
]);
}
public function store(Request $request, Account $account)
{
$request->validate([
'key' => ['required', 'alpha_dash', new NoUppercase],
'code' => ['required', 'alpha_num', new NoUppercase],
'protocol' => 'required|in:' . AccountAction::protocolsRule()
]);
$accountAction = new AccountAction;
$accountAction->account_id = $account->id;
$accountAction->key = $request->get('key');
$accountAction->code = $request->get('code');
$accountAction->protocol = $request->get('protocol');
$accountAction->save();
$request->session()->flash('success', 'Action successfully created');
Log::channel('events')->info('Web Admin: Account action created', ['id' => $account->identifier, 'action' => $accountAction->key]);
return redirect()->route('admin.account.show', $accountAction->account);
}
public function edit(Account $account, int $actionId)
{
$accountAction = $account->actions()
->where('id', $actionId)
->firstOrFail();
return view('admin.account.action.create_edit', [
'action' => $accountAction,
'account' => $account,
'protocols' => AccountAction::$protocols
]);
}
public function update(Request $request, Account $account, int $actionId)
{
$request->validate([
'key' => ['alpha_dash', new NoUppercase],
'code' => ['alpha_num', new NoUppercase],
'protocol' => 'in:' . AccountAction::protocolsRule()
]);
$accountAction = $account->actions()
->where('id', $actionId)
->firstOrFail();
$accountAction->key = $request->get('key');
$accountAction->code = $request->get('code');
$accountAction->protocol = $request->get('protocol');
$accountAction->save();
$request->session()->flash('success', 'Action successfully updated');
Log::channel('events')->info('Web Admin: Account action updated', ['id' => $account->identifier, 'action' => $accountAction->key]);
return redirect()->route('admin.account.show', $account);
}
public function delete(Account $account, int $actionId)
{
return view('admin.account.action.delete', [
'action' => $account->actions()
->where('id', $actionId)
->firstOrFail()
]);
}
public function destroy(Request $request, Account $account, int $actionId)
{
$accountAction = $account->actions()
->where('id', $actionId)
->firstOrFail();
$accountAction->delete();
$request->session()->flash('success', 'Action successfully destroyed');
Log::channel('events')->info('Web Admin: Account action deleted', ['id' => $accountAction->account->identifier, 'action_id' => $accountAction->key]);
return redirect()->route('admin.account.show', $accountAction->account);
}
}

View file

@ -0,0 +1,78 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2021 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Account;
class AccountContactController extends Controller
{
public function create(Account $account)
{
return view('admin.account.contact.create', [
'account' => $account
]);
}
public function store(Request $request, Account $account)
{
$contact = Account::sip($request->get('sip'))->first();
if (!$contact) {
$request->session()->flash('error', 'The contact SIP address doesn\'t exists');
return redirect()->route('admin.account.contact.create', $account);
}
$account->contacts()->detach($contact->id);
$account->contacts()->attach($contact->id);
$request->session()->flash('success', 'Contact successfully added');
Log::channel('events')->info('Web Admin: Account contact added', ['id' => $account->identifier, 'contact' => $contact->identifier]);
return redirect()->route('admin.account.show', $account);
}
public function delete(Account $account, int $contactId)
{
$contact = $account->contacts()->where('id', $contactId)->firstOrFail();
return view('admin.account.contact.delete', [
'account' => $account,
'contact' => $contact
]);
}
public function destroy(Request $request, Account $account)
{
$contact = $account->contacts()->where('id', $request->get('contact_id'))->firstOrFail();
$account->contacts()->detach($contact->id);
$request->session()->flash('success', 'Type successfully removed');
Log::channel('events')->info('Web Admin: Account contact removed', ['id' => $account->identifier, 'contact' => $contact->identifier]);
return redirect()->route('admin.account.show', $account);
}
}

View file

@ -67,6 +67,7 @@ class AccountController extends Controller
$account = new Account;
$account->username = $request->get('username');
$account->email = $request->get('email');
$account->display_name = $request->get('display_name');
$account->domain = config('app.sip_domain');
$account->ip_address = $request->ip();
$account->creation_time = Carbon::now();
@ -93,6 +94,7 @@ class AccountController extends Controller
$account = Account::findOrFail($id);
$account->username = $request->get('username');
$account->email = $request->get('email');
$account->display_name = $request->get('display_name');
$account->save();
$this->fillPassword($request, $account);

View file

@ -0,0 +1,104 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2021 Belledonne Communications SARL, All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Rule;
use App\AccountType;
use App\Rules\NoUppercase;
class AccountTypeController extends Controller
{
public function index()
{
return view('admin.account.type.index', ['types' => AccountType::all()]);
}
public function create()
{
return view('admin.account.type.create_edit', [
'type' => new AccountType
]);
}
public function store(Request $request)
{
$request->validate([
'key' => ['required', 'alpha_dash', new NoUppercase, 'unique:account_types,key'],
]);
$accountType = new AccountType;
$accountType->key = $request->get('key');
$accountType->save();
$request->session()->flash('success', 'Type successfully created');
return redirect()->route('admin.account.type.index');
}
public function edit(int $typeId)
{
return view('admin.account.type.create_edit', [
'type' => AccountType::findOrFail($typeId)
]);
}
public function update(Request $request, int $typeId)
{
$request->validate([
'key' => [
'required',
'alpha_dash',
new NoUppercase,
Rule::unique('account_types')->ignore($typeId)
]
]);
$accountType = AccountType::findOrFail($typeId);
$accountType->key = $request->get('key');
$accountType->save();
$request->session()->flash('success', 'Type successfully updated');
return redirect()->route('admin.account.type.index');
}
public function delete(int $typeId)
{
return view('admin.account.type.delete', [
'type' => AccountType::findOrFail($typeId)
]);
}
public function destroy(Request $request, int $typeId)
{
$type = AccountType::findOrFail($typeId);
$type->delete();
$request->session()->flash('success', 'Type successfully destroyed');
Log::channel('events')->info('Web Admin: Account type deleted', ['type' => $type->key]);
return redirect()->route('admin.account.type.index');
}
}

View file

@ -46,7 +46,7 @@ class AccountActionController extends Controller
$request->validate([
'key' => ['required', 'alpha_dash', new NoUppercase],
'code' => ['required', 'alpha_num', new NoUppercase],
'protocol' => 'required|in:sipinfo,rfc2833'
'protocol' => 'required|in:' . AccountAction::protocolsRule()
]);
$accountAction = new AccountAction;
@ -64,7 +64,7 @@ class AccountActionController extends Controller
$request->validate([
'key' => ['alpha_dash', new NoUppercase],
'code' => ['alpha_num', new NoUppercase],
'protocol' => 'in:sipinfo,rfc2833'
'protocol' => 'in:' . AccountAction::protocolsRule()
]);
$accountAction = Account::findOrFail($id)

223
flexiapi/composer.lock generated
View file

@ -232,34 +232,30 @@
},
{
"name": "doctrine/inflector",
"version": "2.0.3",
"version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210"
"reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/9cf661f4eb38f7c881cac67c75ea9b00bf97b210",
"reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89",
"reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^7.0",
"phpstan/phpstan": "^0.11",
"phpstan/phpstan-phpunit": "^0.11",
"phpstan/phpstan-strict-rules": "^0.11",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
"doctrine/coding-standard": "^8.2",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpstan/phpstan-strict-rules": "^0.12",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
"vimeo/psalm": "^4.10"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Inflector\\": "lib/Doctrine/Inflector"
@ -307,7 +303,7 @@
],
"support": {
"issues": "https://github.com/doctrine/inflector/issues",
"source": "https://github.com/doctrine/inflector/tree/2.0.x"
"source": "https://github.com/doctrine/inflector/tree/2.0.4"
},
"funding": [
{
@ -323,7 +319,7 @@
"type": "tidelift"
}
],
"time": "2020-05-29T15:13:26+00:00"
"time": "2021-10-22T20:16:43+00:00"
},
{
"name": "doctrine/lexer",
@ -848,16 +844,16 @@
},
{
"name": "guzzlehttp/promises",
"version": "1.5.0",
"version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0"
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/136a635e2b4a49b9d79e9c8fee267ffb257fdba0",
"reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0",
"url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
"reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
"shasum": ""
},
"require": {
@ -912,7 +908,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.5.0"
"source": "https://github.com/guzzle/promises/tree/1.5.1"
},
"funding": [
{
@ -928,7 +924,7 @@
"type": "tidelift"
}
],
"time": "2021-10-07T13:05:22+00:00"
"time": "2021-10-22T20:56:57+00:00"
},
{
"name": "guzzlehttp/psr7",
@ -1042,16 +1038,16 @@
},
{
"name": "laravel/framework",
"version": "v8.64.0",
"version": "v8.68.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "3337c029e1bb31d9712d27437cc27010ba302c9e"
"reference": "abe985ff1fb82dd04aab03bc1dc56e83fe61a59f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/3337c029e1bb31d9712d27437cc27010ba302c9e",
"reference": "3337c029e1bb31d9712d27437cc27010ba302c9e",
"url": "https://api.github.com/repos/laravel/framework/zipball/abe985ff1fb82dd04aab03bc1dc56e83fe61a59f",
"reference": "abe985ff1fb82dd04aab03bc1dc56e83fe61a59f",
"shasum": ""
},
"require": {
@ -1065,14 +1061,14 @@
"league/commonmark": "^1.3|^2.0.2",
"league/flysystem": "^1.1",
"monolog/monolog": "^2.0",
"nesbot/carbon": "^2.31",
"nesbot/carbon": "^2.53.1",
"opis/closure": "^3.6",
"php": "^7.3|^8.0",
"psr/container": "^1.0",
"psr/log": "^1.0 || ^2.0",
"psr/simple-cache": "^1.0",
"ramsey/uuid": "^4.2.2",
"swiftmailer/swiftmailer": "^6.0",
"swiftmailer/swiftmailer": "^6.3",
"symfony/console": "^5.1.4",
"symfony/error-handler": "^5.1.4",
"symfony/finder": "^5.1.4",
@ -1127,22 +1123,23 @@
"illuminate/view": "self.version"
},
"require-dev": {
"aws/aws-sdk-php": "^3.189.0",
"aws/aws-sdk-php": "^3.198.1",
"doctrine/dbal": "^2.13.3|^3.1.2",
"filp/whoops": "^2.8",
"filp/whoops": "^2.14.3",
"guzzlehttp/guzzle": "^6.5.5|^7.0.1",
"league/flysystem-cached-adapter": "^1.0",
"mockery/mockery": "^1.4.4",
"orchestra/testbench-core": "^6.23",
"pda/pheanstalk": "^4.0",
"phpunit/phpunit": "^8.5.19|^9.5.8",
"predis/predis": "^1.1.2",
"predis/predis": "^1.1.9",
"symfony/cache": "^5.1.4"
},
"suggest": {
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.189.0).",
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.198.1).",
"brianium/paratest": "Required to run tests in parallel (^6.0).",
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.2).",
"ext-bcmath": "Required to use the multiple_of validation rule.",
"ext-ftp": "Required to use the Flysystem FTP driver.",
"ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().",
"ext-memcached": "Required to use the memcache cache driver.",
@ -1150,7 +1147,7 @@
"ext-posix": "Required to use all features of the queue worker.",
"ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).",
"fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).",
"filp/whoops": "Required for friendly error pages in development (^2.8).",
"filp/whoops": "Required for friendly error pages in development (^2.14.3).",
"guzzlehttp/guzzle": "Required to use the HTTP Client, Mailgun mail driver and the ping methods on schedules (^6.5.5|^7.0.1).",
"laravel/tinker": "Required to use the tinker console command (^2.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).",
@ -1160,7 +1157,7 @@
"nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).",
"pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).",
"phpunit/phpunit": "Required to use assertions and run tests (^8.5.19|^9.5.8).",
"predis/predis": "Required to use the predis connector (^1.1.2).",
"predis/predis": "Required to use the predis connector (^1.1.9).",
"psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
"pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0|^5.0|^6.0).",
"symfony/cache": "Required to PSR-6 cache bridge (^5.1.4).",
@ -1209,7 +1206,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2021-10-12T13:43:13+00:00"
"time": "2021-10-27T12:31:46+00:00"
},
{
"name": "laravel/serializable-closure",
@ -2695,16 +2692,16 @@
},
{
"name": "swiftmailer/swiftmailer",
"version": "v6.2.7",
"version": "v6.3.0",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "15f7faf8508e04471f666633addacf54c0ab5933"
"reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/15f7faf8508e04471f666633addacf54c0ab5933",
"reference": "15f7faf8508e04471f666633addacf54c0ab5933",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c",
"reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c",
"shasum": ""
},
"require": {
@ -2716,7 +2713,7 @@
},
"require-dev": {
"mockery/mockery": "^1.0",
"symfony/phpunit-bridge": "^4.4|^5.0"
"symfony/phpunit-bridge": "^4.4|^5.4"
},
"suggest": {
"ext-intl": "Needed to support internationalized email addresses"
@ -2754,7 +2751,7 @@
],
"support": {
"issues": "https://github.com/swiftmailer/swiftmailer/issues",
"source": "https://github.com/swiftmailer/swiftmailer/tree/v6.2.7"
"source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0"
},
"funding": [
{
@ -2766,20 +2763,20 @@
"type": "tidelift"
}
],
"time": "2021-03-09T12:30:35+00:00"
"time": "2021-10-18T15:26:12+00:00"
},
{
"name": "symfony/console",
"version": "v5.3.7",
"version": "v5.3.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "8b1008344647462ae6ec57559da166c2bfa5e16a"
"reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a",
"reference": "8b1008344647462ae6ec57559da166c2bfa5e16a",
"url": "https://api.github.com/repos/symfony/console/zipball/d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3",
"reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3",
"shasum": ""
},
"require": {
@ -2849,7 +2846,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.3.7"
"source": "https://github.com/symfony/console/tree/v5.3.10"
},
"funding": [
{
@ -2865,7 +2862,7 @@
"type": "tidelift"
}
],
"time": "2021-08-25T20:02:16+00:00"
"time": "2021-10-26T09:30:15+00:00"
},
{
"name": "symfony/css-selector",
@ -3374,16 +3371,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v5.3.7",
"version": "v5.3.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5"
"reference": "9f34f02e8a5fdc7a56bafe011cea1ce97300e54c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/e36c8e5502b4f3f0190c675f1c1f1248a64f04e5",
"reference": "e36c8e5502b4f3f0190c675f1c1f1248a64f04e5",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/9f34f02e8a5fdc7a56bafe011cea1ce97300e54c",
"reference": "9f34f02e8a5fdc7a56bafe011cea1ce97300e54c",
"shasum": ""
},
"require": {
@ -3427,7 +3424,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v5.3.7"
"source": "https://github.com/symfony/http-foundation/tree/v5.3.10"
},
"funding": [
{
@ -3443,20 +3440,20 @@
"type": "tidelift"
}
],
"time": "2021-08-27T11:20:35+00:00"
"time": "2021-10-11T15:41:55+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v5.3.9",
"version": "v5.3.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "ceaf46a992f60e90645e7279825a830f733a17c5"
"reference": "703e4079920468e9522b72cf47fd76ce8d795e86"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/ceaf46a992f60e90645e7279825a830f733a17c5",
"reference": "ceaf46a992f60e90645e7279825a830f733a17c5",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/703e4079920468e9522b72cf47fd76ce8d795e86",
"reference": "703e4079920468e9522b72cf47fd76ce8d795e86",
"shasum": ""
},
"require": {
@ -3539,7 +3536,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v5.3.9"
"source": "https://github.com/symfony/http-kernel/tree/v5.3.10"
},
"funding": [
{
@ -3555,7 +3552,7 @@
"type": "tidelift"
}
],
"time": "2021-09-28T10:25:11+00:00"
"time": "2021-10-29T08:36:48+00:00"
},
{
"name": "symfony/mime",
@ -4681,16 +4678,16 @@
},
{
"name": "symfony/string",
"version": "v5.3.7",
"version": "v5.3.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5"
"reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5",
"reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5",
"url": "https://api.github.com/repos/symfony/string/zipball/d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c",
"reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c",
"shasum": ""
},
"require": {
@ -4744,7 +4741,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v5.3.7"
"source": "https://github.com/symfony/string/tree/v5.3.10"
},
"funding": [
{
@ -4760,20 +4757,20 @@
"type": "tidelift"
}
],
"time": "2021-08-26T08:00:08+00:00"
"time": "2021-10-27T18:21:46+00:00"
},
{
"name": "symfony/translation",
"version": "v5.3.9",
"version": "v5.3.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "6e69f3551c1a3356cf6ea8d019bf039a0f8b6886"
"reference": "6ef197aea2ac8b9cd63e0da7522b3771714035aa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/6e69f3551c1a3356cf6ea8d019bf039a0f8b6886",
"reference": "6e69f3551c1a3356cf6ea8d019bf039a0f8b6886",
"url": "https://api.github.com/repos/symfony/translation/zipball/6ef197aea2ac8b9cd63e0da7522b3771714035aa",
"reference": "6ef197aea2ac8b9cd63e0da7522b3771714035aa",
"shasum": ""
},
"require": {
@ -4839,7 +4836,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/translation/tree/v5.3.9"
"source": "https://github.com/symfony/translation/tree/v5.3.10"
},
"funding": [
{
@ -4855,7 +4852,7 @@
"type": "tidelift"
}
],
"time": "2021-08-26T08:22:53+00:00"
"time": "2021-10-10T06:43:24+00:00"
},
{
"name": "symfony/translation-contracts",
@ -4937,16 +4934,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v5.3.8",
"version": "v5.3.10",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "eaaea4098be1c90c8285543e1356a09c8aa5c8da"
"reference": "875432adb5f5570fff21036fd22aee244636b7d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/eaaea4098be1c90c8285543e1356a09c8aa5c8da",
"reference": "eaaea4098be1c90c8285543e1356a09c8aa5c8da",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/875432adb5f5570fff21036fd22aee244636b7d1",
"reference": "875432adb5f5570fff21036fd22aee244636b7d1",
"shasum": ""
},
"require": {
@ -5005,7 +5002,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v5.3.8"
"source": "https://github.com/symfony/var-dumper/tree/v5.3.10"
},
"funding": [
{
@ -5021,7 +5018,7 @@
"type": "tidelift"
}
],
"time": "2021-09-24T15:59:58+00:00"
"time": "2021-10-26T09:30:15+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
@ -5290,23 +5287,23 @@
"packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.6.2",
"version": "v3.6.4",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "70b89754913fd89fef16d0170a91dbc2a5cd633a"
"reference": "3c2d678269ba60e178bcd93e36f6a91c36b727f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/70b89754913fd89fef16d0170a91dbc2a5cd633a",
"reference": "70b89754913fd89fef16d0170a91dbc2a5cd633a",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/3c2d678269ba60e178bcd93e36f6a91c36b727f1",
"reference": "3c2d678269ba60e178bcd93e36f6a91c36b727f1",
"shasum": ""
},
"require": {
"illuminate/routing": "^6|^7|^8",
"illuminate/session": "^6|^7|^8",
"illuminate/support": "^6|^7|^8",
"maximebf/debugbar": "^1.16.3",
"maximebf/debugbar": "^1.17.2",
"php": ">=7.2",
"symfony/debug": "^4.3|^5",
"symfony/finder": "^4.3|^5"
@ -5320,7 +5317,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.5-dev"
"dev-master": "3.6-dev"
},
"laravel": {
"providers": [
@ -5359,7 +5356,7 @@
],
"support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.2"
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.4"
},
"funding": [
{
@ -5371,7 +5368,7 @@
"type": "github"
}
],
"time": "2021-06-14T14:29:26+00:00"
"time": "2021-10-21T10:57:31+00:00"
},
{
"name": "doctrine/instantiator",
@ -5509,16 +5506,16 @@
},
{
"name": "facade/ignition",
"version": "2.15.0",
"version": "2.16.0",
"source": {
"type": "git",
"url": "https://github.com/facade/ignition.git",
"reference": "3ee6e94815462bcf09bca0efc1c9069685df8da3"
"reference": "23400e6cc565c9dcae2c53704b4de1c4870c0697"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/facade/ignition/zipball/3ee6e94815462bcf09bca0efc1c9069685df8da3",
"reference": "3ee6e94815462bcf09bca0efc1c9069685df8da3",
"url": "https://api.github.com/repos/facade/ignition/zipball/23400e6cc565c9dcae2c53704b4de1c4870c0697",
"reference": "23400e6cc565c9dcae2c53704b4de1c4870c0697",
"shasum": ""
},
"require": {
@ -5582,7 +5579,7 @@
"issues": "https://github.com/facade/ignition/issues",
"source": "https://github.com/facade/ignition"
},
"time": "2021-10-11T15:24:06+00:00"
"time": "2021-10-28T11:47:23+00:00"
},
{
"name": "facade/ignition-contracts",
@ -5816,21 +5813,21 @@
},
{
"name": "maximebf/debugbar",
"version": "v1.17.1",
"version": "v1.17.3",
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
"reference": "0a3532556be0145603f8a9de23e76dc28eed7054"
"reference": "e8ac3499af0ea5b440908e06cc0abe5898008b3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/0a3532556be0145603f8a9de23e76dc28eed7054",
"reference": "0a3532556be0145603f8a9de23e76dc28eed7054",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/e8ac3499af0ea5b440908e06cc0abe5898008b3c",
"reference": "e8ac3499af0ea5b440908e06cc0abe5898008b3c",
"shasum": ""
},
"require": {
"php": "^7.1|^8",
"psr/log": "^1.0",
"psr/log": "^1|^2|^3",
"symfony/var-dumper": "^2.6|^3|^4|^5"
},
"require-dev": {
@ -5875,9 +5872,9 @@
],
"support": {
"issues": "https://github.com/maximebf/php-debugbar/issues",
"source": "https://github.com/maximebf/php-debugbar/tree/v1.17.1"
"source": "https://github.com/maximebf/php-debugbar/tree/v1.17.3"
},
"time": "2021-08-01T09:19:02+00:00"
"time": "2021-10-19T12:33:27+00:00"
},
{
"name": "mockery/mockery",
@ -6262,16 +6259,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.2.2",
"version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "069a785b2141f5bcf49f3e353548dc1cce6df556"
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556",
"reference": "069a785b2141f5bcf49f3e353548dc1cce6df556",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
"shasum": ""
},
"require": {
@ -6282,7 +6279,8 @@
"webmozart/assert": "^1.9.1"
},
"require-dev": {
"mockery/mockery": "~1.3.2"
"mockery/mockery": "~1.3.2",
"psalm/phar": "^4.8"
},
"type": "library",
"extra": {
@ -6312,9 +6310,9 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master"
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0"
},
"time": "2020-09-03T19:13:55+00:00"
"time": "2021-10-19T17:43:47+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@ -6435,23 +6433,23 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.7",
"version": "9.2.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218"
"reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218",
"reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e",
"reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.12.0",
"nikic/php-parser": "^4.13.0",
"php": ">=7.3",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
@ -6500,7 +6498,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.8"
},
"funding": [
{
@ -6508,7 +6506,7 @@
"type": "github"
}
],
"time": "2021-09-17T05:39:03+00:00"
"time": "2021-10-30T08:01:38+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -7707,7 +7705,6 @@
"type": "github"
}
],
"abandoned": true,
"time": "2020-09-28T06:45:17+00:00"
},
{

Binary file not shown.

View file

@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class MakeAccountTypesKeyUnique extends Migration
{
public function up()
{
Schema::table('account_types', function (Blueprint $table) {
$table->unique('key');
});
}
public function down()
{
Schema::table('account_types', function (Blueprint $table) {
$table->dropUnique('account_types_key_unique');
});
}
}

View file

@ -9,7 +9,9 @@ class AccountTypeSeeder extends Seeder
{
public function run()
{
AccountType::create(['key' => 'phone']);
AccountType::create(['key' => 'door']);
AccountType::create(['key' => 'device_audio_intercom']);
AccountType::create(['key' => 'device_video_intercom']);
AccountType::create(['key' => 'device_security_camera']);
AccountType::create(['key' => 'device_internal_unit']);
}
}

View file

@ -99,6 +99,11 @@ input.form-control {
padding: 0 1.5rem;
}
.btn.btn-sm {
padding: 0 0.75rem;
line-height: 1.75rem;
}
.btn.btn-centered {
display: block;
margin: 1rem auto;

View file

@ -54,6 +54,12 @@
</div>
<p class="mb-1">Manage the Flexisip accounts</p>
</a>
<a href="{{ route('admin.account.type.index') }}" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Account types</h5>
</div>
<p class="mb-1">Manage the account types</p>
</a>
<a href="{{ route('admin.statistics.show.day') }}" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Statistics</h5>

View file

@ -0,0 +1,41 @@
@extends('layouts.account')
@section('breadcrumb')
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.show', $account->id) }}">{{ $account->identifier }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
Types
</li>
@endsection
@section('content')
<h2>Add a Type to the Account</h2>
@if ($account_types->count() == 0)
<div class="alert alert-secondary" role="alert">
No Account Type to add
</div>
@else
{!! Form::model($account, [
'route' => ['admin.account.account_type.store', $account->id],
'method' => 'post'
]) !!}
<div class="form-row">
<div class="form-group col-md-12">
{!! Form::label('account_type_id', 'Account Type') !!}
{!! Form::select('account_type_id', $account_types, null, ['class' => 'form-control']); !!}
</div>
</div>
{!! Form::submit('Add', ['class' => 'btn btn-success btn-centered']) !!}
{!! Form::close() !!}
@endif
@endsection

View file

@ -0,0 +1,49 @@
@extends('layouts.account')
@section('breadcrumb')
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.show', $account->id) }}">{{ $account->identifier }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
Actions
</li>
@endsection
@section('content')
@if ($action->id)
<h2>Edit an account action</h2>
@else
<h2>Create an account action</h2>
@endif
{!! Form::model($action, [
'route' => $action->id
? ['admin.account.action.update', $action->account->id, $action->id]
: ['admin.account.action.store', $account->id],
'method' => $action->id
? 'put'
: 'post'
]) !!}
<div class="form-row">
<div class="form-group col-md-12">
{!! Form::label('key', 'Key') !!}
{!! Form::text('key', $action->key, ['class' => 'form-control', 'placeholder' => 'action_key']); !!}
</div>
<div class="form-group col-md-12">
{!! Form::label('code', 'Code') !!}
{!! Form::text('code', $action->code, ['class' => 'form-control', 'placeholder' => '12ab45']); !!}
</div>
<div class="form-group col-md-12">
{!! Form::label('protocol', 'Protocol') !!}
{!! Form::select('protocol', $protocols, $action->protocol, ['class' => 'form-control']); !!}
</div>
</div>
{!! Form::submit(($action->id) ? 'Update' : 'Create', ['class' => 'btn btn-success btn-centered']) !!}
{!! Form::close() !!}
@endsection

View file

@ -0,0 +1,31 @@
@extends('layouts.account')
@section('breadcrumb')
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.show', $action->account) }}">{{ $action->account->identifier }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
Actions
</li>
<li class="breadcrumb-item active" aria-current="page">Delete</li>
@endsection
@section('content')
<h2>Delete an account action</h2>
{!! Form::open(['route' => ['admin.account.action.destroy', $action->account, $action], 'method' => 'delete']) !!}
<p>You are going to permanently delete the following account action. Please confirm your action.</p>
<p><b>{{ $action->key }}</b></p>
{!! Form::hidden('account_id', $action->account->id) !!}
{!! Form::hidden('action_id', $action->id) !!}
{!! Form::submit('Delete', ['class' => 'btn btn-danger btn-centered']) !!}
{!! Form::close() !!}
@endsection

View file

@ -0,0 +1,33 @@
@extends('layouts.account')
@section('breadcrumb')
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.show', $account->id) }}">{{ $account->identifier }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
Contacts
</li>
@endsection
@section('content')
<h2>Add a Contact to the Account</h2>
{!! Form::model($account, [
'route' => ['admin.account.contact.store', $account->id],
'method' => 'post'
]) !!}
<div class="form-row">
<div class="form-group col-md-12">
{!! Form::label('sip', 'Adresse SIP') !!}
{!! Form::text('sip', null, ['class' => 'form-control', 'placeholder' => 'username@server.com']); !!}
</div>
</div>
{!! Form::submit('Add', ['class' => 'btn btn-success btn-centered']) !!}
{!! Form::close() !!}
@endsection

View file

@ -0,0 +1,31 @@
@extends('layouts.account')
@section('breadcrumb')
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.show', $account) }}">{{ $account->identifier }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
Contacts
</li>
<li class="breadcrumb-item active" aria-current="page">Delete</li>
@endsection
@section('content')
<h2>Delete an account contact</h2>
{!! Form::open(['route' => ['admin.account.contact.destroy', $account], 'method' => 'delete']) !!}
<p>You are going to remove the following contact from the contact list. Please confirm your action.</p>
<p><b>{{ $contact->identifier }}</b></p>
{!! Form::hidden('account_id', $account->id) !!}
{!! Form::hidden('contact_id', $contact->id) !!}
{!! Form::submit('Remove', ['class' => 'btn btn-danger btn-centered']) !!}
{!! Form::close() !!}
@endsection

View file

@ -68,6 +68,11 @@
{!! Form::email('email', $account->email, ['class' => 'form-control', 'placeholder' => 'Email']); !!}
</div>
<div class="form-group col-md-6">
{!! Form::label('display_name', 'Display Name') !!}
{!! Form::text('display_name', $account->display_name, ['class' => 'form-control', 'placeholder' => 'John Doe']); !!}
</div>
<div class="form-group col-md-6">
{!! Form::label('phone', 'Phone') !!}
{!! Form::text('phone', $account->phone, ['class' => 'form-control', 'placeholder' => '+12123123']); !!}

View file

@ -16,7 +16,7 @@
{!! Form::open(['route' => 'admin.account.destroy', 'method' => 'delete']) !!}
<p>You are going to permanently delete the following account account. Please confirm your action.</p>
<p>You are going to permanently delete the following account. Please confirm your action.</p>
<p><b>{{ $account->identifier }}</b></p>
{!! Form::hidden('account_id', $account->id) !!}

View file

@ -25,7 +25,6 @@
</div>
</div>
<table class="table table-responsive-md">
<thead>
<tr>
@ -59,7 +58,6 @@
<td>{{ $account->creation_time}}</td>
</tr>
@endforeach
</tbody>
</table>

View file

@ -20,7 +20,8 @@
<b>Id:</b> {{ $account->id }}<br />
<b>Identifier:</b> {{ $account->identifier }}<br />
<b>Email:</b> <a href="mailto:{{ $account->email }}">{{ $account->email }}</a><br />
<b>Phone number:</b>@if ($account->alias) {{ $account->phone }} @else No number @endif
@if ($account->alias)<b>Phone number:</b> {{ $account->phone }}<br />@endif
@if ($account->display_name)<b>Display name:</b> {{ $account->display_name }}<br />@endif
</p>
@if ($account->sha256Password)
@ -43,8 +44,65 @@
<span class="badge badge-danger">Not Admin</span> <a href="{{ route('admin.account.admin', $account->id) }}">Add admin role</a>
@endif
<h3 class="mt-3">Contacts</h3>
<table class="table">
<tbody>
@foreach ($account->contacts as $contact)
<tr>
<th scope="row">{{ $contact->identifier }}</th>
<td>
<a class="btn btn-sm mr-2" href="{{ route('admin.account.contact.delete', [$account, $contact->id]) }}">Delete</a>
</td>
</tr>
@endforeach
</tbody>
</table>
<a class="btn btn-sm" href="{{ route('admin.account.contact.create', $account) }}">Add</a>
<h3 class="mt-3">Actions</h3>
<table class="table">
<tbody>
@foreach ($account->actions as $action)
<tr>
<th scope="row">{{ $action->key }}</th>
<td>{{ $action->code }}</td>
<td>{{ $action->resolvedProtocol }}</td>
<td>
<a class="btn btn-sm mr-2" href="{{ route('admin.account.action.edit', [$account, $action->id]) }}">Edit</a>
<a class="btn btn-sm mr-2" href="{{ route('admin.account.action.delete', [$account, $action->id]) }}">Delete</a>
</td>
</tr>
@endforeach
</tbody>
</table>
<a class="btn btn-sm" href="{{ route('admin.account.action.create', $account) }}">Add</a>
<h3 class="mt-3">Types</h3>
<table class="table">
<tbody>
@foreach ($account->types as $type)
<tr>
<th scope="row">{{ $type->key }}</th>
<td>
{!! Form::open(['route' => ['admin.account.account_type.destroy', $account, $type->id], 'method' => 'delete']) !!}
{!! Form::submit('Delete', ['class' => 'btn btn-sm mr-2']) !!}
{!! Form::close() !!}
</td>
</tr>
@endforeach
</tbody>
</table>
<a class="btn btn-sm" href="{{ route('admin.account.account_type.create', $account) }}">Add</a>
<h3 class="mt-3">Provisioning</h3>
@if ($account->confirmation_key)
<h3 class="mt-3">Provisioning</h3>
<p>Share the following picture with the user or the one-time-use link bellow.</p>
<img src="{{ route('provisioning.qrcode', $account->confirmation_key) }}"><br />

View file

@ -0,0 +1,38 @@
@extends('layouts.account')
@section('breadcrumb')
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
<a href="{{ route('admin.account.type.index') }}">Types</a>
</li>
@endsection
@section('content')
@if ($type->id)
<h2>Edit an account type</h2>
@else
<h2>Create an account type</h2>
@endif
{!! Form::model($type, [
'route' => $type->id
? ['admin.account.type.update', $type->id]
: ['admin.account.type.store'],
'method' => $type->id
? 'put'
: 'post'
]) !!}
<div class="form-row">
<div class="form-group col-md-12">
{!! Form::label('key', 'Key') !!}
{!! Form::text('key', $type->key, ['class' => 'form-control', 'placeholder' => 'type_key']); !!}
</div>
</div>
{!! Form::submit(($type->id) ? 'Update' : 'Create', ['class' => 'btn btn-success btn-centered']) !!}
{!! Form::close() !!}
@endsection

View file

@ -0,0 +1,28 @@
@extends('layouts.account')
@section('breadcrumb')
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.type.index') }}">Types</a>
</li>
<li class="breadcrumb-item" aria-current="page">
{{ $type->key }}
</li>
<li class="breadcrumb-item active" aria-current="page">Delete</li>
@endsection
@section('content')
<h2>Delete an account type</h2>
{!! Form::open(['route' => ['admin.account.type.destroy', $type->id], 'method' => 'delete']) !!}
<p>You are going to permanently delete the following type. Please confirm your action.</p>
<p><b>{{ $type->key }}</b></p>
{!! Form::submit('Delete', ['class' => 'btn btn-danger btn-centered']) !!}
{!! Form::close() !!}
@endsection

View file

@ -0,0 +1,44 @@
@extends('layouts.account')
@section('breadcrumb')
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item" aria-current="page">
<a href="{{ route('admin.account.type.index') }}">Types</a>
</li>
@endsection
@section('content')
<div class="row mb-2">
<div class="col-sm">
<a class="btn btn-success float-right" href="{{ route('admin.account.type.create') }}">Create</a>
<h2>Types</h2>
</div>
</div>
<table class="table table-responsive-md">
<thead>
<tr>
<th scope="col">Key</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach ($types as $type)
<tr>
<td>
{{ $type->key }}
</td>
<td>
<a class="btn btn-sm mr-2" href="{{ route('admin.account.type.edit', [$type->id]) }}">Edit</a>
<a class="btn btn-sm mr-2" href="{{ route('admin.account.type.delete', [$type->id]) }}">Delete</a>
</td>
</tr>
@endforeach
</tbody>
</table>
@endsection

View file

@ -8,6 +8,13 @@
</div>
@endif
@if (Session::has('error'))
<div class="alert alert-danger">
{{Session::get('error')}}
</div>
@endif
@if (Session::has('success'))
<div class="alert alert-success">
{{Session::get('success')}}

View file

@ -79,6 +79,26 @@ Route::group(['middleware' => 'auth.admin'], function () {
Route::get('admin/statistics/week', 'Admin\StatisticsController@showWeek')->name('admin.statistics.show.week');
Route::get('admin/statistics/month', 'Admin\StatisticsController@showMonth')->name('admin.statistics.show.month');
// Account types
Route::get('admin/accounts/types', 'Admin\AccountTypeController@index')->name('admin.account.type.index');
Route::get('admin/accounts/types/create', 'Admin\AccountTypeController@create')->name('admin.account.type.create');
Route::post('admin/accounts/types', 'Admin\AccountTypeController@store')->name('admin.account.type.store');
Route::get('admin/accounts/types/{type_id}/edit', 'Admin\AccountTypeController@edit')->name('admin.account.type.edit');
Route::put('admin/accounts/types/{type_id}', 'Admin\AccountTypeController@update')->name('admin.account.type.update');
Route::get('admin/accounts/types/{type_id}/delete', 'Admin\AccountTypeController@delete')->name('admin.account.type.delete');
Route::delete('admin/accounts/types/{type_id}', 'Admin\AccountTypeController@destroy')->name('admin.account.type.destroy');
Route::get('admin/accounts/{account}/types/create', 'Admin\AccountAccountTypeController@create')->name('admin.account.account_type.create');
Route::post('admin/accounts/{account}/types', 'Admin\AccountAccountTypeController@store')->name('admin.account.account_type.store');
Route::delete('admin/accounts/{account}/types/{type_id}', 'Admin\AccountAccountTypeController@destroy')->name('admin.account.account_type.destroy');
// Contacts
Route::get('admin/accounts/{account}/contacts/create', 'Admin\AccountContactController@create')->name('admin.account.contact.create');
Route::post('admin/accounts/{account}/contacts', 'Admin\AccountContactController@store')->name('admin.account.contact.store');
Route::get('admin/accounts/{account}/contacts/{contact_id}/delete', 'Admin\AccountContactController@delete')->name('admin.account.contact.delete');
Route::delete('admin/accounts/{account}/contacts', 'Admin\AccountContactController@destroy')->name('admin.account.contact.destroy');
// Accounts
Route::get('admin/accounts/{account}/show', 'Admin\AccountController@show')->name('admin.account.show');
Route::get('admin/accounts/{account}/activate', 'Admin\AccountController@activate')->name('admin.account.activate');
@ -100,4 +120,12 @@ Route::group(['middleware' => 'auth.admin'], function () {
Route::get('admin/accounts/{search?}', 'Admin\AccountController@index')->name('admin.account.index');
Route::post('admin/accounts/search', 'Admin\AccountController@search')->name('admin.account.search');
// Account actions
Route::get('admin/accounts/{account}/actions/create', 'Admin\AccountActionController@create')->name('admin.account.action.create');
Route::post('admin/accounts/{account}/actions', 'Admin\AccountActionController@store')->name('admin.account.action.store');
Route::get('admin/accounts/{account}/actions/{action_id}/edit', 'Admin\AccountActionController@edit')->name('admin.account.action.edit');
Route::put('admin/accounts/{account}/actions/{action_id}', 'Admin\AccountActionController@update')->name('admin.account.action.update');
Route::get('admin/accounts/{account}/actions/{action_id}/delete', 'Admin\AccountActionController@delete')->name('admin.account.action.delete');
Route::delete('admin/accounts/{account}/actions/{action_id}', 'Admin\AccountActionController@destroy')->name('admin.account.action.destroy');
});

View file

@ -8,7 +8,7 @@
#%define _datadir %{_datarootdir}
#%define _docdir %{_datadir}/doc
%define build_number 109
%define build_number 110
%define var_dir /var/opt/belledonne-communications
%define opt_dir /opt/belledonne-communications/share/flexisip-account-manager