Fix FLEXIAPI-155 Add a new accountServiceAccountUpdatedHook and accountServiceAccountDeletedHook

This commit is contained in:
Timothée Jaussoin 2024-03-27 16:22:01 +00:00
parent 00196e5957
commit 75599dd5ab
28 changed files with 392 additions and 203 deletions

View file

@ -2,6 +2,7 @@
v1.5
----
- Fix FLEXIAPI-155 Add a new accountServiceAccountUpdatedHook and accountServiceAccountDeletedHook
- Fix FLEXIAPI-153 Add phone and email to be changed in the Activity panel
- Fix FLEXIAPI-151 Migrate to hCaptcha
- Fix FLEXIAPI-150 Use the same account_id parameter for both API and Web routes

View file

@ -120,11 +120,6 @@ class Account extends Authenticatable
return $this->hasOne(ActivationExpiration::class);
}
public function admin()
{
return $this->hasOne(Admin::class);
}
public function alias()
{
return $this->hasOne(Alias::class);
@ -430,13 +425,27 @@ class Account extends Authenticatable
$this->save();
}
public function hasTombstone()
public function hasTombstone(): bool
{
return AccountTombstone::where('username', $this->attributes['username'])
->where('domain', $this->attributes['domain'])
->exists();
}
public function createTombstone(): bool
{
if (!$this->hasTombstone()) {
$tombstone = new AccountTombstone();
$tombstone->username = $this->attributes['username'];
$tombstone->domain = $this->attributes['domain'];
$tombstone->save();
return true;
}
return false;
}
public function failedRecentRecovery(): bool
{
$oneHourAgo = Carbon::now()->subHour();

View file

@ -23,8 +23,7 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\AccountTombstone;
use App\Http\Requests\CreateAccountRequest;
use App\Http\Requests\Account\Create\Web\Request as WebRequest;
use App\Services\AccountService;
class AccountController extends Controller
@ -48,11 +47,9 @@ class AccountController extends Controller
]);
}
public function store(CreateAccountRequest $request)
public function store(WebRequest $request)
{
$request->validate(['h-captcha-response' => captchaConfigured() ? 'required|HCaptcha' : '']);
$account = (new AccountService(api: false))->store($request);
$account = (new AccountService())->store($request);
Auth::login($account);
@ -78,14 +75,10 @@ class AccountController extends Controller
{
$request->validate(['identifier' => 'required|same:identifier_confirm']);
if (!$request->user()->hasTombstone()) {
$tombstone = new AccountTombstone();
$tombstone->username = $request->user()->username;
$tombstone->domain = $request->user()->domain;
$tombstone->save();
}
$request->user()->createTombstone();
(new AccountService)->destroy($request, $request->user()->id);
$request->user()->delete();
Auth::logout();
return redirect()->route('account.login');

View file

@ -72,8 +72,6 @@ class AuthTokenController extends Controller
$authToken->delete();
$request->session()->flash('success', 'Successfully authenticated');
return redirect()->route('account.dashboard');
}
@ -87,8 +85,6 @@ class AuthTokenController extends Controller
if (!$authToken->account_id) {
$authToken->account_id = $request->user()->id;
$authToken->save();
$request->session()->flash('success', 'External device successfully authenticated');
}
return redirect()->route('account.dashboard');

View file

@ -103,8 +103,6 @@ class AuthenticateController extends Controller
$authToken->delete();
$request->session()->flash('success', 'Successfully authenticated');
return redirect()->route('account.dashboard');
}

View file

@ -49,13 +49,11 @@ class PasswordController extends Controller
if ($account->passwords()->count() > 0) {
Log::channel('events')->info('Web: Password changed', ['id' => $account->identifier]);
$request->session()->flash('success', 'Password successfully changed');
return redirect()->route('account.dashboard');
}
Log::channel('events')->info('Web: Password set for the first time', ['id' => $account->identifier]);
$request->session()->flash('success', 'Password successfully set. Your SIP account creation process is now finished.');
if (!empty($account->email)) {
Mail::to($account)->send(new ConfirmedRegistration($account));

View file

@ -53,7 +53,6 @@ class AccountAccountTypeController extends Controller
$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.edit', $account);
@ -65,7 +64,6 @@ class AccountAccountTypeController extends Controller
$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.edit', $account);

View file

@ -54,7 +54,6 @@ class AccountActionController extends Controller
$accountAction->code = $request->get('code');
$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.edit', $accountAction->account);
@ -90,7 +89,6 @@ class AccountActionController extends Controller
$accountAction->code = $request->get('code');
$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.edit', $account);
@ -116,8 +114,6 @@ class AccountActionController extends Controller
->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.edit', $accountAction->account);

View file

@ -77,7 +77,6 @@ class AccountContactController extends Controller
$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.edit', $account);

View file

@ -22,12 +22,13 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
use App\Account;
use App\ContactsList;
use App\Http\Requests\CreateAccountWithoutUsernamePhoneCheck;
use App\Http\Requests\Account\Create\Web\AsAdminRequest;
use App\Http\Requests\Account\Update\Web\AsAdminRequest as WebAsAdminRequest;
use App\Http\Requests\UpdateAccountRequest;
use App\Services\AccountService;
class AccountController extends Controller
{
@ -79,30 +80,9 @@ class AccountController extends Controller
]);
}
public function store(CreateAccountWithoutUsernamePhoneCheck $request)
public function store(AsAdminRequest $request)
{
$request->validate([
'password' => 'confirmed'
]);
$account = new Account;
$account->username = $request->get('username');
$account->email = $request->get('email');
$account->display_name = $request->get('display_name');
$account->domain = resolveDomain($request);
$account->ip_address = $request->ip();
$account->created_at = Carbon::now();
$account->user_agent = config('app.name');
$account->dtmf_protocol = $request->get('dtmf_protocol');
$account->activated = $request->get('activated') == 'true';
$account->blocked = $request->get('blocked') == 'true';
$account->save();
$account->phone = $request->get('phone');
$account->updatePassword($request->get('password'));
$account->refresh();
$account->setRole($request->get('role'));
$account = (new AccountService)->store($request);
Log::channel('events')->info('Web Admin: Account created', ['id' => $account->identifier]);
@ -122,27 +102,9 @@ class AccountController extends Controller
]);
}
public function update(UpdateAccountRequest $request, $id)
public function update(WebAsAdminRequest $request, int $id)
{
$request->validate([
'password' => 'confirmed',
]);
$account = Account::findOrFail($id);
$account->email = $request->get('email');
$account->display_name = $request->get('display_name');
$account->dtmf_protocol = $request->get('dtmf_protocol');
$account->activated = $request->get('activated') == 'true';
$account->blocked = $request->get('blocked') == 'true';
$account->save();
$account->phone = $request->get('phone');
if ($request->get('password')) {
$account->updatePassword($request->get('password'));
}
$account->setRole($request->get('role'));
$account = (new AccountService)->update($request, $id);
Log::channel('events')->info('Web Admin: Account updated', ['id' => $account->identifier]);
@ -172,9 +134,8 @@ class AccountController extends Controller
public function destroy(Request $request)
{
$account = Account::findOrFail($request->get('account_id'));
$account->delete();
$request->session()->flash('success', 'Account successfully destroyed');
(new AccountService)->destroy($request, $request->get('account_id'));
Log::channel('events')->info('Web Admin: Account deleted', ['id' => $account->identifier]);

View file

@ -29,11 +29,10 @@ use Carbon\Carbon;
use App\Account;
use App\AccountCreationToken;
use App\AccountTombstone;
use App\Alias;
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
use App\Http\Requests\CreateAccountRequest;
use App\Http\Requests\Account\Create\Api\Request as ApiRequest;
use App\Libraries\OvhSMS;
use App\Mail\RegisterConfirmation;
@ -251,7 +250,7 @@ class AccountController extends Controller
return $account;
}
public function store(CreateAccountRequest $request)
public function store(ApiRequest $request)
{
return (new AccountService)->store($request);
}
@ -334,14 +333,10 @@ class AccountController extends Controller
public function delete(Request $request)
{
if (!$request->user()->hasTombstone()) {
$tombstone = new AccountTombstone;
$tombstone->username = $request->user()->username;
$tombstone->domain = $request->user()->domain;
$tombstone->save();
}
$request->user()->createTombstone();
return Account::where('id', $request->user()->id)
->delete();
(new AccountService)->destroy($request, $request->user()->id);
return true;
}
}

View file

@ -27,10 +27,8 @@ use App\Account;
use App\AccountTombstone;
use App\AccountType;
use App\ContactsList;
use App\Http\Requests\CreateAccountRequest;
use App\Http\Requests\CreateAccountWithoutUsernamePhoneCheck;
use App\Http\Requests\UpdateAccountRequest;
use App\Rules\PasswordAlgorithm;
use App\Http\Requests\Account\Create\Api\AsAdminRequest;
use App\Http\Requests\Account\Update\Api\AsAdminRequest as ApiAsAdminRequest;
use App\Services\AccountService;
class AccountController extends Controller
@ -55,7 +53,7 @@ class AccountController extends Controller
return Account::where('email', $email)->firstOrFail();
}
public function destroy($accountId)
public function destroy(Request $request, int $accountId)
{
$account = Account::findOrFail($accountId);
@ -66,9 +64,9 @@ class AccountController extends Controller
$tombstone->save();
}
Log::channel('events')->info('API Admin: Account destroyed', ['id' => $account->identifier]);
(new AccountService)->destroy($request, $accountId);
$account->delete();
Log::channel('events')->info('API Admin: Account destroyed', ['id' => $account->identifier]);
}
public function activate(int $accountId)
@ -126,34 +124,14 @@ class AccountController extends Controller
return $account->makeVisible(['provisioning_token']);
}
public function store(CreateAccountWithoutUsernamePhoneCheck $request)
public function store(AsAdminRequest $request)
{
return (new AccountService)->store($request, asAdmin: true)->makeVisible(['confirmation_key', 'provisioning_token']);
return (new AccountService)->store($request)->makeVisible(['confirmation_key', 'provisioning_token']);
}
public function update(UpdateAccountRequest $request, int $accountId)
public function update(ApiAsAdminRequest $request, int $accountId)
{
$request->validate([
'algorithm' => ['required', new PasswordAlgorithm],
'admin' => 'boolean|nullable',
'activated' => 'boolean|nullable'
]);
$account = Account::findOrFail($accountId);
$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->domain = resolveDomain($request);
$account->user_agent = $request->header('User-Agent') ?? config('app.name');
$account->admin = $request->has('admin') && (bool)$request->get('admin');
$account->save();
$account->updatePassword($request->get('password'), $request->get('algorithm'));
$account->phone = $request->get('phone');
// Full reload
$account = Account::withoutGlobalScopes()->find($account->id);
$account = (new AccountService)->update($request, $accountId);
Log::channel('events')->info('API Admin: Account updated', ['id' => $account->identifier]);

View file

@ -0,0 +1,42 @@
<?php
namespace App\Http\Requests\Account\Create\Api;
use App\Http\Requests\Account\Create\Request;
use App\Http\Requests\Api as RequestsApi;
use App\Http\Requests\AsAdmin;
use App\Rules\IsNotPhoneNumber;
use App\Rules\PasswordAlgorithm;
class AsAdminRequest extends Request
{
use RequestsApi, AsAdmin;
public function authorize()
{
return true;
}
public function rules()
{
$rules = parent::rules();
$rules['algorithm'] = ['required', new PasswordAlgorithm()];
$rules['admin'] = 'boolean|nullable';
$rules['activated'] = 'boolean|nullable';
$rules['confirmation_key_expires'] = [
'date_format:Y-m-d H:i:s',
'nullable',
];
if (config('app.allow_phone_number_username_admin_api') == true) {
array_splice(
$rules['username'],
array_search(new IsNotPhoneNumber(), $rules['username']),
1
);
}
return $rules;
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace App\Http\Requests\Account\Create\Api;
use App\Http\Requests\Account\Create\Request as CreateRequest;
use App\Http\Requests\Api as RequestsApi;
use App\Rules\AccountCreationToken;
class Request extends CreateRequest
{
use RequestsApi;
public function authorize()
{
return true;
}
public function rules()
{
$rules = parent::rules();
$rules['account_creation_token'] = ['required', new AccountCreationToken()];
return $rules;
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace App\Http\Requests;
namespace App\Http\Requests\Account\Create;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
@ -13,7 +13,7 @@ use App\Rules\NoUppercase;
use App\Rules\SIPUsername;
use App\Rules\WithoutSpaces;
class CreateAccountRequest extends FormRequest
class Request extends FormRequest
{
public function authorize()
{
@ -25,10 +25,10 @@ class CreateAccountRequest extends FormRequest
return [
'username' => [
'required',
new NoUppercase,
new IsNotPhoneNumber,
new BlacklistedUsername,
new SIPUsername,
new NoUppercase(),
new IsNotPhoneNumber(),
new BlacklistedUsername(),
new SIPUsername(),
Rule::unique('accounts', 'username')->where(function ($query) {
$query->where('domain', resolveDomain($this));
}),
@ -37,7 +37,7 @@ class CreateAccountRequest extends FormRequest
}),
'filled',
],
'dictionary' => [new Dictionary],
'dictionary' => [new Dictionary()],
'password' => 'required|min:3',
'email' => config('app.account_email_unique')
? 'nullable|email|unique:accounts,email'
@ -47,7 +47,7 @@ class CreateAccountRequest extends FormRequest
'nullable',
'unique:aliases,alias',
'unique:accounts,username',
new WithoutSpaces, 'starts_with:+'
new WithoutSpaces(), 'starts_with:+'
]
];
}

View file

@ -0,0 +1,34 @@
<?php
namespace App\Http\Requests\Account\Create\Web;
use App\Http\Requests\Account\Create\Request as CreateRequest;
use App\Http\Requests\AsAdmin;
use App\Rules\IsNotPhoneNumber;
class AsAdminRequest extends CreateRequest
{
use AsAdmin;
public function authorize()
{
return true;
}
public function rules()
{
$rules = parent::rules();
$rules['password'] = 'confirmed';
if (config('app.allow_phone_number_username_admin_api') == true) {
array_splice(
$rules['username'],
array_search(new IsNotPhoneNumber(), $rules['username']),
1
);
}
return $rules;
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace App\Http\Requests\Account\Create\Web;
use App\Http\Requests\Account\Create\Request as CreateRequest;
class Request extends CreateRequest
{
public function authorize()
{
return true;
}
public function rules()
{
$rules = parent::rules();
$rules['h-captcha-response'] = captchaConfigured() ? 'required|HCaptcha' : '';
$rules['password'] = 'confirmed';
$rules['email'] = 'confirmed';
$rules['terms'] = 'accepted';
return $rules;
}
}

View file

@ -0,0 +1,38 @@
<?php
namespace App\Http\Requests\Account\Update\Api;
use App\Http\Requests\Account\Update\Request as UpdateRequest;
use App\Http\Requests\Api as RequestsApi;
use App\Http\Requests\AsAdmin;
use App\Rules\IsNotPhoneNumber;
use App\Rules\PasswordAlgorithm;
class AsAdminRequest extends UpdateRequest
{
use RequestsApi, AsAdmin;
public function authorize()
{
return true;
}
public function rules()
{
$rules = parent::rules();
$rules['algorithm'] = ['required', new PasswordAlgorithm()];
$rules['admin'] = 'boolean|nullable';
$rules['activated'] = 'boolean|nullable';
if (config('app.allow_phone_number_username_admin_api') == true) {
array_splice(
$rules['username'],
array_search(new IsNotPhoneNumber(), $rules['username']),
1
);
}
return $rules;
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace App\Http\Requests;
namespace App\Http\Requests\Account\Update;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
@ -12,7 +12,7 @@ use App\Rules\NoUppercase;
use App\Rules\SIPUsername;
use App\Rules\WithoutSpaces;
class UpdateAccountRequest extends FormRequest
class Request extends FormRequest
{
public function authorize()
{
@ -45,7 +45,7 @@ class UpdateAccountRequest extends FormRequest
Rule::unique('accounts', 'username')->where(function ($query) {
$query->where('domain', resolveDomain($this));
})->ignore($this->route('id'), 'id'),
Rule::unique('aliases', 'alias')->ignore($this->route('id'), 'account_id'),
Rule::unique('aliases', 'alias')->ignore($this->route('account_id'), 'account_id'),
new WithoutSpaces, 'starts_with:+'
]
];

View file

@ -0,0 +1,34 @@
<?php
namespace App\Http\Requests\Account\Update\Web;
use App\Http\Requests\Account\Update\Request as UpdateRequest;
use App\Http\Requests\AsAdmin;
use App\Rules\IsNotPhoneNumber;
class AsAdminRequest extends UpdateRequest
{
use AsAdmin;
public function authorize()
{
return true;
}
public function rules()
{
$rules = parent::rules();
$rules['password'] = 'confirmed';
if (config('app.allow_phone_number_username_admin_api') == true) {
array_splice(
$rules['username'],
array_search(new IsNotPhoneNumber(), $rules['username']),
1
);
}
return $rules;
}
}

View file

@ -0,0 +1,8 @@
<?php
namespace App\Http\Requests;
trait Api
{
public $api = true;
}

View file

@ -0,0 +1,8 @@
<?php
namespace App\Http\Requests;
trait AsAdmin
{
public $asAdmin = true;
}

View file

@ -1,28 +0,0 @@
<?php
namespace App\Http\Requests;
use App\Rules\IsNotPhoneNumber;
class CreateAccountWithoutUsernamePhoneCheck extends CreateAccountRequest
{
public function authorize()
{
return true;
}
public function rules()
{
$parentRules = parent::rules();
if (config('app.allow_phone_number_username_admin_api') == true) {
array_splice(
$parentRules['username'],
array_search(new IsNotPhoneNumber(), $parentRules['username']),
1
);
}
return $parentRules;
}
}

View file

@ -46,7 +46,7 @@ class OvhSMS
if (!empty($smsServices)) {
$this->smsService = $smsServices[0];
}
} catch (\GuzzleHttp\Exception\ClientException $e) {
} catch (\Exception $e) {
Log::channel('events')->info('OVH SMS API unreachable, check the errors log');
Log::error('OVH SMS API not reachable: ' . $e->getMessage());
}
@ -79,7 +79,7 @@ class OvhSMS
// One credit removed
$this->api->get('/sms/'. $this->smsService . '/jobs');
} catch (\GuzzleHttp\Exception\ClientException $e) {
} catch (\Exception $e) {
Log::channel('events')->info('OVH SMS not sent, check the errors log');
Log::error('OVH SMS not sent: ' . $e->getMessage());
}

View file

@ -24,8 +24,9 @@ use App\AccountCreationToken;
use App\ActivationExpiration;
use App\Alias;
use App\EmailChangeCode;
use App\Http\Requests\CreateAccountRequest;
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
use App\Http\Requests\Account\Create\Request as CreateRequest;
use App\Http\Requests\Account\Update\Request as UpdateRequest;
use App\Libraries\OvhSMS;
use App\Mail\NewsletterRegistration;
use App\Mail\RecoverByCode;
@ -33,8 +34,6 @@ use App\Mail\RegisterValidation;
use App\PhoneChangeCode;
use Illuminate\Support\Facades\Log;
use App\Rules\AccountCreationToken as RulesAccountCreationToken;
use App\Rules\PasswordAlgorithm;
use App\Rules\WithoutSpaces;
use Carbon\Carbon;
use Illuminate\Support\Facades\Mail;
@ -57,33 +56,8 @@ class AccountService
/**
* Account creation
*/
public function store(CreateAccountRequest $request, bool $asAdmin = false): Account
public function store(CreateRequest $request): Account
{
$rules = [];
$rules['password'] = 'confirmed';
$rules['email'] = 'confirmed';
$rules['terms'] = 'accepted';
if ($this->api) {
$rules = [];
$rules['account_creation_token'] = ['required', new RulesAccountCreationToken()];
if ($asAdmin) {
$rules = [];
$rules['algorithm'] = ['required', new PasswordAlgorithm()];
$rules['admin'] = 'boolean|nullable';
$rules['activated'] = 'boolean|nullable';
$rules['confirmation_key_expires'] = [
'date_format:Y-m-d H:i:s',
'nullable',
];
}
}
$request->validate($rules);
$account = new Account();
$account->username = $request->get('username');
$account->activated = false;
@ -93,7 +67,7 @@ class AccountService
$account->user_agent = config('app.name');
$account->dtmf_protocol = $request->get('dtmf_protocol');
if ($asAdmin) {
if ($request->asAdmin) {
$account->email = $request->get('email');
$account->display_name = $request->get('display_name');
$account->activated = $request->has('activated') ? (bool)$request->get('activated') : false;
@ -108,7 +82,7 @@ class AccountService
$account->save();
if ($asAdmin) {
if ($request->asAdmin) {
if ((!$request->has('activated') || !(bool)$request->get('activated'))
&& $request->has('confirmation_key_expires')) {
$actionvationExpiration = new ActivationExpiration();
@ -128,18 +102,23 @@ class AccountService
$account->updatePassword($request->get('password'), $request->get('algorithm'));
if ($this->api && !$asAdmin) {
if ($request->api && !$request->asAdmin) {
$token = AccountCreationToken::where('token', $request->get('account_creation_token'))->first();
$token->consume();
$token->account_id = $account->id;
$token->save();
}
Log::channel('events')->info('API: AccountCreationToken redeemed', ['token' => $request->get('account_creation_token')]);
}
Log::channel('events')->info($asAdmin ? 'Account Service as Admin: Account created' : 'Account Service: Account created', ['id' => $account->identifier]);
Log::channel('events')->info(
$request->asAdmin
? 'Account Service as Admin: Account created'
: 'Account Service: Account created',
['id' => $account->identifier]
);
if (!$this->api) {
if (!$request->api) {
if (!empty(config('app.newsletter_registration_address')) && $request->has('newsletter')) {
Mail::to(config('app.newsletter_registration_address'))->send(new NewsletterRegistration($account));
}
@ -152,6 +131,82 @@ class AccountService
return Account::withoutGlobalScopes()->find($account->id);
}
/**
* Account update
*/
public function update(UpdateRequest $request, int $accountId): ?Account
{
$account = Account::findOrFail($accountId);
if ($request->asAdmin) {
$account->username = $request->get('username') ?? $account->username;
$account->domain = $request->has('domain') ? resolveDomain($request) : $account->domain;
$account->email = $request->get('email');
$account->display_name = $request->get('display_name');
$account->dtmf_protocol = $request->get('dtmf_protocol');
$account->user_agent = $request->header('User-Agent') ?? config('app.name');
$account->admin = $request->has('admin') && (bool)$request->get('admin');
if ($request->api && $request->has('admin')) {
$account->admin = (bool)$request->get('admin');
}
if (!$request->api && $request->has('role')) {
$account->setRole($request->get('role'));
}
if (!$request->api && $request->has('activated')) {
$account->activated = $request->get('activated') == 'true';
}
if (!$request->api && $request->has('blocked')) {
$account->blocked = $request->get('blocked') == 'true';
}
if ($request->get('password')) {
$account->updatePassword(
$request->get('password'),
$request->api ? $request->get('algorithm') : null
);
}
$account->save();
$account->phone = $request->get('phone');
}
Log::channel('events')->info(
$request->asAdmin
? 'Account Service as Admin: Account updated'
: 'Account Service: Account updated',
['id' => $account->identifier]
);
if (function_exists('accountServiceAccountEditedHook')) {
accountServiceAccountEditedHook($request, $account);
}
return Account::withoutGlobalScopes()->find($account->id);
}
/**
* Account destroy
*/
public function destroy(Request $request, int $accountId)
{
$account = Account::findOrFail($accountId);
$account->delete();
Log::channel('events')->info(
'Account Service: Account destroyed',
['id' => $account->identifier]
);
if (function_exists('accountServiceAccountDestroyedHook')) {
accountServiceAccountDestroyedHook($request, $account);
}
}
/**
* Link a phone number to an account
*/

View file

@ -20,3 +20,29 @@ function accountServiceAccountCreatedHook(Request $request, Account $account)
*/
}
/**
* @brief Run specific code if an account was edited
* @param Request $request
* @param Account $account
* @return void
*/
function accountServiceAccountEditedHook(Request $request, Account $account)
{
/*
*/
}
/**
* @brief Run specific code if an account was destroed
* @param Request $request
* @param Account $account
* @return void
*/
function accountServiceAccountDestroyedHook(Request $request, Account $account)
{
/*
*/
}

View file

@ -255,5 +255,4 @@
<a class="btn" href="{{ route('admin.account.account_type.create', $account) }}">Add</a>
@endif
@endif
@endsection

View file

@ -310,16 +310,17 @@ JSON parameters:
### `PUT /accounts/{id}`
<span class="badge badge-warning">Admin</span>
Update an existing account.
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**. Only configurable if `APP_ADMINS_MANAGE_MULTI_DOMAINS` is set to `true` in the global configuration. Otherwise `APP_SIP_DOMAIN` 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, create an admin account
* `admin` optional, a boolean, set to `false` by default
* `phone` optional, a phone number, set a phone number to the account
* `dtmf_protocol` optional, values must be `sipinfo`, `sipmessage` or `rfc2833`