@@ -6,8 +6,10 @@ use Illuminate\Http\Request; | |||||
use App\Models\User; | use App\Models\User; | ||||
use App\Models\Order; | use App\Models\Order; | ||||
use App\Models\Service; | use App\Models\Service; | ||||
use App\Notifications\ChangeEmail; | |||||
use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||
use Illuminate\Support\Facades\Hash; | use Illuminate\Support\Facades\Hash; | ||||
use Illuminate\Support\Facades\URL; | |||||
use Illuminate\Auth\Events\Registered; | use Illuminate\Auth\Events\Registered; | ||||
use Illuminate\Support\Facades\Password; | use Illuminate\Support\Facades\Password; | ||||
use Illuminate\Support\Facades\Auth; | use Illuminate\Support\Facades\Auth; | ||||
@@ -102,6 +104,33 @@ class UserController extends Controller | |||||
$validated = $request->validate([ | $validated = $request->validate([ | ||||
'email' => 'required|email|unique:users,email', | 'email' => 'required|email|unique:users,email', | ||||
]); | ]); | ||||
$link = URL::temporarySignedRoute('reset-email', now()->addDays(30), | |||||
['user' => Auth::user()->id, 'email' => $request->email]); | |||||
Auth::user()->notify(new ChangeEmail($link)); | |||||
} | |||||
public function resetEmail(Request $request) { | |||||
if (! $request->hasValidSignature()) { | |||||
abort(401); | |||||
} | |||||
$validated = $request->validate([ | |||||
'email' => 'required|email|unique:users,email', | |||||
]); | |||||
if (! $validated) { | |||||
abort(401); | |||||
} | |||||
$user = User::find($request->user); | |||||
$user->email = $request->email; | |||||
$user->save(); | |||||
return view('email-changed'); | |||||
} | } | ||||
public function changePassword(Request $request) { | public function changePassword(Request $request) { | ||||
@@ -0,0 +1,62 @@ | |||||
<?php | |||||
namespace App\Notifications; | |||||
use Illuminate\Bus\Queueable; | |||||
use Illuminate\Contracts\Queue\ShouldQueue; | |||||
use Illuminate\Notifications\Messages\MailMessage; | |||||
use Illuminate\Notifications\Notification; | |||||
class ChangeEmail extends Notification | |||||
{ | |||||
use Queueable; | |||||
private $link; | |||||
/** | |||||
* Create a new notification instance. | |||||
* | |||||
* @return void | |||||
*/ | |||||
public function __construct($link) | |||||
{ | |||||
$this->link = $link; | |||||
} | |||||
/** | |||||
* Get the notification's delivery channels. | |||||
* | |||||
* @param mixed $notifiable | |||||
* @return array | |||||
*/ | |||||
public function via($notifiable) | |||||
{ | |||||
return ['mail']; | |||||
} | |||||
/** | |||||
* Get the mail representation of the notification. | |||||
* | |||||
* @param mixed $notifiable | |||||
* @return \Illuminate\Notifications\Messages\MailMessage | |||||
*/ | |||||
public function toMail($notifiable) | |||||
{ | |||||
return (new MailMessage) | |||||
->line('An email change has been requested. Please confirm your new address by clicking the link below.') | |||||
->action('Confirm', $this->link) | |||||
->line('If you do not recognize this activity, please disregard this email.'); | |||||
} | |||||
/** | |||||
* Get the array representation of the notification. | |||||
* | |||||
* @param mixed $notifiable | |||||
* @return array | |||||
*/ | |||||
public function toArray($notifiable) | |||||
{ | |||||
return [ | |||||
// | |||||
]; | |||||
} | |||||
} |
@@ -0,0 +1,3 @@ | |||||
<template> | |||||
<svg class="loading-icon" data-set="loaders" data-loading="lazy" width="30px" height="30px" data-src="https://s2.svgbox.net/loaders.svg?ic=oval" data-icon="oval" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" color="" data-attributes-set="viewBox,xmlns,stroke,color" data-rendered="true"><g transform="translate(1 1)" stroke-width="2" fill="none" fill-rule="evenodd"><circle stroke-opacity=".5" cx="18" cy="18" r="18"></circle><path d="M36 18c0-9.94-8.06-18-18-18"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="1s" repeatCount="indefinite"></animateTransform></path></g></svg> | |||||
</template> |
@@ -75,13 +75,14 @@ | |||||
<h3>Settings</h3> | <h3>Settings</h3> | ||||
<h4>Name</h4> | <h4>Name</h4> | ||||
<input :value="user.name" name="name" id="changed_name" type="text"> | <input :value="user.name" name="name" id="changed_name" type="text"> | ||||
<button @click="changeName">Save <img class="loading-icon" src="../../images/loading-white.svg" alt=""></button> | |||||
<button @click="changeName">Save <loading src="../../images/loading-white.svg" alt=""></loading></button> | |||||
<span></span> | <span></span> | ||||
</section> | </section> | ||||
<section class="change-email-pane"> | <section class="change-email-pane"> | ||||
<h4>Email</h4> | <h4>Email</h4> | ||||
<input :value="user.email" name="email" type="text" id="changed_email"> | <input :value="user.email" name="email" type="text" id="changed_email"> | ||||
<button @click="changeName">Save<img class="loading-icon" src="../../images/loading-white.svg" alt=""></button> | |||||
<button @click="changeEmail">Save<img class="loading-icon" src="../../images/loading-white.svg" alt=""></button> | |||||
<span></span> | |||||
</section> | </section> | ||||
<section class="change-password-pane"> | <section class="change-password-pane"> | ||||
<h4>Change Password</h4> | <h4>Change Password</h4> | ||||
@@ -89,6 +90,7 @@ | |||||
<h5>New Password</h5><input id="changed_password" name="passowrd" type="password"> | <h5>New Password</h5><input id="changed_password" name="passowrd" type="password"> | ||||
<h5>Confirm Password</h5><input id="confirm_password" name="confirm_passowrd" type="password"> | <h5>Confirm Password</h5><input id="confirm_password" name="confirm_passowrd" type="password"> | ||||
<button @click="changePassword">Save<img class="loading-icon" src="../../images/loading-white.svg" alt=""></button> | <button @click="changePassword">Save<img class="loading-icon" src="../../images/loading-white.svg" alt=""></button> | ||||
<span></span> | |||||
</section> | </section> | ||||
</div> | </div> | ||||
</transition> | </transition> | ||||
@@ -96,6 +98,7 @@ | |||||
<script> | <script> | ||||
import Sidebar from './sidebar.vue' | import Sidebar from './sidebar.vue' | ||||
import Loading from '../icons/loading.vue' | |||||
function togglePending(event) { | function togglePending(event) { | ||||
event.target.parentNode.parentNode.classList.toggle('selected') | event.target.parentNode.parentNode.classList.toggle('selected') | ||||
@@ -146,14 +149,40 @@ function changeName() { | |||||
}) | }) | ||||
} | } | ||||
function changeEmail() { | |||||
let email = document.getElementById('changed_email').value | |||||
let info = document.querySelector('.change-email-pane span') | |||||
let pane = document.querySelector('.change-email-pane') | |||||
pane.classList.add('loading') | |||||
fetch("/panel/change-name", { | |||||
method: 'POST', | |||||
headers: {'Content-Type': 'application/json', | |||||
'Accept': 'application/json', | |||||
'X-XSRF-TOKEN': this.token}, | |||||
body: JSON.stringify({'email': email}), | |||||
}).then(response => { | |||||
if (response.ok) { | |||||
response.json().then(data => {this.user = data}) | |||||
pane.classList.add('completed') | |||||
info.textContent = 'Completed' | |||||
} else { | |||||
pane.classList.add('error') | |||||
info.textContent = 'Error:' + response.status | |||||
} | |||||
pane.classList.remove('loading') | |||||
}) | |||||
} | |||||
export default { | export default { | ||||
components: { | components: { | ||||
Sidebar, | |||||
Sidebar, Loading | |||||
}, | }, | ||||
data() { | data() { | ||||
return {active: window.location.hash, user: '', | return {active: window.location.hash, user: '', | ||||
token: '', orders: '', historyPage: 1} | token: '', orders: '', historyPage: 1} | ||||
}, | }, | ||||
methods: {togglePending, toggleOrderItem, moveHistory, changeName} | |||||
methods: {togglePending, toggleOrderItem, moveHistory, changeName, changeEmail} | |||||
} | } | ||||
</script> | </script> |
@@ -942,6 +942,7 @@ main.panel { | |||||
width: 1.5em; | width: 1.5em; | ||||
height: 1.5em; | height: 1.5em; | ||||
display: none; | display: none; | ||||
color: white; | |||||
} | } | ||||
.loading .loading-icon { | .loading .loading-icon { | ||||
@@ -0,0 +1,25 @@ | |||||
@extends('master') | |||||
@section('title', 'Settings') | |||||
@section('heading-style', 'info-page') | |||||
@section('head-metas') | |||||
@parent | |||||
<link rel="stylesheet" href="{{asset('panel.css')}}"> | |||||
@endsection | |||||
@section('content') | |||||
<main> | |||||
<div class="info-heading"> | |||||
<h3>Your email has been reset.</h3> | |||||
<a href="/panel"><button class="brand-button">Return</button></a> | |||||
</div> | |||||
</main> | |||||
@endsection | |||||
@section('scripts') | |||||
@parent | |||||
<script src="js/app.js"></script> | |||||
<script src="js/chunk-vendors.js"></script> | |||||
<!-- <script src="main.js"></script> --> | |||||
@endsection |
@@ -5,6 +5,7 @@ use App\Http\Controllers\UserController; | |||||
use Illuminate\Foundation\Auth\EmailVerificationRequest; | use Illuminate\Foundation\Auth\EmailVerificationRequest; | ||||
use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||
use Illuminate\Support\Facades\Auth; | use Illuminate\Support\Facades\Auth; | ||||
use App\Notifications\ChangeEmail; | |||||
/* | /* | ||||
|-------------------------------------------------------------------------- | |-------------------------------------------------------------------------- | ||||
@@ -57,19 +58,22 @@ Route::post('/login', [UserController::class, | |||||
Route::get('/panel/user', function (Request $request) { | Route::get('/panel/user', function (Request $request) { | ||||
return $request->user(); | return $request->user(); | ||||
})->middleware('auth'); | |||||
})->middleware([ 'auth', 'verified' ]); | |||||
Route::get('/panel/orders', [UserController::class, | Route::get('/panel/orders', [UserController::class, | ||||
'getOrders'])->middleware('auth'); | |||||
'getOrders'])->middleware([ 'auth', 'verified' ]); | |||||
Route::get('/logout', [UserController::class, | Route::get('/logout', [UserController::class, | ||||
'logout'])->middleware('auth'); | 'logout'])->middleware('auth'); | ||||
Route::post('/panel/change-name', [UserController::class, | Route::post('/panel/change-name', [UserController::class, | ||||
'changeName'])->middleware('auth'); | |||||
'changeName'])->middleware([ 'auth', 'verified' ]); | |||||
Route::post('/panel/change-email', [UserController::class, | Route::post('/panel/change-email', [UserController::class, | ||||
'changeEmail'])->middleware('auth'); | |||||
'changeEmail'])->middleware([ 'auth', 'verified' ]); | |||||
Route::post('/panel/change-password', [UserController::class, | Route::post('/panel/change-password', [UserController::class, | ||||
'changePassword'])->middleware('auth'); | |||||
'changePassword'])->middleware([ 'auth', 'verified' ]); | |||||
Route::get('/reset-email', [UserController::class, | |||||
'resetEmail'])->name('reset-email'); |