mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Move the DTMF protocol from AccountAction to Account
Ensure that the account actions are not reachable if the account doesn't have the DTMF protocol configured Update the documentation Update the tests Fix migration for SQLite
This commit is contained in:
parent
f16776e29b
commit
717d3e3cc9
22 changed files with 202 additions and 169 deletions
4
Makefile
4
Makefile
|
|
@ -1,10 +1,10 @@
|
|||
$(eval GIT_DESCRIBE = $(shell sh -c "git describe"))
|
||||
OUTPUT_DIR = ${CURDIR}
|
||||
prepare:
|
||||
cd flexiapi && composer install --no-dev
|
||||
cd flexiapi && php composer.phar install --no-dev
|
||||
|
||||
prepare-dev:
|
||||
cd flexiapi && composer install
|
||||
cd flexiapi && php composer.phar install
|
||||
|
||||
package-common:
|
||||
rm -rf $(OUTPUT_DIR)/flexisip-account-manager
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ use App\Password;
|
|||
use App\EmailChanged;
|
||||
use App\Helpers\Utils;
|
||||
use App\Mail\ChangingEmail;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Account extends Authenticatable
|
||||
{
|
||||
|
|
@ -45,6 +46,8 @@ class Account extends Authenticatable
|
|||
];
|
||||
public $timestamps = false;
|
||||
|
||||
public static $dtmfProtocols = ['sipinfo' => 'SIPInfo', 'rfc2833' => 'RFC2833'];
|
||||
|
||||
/**
|
||||
* Scopes
|
||||
*/
|
||||
|
|
@ -79,7 +82,11 @@ class Account extends Authenticatable
|
|||
*/
|
||||
public function actions()
|
||||
{
|
||||
return $this->hasMany('App\AccountAction');
|
||||
return $this->hasMany('App\AccountAction')->whereIn('account_id', function ($query) {
|
||||
$query->select('id')
|
||||
->from('accounts')
|
||||
->whereNotNull('dtmf_protocol');
|
||||
});
|
||||
}
|
||||
|
||||
public function activationExpiration()
|
||||
|
|
@ -173,6 +180,16 @@ class Account extends Authenticatable
|
|||
return $this->passwords()->where('algorithm', 'SHA-256')->exists();
|
||||
}
|
||||
|
||||
public static function dtmfProtocolsRule()
|
||||
{
|
||||
return implode(',', array_keys(self::$dtmfProtocols));
|
||||
}
|
||||
|
||||
public function getResolvedDtmfProtocolAttribute()
|
||||
{
|
||||
return self::$dtmfProtocols[$this->attributes['dtmf_protocol']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
|
@ -249,6 +266,11 @@ FN:'.$this->attributes['display_name'];
|
|||
FN:'.$this->getIdentifierAttribute();
|
||||
}
|
||||
|
||||
if ($this->dtmf_protocol) {
|
||||
$vcard .= '
|
||||
X-LINPHONE-ACCOUNT-DTMF-PROTOCOL:'.$this->dtmf_protocol;
|
||||
}
|
||||
|
||||
if ($this->types->count() > 0) {
|
||||
$vcard .= '
|
||||
X-LINPHONE-ACCOUNT-TYPE:'.$this->types->implode('key', ',');
|
||||
|
|
@ -256,7 +278,7 @@ X-LINPHONE-ACCOUNT-TYPE:'.$this->types->implode('key', ',');
|
|||
|
||||
foreach ($this->actions as $action) {
|
||||
$vcard .= '
|
||||
X-LINPHONE-ACCOUNT-ACTION:'.$action->key.';'.$action->code.';'.$action->protocol;
|
||||
X-LINPHONE-ACCOUNT-ACTION:'.$action->key.';'.$action->code;
|
||||
}
|
||||
|
||||
return $vcard . '
|
||||
|
|
|
|||
|
|
@ -9,18 +9,6 @@ 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');
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ class AccountActionController extends Controller
|
|||
|
||||
return view('admin.account.action.create_edit', [
|
||||
'action' => new AccountAction,
|
||||
'account' => $account,
|
||||
'protocols' => AccountAction::$protocols
|
||||
'account' => $account
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -46,15 +45,13 @@ class AccountActionController extends Controller
|
|||
|
||||
$request->validate([
|
||||
'key' => ['required', 'alpha_dash', new NoUppercase],
|
||||
'code' => ['required', 'alpha_num', new NoUppercase],
|
||||
'protocol' => 'required|in:' . AccountAction::protocolsRule()
|
||||
'code' => ['required', 'alpha_num', new NoUppercase]
|
||||
]);
|
||||
|
||||
$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');
|
||||
|
|
@ -73,8 +70,7 @@ class AccountActionController extends Controller
|
|||
|
||||
return view('admin.account.action.create_edit', [
|
||||
'action' => $accountAction,
|
||||
'account' => $account,
|
||||
'protocols' => AccountAction::$protocols
|
||||
'account' => $account
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -84,8 +80,7 @@ class AccountActionController extends Controller
|
|||
|
||||
$request->validate([
|
||||
'key' => ['alpha_dash', new NoUppercase],
|
||||
'code' => ['alpha_num', new NoUppercase],
|
||||
'protocol' => 'in:' . AccountAction::protocolsRule()
|
||||
'code' => ['alpha_num', new NoUppercase]
|
||||
]);
|
||||
|
||||
$accountAction = $account->actions()
|
||||
|
|
@ -93,7 +88,6 @@ class AccountActionController extends Controller
|
|||
->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');
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ class AccountController extends Controller
|
|||
public function create(Request $request)
|
||||
{
|
||||
return view('admin.account.create_edit', [
|
||||
'account' => new Account
|
||||
'account' => new Account,
|
||||
'protocols' => [null => 'None'] + Account::$dtmfProtocols
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ class AccountController extends Controller
|
|||
$account->ip_address = $request->ip();
|
||||
$account->creation_time = Carbon::now();
|
||||
$account->user_agent = config('app.name');
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->save();
|
||||
|
||||
$this->fillPassword($request, $account);
|
||||
|
|
@ -87,7 +89,8 @@ class AccountController extends Controller
|
|||
public function edit(int $id)
|
||||
{
|
||||
return view('admin.account.create_edit', [
|
||||
'account' => Account::findOrFail($id)
|
||||
'account' => Account::findOrFail($id),
|
||||
'protocols' => [null => 'None'] + Account::$dtmfProtocols
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +100,7 @@ class AccountController extends Controller
|
|||
$account->username = $request->get('username');
|
||||
$account->email = $request->get('email');
|
||||
$account->display_name = $request->get('display_name');
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->save();
|
||||
|
||||
$this->fillPassword($request, $account);
|
||||
|
|
@ -201,20 +205,16 @@ class AccountController extends Controller
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
private function fillPassword(Request $request, int $id)
|
||||
private function fillPassword(Request $request, Account $account)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$algorithm = $request->has('password_sha256') ? 'SHA-256' : 'MD5';
|
||||
$account->updatePassword($request->get('password'), $algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
private function fillPhone(Request $request, int $id)
|
||||
private function fillPhone(Request $request, Account $account)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
|
||||
if ($request->filled('phone')) {
|
||||
$account->alias()->delete();
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ class AccountController extends Controller
|
|||
],
|
||||
'algorithm' => 'required|in:SHA-256,MD5',
|
||||
'password' => 'required|filled',
|
||||
'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(),
|
||||
'domain' => 'min:3',
|
||||
'token' => [
|
||||
'required',
|
||||
|
|
@ -91,6 +92,7 @@ class AccountController extends Controller
|
|||
$account->ip_address = $request->ip();
|
||||
$account->creation_time = Carbon::now();
|
||||
$account->user_agent = config('app.name');
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->confirmation_key = Str::random(WebAuthenticateController::$emailCodeSize);
|
||||
$account->save();
|
||||
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@ class AccountActionController extends Controller
|
|||
{
|
||||
public function index(int $id)
|
||||
{
|
||||
return Account::findOrFail($id)->actions;
|
||||
return $this->resolveAccount($id)->actions;
|
||||
}
|
||||
|
||||
public function get(int $id, int $actionId)
|
||||
{
|
||||
return Account::findOrFail($id)
|
||||
return $this->resolveAccount($id)
|
||||
->actions()
|
||||
->where('id', $actionId)
|
||||
->firstOrFail();
|
||||
|
|
@ -43,17 +43,17 @@ class AccountActionController extends Controller
|
|||
|
||||
public function store(Request $request, int $id)
|
||||
{
|
||||
$account = $this->resolveAccount($id);
|
||||
|
||||
$request->validate([
|
||||
'key' => ['required', 'alpha_dash', new NoUppercase],
|
||||
'code' => ['required', 'alpha_num', new NoUppercase],
|
||||
'protocol' => 'required|in:' . AccountAction::protocolsRule()
|
||||
'code' => ['required', 'alpha_num', new NoUppercase]
|
||||
]);
|
||||
|
||||
$accountAction = new AccountAction;
|
||||
$accountAction->account_id = Account::findOrFail($id)->id;
|
||||
$accountAction->account_id = $account->id;
|
||||
$accountAction->key = $request->get('key');
|
||||
$accountAction->code = $request->get('code');
|
||||
$accountAction->protocol = $request->get('protocol');
|
||||
$accountAction->save();
|
||||
|
||||
return $accountAction;
|
||||
|
|
@ -61,19 +61,19 @@ class AccountActionController extends Controller
|
|||
|
||||
public function update(Request $request, int $id, int $actionId)
|
||||
{
|
||||
$account = $this->resolveAccount($id);
|
||||
|
||||
$request->validate([
|
||||
'key' => ['alpha_dash', new NoUppercase],
|
||||
'code' => ['alpha_num', new NoUppercase],
|
||||
'protocol' => 'in:' . AccountAction::protocolsRule()
|
||||
'code' => ['alpha_num', new NoUppercase]
|
||||
]);
|
||||
|
||||
$accountAction = Account::findOrFail($id)
|
||||
$accountAction = $account
|
||||
->actions()
|
||||
->where('id', $actionId)
|
||||
->firstOrFail();
|
||||
$accountAction->key = $request->get('key');
|
||||
$accountAction->code = $request->get('code');
|
||||
$accountAction->protocol = $request->get('protocol');
|
||||
$accountAction->save();
|
||||
|
||||
return $accountAction;
|
||||
|
|
@ -81,9 +81,17 @@ class AccountActionController extends Controller
|
|||
|
||||
public function destroy(int $id, int $actionId)
|
||||
{
|
||||
return Account::findOrFail($id)
|
||||
return $this->resolveAccount($id)
|
||||
->actions()
|
||||
->where('id', $actionId)
|
||||
->delete();
|
||||
}
|
||||
|
||||
private function resolveAccount(int $id)
|
||||
{
|
||||
$account = Account::findOrFail($id);
|
||||
if ($account->dtmf_protocol == null) abort(403, 'DTMF Protocol must be configured');
|
||||
|
||||
return $account;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ class AccountController extends Controller
|
|||
'email' => 'email',
|
||||
'admin' => 'boolean|nullable',
|
||||
'activated' => 'boolean|nullable',
|
||||
'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(),
|
||||
'confirmation_key_expires' => [
|
||||
'date_format:Y-m-d H:i:s',
|
||||
'nullable',
|
||||
|
|
@ -127,6 +128,7 @@ class AccountController extends Controller
|
|||
? (bool)$request->get('activated')
|
||||
: false;
|
||||
$account->ip_address = $request->ip();
|
||||
$account->dtmf_protocol = $request->get('dtmf_protocol');
|
||||
$account->creation_time = Carbon::now();
|
||||
$account->domain = $request->has('domain') && config('app.admins_manage_multi_domains')
|
||||
? $request->get('domain')
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
use App\Account;
|
||||
use App\Rules\WithoutSpaces;
|
||||
|
||||
class CreateAccountRequest extends FormRequest
|
||||
|
|
@ -27,6 +28,7 @@ class CreateAccountRequest extends FormRequest
|
|||
'domain' => config('app.admins_manage_multi_domains') ? 'required' : '',
|
||||
'password' => 'required|min:3',
|
||||
'email' => 'nullable|email',
|
||||
'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(),
|
||||
'phone' => [
|
||||
'nullable',
|
||||
'unique:aliases,alias',
|
||||
|
|
|
|||
|
|
@ -3,8 +3,9 @@
|
|||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
use App\Account;
|
||||
use App\Rules\WithoutSpaces;
|
||||
|
||||
class UpdateAccountRequest extends FormRequest
|
||||
|
|
@ -27,6 +28,7 @@ class UpdateAccountRequest extends FormRequest
|
|||
'domain' => config('app.admins_manage_multi_domains') ? 'required' : '',
|
||||
'email' => 'nullable|email',
|
||||
'password_sha256' => 'nullable|min:3',
|
||||
'dtmf_protocol' => 'nullable|in:' . Account::dtmfProtocolsRule(),
|
||||
'phone' => [
|
||||
'nullable',
|
||||
Rule::unique('accounts', 'username')->where(function ($query) {
|
||||
|
|
|
|||
113
flexiapi/composer.lock
generated
113
flexiapi/composer.lock
generated
|
|
@ -183,79 +183,6 @@
|
|||
],
|
||||
"time": "2021-08-15T20:50:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/package-versions-deprecated",
|
||||
"version": "1.11.99.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/package-versions-deprecated.git",
|
||||
"reference": "b174585d1fe49ceed21928a945138948cb394600"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b174585d1fe49ceed21928a945138948cb394600",
|
||||
"reference": "b174585d1fe49ceed21928a945138948cb394600",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.1.0 || ^2.0",
|
||||
"php": "^7 || ^8"
|
||||
},
|
||||
"replace": {
|
||||
"ocramius/package-versions": "1.11.99"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "^1.9.3 || ^2.0@dev",
|
||||
"ext-zip": "^1.13",
|
||||
"phpunit/phpunit": "^6.5 || ^7"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "PackageVersions\\Installer",
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PackageVersions\\": "src/PackageVersions"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be"
|
||||
}
|
||||
],
|
||||
"description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/package-versions-deprecated/issues",
|
||||
"source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/composer",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-09-13T08:41:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dasprid/enum",
|
||||
"version": "1.0.3",
|
||||
|
|
@ -404,20 +331,20 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "3.2.1",
|
||||
"version": "3.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "4caf37acf14b513a91dd4f087f7eda424fa25542"
|
||||
"reference": "a4b37db6f186b6843474189b424aed6a7cc5de4b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/4caf37acf14b513a91dd4f087f7eda424fa25542",
|
||||
"reference": "4caf37acf14b513a91dd4f087f7eda424fa25542",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/a4b37db6f186b6843474189b424aed6a7cc5de4b",
|
||||
"reference": "a4b37db6f186b6843474189b424aed6a7cc5de4b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/package-versions-deprecated": "^1.11.99",
|
||||
"composer-runtime-api": "^2",
|
||||
"doctrine/cache": "^1.11|^2.0",
|
||||
"doctrine/deprecations": "^0.5.3",
|
||||
"doctrine/event-manager": "^1.0",
|
||||
|
|
@ -428,13 +355,13 @@
|
|||
"require-dev": {
|
||||
"doctrine/coding-standard": "9.0.0",
|
||||
"jetbrains/phpstorm-stubs": "2021.1",
|
||||
"phpstan/phpstan": "1.3.0",
|
||||
"phpstan/phpstan": "1.4.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.1",
|
||||
"phpunit/phpunit": "9.5.11",
|
||||
"psalm/plugin-phpunit": "0.16.1",
|
||||
"squizlabs/php_codesniffer": "3.6.2",
|
||||
"symfony/cache": "^5.2|^6.0",
|
||||
"symfony/console": "^2.0.5|^3.0|^4.0|^5.0|^6.0",
|
||||
"symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0",
|
||||
"vimeo/psalm": "4.16.1"
|
||||
},
|
||||
"suggest": {
|
||||
|
|
@ -495,7 +422,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/dbal/issues",
|
||||
"source": "https://github.com/doctrine/dbal/tree/3.2.1"
|
||||
"source": "https://github.com/doctrine/dbal/tree/3.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -511,7 +438,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-05T08:52:06+00:00"
|
||||
"time": "2022-01-18T00:13:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
|
|
@ -819,16 +746,16 @@
|
|||
},
|
||||
{
|
||||
"name": "dragonmantank/cron-expression",
|
||||
"version": "v3.3.0",
|
||||
"version": "v3.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dragonmantank/cron-expression.git",
|
||||
"reference": "63f2a76a045bac6ec93cc2daf2b534b412aa0313"
|
||||
"reference": "be85b3f05b46c39bbc0d95f6c071ddff669510fa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/63f2a76a045bac6ec93cc2daf2b534b412aa0313",
|
||||
"reference": "63f2a76a045bac6ec93cc2daf2b534b412aa0313",
|
||||
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/be85b3f05b46c39bbc0d95f6c071ddff669510fa",
|
||||
"reference": "be85b3f05b46c39bbc0d95f6c071ddff669510fa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -868,7 +795,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dragonmantank/cron-expression/issues",
|
||||
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.0"
|
||||
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -876,7 +803,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-14T16:02:05+00:00"
|
||||
"time": "2022-01-18T15:43:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "egulias/email-validator",
|
||||
|
|
@ -1455,16 +1382,16 @@
|
|||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v8.79.0",
|
||||
"version": "v8.80.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "8091f07558ff4a890435ff9d25fa9aca0189ad63"
|
||||
"reference": "8949a2e46b0f274f39c61eee8d5de1dc6a1f686b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/8091f07558ff4a890435ff9d25fa9aca0189ad63",
|
||||
"reference": "8091f07558ff4a890435ff9d25fa9aca0189ad63",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/8949a2e46b0f274f39c61eee8d5de1dc6a1f686b",
|
||||
"reference": "8949a2e46b0f274f39c61eee8d5de1dc6a1f686b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1624,7 +1551,7 @@
|
|||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2022-01-12T16:12:41+00:00"
|
||||
"time": "2022-01-18T15:51:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -38,6 +38,7 @@ class AccountFactory extends Factory
|
|||
'confirmation_key' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'ip_address' => $this->faker->ipv4,
|
||||
'creation_time' => $this->faker->dateTime,
|
||||
'dtmf_protocol' => Account::$dtmfProtocols[array_rand(Account::$dtmfProtocols)],
|
||||
'activated' => true
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class CreateContactsTable extends Migration
|
||||
{
|
||||
|
|
@ -47,7 +48,15 @@ class CreateContactsTable extends Migration
|
|||
->on('accounts')->onDelete('cascade');
|
||||
$table->string('key');
|
||||
$table->string('code');
|
||||
$table->string('protocol');
|
||||
|
||||
/**
|
||||
* See 2022_01_19_160606_move_protocol_from_account_actions_to_account.php
|
||||
* SQLite can't handle the migration in the testing pipeline, so we must
|
||||
* prevent the column to be created in the first place
|
||||
**/
|
||||
if (DB::getDriverName() !== 'sqlite') {
|
||||
$table->string('protocol');
|
||||
}
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class MoveProtocolFromAccountActionsToAccount extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->string('dtmf_protocol')->nullable();
|
||||
});
|
||||
|
||||
// See 2021_10_13_092937_create_contacts_table.php
|
||||
Schema::table('account_actions', function (Blueprint $table) {
|
||||
if (DB::getDriverName() !== 'sqlite') {
|
||||
$table->dropColumn('protocol');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
if (DB::getDriverName() !== 'sqlite') {
|
||||
$table->dropColumn('dtmf_protocol');
|
||||
}
|
||||
});
|
||||
|
||||
Schema::table('account_actions', function (Blueprint $table) {
|
||||
$table->string('protocol');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -37,10 +37,6 @@
|
|||
{!! 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']) !!}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="basic-addon1">@</span>
|
||||
</div>
|
||||
{!! Form::text('username', $account->domain ?? config('app.sip_domain'), ['class' => 'form-control', 'placeholder' => 'domain.com', 'required' => 'required']); !!}
|
||||
{!! Form::text('domain', $account->domain ?? config('app.sip_domain'), ['class' => 'form-control', 'placeholder' => 'domain.com', 'required' => 'required']); !!}
|
||||
@else
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text" id="basic-addon1">@ {{ config('app.sip_domain') }}</span>
|
||||
|
|
@ -70,6 +70,7 @@
|
|||
<div class="form-group col-md-12 mb-0">
|
||||
<h4>Optional</h4>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-6">
|
||||
{!! Form::label('email', 'Email') !!}
|
||||
{!! Form::email('email', $account->email, ['class' => 'form-control', 'placeholder' => 'Email']); !!}
|
||||
|
|
@ -84,6 +85,11 @@
|
|||
{!! Form::label('phone', 'Phone') !!}
|
||||
{!! Form::text('phone', $account->phone, ['class' => 'form-control', 'placeholder' => '+12123123']); !!}
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-6">
|
||||
{!! Form::label('dtmf_protocol', 'DTMF Protocol') !!}
|
||||
{!! Form::select('dtmf_protocol', $protocols, $account->dtmf_protocol, ['class' => 'form-control']); !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Form::submit(($account->id) ? 'Update' : 'Create', ['class' => 'btn btn-success btn-centered']) !!}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
<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>DTMF Protocol:</b> @if ($account->dtmf_protocol) {{ $account->resolvedDtmfProtocol }}@endif<br />
|
||||
@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>
|
||||
|
|
@ -63,13 +64,14 @@
|
|||
|
||||
<h3 class="mt-3">Actions</h3>
|
||||
|
||||
@if (!$account->dtmf_protocol)
|
||||
|
||||
<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>
|
||||
|
|
@ -81,6 +83,10 @@
|
|||
|
||||
<a class="btn btn-sm" href="{{ route('admin.account.action.create', $account) }}">Add</a>
|
||||
|
||||
@else
|
||||
<p>To manage actions, you must configure the DTMF protocol in the account settings.</p>
|
||||
@endif
|
||||
|
||||
<h3 class="mt-3">Types</h3>
|
||||
|
||||
<table class="table">
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ JSON parameters:
|
|||
* `algorithm` required, values can be `SHA-256` or `MD5`
|
||||
* `domain` **not configurable except during test deployments** the value is enforced to the default registration domain set in the global configuration
|
||||
* `token` the unique token
|
||||
* `dtmf_protocol` optional, values must be `sipinfo` or `rfc2833`
|
||||
|
||||
#### `GET /accounts/{sip}/info`
|
||||
Retrieve public information about the account.
|
||||
|
|
@ -179,6 +180,7 @@ The `domain` field is taken into account ONLY when `app.admins_manage_multi_doma
|
|||
* `display_name` optional, string
|
||||
* `admin` optional, a boolean, set to `false` by default, create an admin account
|
||||
* `phone` optional, a phone number, set a phone number to the account
|
||||
* `dtmf_protocol` optional, values must be `sipinfo` or `rfc2833`
|
||||
* `confirmation_key_expires` optional, a datetime of this format: Y-m-d H:i:s. Only used when `activated` is not used or `false`. Enforces an expiration date on the returned `confirmation_key`. After that datetime public email or phone activation endpoints will return `403`.
|
||||
|
||||
#### `GET /accounts`
|
||||
|
|
@ -212,6 +214,8 @@ Remove a contact from the list.
|
|||
|
||||
### Account Actions
|
||||
|
||||
The following endpoints will return `403 Forbidden` if the requested account doesn't have a DTMF protocol configured.
|
||||
|
||||
#### `GET /accounts/{id}/actions/`
|
||||
Show an account related actions.
|
||||
|
||||
|
|
@ -225,7 +229,6 @@ JSON parameters:
|
|||
|
||||
* `key` required, alpha numeric with dashes, lowercase
|
||||
* `code` required, alpha numeric, lowercase
|
||||
* `protocol` required, values must be `sipinfo` or `rfc2833`
|
||||
|
||||
#### `PUT /accounts/{id}/actions/{action_id}`
|
||||
Create an account action.
|
||||
|
|
@ -234,7 +237,6 @@ JSON parameters:
|
|||
|
||||
* `key` required, alpha numeric with dashes, lowercase
|
||||
* `code` required, alpha numeric, lowercase
|
||||
* `protocol` required, values must be `sipinfo` or `rfc2833`
|
||||
|
||||
#### `DELETE /accounts/{id}/actions/{action_id}`
|
||||
Delete an account related action.
|
||||
|
|
@ -311,5 +313,26 @@ Return the same base content as the previous URL and the account related informa
|
|||
### `GET /contacts/vcard`
|
||||
Return the authenticated user contacts list, in [vCard 4.0 format](https://datatracker.ietf.org/doc/html/rfc6350).
|
||||
|
||||
Here is the format of the vCard list returned by the endpoint:
|
||||
|
||||
```
|
||||
BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
KIND:individual
|
||||
IMPP:sip:schoen.tatyana@sip.linphone.org
|
||||
FN:schoen.tatyana@sip.linphone.org
|
||||
X-LINPHONE-ACCOUNT-DTMF-PROTOCOL:SIPInfo
|
||||
X-LINPHONE-ACCOUNT-TYPE:phone
|
||||
X-LINPHONE-ACCOUNT-ACTION:action_key;123
|
||||
END:VCARD
|
||||
BEGIN:VCARD
|
||||
VERSION:4.0
|
||||
KIND:individual
|
||||
IMPP:sip:dhand@sip.linphone.org
|
||||
FN:dhand@sip.linphone.org
|
||||
X-LINPHONE-ACCOUNT-DTMF-PROTOCOL:SIPInfo
|
||||
END:VCARD
|
||||
```
|
||||
|
||||
### `GET /contacts/vcard/{sip}`
|
||||
Return a specific user authenticated contact, in [vCard 4.0 format](https://datatracker.ietf.org/doc/html/rfc6350).
|
||||
|
|
@ -43,8 +43,7 @@ class AccountActionTest extends TestCase
|
|||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->id.'/actions', [
|
||||
'key' => '123',
|
||||
'code' => '123',
|
||||
'protocol' => 'sipinfo'
|
||||
'code' => '123'
|
||||
])
|
||||
->assertStatus(201);
|
||||
|
||||
|
|
@ -53,17 +52,7 @@ class AccountActionTest extends TestCase
|
|||
// Missing key
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->id.'/actions', [
|
||||
'code' => '123',
|
||||
'protocol' => 'sipinfo'
|
||||
])
|
||||
->assertStatus(422);
|
||||
|
||||
// Invalid protocol
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->id.'/actions', [
|
||||
'key' => 'abc1234',
|
||||
'code' => '123',
|
||||
'protocol' => 'wrong'
|
||||
'code' => '123'
|
||||
])
|
||||
->assertStatus(422);
|
||||
|
||||
|
|
@ -71,8 +60,7 @@ class AccountActionTest extends TestCase
|
|||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->id.'/actions', [
|
||||
'key' => 'Abc1234',
|
||||
'code' => '123',
|
||||
'protocol' => 'wrong'
|
||||
'code' => '123'
|
||||
])
|
||||
->assertStatus(422);
|
||||
|
||||
|
|
@ -81,10 +69,29 @@ class AccountActionTest extends TestCase
|
|||
->assertJson([
|
||||
[
|
||||
'key' => '123',
|
||||
'code' => '123',
|
||||
'protocol' => 'sipinfo'
|
||||
'code' => '123'
|
||||
]
|
||||
]);
|
||||
|
||||
// No protocol
|
||||
$password->account->dtmf_protocol = null;
|
||||
$password->account->save();
|
||||
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->json($this->method, $this->route.'/'.$password->account->id.'/actions', [
|
||||
'key' => 'abc1234',
|
||||
'code' => '123'
|
||||
])
|
||||
->assertStatus(403);
|
||||
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->get($this->route.'/'.$password->account->id.'/actions')
|
||||
->assertStatus(403);
|
||||
|
||||
$this->keyAuthenticated($admin->account)
|
||||
->get($this->route.'/'.$password->account->id)
|
||||
->assertStatus(200)
|
||||
->assertJsonPath('actions', []);
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
|
|
|
|||
|
|
@ -121,13 +121,15 @@ class AccountContactTest extends TestCase
|
|||
->get('/contacts/vcard')
|
||||
->assertStatus(200)
|
||||
->assertSeeText($typeKey)
|
||||
->assertSeeText($actionKey.';'.$actionCode.';'.$actionProtocol);
|
||||
->assertSeeText($password2->dtmf_protocol)
|
||||
->assertSeeText($actionKey.';'.$actionCode);
|
||||
|
||||
$this->keyAuthenticated($password1->account)
|
||||
->get('/contacts/vcard/'.$password2->account->identifier)
|
||||
->assertStatus(200)
|
||||
->assertSeeText($typeKey)
|
||||
->assertSeeText($actionKey.';'.$actionCode.';'.$actionProtocol);
|
||||
->assertSeeText($password2->dtmf_protocol)
|
||||
->assertSeeText($actionKey.';'.$actionCode);
|
||||
|
||||
$this->keyAuthenticated($password1->account)
|
||||
->get($this->route.'/me/contacts/'.$password2->account->identifier)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#%define _datadir %{_datarootdir}
|
||||
#%define _docdir %{_datadir}/doc
|
||||
|
||||
%define build_number 123
|
||||
%define build_number 124
|
||||
%define var_dir /var/opt/belledonne-communications
|
||||
%define opt_dir /opt/belledonne-communications/share/flexisip-account-manager
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue