@@ -6,8 +6,10 @@ use Illuminate\Http\Request; | |||
use App\Models\User; | |||
use App\Models\Order; | |||
use App\Models\Service; | |||
use App\Notifications\ChangeEmail; | |||
use Illuminate\Support\Facades\Log; | |||
use Illuminate\Support\Facades\Hash; | |||
use Illuminate\Support\Facades\URL; | |||
use Illuminate\Auth\Events\Registered; | |||
use Illuminate\Support\Facades\Password; | |||
use Illuminate\Support\Facades\Auth; | |||
@@ -102,6 +104,33 @@ class UserController extends Controller | |||
$validated = $request->validate([ | |||
'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) { | |||
@@ -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> | |||
<h4>Name</h4> | |||
<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> | |||
</section> | |||
<section class="change-email-pane"> | |||
<h4>Email</h4> | |||
<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 class="change-password-pane"> | |||
<h4>Change Password</h4> | |||
@@ -89,6 +90,7 @@ | |||
<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"> | |||
<button @click="changePassword">Save<img class="loading-icon" src="../../images/loading-white.svg" alt=""></button> | |||
<span></span> | |||
</section> | |||
</div> | |||
</transition> | |||
@@ -96,6 +98,7 @@ | |||
<script> | |||
import Sidebar from './sidebar.vue' | |||
import Loading from '../icons/loading.vue' | |||
function togglePending(event) { | |||
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 { | |||
components: { | |||
Sidebar, | |||
Sidebar, Loading | |||
}, | |||
data() { | |||
return {active: window.location.hash, user: '', | |||
token: '', orders: '', historyPage: 1} | |||
}, | |||
methods: {togglePending, toggleOrderItem, moveHistory, changeName} | |||
methods: {togglePending, toggleOrderItem, moveHistory, changeName, changeEmail} | |||
} | |||
</script> |
@@ -942,6 +942,7 @@ main.panel { | |||
width: 1.5em; | |||
height: 1.5em; | |||
display: none; | |||
color: white; | |||
} | |||
.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\Http\Request; | |||
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) { | |||
return $request->user(); | |||
})->middleware('auth'); | |||
})->middleware([ 'auth', 'verified' ]); | |||
Route::get('/panel/orders', [UserController::class, | |||
'getOrders'])->middleware('auth'); | |||
'getOrders'])->middleware([ 'auth', 'verified' ]); | |||
Route::get('/logout', [UserController::class, | |||
'logout'])->middleware('auth'); | |||
Route::post('/panel/change-name', [UserController::class, | |||
'changeName'])->middleware('auth'); | |||
'changeName'])->middleware([ 'auth', 'verified' ]); | |||
Route::post('/panel/change-email', [UserController::class, | |||
'changeEmail'])->middleware('auth'); | |||
'changeEmail'])->middleware([ 'auth', 'verified' ]); | |||
Route::post('/panel/change-password', [UserController::class, | |||
'changePassword'])->middleware('auth'); | |||
'changePassword'])->middleware([ 'auth', 'verified' ]); | |||
Route::get('/reset-email', [UserController::class, | |||
'resetEmail'])->name('reset-email'); |