Fix FLEXIAPI-284 Add configurable admin API Keys

This commit is contained in:
Timothée Jaussoin 2025-04-10 09:11:26 +00:00
parent 672d6291b7
commit a3861304cc
49 changed files with 503 additions and 179 deletions

View file

@ -29,6 +29,7 @@ v1.7
- Fix FLEXIAPI-233 Add External Accounts (new version)
- Fix FLEXIAPI-277 Restrict authorized ini keys that can be set to prevent conflict with the existing ones set in the UI
- Fix FLEXIAPI-272 Add Space based email server integration
- Fix FLEXIAPI-284 Add configurable admin API Keys
v1.6
----

View file

@ -118,7 +118,12 @@ class Account extends Authenticatable
public function apiKey()
{
return $this->hasOne(ApiKey::class);
return $this->hasOne(ApiKey::class)->whereNull('expires_after_last_used_minutes');
}
public function adminApiKeys()
{
return $this->hasMany(ApiKey::class)->whereNotNull('expires_after_last_used_minutes');
}
public function external()
@ -352,7 +357,7 @@ class Account extends Authenticatable
return ($this->activationExpiration && $this->activationExpiration->isExpired());
}
public function generateApiKey(?string $ip = null): ApiKey
public function generateUserApiKey(?string $ip = null): ApiKey
{
$this->apiKey()->delete();

View file

@ -28,8 +28,12 @@ class ApiKey extends Model
protected $table = 'api_keys';
protected $casts = [
'last_used_at' => 'datetime',
];
public function account()
{
return $this->belongsTo(Account::class);
return $this->belongsTo(Account::class)->withoutGlobalScopes();
}
}

View file

@ -27,15 +27,11 @@ use App\ApiKey;
class ClearApiKeys extends Command
{
protected $signature = 'accounts:clear-api-keys {minutes?}';
protected $description = 'Clear the expired API Keys after n minutes';
public function __construct()
{
parent::__construct();
}
protected $description = 'Clear the expired user API Keys after n minutes and clear the other expired admin keys';
public function handle()
{
// User API Keys
$minutes = $this->argument('minutes') ?? config('app.api_key_expiration_minutes');
if ($minutes == 0) {
@ -43,14 +39,30 @@ class ClearApiKeys extends Command
return 0;
}
$this->info('Deleting api keys unused after ' . $minutes . ' minutes');
$this->info('Deleting user API Keys unused after ' . $minutes . ' minutes');
$count = ApiKey::where(
'last_used_at',
'<',
Carbon::now()->subMinutes($minutes)->toDateTimeString()
)->delete();
$count = ApiKey::whereNull('expires_after_last_used_minutes')
->where('last_used_at', '<', Carbon::now()->subMinutes($minutes)->toDateTimeString())
->delete();
$this->info($count . ' api keys deleted');
$this->info($count . ' user API Keys deleted');
// Admin API Keys
$keys = ApiKey::whereNotNull('expires_after_last_used_minutes')
->where('expires_after_last_used_minutes', '>', 0)
->with('account')
->get();
$count = 0;
foreach ($keys as $key) {
if ($key->last_used_at->addMinutes($key->expires_after_last_used_minutes)->isPast()) {
$this->info('Deleting ' . $key->account->identifier . ' admin API Key expired after ' . $key->expires_after_last_used_minutes .'min');
$key->delete();
$count++;
}
}
$this->info($count . ' admin API Keys deleted');
}
}

View file

@ -90,7 +90,7 @@ class CreateAdminAccount extends Command
$account->created_at = Carbon::now()->subYears(3);
$account->save();
$account->generateApiKey(ip: $this->option('api_key_ip') ?? null);
$account->generateUserApiKey(ip: $this->option('api_key_ip') ?? null);
$account->updatePassword($password);
$this->info('Admin test account created: "' . $username . '@' . $domain . '" | Password: "' . $password . '" | API Key: "' . $account->apiKey->key . '" (valid on ' . ($account->apiKey->ip ?? 'any') . ' ip)');

View file

@ -34,7 +34,7 @@ class ApiKeyController extends Controller
public function update(Request $request)
{
$account = $request->user();
$account->generateApiKey($request->ip());
$account->generateUserApiKey($request->ip());
return redirect()->back();
}

View file

@ -0,0 +1,95 @@
<?php
/*
Flexisip Account Manager is a set of tools to manage SIP accounts.
Copyright (C) 2020 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\ApiKey;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Carbon\Carbon;
class ApiKeyController extends Controller
{
public function index(Request $request)
{
return view('admin.api_key.index', [
'api_keys' => $this->getApiKeysQuery($request)->with('account')->get()
]);
}
public function create(Request $request)
{
return view('admin.api_key.create', [
'account' => $request->user()
]);
}
public function store(Request $request)
{
$request->validate([
'name' => 'required|min:3',
'expires_after_last_used_minutes' => 'integer|min:0'
]);
$apiKey = new ApiKey;
$apiKey->account_id = $request->user()->id;
$apiKey->name = $request->get('name');
$apiKey->expires_after_last_used_minutes = $request->get('expires_after_last_used_minutes');
$apiKey->last_used_at = Carbon::now();
$apiKey->key = Str::random(40);
$apiKey->save();
return redirect()->route('admin.api_keys.index');
}
public function delete(Request $request, string $key)
{
return view('admin.api_key.delete', [
'api_key' => $this->getApiKeysQuery($request)->where('key', $key)->first()
]);
}
public function destroy(Request $request)
{
$this->getApiKeysQuery($request)->where('key', $request->get('key'))->delete();
return redirect()->route('admin.api_keys.index');
}
private function getApiKeysQuery(Request $request)
{
$apiKeys = ApiKey::whereIn('account_id', function ($query) {
$query->select('id')
->from('accounts')
->where('admin', true);
})->whereNotNull('expires_after_last_used_minutes');
if (!$request->user()->superAdmin) {
$apiKeys->whereIn('account_id', function ($query) use ($request) {
$query->select('id')
->from('accounts')
->where('domain', $request->user()->domain);
});
}
return $apiKeys;
}
}

View file

@ -29,7 +29,7 @@ class ApiKeyController extends Controller
public function generate(Request $request)
{
$account = $request->user();
$account->generateApiKey($request->ip());
$account->generateUserApiKey($request->ip());
$account->refresh();
Cookie::queue('x-api-key', $account->apiKey->key, config('app.api_key_expiration_minutes'));
@ -42,7 +42,7 @@ class ApiKeyController extends Controller
$authToken = AuthToken::where('token', $token)->valid()->firstOrFail();
if ($authToken->account) {
$authToken->account->generateApiKey($request->ip());
$authToken->account->generateUserApiKey($request->ip());
$authToken->account->refresh();
Cookie::queue('x-api-key', $authToken->account->apiKey->key, config('app.api_key_expiration_minutes'));

View file

@ -30,7 +30,7 @@ class EmailChangeCodeFactory extends Factory
public function definition()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
return [
'account_id' => $account->id,

View file

@ -30,7 +30,7 @@ class PhoneChangeCodeFactory extends Factory
public function definition()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
return [
'account_id' => $account->id,

View file

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('api_keys', function (Blueprint $table) {
$table->string('name')->nullable();
$table->integer('expires_after_last_used_minutes')->nullable();
if (DB::getDriverName() !== 'sqlite') {
$table->dropForeign(['account_id']);
}
$table->dropUnique(['account_id']);
if (DB::getDriverName() !== 'sqlite') {
$table->foreign('account_id')->references('id')
->on('accounts')->onDelete('cascade');
}
});
}
public function down(): void
{
Schema::table('api_keys', function (Blueprint $table) {
$table->dropColumn('name');
$table->dropColumn('expires_after_last_used_minutes');
$table->unique('account_id');
});
}
};

View file

@ -13,6 +13,7 @@
"Activate": "Activer",
"Activated": "Activé",
"Activity": "Activité",
"Activity expiration delay": "Délais d'expiration après activité",
"Add contact": "Ajout d'un contact",
"Add contacts": "Ajouter des contacts",
"Add": "Ajouter",
@ -24,8 +25,10 @@
"An email will be sent to :email with a unique link allowing the user to reset its password.": "Un email sera envoyé à :email avec un lien unique l'invitant à réinitialiser son mot de passe",
"An email will be sent to this email when someone join the newsletter": "Un email sera envoyé à cette addresse quand quelqu'un rejoint la liste de diffusion",
"App Configuration": "Configuration de l'App",
"Api Keys": "Clefs d'API",
"Assistant": "Assistant",
"Blocked": "Bloqué",
"By": "Par",
"Calls logs": "Journaux d'appel",
"Cancel": "Annuler",
"Cannot be changed once created.": "Ne peut être changé par la suite.",
@ -47,7 +50,7 @@
"Copyright text": "Texte droits d'auteurs",
"Country code": "Code du pays",
"Create": "Créer",
"Created on": "Créé le",
"Created": "Créé",
"Currently set": "Actuellement remplit",
"Custom entries": "Entrées personnalisées",
"Dactivate": "Désactiver",
@ -94,6 +97,7 @@
"Intercom features": "Fonctionnalités d'interphonie",
"It might actually disable this page, be careful": "Cette page pourrait être désactivée, faites attention",
"Key": "Clef",
"Last used": "Dernière utilisation",
"Leave empty to create a root Space.": "Laisser vide si vous souhaitez créer un Espace à la racine",
"Login using a QRCode": "S'authentifier avec un QRCode",
"Login": "Authentification",
@ -105,6 +109,7 @@
"My Account": "Mon Compte",
"My Space": "Mon Espace",
"Name": "Nom",
"Never": "Jamais",
"Never expire": "N'expire jamais",
"New Admin": "Nouvel Admin",
"Newsletter registration email address": "Addresse email d'inscription à la liste de diffusion",
@ -113,6 +118,7 @@
"No email yet": "Pas d'email pour le moment",
"No limit": "Sans limite",
"No phone yet": "Pas de téléphone pour le moment",
"Number of minutes to expire the key after the last request.": "Nombre de minutes avant l'expiration de la clef après son dernier usage.",
"Only display usernames (hide SIP addresses)": "N'afficher que les num d'utilisateur (cacher les addresses SIP)",
"Other information": "Autres informations",
"Outbound proxy": "Outbound proxy",
@ -149,6 +155,7 @@
"Select a file": "Choisir un fichier",
"Send an email to the user to reset the password": "Envoyer un email à l'utilisateur pour réinitialiser son mot de passe",
"Send": "Envoyer",
"Settings": "Paramètres",
"Sip Adress": "Adresse SIP",
"SIP Domain": "Domaine SIP",
"Space": "Espace",

View file

@ -24,8 +24,6 @@ p .btn {
}
.btn i {
margin-right: 0.5rem;
margin-left: -0.5rem;
font-size: 2rem;
vertical-align: middle;
}
@ -154,18 +152,6 @@ form .disabled:not(a) {
}
}
form small {
display: block;
font-weight: 300;
color: var(--second-6);
font-size: 1.25rem;
margin-top: 0.25rem;
}
form small.error {
color: var(--danger-6);
}
form label {
color: var(--second-6);
font-size: 1.5rem;

View file

@ -434,10 +434,9 @@ content>nav {
width: 20rem;
margin-left: 0;
padding: 1.5rem;
border-radius: 0 3rem 0 0;
padding-left: 1rem;
padding-bottom: 10rem;
padding-top: 4rem;
border-radius: 0 3rem 0 0;
background-size: auto 10rem;
background-position: bottom center;
background-repeat: repeat-x;
@ -453,13 +452,17 @@ content>nav a {
display: flex;
align-items: center;
line-height: 5rem;
margin: 1rem 0;
margin: 0.5rem 0;
position: relative;
white-space: nowrap;
padding: 0 1rem;
padding: 0 1.5rem;
overflow: hidden;
}
content>nav a:first-child {
margin-top: 0;
}
content>nav a.current {
background-color: white;
border-radius: 4rem;
@ -468,8 +471,7 @@ content>nav a.current {
}
content>nav a i {
margin-right: 0.75rem;
margin-left: 0.25rem;
margin-right: 1rem;
font-size: 2rem;
}
@ -610,6 +612,10 @@ h3+p:has(span.badge) {
display: inline-block;
}
.badge.oppose {
float: right;
}
h3 .badge {
margin-left: 1rem;
}
@ -659,6 +665,9 @@ table tr th {
table tr th {
padding: 0 1rem;
line-height: 4rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
table tr td.line,
@ -968,3 +977,21 @@ details[open] > summary::before {
details > summary:hover {
cursor: pointer;
}
/** Small **/
small {
display: block;
font-weight: 300;
color: var(--second-6);
font-size: 1.25rem;
margin-top: 0.25rem;
}
small a {
font-size: 1.25rem;
}
small.error {
color: var(--danger-6);
}

View file

@ -21,12 +21,12 @@
<div>
<input type="text" readonly value="{{ $account->apiKey->key }}">
<label>Key</label>
<small>Can only be used from the following ip: {{ $account->apiKey->ip }} | {{ $account->apiKey->requests }} requests</small>
<small>Can only be used from the following ip: {{ $account->apiKey->ip }} | {{ __('Requests ')}} {{ $account->apiKey->requests }}</small>
</div>
</form>
@endif
<form method="POST" action="{{ route('account.api_key.update') }}" accept-charset="UTF-8">
<form method="POST" action="{{ route('account.api_keys.update') }}" accept-charset="UTF-8">
@csrf
<div>
<button type="submit" class="btn btn-primary">@if ($account->apiKey)Refresh the current key @else Generate a new key @endif</button>

View file

@ -51,7 +51,7 @@
<p>
<i class="ph">key</i>
{{ __('API Key') }}
<a href="{{ route('account.api_key.show') }}">
<a href="{{ route('account.api_keys.show') }}">
{{ __('Manage') }}
</a>
</p>

View file

@ -20,7 +20,7 @@
<thead>
<tr>
<th>{{ __('Code') }}</th>
<th>{{ __('Created on') }}</th>
<th>{{ __('Created') }}</th>
<th>{{ __('Used on') }}</th>
<th>IP</th>
<th>{{ __('Requests') }}</th>
@ -54,7 +54,7 @@
<thead>
<tr>
<th>{{ __('Code') }}</th>
<th>{{ __('Created on') }}</th>
<th>{{ __('Created') }}</th>
<th>{{ __('Used on') }}</th>
<th>IP</th>
</tr>
@ -82,7 +82,7 @@
<thead>
<tr>
<th>{{ __('Code') }}</th>
<th>{{ __('Created on') }}</th>
<th>{{ __('Created') }}</th>
<th>{{ __('Used on') }}</th>
<th>IP</th>
</tr>
@ -113,7 +113,7 @@
<tr>
<th>{{ __('Phone number') }}</th>
<th>{{ __('Code') }}</th>
<th>{{ __('Created on') }}</th>
<th>{{ __('Created') }}</th>
<th>{{ __('Used on') }}</th>
<th>IP</th>
</tr>
@ -145,7 +145,7 @@
<tr>
<th>{{ __('Email') }}</th>
<th>{{ __('Code') }}</th>
<th>{{ __('Created on') }}</th>
<th>{{ __('Created') }}</th>
<th>{{ __('Used on') }}</th>
<th>IP</th>
</tr>
@ -176,7 +176,7 @@
<thead>
<tr>
<th>Token</th>
<th>{{ __('Created on') }}</th>
<th>{{ __('Created') }}</th>
<th>{{ __('Used on') }}</th>
<th>IP</th>
</tr>
@ -206,7 +206,7 @@
<thead>
<tr>
<th>Token</th>
<th>{{ __('Created on') }}</th>
<th>{{ __('Created') }}</th>
<th>{{ __('Used on') }}</th>
<th>{{ __('Email') }}</th>
</tr>

View file

@ -63,7 +63,6 @@
<tr>
@include('parts.column_sort', ['key' => 'username', 'title' => __('Identifier')])
<th>{{ __('Contacts Lists') }}</th>
<th>Badges</th>
@include('parts.column_sort', ['key' => 'updated_at', 'title' => __('Updated')])
</tr>
</thead>
@ -79,6 +78,17 @@
<a href="{{ route('admin.account.edit', $account->id) }}">
{{ $account->identifier }}
</a>
@if ($account->activated)
<span class="badge badge-success oppose" title="{{ __('Activated') }}"><i class="ph">check</i></span>
@endif
@if ($account->superAdmin)
<span class="badge badge-error oppose" title="{{ __('Super Admin') }}">Super Adm.</span>
@elseif ($account->admin)
<span class="badge badge-primary oppose" title="{{ __('Admin') }}">Adm.</span>
@endif
@if ($account->blocked)
<span class="badge badge-error oppose" title="{{ __('Blocked') }}"><i class="ph">prohibit</i></span>
@endif
</td>
<td>
@if ($account->contactsLists->isNotEmpty())
@ -88,19 +98,6 @@
@endif
@endif
</td>
<td>
@if ($account->activated)
<span class="badge badge-success" title="{{ __('Activated') }}"><i class="ph">check</i></span>
@endif
@if ($account->superAdmin)
<span class="badge badge-error" title="{{ __('Super Admin') }}">Super Adm.</span>
@elseif ($account->admin)
<span class="badge badge-primary" title="{{ __('Admin') }}">Adm.</span>
@endif
@if ($account->blocked)
<span class="badge badge-error" title="{{ __('Blocked') }}"><i class="ph">prohibit</i></span>
@endif
</td>
<td>{{ $account->updated_at }}</td>
</tr>
@endforeach

View file

@ -0,0 +1,40 @@
@extends('layouts.main')
@section('breadcrumb')
<li class="breadcrumb-item">
<a href="{{ route('admin.api_keys.index') }}">{{ __('API Keys') }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
{{ __('Create') }}
</li>
@endsection
@section('content')
<header>
<h1><i class="ph">key</i> {{ __('Create') }}</h1>
<a href="{{ route('admin.api_keys.index') }}" class="btn btn-secondary oppose">{{ __('Cancel') }}</a>
</header>
<form method="POST"
action="{{ route('admin.api_keys.store') }}"
accept-charset="UTF-8">
@csrf
@method('post')
<div>
<input name="name" id="name" placeholder="My Key Name" required="required" type="text" value="{{ old('name') }}">
<label for="name">{{ __('Name') }}</label>
@include('parts.errors', ['name' => 'name'])
</div>
<div>
<input placeholder="60" required="required" name="expires_after_last_used_minutes" type="number" value="{{ old('expires_after_last_used_minutes') ?? 60 }}">
<label for="username">{{ __('Activity expiration delay') }}</label>
@include('parts.errors', ['name' => 'expires_after_last_used_minutes'])
<span class="supporting">{{ __('Number of minutes to expire the key after the last request.') }} {{ __('Unlimited if set to 0') }}</span>
</div>
<div class="large">
<input class="btn" type="submit" value="{{ __('Create') }}">
</div>
</form>
@endsection

View file

@ -0,0 +1,32 @@
@extends('layouts.main')
@section('breadcrumb')
<li class="breadcrumb-item">
<a href="{{ route('admin.api_keys.index') }}">{{ __('API Keys') }}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
{{ __('Delete') }}
</li>
@endsection
@section('content')
<header>
<h1><i class="ph">trash</i> {{ __('Delete') }}</h1>
<a href="{{ route('admin.api_keys.index') }}" class="btn btn-secondary oppose">{{ __('Cancel') }}</a>
<input form="delete" class="btn" type="submit" value="{{ __('Delete') }}">
</header>
<form id="delete" method="POST" action="{{ route('admin.api_keys.destroy', $api_key->key) }}" accept-charset="UTF-8">
@csrf
@method('delete')
<div class="large">
<p>{{ __('You are going to permanently delete the following element. Please confirm your action.') }}</p>
<p>
<i class="ph">key</i> <code>{{ $api_key->key }}</code>
</p>
</div>
<input name="key" type="hidden" value="{{ $api_key->key }}">
</form>
@endsection

View file

@ -0,0 +1,53 @@
@extends('layouts.main')
@section('content')
<header>
<h1><i class="ph">key</i> {{ __('API Keys') }}</h1>
<a href="{{ route('admin.api_keys.create') }}" class="btn oppose">
<i class="ph">plus</i>
{{ __('Create') }}
</a>
</header>
@include('admin.parts.settings_tabs')
<table>
<thead>
<tr>
<th>{{ __('Name') }}</th>
<th>{{ __('Key') }}</th>
<th>{{ __('Created') }}</th>
</tr>
</thead>
<tbody>
@if ($api_keys->isEmpty())
<tr class="empty">
<td colspan="3">{{ __('Empty') }}</td>
</tr>
@endif
@foreach ($api_keys as $api_key)
<tr>
<td>{{ $api_key->name }}
<br />
<small>
{{ __('Requests') }}: {{ $api_key->requests }}
</small>
</td>
<td>
<code>{{ $api_key->key }}</code><br />
<small>{{ __('Activity expiration delay') }}: {{ $api_key->expires_after_last_used_minutes ? $api_key->expires_after_last_used_minutes . ' min' : __('Never')}} | {{ __('Last used') }}: {{ $api_key->last_used_at ?? __('Never') }}</small>
</td>
<td>{{ $api_key->created_at }}
<a class="btn btn-secondary small oppose" href="{{ route('admin.api_keys.delete', $api_key->key) }}"><i class="ph">trash</i></a>
<small>
<a href="{{ route('admin.account.edit', $api_key->account->id) }}">
{{ __('By') }}: {{ $api_key->account->identifier }}
</a>
</small>
</td>
</tr>
@endforeach
</tbody>
</table>
@endsection

View file

@ -9,7 +9,7 @@
@section('content')
<header>
<h2><i class="ph">trash</i> {{ __('Delete') }}</h2>
<h1><i class="ph">trash</i> {{ __('Delete') }}</h1>
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}" class="btn btn-secondary oppose">{{ __('Cancel') }}</a>
<input form="delete" class="btn" type="submit" value="{{ __('Delete') }}">
</header>

View file

@ -0,0 +1,13 @@
@php
$items = [
route('admin.api_keys.index') => __('API Keys')
];
if (auth()->user()->superAdmin) {
$items[route('admin.phone_countries.index')] = __('Phone Countries');
}
@endphp
@include('parts.tabs', [
'items' => $items
])

View file

@ -5,37 +5,45 @@
<header>
<h1><i class="ph">flag</i> {{ __('Phone Countries') }}</h1>
<a class="btn btn-secondary oppose" href="{{ route('admin.phone_countries.activate_all') }}">
<i class="ph">plus</i>
{{ __('Activate All') }}
<i class="ph">eye</i> {{ __('Activate All') }}
</a>
<a class="btn btn-secondary" href="{{ route('admin.phone_countries.deactivate_all') }}">
<i class="ph">minus</i>
{{ __('Deactivate All') }}
<i class="ph">eye-closed</i> {{ __('Deactivate All') }}
</a>
</header>
@include('admin.parts.settings_tabs')
<table>
<thead>
<tr>
<th>{{ __('Code') }}</th>
<th>{{ __('Name') }}</th>
<th>{{ __('Country code') }}</th>
<th style="width: 100%;">{{ __('Name') }}</th>
<th>{{ __('Actions') }}</th>
</tr>
</thead>
<tbody>
@foreach ($phone_countries as $phone_country)
<tr>
<td>{{ $phone_country->code }}</td>
<td>{{ $phone_country->name }}</td>
<td>{{ $phone_country->country_code }}</td>
<td>
@if ($phone_country->activated)
<span class="badge badge-success" title="Activated">{{ __('Activated') }}</span>
<a href="{{ route('admin.phone_countries.deactivate', $phone_country->code) }}">{{ __('Deactivate') }}</a>
<span class="badge badge-success oppose" title="Activated">{{ __('Activated') }}</span>
@else
<span class="badge badge-error" title="Deactivated">{{ __('Deactivated') }}</span>
<a href="{{ route('admin.phone_countries.activate', $phone_country->code) }}">{{ __('Activate') }}</a>
<span class="badge badge-error oppose" title="Deactivated">{{ __('Deactivated') }}</span>
@endif
{{ $phone_country->name }}
<small>
{{ $phone_country->code }} - {{ $phone_country->country_code }}
</small>
</td>
<td>
@if ($phone_country->activated)
<a class="btn btn-secondary small" href="{{ route('admin.phone_countries.deactivate', $phone_country->code) }}">
<i class="ph">eye-closed</i>
</a>
@else
<a class="btn btn-secondary small" href="{{ route('admin.phone_countries.activate', $phone_country->code) }}">
<i class="ph">eye</i>
</a>
@endif
</td>
</tr>

View file

@ -14,9 +14,7 @@
<thead>
<tr>
<th>{{ __('Space') }}</th>
<th>{{ __('Host') }}</th>
<th>{{ __('SIP Domain') }}</th>
<th>{{ __('Accounts') }}</th>
<th>{{ __('Expiration') }}</th>
</tr>
</thead>
@ -24,15 +22,15 @@
@foreach ($spaces as $space)
<tr>
<td>
<a href="{{ route('admin.spaces.show', $space->id) }}">
{{ $space->name }}
@if ($space->super) <span class="badge badge-error" title="Super domain">Super</span> @endif
</a>
<a href="{{ route('admin.spaces.show', $space->id) }}">{{ $space->name }}</a>
@if ($space->super) <span class="badge badge-error oppose" title="Super domain">Super</span> @endif
<br />
<small>{{ $space->host }}</small>
</td>
<td>{{ $space->host }}</td>
<td>{{ $space->domain }}</td>
<td>
{{ $space->accounts_count }} / @if ($space->max_accounts > 0){{ $space->max_accounts }} @else <i class="ph">infinity</i>@endif
<td>{{ $space->domain }}
<small>
{{ $space->accounts_count }} / @if ($space->max_accounts > 0){{ $space->max_accounts }} @else <i class="ph">infinity</i>@endif<i class="ph">user</i>
</small>
</td>
<td>
@if ($space->isExpired())

View file

@ -5,7 +5,6 @@
if (auth()->user() && auth()->user()->admin) {
if (auth()->user()->superAdmin) {
$items['admin.spaces.index'] = ['title' => __('Spaces'), 'icon' => 'globe-hemisphere-west'];
$items['admin.phone_countries.index'] = ['title' => __('Phone Countries'), 'icon' => 'flag'];
} elseif (auth()->user()->admin) {
$items['admin.spaces.me'] = ['title' => __('My Space'), 'icon' => 'globe-hemisphere-west'];
}
@ -13,6 +12,7 @@
$items['admin.account.index'] = ['title' => __('Accounts'), 'icon' => 'users'];
$items['admin.contacts_lists.index'] = ['title' => __('Contacts Lists'), 'icon' => 'user-rectangle'];
$items['admin.statistics.show'] = ['title' => __('Statistics'), 'icon' => 'chart-donut'];
$items['admin.api_keys.index'] = ['title' => __('Settings'), 'icon' => 'gear'];
}
@endphp

View file

@ -30,20 +30,21 @@ use App\Http\Controllers\Admin\AccountAccountTypeController;
use App\Http\Controllers\Admin\AccountActionController;
use App\Http\Controllers\Admin\AccountActivityController;
use App\Http\Controllers\Admin\AccountContactController;
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
use App\Http\Controllers\Admin\AccountDeviceController;
use App\Http\Controllers\Admin\AccountDictionaryController;
use App\Http\Controllers\Admin\AccountImportController;
use App\Http\Controllers\Admin\AccountTypeController;
use App\Http\Controllers\Admin\AccountController as AdminAccountController;
use App\Http\Controllers\Admin\AccountStatisticsController;
use App\Http\Controllers\Admin\ContactsListController;
use App\Http\Controllers\Admin\AccountTypeController;
use App\Http\Controllers\Admin\ApiKeyController as AdminApiKeyController;
use App\Http\Controllers\Admin\ContactsListContactController;
use App\Http\Controllers\Admin\ContactsListController;
use App\Http\Controllers\Admin\ExternalAccountController;
use App\Http\Controllers\Admin\PhoneCountryController;
use App\Http\Controllers\Admin\ResetPasswordEmailController;
use App\Http\Controllers\Admin\StatisticsController;
use App\Http\Controllers\Admin\SpaceController;
use App\Http\Controllers\Admin\Space\EmailServerController;
use App\Http\Controllers\Admin\SpaceController;
use App\Http\Controllers\Admin\StatisticsController;
use Illuminate\Support\Facades\Route;
Route::redirect('/', 'login')->name('account.home');
@ -139,14 +140,14 @@ Route::middleware(['web_panel_enabled', 'space.check'])->group(function () {
Route::delete('delete', 'destroy')->name('destroy');
});
Route::prefix('password')->controller(PasswordController::class)->group(function () {
Route::get('/', 'show')->name('password.show');
Route::post('/', 'update')->name('password.update');
Route::name('password.')->prefix('password')->controller(PasswordController::class)->group(function () {
Route::get('/', 'show')->name('show');
Route::post('/', 'update')->name('update');
});
Route::prefix('api_key')->controller(ApiKeyController::class)->group(function () {
Route::get('/', 'show')->name('api_key.show');
Route::post('/', 'update')->name('api_key.update');
Route::name('api_keys.')->prefix('api_key')->controller(ApiKeyController::class)->group(function () {
Route::get('/', 'show')->name('show');
Route::post('/', 'update')->name('update');
});
Route::post('auth_tokens', 'Account\AuthTokenController@create')->name('auth_tokens.create');
@ -171,6 +172,14 @@ Route::middleware(['web_panel_enabled', 'space.check'])->group(function () {
});
});
Route::name('api_keys.')->prefix('api_keys')->controller(AdminApiKeyController::class)->group(function () {
Route::get('/', 'index')->name('index');
Route::get('create', 'create')->name('create');
Route::post('/', 'store')->name('store');
Route::get('{key}/delete', 'delete')->name('delete');
Route::delete('/', 'destroy')->name('destroy');
});
Route::middleware(['auth.super_admin'])->group(function () {
Route::resource('spaces', SpaceController::class);
Route::get('spaces/delete/{id}', 'Admin\SpaceController@delete')->name('spaces.delete');

View file

@ -30,7 +30,7 @@ class AccountBlockingTest extends TestCase
public function testBlocking()
{
$account = Account::factory()->withConsumedAccountCreationToken()->create();
$account->generateApiKey();
$account->generateUserApiKey();
config()->set('app.blocking_amount_events_authorized_during_period', 2);
@ -48,10 +48,10 @@ class AccountBlockingTest extends TestCase
public function testAdminBlocking()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($account)
->get($this->route . '/me')->assertStatus(200);

View file

@ -72,7 +72,7 @@ class AccountProvisioningTest extends TestCase
space(reload: true);
$account = Account::factory()->deactivated()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->assertEquals(false, $account->activated);
$this->assertFalse($account->currentProvisioningToken->used);
@ -108,7 +108,7 @@ class AccountProvisioningTest extends TestCase
public function testAuthenticatedWithPasswordProvisioning()
{
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$this->keyAuthenticated($password->account)
->get($this->accountRoute)
@ -141,7 +141,7 @@ class AccountProvisioningTest extends TestCase
$secondDomain = Space::factory()->create();
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$password->account->domain = $secondDomain->domain;
$password->account->save();
@ -162,7 +162,7 @@ class AccountProvisioningTest extends TestCase
$password = Password::factory()->create();
$password->account->display_name = "Anna O'Reily";
$password->account->save();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$provisioningToken = $password->account->provisioning_token;
@ -190,7 +190,7 @@ class AccountProvisioningTest extends TestCase
public function testPasswordResetProvisioning()
{
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$currentPassword = $password->password;
@ -232,7 +232,7 @@ class AccountProvisioningTest extends TestCase
$response->assertStatus(404);
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$password->account->activated = false;
$password->account->save();
@ -258,7 +258,7 @@ class AccountProvisioningTest extends TestCase
// Refresh the provisioning_token
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, '/api/accounts/' . $password->account->id . '/provision')
@ -292,7 +292,7 @@ class AccountProvisioningTest extends TestCase
$authToken = $response->json('token');
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$this->keyAuthenticated($password->account)
->json($this->method, '/api/accounts/auth_token/' . $authToken . '/attach')
@ -322,7 +322,7 @@ class AccountProvisioningTest extends TestCase
public function testTokenExpiration()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$expirationMinutes = 10;
$this->keyAuthenticated($account)
@ -356,7 +356,7 @@ class AccountProvisioningTest extends TestCase
public function testCoTURN()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$host = 'coturn.tld';
$realm = 'realm.tld';

View file

@ -34,7 +34,7 @@ class ApiAccountActionTest extends TestCase
$password = Password::factory()->create();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, $this->route.'/'.$password->account->id.'/actions', [
@ -95,7 +95,7 @@ class ApiAccountActionTest extends TestCase
$password = Password::factory()->create();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, $this->route.'/'.$password->account->id.'/actions', [
@ -119,7 +119,7 @@ class ApiAccountActionTest extends TestCase
$password = Password::factory()->create();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, $this->route.'/'.$password->account->id.'/actions', [

View file

@ -58,7 +58,7 @@ class ApiAccountApiKeyTest extends TestCase
public function testRequest()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->keyAuthenticated($account)
->json($this->method, '/api/accounts/me')
@ -104,7 +104,7 @@ class ApiAccountApiKeyTest extends TestCase
// Attach the auth_token to the account
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$this->keyAuthenticated($password->account)
->json($this->method, '/api/accounts/auth_token/' . $authToken . '/attach')

View file

@ -43,7 +43,7 @@ class ApiAccountContactsTest extends TestCase
$actionCode = '123';
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, $this->route . '/' . $password1->account->id . '/contacts/' . $password2->account->id)
@ -90,7 +90,7 @@ class ApiAccountContactsTest extends TestCase
]);
// /me
$password1->account->generateApiKey();
$password1->account->generateUserApiKey();
$password1->account->save();
$this->keyAuthenticated($password1->account)

View file

@ -132,7 +132,7 @@ class ApiAccountCreationTokenTest extends TestCase
public function testAdminEndpoint()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$response = $this->keyAuthenticated($admin)
->json($this->method, $this->adminRoute)
@ -268,7 +268,7 @@ class ApiAccountCreationTokenTest extends TestCase
public function testConsume()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$accountCreationToken = AccountCreationToken::factory()->create();
$token = $accountCreationToken->token;

View file

@ -31,7 +31,7 @@ class ApiAccountDictionaryTest extends TestCase
{
$account = Account::factory()->create();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$key = 'foo';
$value = 'bar';

View file

@ -31,9 +31,9 @@ class ApiAccountEmailChangeTest extends TestCase
public function testRequest()
{
$account = Account::factory()->withConsumedAccountCreationToken()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$otherAccount = Account::factory()->withEmail()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$newEmail = 'test@test.com';
$this->keyAuthenticated($account)
@ -77,7 +77,7 @@ class ApiAccountEmailChangeTest extends TestCase
public function testCodeExpiration()
{
$account = Account::factory()->withConsumedAccountCreationToken()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/request', [
@ -100,7 +100,7 @@ class ApiAccountEmailChangeTest extends TestCase
public function testUnvalidatedAccount()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/request', [
@ -126,7 +126,7 @@ class ApiAccountEmailChangeTest extends TestCase
$email = $emailChange->email;
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($emailChange->account)
->get('/api/accounts/me')

View file

@ -31,7 +31,7 @@ class ApiAccountExternalAccountTest extends TestCase
{
$account = Account::factory()->create();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$username = 'foo';

View file

@ -31,7 +31,7 @@ class ApiAccountMessageTest extends TestCase
public function testRequest()
{
$password = Password::factory()->admin()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$this->keyAuthenticated($password->account)
->json($this->method, $this->route, [

View file

@ -32,7 +32,7 @@ class ApiAccountPhoneChangeTest extends TestCase
public function testRequest()
{
$account = Account::factory()->withConsumedAccountCreationToken()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/request', [
@ -51,7 +51,7 @@ class ApiAccountPhoneChangeTest extends TestCase
public function testCodeExpiration()
{
$account = Account::factory()->withConsumedAccountCreationToken()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/request', [
@ -74,7 +74,7 @@ class ApiAccountPhoneChangeTest extends TestCase
public function testCreatePhoneByCountry()
{
$account = Account::factory()->withConsumedAccountCreationToken()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$frenchPhoneNumber = '+33612121212';
$dutchPhoneNumber = '+31612121212';
@ -103,7 +103,7 @@ class ApiAccountPhoneChangeTest extends TestCase
public function testUnvalidatedAccount()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/request', [
@ -129,7 +129,7 @@ class ApiAccountPhoneChangeTest extends TestCase
$phone = $phoneChange->phone;
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($phoneChange->account)
->get('/api/accounts/me')

View file

@ -77,7 +77,7 @@ class ApiAccountTest extends TestCase
public function testEmptyDevices()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->keyAuthenticated($account)
->get($this->route . '/me/devices')
@ -88,7 +88,7 @@ class ApiAccountTest extends TestCase
public function testUsernameNotPhone()
{
$account = Account::factory()->admin()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$username = '+33612121212';
$domain = Space::first()->domain;
@ -117,7 +117,7 @@ class ApiAccountTest extends TestCase
public function testUsernameNotSIP()
{
$password = Password::factory()->admin()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$username = 'blabla🔥';
$domain = Space::first()->domain;
@ -192,7 +192,7 @@ class ApiAccountTest extends TestCase
config()->set('app.sip_domain', $configDomain);
$account = Account::factory()->superAdmin()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$account->save();
$username = 'foobar';
@ -247,7 +247,7 @@ class ApiAccountTest extends TestCase
public function testCreateDomainAsAdmin()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$admin->save();
$username = 'foo';
@ -276,7 +276,7 @@ class ApiAccountTest extends TestCase
/*public function testCreateDomainAsSuperAdmin()
{
$superAdmin = Account::factory()->superAdmin()->create();
$superAdmin->generateApiKey();
$superAdmin->generateUserApiKey();
$superAdmin->save();
$username = 'foo';
@ -401,7 +401,7 @@ class ApiAccountTest extends TestCase
public function testAdminWithDictionary()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$entryKey = 'foo';
$entryValue = 'bar';
@ -588,7 +588,7 @@ class ApiAccountTest extends TestCase
$password = Password::factory()->create();
$password->account->activated = false;
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$password->account->save();
/**
@ -634,7 +634,7 @@ class ApiAccountTest extends TestCase
{
$confirmationKey = '0123456789abc';
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$password->account->confirmation_key = $confirmationKey;
$password->account->activated = false;
$password->account->save();
@ -704,7 +704,7 @@ class ApiAccountTest extends TestCase
config()->set('app.account_email_unique', true);
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$admin->save();
$this->keyAuthenticated($admin)
@ -720,7 +720,7 @@ class ApiAccountTest extends TestCase
public function testNonAsciiPasswordAdmin()
{
$password = Password::factory()->admin()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$username = 'username';
$domain = Space::first()->domain;
@ -747,7 +747,7 @@ class ApiAccountTest extends TestCase
$account = $password->account;
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$admin->save();
$username = 'changed';
@ -801,7 +801,7 @@ class ApiAccountTest extends TestCase
{
$confirmationKey = '0123';
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$password->account->confirmation_key = $confirmationKey;
$password->account->activated = false;
$password->account->save();
@ -853,7 +853,7 @@ class ApiAccountTest extends TestCase
$confirmationKey = '1234';
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$password->account->confirmation_key = $confirmationKey;
$password->account->activated = false;
$password->account->save();
@ -873,7 +873,7 @@ class ApiAccountTest extends TestCase
$phone = '+33612312312';
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$password->account->activated = false;
$password->account->phone = $phone;
$password->account->save();
@ -1079,7 +1079,7 @@ class ApiAccountTest extends TestCase
{
$confirmationKey = '0123';
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$password->account->confirmation_key = $confirmationKey;
$password->account->activated = false;
$password->account->save();
@ -1120,7 +1120,7 @@ class ApiAccountTest extends TestCase
public function testChangePassword()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$password = 'password';
$algorithm = 'MD5';
$newPassword = 'new_password';
@ -1193,7 +1193,7 @@ class ApiAccountTest extends TestCase
$account = Account::factory()->withEmail()->create();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
// deactivate
$this->keyAuthenticated($admin)
@ -1255,7 +1255,7 @@ class ApiAccountTest extends TestCase
Password::factory()->create();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
// /accounts
$this->keyAuthenticated($admin)
@ -1278,7 +1278,7 @@ class ApiAccountTest extends TestCase
public function testCodeExpires()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
// Activated, no no confirmation_key
$this->keyAuthenticated($admin)
@ -1326,7 +1326,7 @@ class ApiAccountTest extends TestCase
$password = Password::factory()->create();
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->delete($this->route . '/' . $password->account->id)

View file

@ -33,7 +33,7 @@ class ApiAccountTypeTest extends TestCase
public function testCreate()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, $this->route, [
@ -75,7 +75,7 @@ class ApiAccountTypeTest extends TestCase
public function testDelete()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, $this->route, [
@ -96,7 +96,7 @@ class ApiAccountTypeTest extends TestCase
public function testUpdate()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, $this->route, [
@ -125,7 +125,7 @@ class ApiAccountTypeTest extends TestCase
public function testAccountAddType()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$this->keyAuthenticated($admin)
->json($this->method, $this->route, [

View file

@ -30,10 +30,10 @@ class ApiAccountVcardsStorageTest extends TestCase
public function testAccountCrud()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$adminRoute = '/api/accounts/' . $account->id . '/vcards-storage';

View file

@ -58,7 +58,7 @@ class ApiAuthenticationTest extends TestCase
public function testAuthenticateWithKey()
{
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$response = $this->withHeaders([
'From' => 'sip:'.$password->account->identifier,

View file

@ -30,7 +30,7 @@ class ApiLocalizationTest extends TestCase
public function testUsernameNotPhone()
{
$password = Password::factory()->admin()->create();
$password->account->generateApiKey();
$password->account->generateUserApiKey();
$this->keyAuthenticated($password->account)
->withHeaders([

View file

@ -33,7 +33,7 @@ class ApiPhoneCountryTest extends TestCase
public function testCreatePhoneByCountry()
{
$account = Account::factory()->withConsumedAccountCreationToken()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$frenchPhoneNumber = '+33612121212';
$dutchPhoneNumber = '+31612121212';

View file

@ -40,7 +40,7 @@ class ApiPushNotificationTest extends TestCase
public function testCorrectParameters()
{
$account = Account::factory()->create();
$account->generateApiKey();
$account->generateUserApiKey();
$this->keyAuthenticated($account)
->json($this->method, $this->tokenRoute, [

View file

@ -32,7 +32,7 @@ class ApiSpaceEmailServerTest extends TestCase
public function testEmailServer()
{
$admin = Account::factory()->superAdmin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$emailHost = 'email.domain';
$route = $this->route . '/' . $admin->space->host . '/email';

View file

@ -33,7 +33,7 @@ class ApiSpaceTest extends TestCase
public function testBaseAdmin()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$secondDomain = Space::factory()->secondDomain()->create();
$username = 'foo';
@ -75,7 +75,7 @@ class ApiSpaceTest extends TestCase
public function testSuperAdmin()
{
$admin = Account::factory()->superAdmin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$thirdDomain = 'third.domain';
@ -139,7 +139,7 @@ class ApiSpaceTest extends TestCase
public function testUserCreation()
{
$admin = Account::factory()->superAdmin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$domain = 'domain.com';

View file

@ -33,7 +33,7 @@ class ApiSpaceWithMiddlewareTest extends TestCaseWithSpaceMiddleware
public function testExpiredSpace()
{
$superAdmin = Account::factory()->superAdmin()->create();
$superAdmin->generateApiKey();
$superAdmin->generateUserApiKey();
$username = 'username';
@ -41,7 +41,7 @@ class ApiSpaceWithMiddlewareTest extends TestCaseWithSpaceMiddleware
$admin = Account::factory()->fromSpace($space)->admin()->create();
// Try to create a new user as an admin
$admin->generateApiKey();
$admin->generateUserApiKey();
config()->set('app.root_host', $admin->domain);
space(reload: true);

View file

@ -35,7 +35,7 @@ class ApiStatisticsTest extends TestCase
public function testMessages()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$id = '1234';
$fromUsername = 'username';
@ -128,7 +128,7 @@ class ApiStatisticsTest extends TestCase
public function testCalls()
{
$admin = Account::factory()->admin()->create();
$admin->generateApiKey();
$admin->generateUserApiKey();
$id = '1234';
$fromUsername = 'username';