mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
New code for email address change in profile. See #857
This commit is contained in:
parent
ea1d543795
commit
91e96aa4b9
51
app/Events/UserChangedEmail.php
Normal file
51
app/Events/UserChangedEmail.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* UserChangedEmail.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the
|
||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events;
|
||||
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class UserChangedEmail
|
||||
*
|
||||
* @package FireflyIII\Events
|
||||
*/
|
||||
class UserChangedEmail extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/** @var string */
|
||||
public $ipAddress;
|
||||
/** @var string */
|
||||
public $newEmail;
|
||||
/** @var string */
|
||||
public $oldEmail;
|
||||
/** @var User */
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* UserChangedEmail constructor.
|
||||
*
|
||||
* @param User $user
|
||||
* @param string $newEmail
|
||||
* @param string $oldEmail
|
||||
* @param string $ipAddress
|
||||
*/
|
||||
public function __construct(User $user, string $newEmail, string $oldEmail, string $ipAddress)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->ipAddress = $ipAddress;
|
||||
$this->oldEmail = $oldEmail;
|
||||
$this->newEmail = $newEmail;
|
||||
}
|
||||
}
|
@ -15,11 +15,15 @@ namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Events\RegisteredUser;
|
||||
use FireflyIII\Events\RequestedNewPassword;
|
||||
use FireflyIII\Events\UserChangedEmail;
|
||||
use FireflyIII\Mail\ConfirmEmailChangeMail;
|
||||
use FireflyIII\Mail\RegisteredUser as RegisteredUserMail;
|
||||
use FireflyIII\Mail\RequestedNewPassword as RequestedNewPasswordMail;
|
||||
use FireflyIII\Mail\UndoEmailChangeMail;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Log;
|
||||
use Mail;
|
||||
use Preferences;
|
||||
use Swift_TransportException;
|
||||
|
||||
/**
|
||||
@ -54,6 +58,54 @@ class UserEventHandler
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserChangedEmail $event
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function sendEmailChangeConfirmMail(UserChangedEmail $event): bool
|
||||
{
|
||||
$newEmail = $event->newEmail;
|
||||
$oldEmail = $event->oldEmail;
|
||||
$user = $event->user;
|
||||
$ipAddress = $event->ipAddress;
|
||||
$token = Preferences::getForUser($user, 'email_change_confirm_token', 'invalid');
|
||||
$uri = route('profile.confirm-email-change', [$token->data]);
|
||||
try {
|
||||
Mail::to($newEmail)->send(new ConfirmEmailChangeMail($newEmail, $oldEmail, $uri, $ipAddress));
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Swift_TransportException $e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserChangedEmail $event
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function sendEmailChangeUndoMail(UserChangedEmail $event): bool
|
||||
{
|
||||
$newEmail = $event->newEmail;
|
||||
$oldEmail = $event->oldEmail;
|
||||
$user = $event->user;
|
||||
$ipAddress = $event->ipAddress;
|
||||
$token = Preferences::getForUser($user, 'email_change_undo_token', 'invalid');
|
||||
$uri = route('profile.undo-email-change', [$token->data, hash('sha256', $oldEmail)]);
|
||||
try {
|
||||
Mail::to($oldEmail)->send(new UndoEmailChangeMail($newEmail, $oldEmail, $uri, $ipAddress));
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Swift_TransportException $e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestedNewPassword $event
|
||||
*
|
||||
|
@ -14,6 +14,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
use FireflyConfig;
|
||||
use FireflyIII\Events\UserChangedEmail;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Cookie\CookieJar;
|
||||
|
@ -13,10 +13,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Events\UserChangedEmail;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Exceptions\ValidationException;
|
||||
use FireflyIII\Http\Middleware\IsLimitedUser;
|
||||
use FireflyIII\Http\Requests\DeleteAccountFormRequest;
|
||||
use FireflyIII\Http\Requests\EmailFormRequest;
|
||||
use FireflyIII\Http\Requests\ProfileFormRequest;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Hash;
|
||||
@ -48,10 +53,23 @@ class ProfileController extends Controller
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
$this->middleware(IsLimitedUser::class);
|
||||
$this->middleware(IsLimitedUser::class)->except(['confirmEmailChange', 'undoEmailChange']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return View
|
||||
*/
|
||||
public function changeEmail()
|
||||
{
|
||||
$title = auth()->user()->email;
|
||||
$email = auth()->user()->email;
|
||||
$subTitle = strval(trans('firefly.change_your_email'));
|
||||
$subTitleIcon = 'fa-envelope';
|
||||
|
||||
return view('profile.change-email', compact('title', 'subTitle', 'subTitleIcon', 'email'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return View
|
||||
*/
|
||||
@ -64,6 +82,37 @@ class ProfileController extends Controller
|
||||
return view('profile.change-password', compact('title', 'subTitle', 'subTitleIcon'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function confirmEmailChange(string $token)
|
||||
{
|
||||
// find preference with this token value.
|
||||
$set = Preferences::findByName('email_change_confirm_token');
|
||||
$user = null;
|
||||
/** @var Preference $preference */
|
||||
foreach ($set as $preference) {
|
||||
if ($preference->data === $token) {
|
||||
$user = $preference->user;
|
||||
}
|
||||
}
|
||||
// update user to clear blocked and blocked_code.
|
||||
if (is_null($user)) {
|
||||
throw new FireflyException('Invalid token.');
|
||||
}
|
||||
$user->blocked = 0;
|
||||
$user->blocked_code = '';
|
||||
$user->save();
|
||||
|
||||
// return to login.
|
||||
Session::flash('success', strval(trans('firefly.login_with_new_email')));
|
||||
|
||||
return redirect(route('login'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return View
|
||||
*/
|
||||
@ -95,6 +144,49 @@ class ProfileController extends Controller
|
||||
return view('profile.index', compact('subTitle', 'userId', 'accessToken'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EmailFormRequest $request
|
||||
* @param UserRepositoryInterface $repository
|
||||
*
|
||||
* @return $this|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function postChangeEmail(EmailFormRequest $request, UserRepositoryInterface $repository)
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$newEmail = $request->string('email');
|
||||
$oldEmail = $user->email;
|
||||
if ($newEmail === $user->email) {
|
||||
Session::flash('error', strval(trans('firefly.email_not_changed')));
|
||||
|
||||
return redirect(route('profile.change-email'))->withInput();
|
||||
}
|
||||
$existing = $repository->findByEmail($newEmail);
|
||||
if (!is_null($existing)) {
|
||||
// force user logout.
|
||||
$this->guard()->logout();
|
||||
$request->session()->invalidate();
|
||||
|
||||
Session::flash('success', strval(trans('firefly.email_changed')));
|
||||
|
||||
return redirect(route('index'));
|
||||
}
|
||||
|
||||
// now actually update user:
|
||||
$repository->changeEmail($user, $newEmail);
|
||||
|
||||
// call event.
|
||||
$ipAddress = $request->ip();
|
||||
event(new UserChangedEmail($user, $newEmail, $oldEmail, $ipAddress));
|
||||
|
||||
// force user logout.
|
||||
Auth::guard()->logout();
|
||||
$request->session()->invalidate();
|
||||
Session::flash('success', strval(trans('firefly.email_changed')));
|
||||
|
||||
return redirect(route('index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProfileFormRequest $request
|
||||
* @param UserRepositoryInterface $repository
|
||||
@ -160,6 +252,53 @@ class ProfileController extends Controller
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
* @param string $hash
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function undoEmailChange(string $token, string $hash)
|
||||
{
|
||||
// find preference with this token value.
|
||||
$set = Preferences::findByName('email_change_undo_token');
|
||||
$user = null;
|
||||
/** @var Preference $preference */
|
||||
foreach ($set as $preference) {
|
||||
if ($preference->data === $token) {
|
||||
$user = $preference->user;
|
||||
}
|
||||
}
|
||||
if (is_null($user)) {
|
||||
throw new FireflyException('Invalid token.');
|
||||
}
|
||||
|
||||
// found user.
|
||||
// which email address to return to?
|
||||
$set = Preferences::beginsWith($user, 'previous_email_');
|
||||
$match = null;
|
||||
foreach ($set as $entry) {
|
||||
$hashed = hash('sha256', $entry->data);
|
||||
if ($hashed === $hash) {
|
||||
$match = $entry->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_null($match)) {
|
||||
throw new FireflyException('Invalid token.');
|
||||
}
|
||||
// change user back
|
||||
$user->email = $match;
|
||||
$user->blocked = 0;
|
||||
$user->blocked_code = '';
|
||||
$user->save();
|
||||
|
||||
// return to login.
|
||||
Session::flash('success', strval(trans('firefly.login_with_old_email')));
|
||||
|
||||
return redirect(route('login'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $current
|
||||
|
@ -44,8 +44,13 @@ class Authenticate
|
||||
return redirect()->guest('login');
|
||||
}
|
||||
if (intval(auth()->user()->blocked) === 1) {
|
||||
$message = strval(trans('firefly.block_account_logout'));
|
||||
if (auth()->user()->blocked_code === 'email_changed') {
|
||||
$message = strval(trans('firefly.email_changed_logout'));
|
||||
}
|
||||
|
||||
Session::flash('logoutMessage', $message);
|
||||
Auth::guard($guard)->logout();
|
||||
Session::flash('logoutMessage', trans('firefly.block_account_logout'));
|
||||
|
||||
return redirect()->guest('login');
|
||||
}
|
||||
|
42
app/Http/Requests/EmailFormRequest.php
Normal file
42
app/Http/Requests/EmailFormRequest.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* EmailFormRequest.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
* This software may be modified and distributed under the terms of the
|
||||
* Creative Commons Attribution-ShareAlike 4.0 International License.
|
||||
*
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
/**
|
||||
* Class EmailFormRequest
|
||||
*
|
||||
*
|
||||
* @package FireflyIII\Http\Requests
|
||||
*/
|
||||
class EmailFormRequest extends Request
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// Only allow logged in users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
// fixed
|
||||
return [
|
||||
'email' => 'required|email',
|
||||
];
|
||||
}
|
||||
}
|
49
app/Mail/ConfirmEmailChangeMail.php
Normal file
49
app/Mail/ConfirmEmailChangeMail.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ConfirmEmailChangeMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
/** @var string */
|
||||
public $ipAddress;
|
||||
/** @var string */
|
||||
public $newEmail;
|
||||
/** @var string */
|
||||
public $oldEmail;
|
||||
/** @var string */
|
||||
public $uri;
|
||||
|
||||
/**
|
||||
* ConfirmEmailChangeMail constructor.
|
||||
*
|
||||
* @param string $newEmail
|
||||
* @param string $oldEmail
|
||||
* @param string $uri
|
||||
* @param string $ipAddress
|
||||
*/
|
||||
public function __construct(string $newEmail, string $oldEmail, string $uri, string $ipAddress)
|
||||
{
|
||||
|
||||
$this->newEmail = $newEmail;
|
||||
$this->oldEmail = $oldEmail;
|
||||
$this->uri = $uri;
|
||||
$this->ipAddress = $ipAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->view('emails.confirm-email-change-html')->text('emails.confirm-email-change-text')
|
||||
->subject('Your Firefly III email address has changed.');
|
||||
}
|
||||
}
|
50
app/Mail/UndoEmailChangeMail.php
Normal file
50
app/Mail/UndoEmailChangeMail.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class UndoEmailChangeMail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
/** @var string */
|
||||
public $ipAddress;
|
||||
/** @var string */
|
||||
public $newEmail;
|
||||
/** @var string */
|
||||
public $oldEmail;
|
||||
/** @var string */
|
||||
public $uri;
|
||||
|
||||
/**
|
||||
* UndoEmailChangeMail constructor.
|
||||
*
|
||||
* @param string $newEmail
|
||||
* @param string $oldEmail
|
||||
* @param string $uri
|
||||
* @param string $ipAddress
|
||||
*/
|
||||
public function __construct(string $newEmail, string $oldEmail, string $uri, string $ipAddress)
|
||||
{
|
||||
|
||||
$this->newEmail = $newEmail;
|
||||
$this->oldEmail = $oldEmail;
|
||||
$this->uri = $uri;
|
||||
$this->ipAddress = $ipAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->view('emails.undo-email-change-html')->text('emails.undo-email-change-text')
|
||||
->subject('Your Firefly III email address has changed.');
|
||||
}
|
||||
}
|
@ -36,26 +36,35 @@ class EventServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected $listen
|
||||
= [
|
||||
// new event handlers:
|
||||
'FireflyIII\Events\RegisteredUser' => // is a User related event.
|
||||
// is a User related event.
|
||||
'FireflyIII\Events\RegisteredUser' =>
|
||||
[
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationMail',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@attachUserRole',
|
||||
],
|
||||
'FireflyIII\Events\RequestedNewPassword' => [ // is a User related event.
|
||||
// is a User related event.
|
||||
'FireflyIII\Events\RequestedNewPassword' => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendNewPassword',
|
||||
],
|
||||
'FireflyIII\Events\StoredTransactionJournal' => // is a Transaction Journal related event.
|
||||
// is a User related event.
|
||||
'FireflyIII\Events\UserChangedEmail' => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeConfirmMail',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeUndoMail',
|
||||
],
|
||||
// is a Transaction Journal related event.
|
||||
'FireflyIII\Events\StoredTransactionJournal' =>
|
||||
[
|
||||
'FireflyIII\Handlers\Events\StoredJournalEventHandler@scanBills',
|
||||
'FireflyIII\Handlers\Events\StoredJournalEventHandler@connectToPiggyBank',
|
||||
'FireflyIII\Handlers\Events\StoredJournalEventHandler@processRules',
|
||||
],
|
||||
'FireflyIII\Events\UpdatedTransactionJournal' => // is a Transaction Journal related event.
|
||||
// is a Transaction Journal related event.
|
||||
'FireflyIII\Events\UpdatedTransactionJournal' =>
|
||||
[
|
||||
'FireflyIII\Handlers\Events\UpdatedJournalEventHandler@scanBills',
|
||||
'FireflyIII\Handlers\Events\UpdatedJournalEventHandler@processRules',
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -52,6 +52,33 @@ class UserRepository implements UserRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $newEmail
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function changeEmail(User $user, string $newEmail): bool
|
||||
{
|
||||
$oldEmail = $user->email;
|
||||
|
||||
// save old email as pref
|
||||
Preferences::setForUser($user, 'previous_email_latest', $oldEmail);
|
||||
Preferences::setForUser($user, 'previous_email_' . date('Y-m-d-H-i-s'), $oldEmail);
|
||||
|
||||
// set undo and confirm token:
|
||||
Preferences::setForUser($user, 'email_change_undo_token', strval(bin2hex(random_bytes(16))));
|
||||
Preferences::setForUser($user, 'email_change_confirm_token', strval(bin2hex(random_bytes(16))));
|
||||
// update user
|
||||
|
||||
$user->email = $newEmail;
|
||||
$user->blocked = 1;
|
||||
$user->blocked_code = 'email_changed';
|
||||
$user->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $password
|
||||
@ -119,6 +146,16 @@ class UserRepository implements UserRepositoryInterface
|
||||
return new User;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $email
|
||||
*
|
||||
* @return User|null
|
||||
*/
|
||||
public function findByEmail(string $email): ?User
|
||||
{
|
||||
return User::where('email', $email)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return basic user information.
|
||||
*
|
||||
|
@ -42,6 +42,14 @@ interface UserRepositoryInterface
|
||||
*/
|
||||
public function attachRole(User $user, string $role): bool;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $newEmail
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function changeEmail(User $user, string $newEmail): bool;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $password
|
||||
@ -80,6 +88,13 @@ interface UserRepositoryInterface
|
||||
*/
|
||||
public function find(int $userId): User;
|
||||
|
||||
/**
|
||||
* @param string $email
|
||||
*
|
||||
* @return User|null
|
||||
*/
|
||||
public function findByEmail(string $email): ?User;
|
||||
|
||||
/**
|
||||
* Return basic user information.
|
||||
*
|
||||
|
@ -16,6 +16,7 @@ namespace FireflyIII\Support;
|
||||
use Cache;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
@ -25,13 +26,26 @@ use Session;
|
||||
*/
|
||||
class Preferences
|
||||
{
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $search
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function beginsWith(User $user, string $search): Collection
|
||||
{
|
||||
$set = Preference::where('user_id', $user->id)->where('name', 'LIKE', $search . '%')->get();
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function delete($name): bool
|
||||
public function delete(string $name): bool
|
||||
{
|
||||
$fullName = sprintf('preference%s%s', auth()->user()->id, $name);
|
||||
if (Cache::has($fullName)) {
|
||||
@ -42,6 +56,18 @@ class Preferences
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function findByName(string $name): Collection
|
||||
{
|
||||
$set = Preference::where('name', $name)->get();
|
||||
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param null $default
|
||||
|
@ -424,6 +424,11 @@ return [
|
||||
'explain_access_token' => 'You need this token to perform command line options, such as importing or exporting data. Without it, such sensitive commands will not work. Do not share your access token. Nobody will ask you for this token, not even me. If you fear you lost this, or when you\'re paranoid, regenerate this token using the button.',
|
||||
'regenerate_access_token' => 'Regenerate access token',
|
||||
'token_regenerated' => 'A new token was generated',
|
||||
'change_your_email' => 'Change your email address',
|
||||
'email_verification' => 'An email message will be sent to your old AND new email address. For security purposes, you will not be able to login until you verify your new email address. If you are unsure if your Firefly III installation is capable of sending email, please do not use this feature. You can test this in the <a href="/admin">Administration</a>.',
|
||||
'email_changed_logout' => 'Until you verify your email address, you cannot login.',
|
||||
'login_with_new_email' => 'You can now login with your new email address.',
|
||||
'login_with_old_email' => 'You can now login with your old email address again.',
|
||||
|
||||
// attachments
|
||||
'nr_of_attachments' => 'One attachment|:count attachments',
|
||||
|
@ -67,6 +67,8 @@ return [
|
||||
'source_amount' => 'Amount (source)',
|
||||
'destination_amount' => 'Amount (destination)',
|
||||
'native_amount' => 'Native amount',
|
||||
'new_email_address' => 'New email address',
|
||||
'verification' => 'Verification',
|
||||
|
||||
'source_account_asset' => 'Source account (asset account)',
|
||||
'destination_account_expense' => 'Destination account (expense account)',
|
||||
|
@ -13,6 +13,16 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# SUCCESS MESSAGE (ALWAYS SINGULAR) #}
|
||||
{% if Session.has('success') %}
|
||||
<div class="alert alert-success alert-dismissible" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert">
|
||||
<span>×</span><span class="sr-only">{{ 'close'|_ }}</span>
|
||||
</button>
|
||||
<strong>{{ 'flash_success'|_ }}</strong> {{ session('success') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if errors.has('email') %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
|
18
resources/views/emails/confirm-email-change-html.twig
Normal file
18
resources/views/emails/confirm-email-change-html.twig
Normal file
@ -0,0 +1,18 @@
|
||||
{% include 'emails.header-html' %}
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
You or somebody with access to your Firefly III account has changed your email address. If you did not expect this message, please ignore and delete it.
|
||||
</p>
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
The old email addres was: {{ oldEmail }}
|
||||
</p>
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
The new email address is: <strong>{{ newEmail }}</strong>
|
||||
</p>
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
You cannot use Firefly III until you confirm this change. Please follow the link below to do so.
|
||||
</p>
|
||||
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
<a href="{{ uri }}">{{ uri }}</a>
|
||||
</p>
|
||||
{% include 'emails.footer-html' %}
|
9
resources/views/emails/confirm-email-change-text.twig
Normal file
9
resources/views/emails/confirm-email-change-text.twig
Normal file
@ -0,0 +1,9 @@
|
||||
{% include 'emails.header-text' %}
|
||||
You or somebody with access to your Firefly III account has changed your email address. If you did not expect this message, please ignore and delete it.
|
||||
|
||||
The old email addres was: {{ oldEmail }}
|
||||
|
||||
The new email address is: {{ newEmail }}
|
||||
|
||||
You cannot use Firefly III until you confirm this change. Please follow the link to do so: {{ uri }}
|
||||
{% include 'emails.footer-text' %}
|
18
resources/views/emails/undo-email-change-html.twig
Normal file
18
resources/views/emails/undo-email-change-html.twig
Normal file
@ -0,0 +1,18 @@
|
||||
{% include 'emails.header-html' %}
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
You or somebody with access to your Firefly III account has changed your email address.
|
||||
If you did not expect this to happen, you <strong>must</strong> follow the "undo"-link below to protect your account!
|
||||
</p>
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
If you initiated this change, you may safely ignore this message.
|
||||
</p>
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
The old email addres was: <strong>{{ oldEmail }}</strong>
|
||||
</p>
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
The new email address is: {{ newEmail }}
|
||||
</p>
|
||||
<p style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;">
|
||||
To undo the change, follow this link: <a href="{{ uri }}">{{ uri }}</a>
|
||||
</p>
|
||||
{% include 'emails.footer-html' %}
|
12
resources/views/emails/undo-email-change-text.twig
Normal file
12
resources/views/emails/undo-email-change-text.twig
Normal file
@ -0,0 +1,12 @@
|
||||
{% include 'emails.header-text' %}
|
||||
You or somebody with access to your Firefly III account has changed your email address. If you did not expect this to happen,
|
||||
you must follow the "undo"-link below to protect your account!
|
||||
|
||||
If you initiated this change, you may safely ignore this message.
|
||||
|
||||
The old email addres was: {{ oldEmail }}
|
||||
|
||||
The new email address is: {{ newEmail }}
|
||||
|
||||
To undo the change, follow this link: {{ uri }}
|
||||
{% include 'emails.footer-text' %}
|
47
resources/views/profile/change-email.twig
Normal file
47
resources/views/profile/change-email.twig
Normal file
@ -0,0 +1,47 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="POST" action="{{ route('profile.change-email.post') }}" accept-charset="UTF-8" class="form-horizontal" id="change-password">
|
||||
<input name="_token" type="hidden" value="{{ csrf_token() }}">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-12 col-sm-12">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'change_your_email'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
|
||||
{% if errors|length > 0 %}
|
||||
<ul>
|
||||
{% for error in errors.all %}
|
||||
<li class="text-danger">{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email" class="col-sm-4 control-label">{{ trans('form.new_email_address') }}</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="email" class="form-control" id="email" placeholder="{{ 'new_email_address'|_ }}"
|
||||
value="{{ old('email')|default(email) }}"
|
||||
name="email">
|
||||
</div>
|
||||
</div>
|
||||
{{ ExpandedForm.staticText('verification',trans('firefly.email_verification')) }}
|
||||
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-success pull-right">{{ 'change_your_email'|_ }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
@ -16,6 +16,7 @@
|
||||
{{ trans('firefly.user_id_is',{user: userId})|raw }}
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="{{ route('profile.change-email') }}">{{ 'change_your_email'|_ }}</a></li>
|
||||
<li><a href="{{ route('profile.change-password') }}">{{ 'change_your_password'|_ }}</a></li>
|
||||
<li><a class="text-danger" href="{{ route('profile.delete-account') }}">{{ 'delete_account'|_ }}</a></li>
|
||||
</ul>
|
||||
|
@ -32,6 +32,9 @@ Route::group(
|
||||
Route::post('password/reset', 'Auth\ResetPasswordController@reset');
|
||||
Route::get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm');
|
||||
|
||||
// Change email routes:
|
||||
Route::get('profile/confirm-email-change/{token}', ['uses' => 'ProfileController@confirmEmailChange', 'as' => 'profile.confirm-email-change']);
|
||||
Route::get('profile/undo-email-change/{token}/{oldAddressHash}', ['uses' => 'ProfileController@undoEmailChange', 'as' => 'profile.undo-email-change']);
|
||||
|
||||
}
|
||||
);
|
||||
@ -521,11 +524,13 @@ Route::group(
|
||||
['middleware' => 'user-full-auth', 'prefix' => 'profile', 'as' => 'profile.'], function () {
|
||||
|
||||
Route::get('', ['uses' => 'ProfileController@index', 'as' => 'index']);
|
||||
Route::get('change-email', ['uses' => 'ProfileController@changeEmail', 'as' => 'change-email']);
|
||||
Route::get('change-password', ['uses' => 'ProfileController@changePassword', 'as' => 'change-password']);
|
||||
Route::get('delete-account', ['uses' => 'ProfileController@deleteAccount', 'as' => 'delete-account']);
|
||||
|
||||
Route::post('delete-account', ['uses' => 'ProfileController@postDeleteAccount', 'as' => 'delete-account.post']);
|
||||
Route::post('change-password', ['uses' => 'ProfileController@postChangePassword', 'as' => 'change-password.post']);
|
||||
Route::post('change-email', ['uses' => 'ProfileController@postChangeEmail', 'as' => 'change-email.post']);
|
||||
Route::post('regenerate', ['uses' => 'ProfileController@regenerate', 'as' => 'regenerate']);
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user