mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 01:58:07 +00:00
Fix FLEXIAPI-228 Add reset password email flow
This commit is contained in:
parent
93c98ae73f
commit
3d715afc23
25 changed files with 464 additions and 133 deletions
|
|
@ -1,7 +1,7 @@
|
|||
variables:
|
||||
ROCKY_8_IMAGE_VERSION: 20241113_143521_update_php_82
|
||||
ROCKY_9_IMAGE_VERSION: 20241114_161138_remove_redis
|
||||
DEBIAN_12_IMAGE_VERSION: 20241112_113948_update_package_and_dependencies
|
||||
DEBIAN_12_IMAGE_VERSION: 20241204_162237_update_download_linphone_org
|
||||
PHP_REDIS_REMI_VERSION: php-pecl-redis6-6.1.0-1
|
||||
PHP_IGBINARY_REMI_VERSION: php-pecl-igbinary-3.2.16-2
|
||||
PHP_MSGPACK_REMI_VERSION: php-pecl-msgpack-2.2.0-3
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ APP_PHONE_CHANGE_CODE_EXPIRATION_MINUTES=10
|
|||
APP_RECOVERY_CODE_EXPIRATION_MINUTES=10
|
||||
APP_PROVISIONING_TOKEN_EXPIRATION_MINUTES=0
|
||||
APP_API_KEY_EXPIRATION_MINUTES=60 # Number of minutes the unused API Keys are valid
|
||||
APP_RESET_PASSWORD_EMAIL_TOKEN_EXPIRATION_MINUTES=1440 # 24h
|
||||
|
||||
# Account creation and authentication
|
||||
ACCOUNT_EMAIL_UNIQUE=false # Emails are unique between all the accounts
|
||||
|
|
|
|||
|
|
@ -256,6 +256,11 @@ class Account extends Authenticatable
|
|||
return $this->hasMany(AuthToken::class);
|
||||
}
|
||||
|
||||
public function resetPasswordEmailTokens()
|
||||
{
|
||||
return $this->hasMany(ResetPasswordEmailToken::class)->latest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ abstract class Consommable extends Model
|
|||
$this->user_agent = $request->userAgent();
|
||||
}
|
||||
|
||||
public function offed(): bool
|
||||
{
|
||||
return $this->consumed() || $this->expired();
|
||||
}
|
||||
|
||||
public function consumed(): bool
|
||||
{
|
||||
return $this->{$this->consommableAttribute} == null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Account;
|
||||
|
||||
use App\ResetPasswordEmailToken;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ResetPasswordEmailController extends Controller
|
||||
{
|
||||
public function change(string $token)
|
||||
{
|
||||
$token = ResetPasswordEmailToken::where('token', $token)->firstOrFail();
|
||||
|
||||
return view('account.password_reset', [
|
||||
'token' => $token
|
||||
]);
|
||||
}
|
||||
|
||||
public function reset(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'token' => 'required|size:16',
|
||||
'password' => 'required|min:8|confirmed',
|
||||
'h-captcha-response' => captchaConfigured() ? 'required|HCaptcha' : ''
|
||||
]);
|
||||
|
||||
$token = ResetPasswordEmailToken::where('token', $request->get('token'))->firstOrFail();
|
||||
|
||||
if ($token->offed()) abort(403);
|
||||
|
||||
$token->account->updatePassword($request->get('password'));
|
||||
$token->consume();
|
||||
|
||||
return view('account.password_changed');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Account;
|
||||
use App\ResetPasswordEmailToken;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\ResetPassword;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class ResetPasswordEmailController extends Controller
|
||||
{
|
||||
public function create(int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
|
||||
return view('admin.account.reset_password_email.create', [
|
||||
'account' => $account
|
||||
]);
|
||||
}
|
||||
|
||||
public function send(int $accountId)
|
||||
{
|
||||
$account = Account::findOrFail($accountId);
|
||||
|
||||
$resetPasswordEmail = new ResetPasswordEmailToken;
|
||||
$resetPasswordEmail->account_id = $account->id;
|
||||
$resetPasswordEmail->token = Str::random(16);
|
||||
$resetPasswordEmail->email = $account->email;
|
||||
$resetPasswordEmail->save();
|
||||
|
||||
Mail::to($account)->send(new ResetPassword($resetPasswordEmail));
|
||||
|
||||
return redirect()->route('admin.account.activity.index', $account);
|
||||
}
|
||||
}
|
||||
|
|
@ -35,8 +35,7 @@ class Kernel extends HttpKernel
|
|||
\App\Http\Middleware\CheckForMaintenanceMode::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
\App\Http\Middleware\Space::class
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -59,8 +58,7 @@ class Kernel extends HttpKernel
|
|||
'throttle:600,1', // move to 600 instead of 60
|
||||
'bindings',
|
||||
'validate_json',
|
||||
'localization',
|
||||
'space'
|
||||
'localization'
|
||||
],
|
||||
];
|
||||
|
||||
|
|
@ -89,7 +87,6 @@ class Kernel extends HttpKernel
|
|||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'space' => \App\Http\Middleware\Space::class,
|
||||
'space.expired' => \App\Http\Middleware\IsSpaceExpired::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
|
|
|
|||
|
|
@ -4,16 +4,34 @@ namespace App\Http\Middleware;
|
|||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class IsSpaceExpired
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if ($request->user() && !$request->user()->superAdmin && $request->get('resolvedSpace')?->isExpired()) {
|
||||
abort(403, 'The related Space has expired');
|
||||
if (empty(config('app.root_domain'))) {
|
||||
return abort(503, 'APP_ROOT_DOMAIN is not configured');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
$space = \App\Space::where('host', $request->header('host'))->first();
|
||||
|
||||
if ($space) {
|
||||
if (!str_ends_with($space->host, config('app.root_domain'))) {
|
||||
return abort(503, 'The APP_ROOT_DOMAIN configured does not match with the current root domain');
|
||||
}
|
||||
|
||||
Config::set('app.url', '://' . $space->host);
|
||||
Config::set('app.sip_domain', $space->domain);
|
||||
|
||||
if ($request->user() && !$request->user()->superAdmin && $space?->isExpired()) {
|
||||
abort(403, 'The related Space has expired');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return abort(404, 'Host not configured');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class Space
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (empty(config('app.root_domain'))) {
|
||||
return abort(503, 'APP_ROOT_DOMAIN is not configured');
|
||||
}
|
||||
|
||||
$space = \App\Space::where('host', $request->header('host'))->first();
|
||||
|
||||
if ($space) {
|
||||
if (!str_ends_with($space->host, config('app.root_domain'))) {
|
||||
return abort(503, 'The APP_ROOT_DOMAIN configured does not match with the current root domain');
|
||||
}
|
||||
|
||||
Config::set('app.url', '://' . $space->host);
|
||||
Config::set('app.sip_domain', $space->domain);
|
||||
|
||||
$request->request->set('resolvedSpace', $space);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return abort(404, 'Host not configured');
|
||||
}
|
||||
}
|
||||
48
flexiapi/app/Mail/ResetPassword.php
Normal file
48
flexiapi/app/Mail/ResetPassword.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2024 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\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
use App\Account;
|
||||
use App\ResetPasswordEmailToken;
|
||||
|
||||
class ResetPassword extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
private $token;
|
||||
|
||||
public function __construct(ResetPasswordEmailToken $token)
|
||||
{
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
public function build()
|
||||
{
|
||||
return $this->view('mails.reset_password')
|
||||
->text('mails.reset_password')
|
||||
->with([
|
||||
'token' => $this->token
|
||||
]);
|
||||
}
|
||||
}
|
||||
28
flexiapi/app/ResetPasswordEmailToken.php
Normal file
28
flexiapi/app/ResetPasswordEmailToken.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ResetPasswordEmailToken extends Consommable
|
||||
{
|
||||
use HasFactory;
|
||||
protected ?string $configExpirationMinutesKey = 'reset_password_email_token_expiration_minutes';
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
|
||||
public function consume()
|
||||
{
|
||||
$this->used = true;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function consumed(): bool
|
||||
{
|
||||
return $this->used == true;
|
||||
}
|
||||
}
|
||||
144
flexiapi/composer.lock
generated
144
flexiapi/composer.lock
generated
|
|
@ -1325,16 +1325,16 @@
|
|||
},
|
||||
{
|
||||
"name": "giggsey/libphonenumber-for-php-lite",
|
||||
"version": "8.13.50",
|
||||
"version": "8.13.51",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/giggsey/libphonenumber-for-php-lite.git",
|
||||
"reference": "57bb2bfd8d4a9896ed961c584141247f2a35bc04"
|
||||
"reference": "34e43f33e21a8cdeebc36e9de57157ae821ef56b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/giggsey/libphonenumber-for-php-lite/zipball/57bb2bfd8d4a9896ed961c584141247f2a35bc04",
|
||||
"reference": "57bb2bfd8d4a9896ed961c584141247f2a35bc04",
|
||||
"url": "https://api.github.com/repos/giggsey/libphonenumber-for-php-lite/zipball/34e43f33e21a8cdeebc36e9de57157ae821ef56b",
|
||||
"reference": "34e43f33e21a8cdeebc36e9de57157ae821ef56b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1404,7 +1404,7 @@
|
|||
"issues": "https://github.com/giggsey/libphonenumber-for-php-lite/issues",
|
||||
"source": "https://github.com/giggsey/libphonenumber-for-php-lite"
|
||||
},
|
||||
"time": "2024-11-18T09:58:30+00:00"
|
||||
"time": "2024-12-02T09:22:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "graham-campbell/result-type",
|
||||
|
|
@ -4790,16 +4790,16 @@
|
|||
},
|
||||
{
|
||||
"name": "psy/psysh",
|
||||
"version": "v0.12.4",
|
||||
"version": "v0.12.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bobthecow/psysh.git",
|
||||
"reference": "2fd717afa05341b4f8152547f142cd2f130f6818"
|
||||
"reference": "36a03ff27986682c22985e56aabaf840dd173cb5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/2fd717afa05341b4f8152547f142cd2f130f6818",
|
||||
"reference": "2fd717afa05341b4f8152547f142cd2f130f6818",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/36a03ff27986682c22985e56aabaf840dd173cb5",
|
||||
"reference": "36a03ff27986682c22985e56aabaf840dd173cb5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4826,12 +4826,12 @@
|
|||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "0.12.x-dev"
|
||||
},
|
||||
"bamarni-bin": {
|
||||
"bin-links": false,
|
||||
"forward-command": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "0.12.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
|
@ -4863,9 +4863,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bobthecow/psysh/issues",
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.4"
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.5"
|
||||
},
|
||||
"time": "2024-06-10T01:18:23+00:00"
|
||||
"time": "2024-11-29T06:14:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
|
|
@ -5599,16 +5599,16 @@
|
|||
},
|
||||
{
|
||||
"name": "respect/validation",
|
||||
"version": "2.3.8",
|
||||
"version": "2.3.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Respect/Validation.git",
|
||||
"reference": "25ce44c7ee9613d260c7c0e44e27daa2131f383a"
|
||||
"reference": "c96758eb27339c97486f311f25fbc797df2f6736"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Respect/Validation/zipball/25ce44c7ee9613d260c7c0e44e27daa2131f383a",
|
||||
"reference": "25ce44c7ee9613d260c7c0e44e27daa2131f383a",
|
||||
"url": "https://api.github.com/repos/Respect/Validation/zipball/c96758eb27339c97486f311f25fbc797df2f6736",
|
||||
"reference": "c96758eb27339c97486f311f25fbc797df2f6736",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -5661,9 +5661,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Respect/Validation/issues",
|
||||
"source": "https://github.com/Respect/Validation/tree/2.3.8"
|
||||
"source": "https://github.com/Respect/Validation/tree/2.3.9"
|
||||
},
|
||||
"time": "2024-11-26T09:14:36+00:00"
|
||||
"time": "2024-11-28T09:44:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/uri",
|
||||
|
|
@ -5922,12 +5922,12 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Scyllaly\\HCaptcha\\HCaptchaServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"HCaptcha": "Scyllaly\\HCaptcha\\Facades\\HCaptcha"
|
||||
}
|
||||
},
|
||||
"providers": [
|
||||
"Scyllaly\\HCaptcha\\HCaptchaServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
|
@ -7034,16 +7034,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.5.0",
|
||||
"version": "v3.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
|
||||
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
|
||||
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
|
||||
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -7081,7 +7081,7 @@
|
|||
"description": "A generic function and convention to trigger deprecation notices",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7097,7 +7097,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
"time": "2024-09-25T14:20:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/error-handler",
|
||||
|
|
@ -7256,16 +7256,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher-contracts",
|
||||
"version": "v3.5.0",
|
||||
"version": "v3.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
|
||||
"reference": "8f93aec25d41b72493c6ddff14e916177c9efc50"
|
||||
"reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50",
|
||||
"reference": "8f93aec25d41b72493c6ddff14e916177c9efc50",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f",
|
||||
"reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -7312,7 +7312,7 @@
|
|||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0"
|
||||
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7328,7 +7328,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
"time": "2024-09-25T14:20:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
|
|
@ -7396,16 +7396,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v6.4.15",
|
||||
"version": "v6.4.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6"
|
||||
"reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6",
|
||||
"reference": "9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/431771b7a6f662f1575b3cfc8fd7617aa9864d57",
|
||||
"reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -7453,7 +7453,7 @@
|
|||
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v6.4.15"
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v6.4.16"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7469,20 +7469,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-08T16:09:24+00:00"
|
||||
"time": "2024-11-13T18:58:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v6.4.15",
|
||||
"version": "v6.4.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "b002a5b3947653c5aee3adac2a024ea615fd3ff5"
|
||||
"reference": "8838b5b21d807923b893ccbfc2cbeda0f1bc00f0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/b002a5b3947653c5aee3adac2a024ea615fd3ff5",
|
||||
"reference": "b002a5b3947653c5aee3adac2a024ea615fd3ff5",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/8838b5b21d807923b893ccbfc2cbeda0f1bc00f0",
|
||||
"reference": "8838b5b21d807923b893ccbfc2cbeda0f1bc00f0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -7567,7 +7567,7 @@
|
|||
"description": "Provides a structured process for converting a Request into a Response",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v6.4.15"
|
||||
"source": "https://github.com/symfony/http-kernel/tree/v6.4.16"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -7583,7 +7583,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-13T13:57:37+00:00"
|
||||
"time": "2024-11-27T12:49:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mailer",
|
||||
|
|
@ -8449,16 +8449,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v6.4.13",
|
||||
"version": "v6.4.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/routing.git",
|
||||
"reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278"
|
||||
"reference": "91e02e606b4b705c2f4fb42f7e7708b7923a3220"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/640a74250d13f9c30d5ca045b6aaaabcc8215278",
|
||||
"reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/91e02e606b4b705c2f4fb42f7e7708b7923a3220",
|
||||
"reference": "91e02e606b4b705c2f4fb42f7e7708b7923a3220",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8512,7 +8512,7 @@
|
|||
"url"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/routing/tree/v6.4.13"
|
||||
"source": "https://github.com/symfony/routing/tree/v6.4.16"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8528,20 +8528,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-01T08:30:56+00:00"
|
||||
"time": "2024-11-13T15:31:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
"version": "v3.5.0",
|
||||
"version": "v3.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/service-contracts.git",
|
||||
"reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
|
||||
"reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
|
||||
"reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
|
||||
"reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8595,7 +8595,7 @@
|
|||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.5.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8611,7 +8611,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
"time": "2024-09-25T14:20:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
|
|
@ -8796,16 +8796,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/translation-contracts",
|
||||
"version": "v3.5.0",
|
||||
"version": "v3.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation-contracts.git",
|
||||
"reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a"
|
||||
"reference": "4667ff3bd513750603a09c8dedbea942487fb07c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
|
||||
"reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
|
||||
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c",
|
||||
"reference": "4667ff3bd513750603a09c8dedbea942487fb07c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -8854,7 +8854,7 @@
|
|||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/translation-contracts/tree/v3.5.0"
|
||||
"source": "https://github.com/symfony/translation-contracts/tree/v3.5.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8870,7 +8870,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
"time": "2024-09-25T14:20:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/uid",
|
||||
|
|
@ -10101,16 +10101,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/dependency-injection",
|
||||
"version": "v6.4.15",
|
||||
"version": "v6.4.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dependency-injection.git",
|
||||
"reference": "70ab1f65a4516ef741e519ea938e6aa465e6aa36"
|
||||
"reference": "7a379d8871f6a36f01559c14e11141cc02eb8dc8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/70ab1f65a4516ef741e519ea938e6aa465e6aa36",
|
||||
"reference": "70ab1f65a4516ef741e519ea938e6aa465e6aa36",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7a379d8871f6a36f01559c14e11141cc02eb8dc8",
|
||||
"reference": "7a379d8871f6a36f01559c14e11141cc02eb8dc8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -10162,7 +10162,7 @@
|
|||
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/dependency-injection/tree/v6.4.15"
|
||||
"source": "https://github.com/symfony/dependency-injection/tree/v6.4.16"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -10178,7 +10178,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-09T06:56:25+00:00"
|
||||
"time": "2024-11-25T14:52:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ return [
|
|||
'phone_change_code_expiration_minutes' => env('APP_PHONE_CHANGE_CODE_EXPIRATION_MINUTES', 10),
|
||||
'recovery_code_expiration_minutes' => env('APP_RECOVERY_CODE_EXPIRATION_MINUTES', 10),
|
||||
'provisioning_token_expiration_minutes' => env('APP_PROVISIONING_TOKEN_EXPIRATION_MINUTES', 0),
|
||||
'reset_password_email_token_expiration_minutes' => env('APP_RESET_PASSWORD_EMAIL_TOKEN_EXPIRATION_MINUTES', 1440),
|
||||
/**
|
||||
* Amount of minutes before re-authorizing the generation of a new account creation token
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
<?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::create('reset_password_email_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('token', 16);
|
||||
$table->boolean('used')->default(false);
|
||||
$table->string('email');
|
||||
$table->integer('account_id')->unsigned();
|
||||
$table->string('ip')->nullable();
|
||||
$table->string('user_agent')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('account_id')->references('id')
|
||||
->on('accounts')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('reset_password_email_tokens');
|
||||
}
|
||||
};
|
||||
1
flexiapi/public/css/style.css
vendored
1
flexiapi/public/css/style.css
vendored
|
|
@ -619,6 +619,7 @@ table tr td a {
|
|||
|
||||
table tr td,
|
||||
table tr th {
|
||||
width: 20rem;
|
||||
padding: 1rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
|
|
|||
18
flexiapi/resources/views/account/password_changed.blade.php
Normal file
18
flexiapi/resources/views/account/password_changed.blade.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
@extends('layouts.main', ['welcome' => true])
|
||||
|
||||
@section('content')
|
||||
<section>
|
||||
<header>
|
||||
<h1><i class="ph">lock</i> Reset password</h1>
|
||||
</header>
|
||||
|
||||
<p>Your password was updated properly.</p>
|
||||
<p>
|
||||
<a class="btn" href="{{ route('account.login')}}">Authenticate</a>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="on_desktop">
|
||||
<img src="{{ asset('img/lock.svg') }}">
|
||||
</section>
|
||||
@endsection
|
||||
39
flexiapi/resources/views/account/password_reset.blade.php
Normal file
39
flexiapi/resources/views/account/password_reset.blade.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
@extends('layouts.main', ['welcome' => true])
|
||||
|
||||
@section('content')
|
||||
<section>
|
||||
<header>
|
||||
<h1><i class="ph">lock</i> Reset password</h1>
|
||||
</header>
|
||||
|
||||
@if ($token->offed())
|
||||
<p>This link is not available anymore.</p>
|
||||
@else
|
||||
<form id="password_update" method="POST" action="{{ route('account.reset_password_email.reset') }}" accept-charset="UTF-8">
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="token" value="{{ $token->token }}">
|
||||
<div class="large">
|
||||
<input type="password" name="password" required>
|
||||
<label for="password">Password</label>
|
||||
@include('parts.errors', ['name' => 'password'])
|
||||
</div>
|
||||
<div class="large">
|
||||
<input type="password" name="password_confirmation" required>
|
||||
<label for="password_confirmation">Password confirmation</label>
|
||||
@include('parts.errors', ['name' => 'password_confirmation'])
|
||||
</div>
|
||||
|
||||
@include('parts.captcha')
|
||||
|
||||
<div class="large">
|
||||
<input class="btn" type="submit" value="Reset">
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
</section>
|
||||
|
||||
<section class="on_desktop">
|
||||
<img src="{{ asset('img/lock.svg') }}">
|
||||
</section>
|
||||
@endsection
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr @if ($account->accountCreationToken->consumed()) class="disabled crossed" @endif>
|
||||
<tr @if ($account->accountCreationToken->offed()) class="disabled crossed" @endif>
|
||||
<td>****</td>
|
||||
<td>
|
||||
{{ $account->accountCreationToken->created_at }}
|
||||
|
|
@ -88,8 +88,8 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($account->recoveryCodes as $recoveryCode)
|
||||
<tr @if ($recoveryCode->consumed()) class="disabled crossed" @endif>
|
||||
@foreach ($account->recoveryCodes as $key => $recoveryCode)
|
||||
<tr @if ($recoveryCode->offed() || $key > 0) class="disabled crossed" @endif>
|
||||
<td>****</td>
|
||||
<td>
|
||||
{{ $recoveryCode->created_at }}
|
||||
|
|
@ -119,8 +119,8 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($account->phoneChangeCodes as $phoneChangeCode)
|
||||
<tr @if ($phoneChangeCode->consumed()) class="disabled crossed" @endif>
|
||||
@foreach ($account->phoneChangeCodes as $key => $phoneChangeCode)
|
||||
<tr @if ($phoneChangeCode->offed() || $key > 0) class="disabled crossed" @endif>
|
||||
<td>{{ $phoneChangeCode->phone }}</td>
|
||||
<td>{{ $phoneChangeCode->code ?? '-' }}</td>
|
||||
<td>
|
||||
|
|
@ -151,8 +151,8 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($account->emailChangeCodes as $emailChangeCode)
|
||||
<tr @if ($emailChangeCode->consumed()) class="disabled crossed" @endif>
|
||||
@foreach ($account->emailChangeCodes as $key => $emailChangeCode)
|
||||
<tr @if ($emailChangeCode->offed() || $key > 0) class="disabled crossed" @endif>
|
||||
<td>{{ $emailChangeCode->email }}</td>
|
||||
<td>{{ $emailChangeCode->code ?? '-' }}</td>
|
||||
<td>
|
||||
|
|
@ -182,8 +182,8 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($account->provisioningTokens as $provisioningToken)
|
||||
<tr @if ($provisioningToken->consumed()) class="disabled crossed" @endif>
|
||||
@foreach ($account->provisioningTokens as $key => $provisioningToken)
|
||||
<tr @if ($provisioningToken->offed() || $key > 0) class="disabled crossed" @endif>
|
||||
<td>{{ $provisioningToken->token }}</td>
|
||||
<td>
|
||||
{{ $provisioningToken->created_at }}
|
||||
|
|
@ -200,4 +200,34 @@
|
|||
</table>
|
||||
@endif
|
||||
|
||||
@if ($account->resetPasswordEmailTokens->isNotEmpty())
|
||||
<h3>Set Password Emails</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Token</th>
|
||||
<th>Created</th>
|
||||
<th>Used</th>
|
||||
<th>Email</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($account->resetPasswordEmailTokens as $key => $resetPasswordEmailToken)
|
||||
<tr @if ($resetPasswordEmailToken->offed() || $key > 0) class="disabled crossed" @endif>
|
||||
<td>{{ $resetPasswordEmailToken->token }}</td>
|
||||
<td>
|
||||
{{ $resetPasswordEmailToken->created_at }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $resetPasswordEmailToken->consumed() ? $resetPasswordEmailToken->updated_at : '-' }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $resetPasswordEmailToken->email }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@endif
|
||||
|
||||
@endsection
|
||||
|
|
@ -83,6 +83,14 @@
|
|||
value="@if($account->id){{ $account->email }}@else{{ old('email') }}@endif">
|
||||
<label for="email">Email</label>
|
||||
@include('parts.errors', ['name' => 'email'])
|
||||
|
||||
@if (!empty($account->email))
|
||||
<p class="oppose">
|
||||
<a href="{{ route('admin.account.reset_password_email.create', $account) }}">
|
||||
Send an email to the user to reset the password
|
||||
</a>
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumb')
|
||||
@include('admin.account.parts.breadcrumb_accounts_index')
|
||||
@include('admin.account.parts.breadcrumb_accounts_edit', ['account' => $account])
|
||||
<li class="breadcrumb-item active" aria-current="page">Reset Password emails</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<header>
|
||||
<h1><i class="ph">envelope</i> Send a Reset Password email</h1>
|
||||
</header>
|
||||
|
||||
<p>An email will be sent to <b>{{ $account->email }}</b> with a unique link allowing the user to reset its password.</p>
|
||||
|
||||
<p>This link will be available for {{ config('app.reset_password_email_token_expiration_minutes')/60 }} hours.</p>
|
||||
|
||||
<p>
|
||||
<a class="btn" href="{{ route('admin.account.reset_password_email.send', $account) }}">
|
||||
<i class="ph">paper-plane-right</i> Send
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@endsection
|
||||
21
flexiapi/resources/views/mails/reset_password.blade.php
Normal file
21
flexiapi/resources/views/mails/reset_password.blade.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Reset your password on {{ config('app.name') }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hello,</p>
|
||||
<p>
|
||||
You are invited to reset your {{ $token->account->identifier }} account password on {{ config('app.name') }} via your email account.
|
||||
</p>
|
||||
<p>The following link will be valid for {{ config('app.reset_password_email_token_expiration_minutes')/60 }} hours.</p>
|
||||
<p>
|
||||
<a href="{{ route('account.reset_password_email.change', $token->token) }}">
|
||||
{{ route('account.reset_password_email.change', $token->token) }}
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
Regards,<br />
|
||||
{{ config('mail.signature') }}
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
10
flexiapi/resources/views/mails/reset_password_text.blade.php
Normal file
10
flexiapi/resources/views/mails/reset_password_text.blade.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
Hello,
|
||||
|
||||
You are invited to reset your {{ $token->account->identifier }} account password on {{ config('app.name') }} via your email account.
|
||||
|
||||
The following link will be valid for {{ config('app.reset_password_email_token_expiration_minutes')/60 }} hours.
|
||||
|
||||
{{ route('account.reset_password_email.change', $token->token) }}
|
||||
|
||||
Regards,
|
||||
{{ config('mail.signature') }}
|
||||
|
|
@ -39,6 +39,7 @@ use App\Http\Controllers\Admin\AccountStatisticsController;
|
|||
use App\Http\Controllers\Admin\ContactsListController;
|
||||
use App\Http\Controllers\Admin\ContactsListContactController;
|
||||
use App\Http\Controllers\Admin\PhoneCountryController;
|
||||
use App\Http\Controllers\Admin\ResetPasswordEmailController;
|
||||
use App\Http\Controllers\Admin\SpaceController;
|
||||
use App\Http\Controllers\Admin\StatisticsController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
|
@ -47,10 +48,14 @@ Route::redirect('/', 'login')->name('account.home');
|
|||
Route::get('documentation', 'Account\AccountController@documentation')->name('account.documentation');
|
||||
Route::get('about', 'AboutController@about')->name('about');
|
||||
|
||||
Route::group(['middleware' => 'web_panel_enabled'], function () {
|
||||
Route::middleware(['web_panel_enabled', 'space.expired'])->group(function () {
|
||||
Route::get('login', 'Account\AuthenticateController@login')->name('account.login');
|
||||
Route::post('authenticate', 'Account\AuthenticateController@authenticate')->name('account.authenticate');
|
||||
Route::get('authenticate/qrcode/{token?}', 'Account\AuthenticateController@loginAuthToken')->name('account.authenticate.auth_token');
|
||||
Route::get('logout', 'Account\AuthenticateController@logout')->name('account.logout');
|
||||
|
||||
Route::get('reset_password/{token}', 'Account\ResetPasswordEmailController@change')->name('account.reset_password_email.change');
|
||||
Route::post('reset_password', 'Account\ResetPasswordEmailController@reset')->name('account.reset_password_email.reset');
|
||||
|
||||
// Deprecated
|
||||
Route::get('authenticate/email/{code}', 'Account\AuthenticateController@validateEmail')->name('account.authenticate.email_confirm');
|
||||
|
|
@ -100,10 +105,6 @@ Route::middleware(['web_panel_enabled', 'space.expired'])->group(function () {
|
|||
Route::post('confirm', 'confirm')->name('account.recovery.confirm');
|
||||
});
|
||||
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::get('logout', 'Account\AuthenticateController@logout')->name('account.logout');
|
||||
});
|
||||
|
||||
Route::name('account.')->middleware(['auth', 'auth.check_blocked'])->group(function () {
|
||||
Route::get('blocked', 'Account\AccountController@blocked')->name('blocked');
|
||||
|
||||
|
|
@ -201,6 +202,11 @@ Route::middleware(['web_panel_enabled', 'space.expired'])->group(function () {
|
|||
Route::post('{account_id}/contacts_lists', 'contactsListAdd')->name('contacts_lists.attach');
|
||||
});
|
||||
|
||||
Route::name('reset_password_email.')->controller(ResetPasswordEmailController::class)->prefix('{account_id}/reset_password_emails')->group(function () {
|
||||
Route::get('create', 'create')->name('create');
|
||||
Route::get('send', 'send')->name('send');
|
||||
});
|
||||
|
||||
Route::name('import.')->prefix('import')->controller(AccountImportController::class)->group(function () {
|
||||
Route::get('/', 'create')->name('create');
|
||||
Route::post('/', 'store')->name('store');
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
namespace Tests;
|
||||
|
||||
use App\PhoneCountry;
|
||||
use App\Http\Middleware\Space;
|
||||
use App\Http\Middleware\IsSpaceExpired;
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ abstract class TestCase extends BaseTestCase
|
|||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->withoutMiddleware([Space::class]);
|
||||
$this->withoutMiddleware([IsSpaceExpired::class]);
|
||||
|
||||
PhoneCountry::truncate();
|
||||
PhoneCountry::factory()->france()->activated()->create();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
namespace Tests;
|
||||
|
||||
use App\Http\Middleware\Space;
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue