ソースを参照

Add email changing controller functions and routing

tags/v0.1.0
コミット
58006c7f5a
7個のファイルの変更162行の追加9行の削除
  1. +29
    -0
      app/Http/Controllers/UserController.php
  2. +62
    -0
      app/Notifications/ChangeEmail.php
  3. +3
    -0
      resources/js/icons/loading.vue
  4. +33
    -4
      resources/js/panel/panel.vue
  5. +1
    -0
      resources/scss/main.scss
  6. +25
    -0
      resources/views/email-changed.blade.php
  7. +9
    -5
      routes/web.php

+ 29
- 0
app/Http/Controllers/UserController.php ファイルの表示

@@ -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) {


+ 62
- 0
app/Notifications/ChangeEmail.php ファイルの表示

@@ -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 [
//
];
}
}

+ 3
- 0
resources/js/icons/loading.vue ファイルの表示

@@ -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>

+ 33
- 4
resources/js/panel/panel.vue ファイルの表示

@@ -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>

+ 1
- 0
resources/scss/main.scss ファイルの表示

@@ -942,6 +942,7 @@ main.panel {
width: 1.5em;
height: 1.5em;
display: none;
color: white;
}

.loading .loading-icon {


+ 25
- 0
resources/views/email-changed.blade.php ファイルの表示

@@ -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

+ 9
- 5
routes/web.php ファイルの表示

@@ -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');

読み込み中…
キャンセル
保存