Add PIN code error handling and proper redirect

This commit is contained in:
Timothée Jaussoin 2023-08-17 09:42:09 +00:00
parent 49d414c9ee
commit f8ae6d93ff
26 changed files with 202 additions and 110 deletions

View file

@ -54,6 +54,8 @@ class EmailController extends Controller
return redirect()->route('account.dashboard');
}
return redirect()->route('account.email.change');
return redirect()->route('account.email.change')->withErrors([
'code' => 'The code entered was not valid'
]);
}
}

View file

@ -54,6 +54,8 @@ class PhoneController extends Controller
return redirect()->route('account.dashboard');
}
return redirect()->route('account.phone.change');
return redirect()->route('account.phone.change')->withErrors([
'code' => 'The code entered was not valid'
]);
}
}

View file

@ -88,6 +88,7 @@ class RecoveryController extends Controller
}
return view('account.recovery.confirm', [
'method' => $request->get('phone') ? 'phone' : 'email',
'account_id' => Crypt::encryptString($account->id)
]);
}
@ -96,6 +97,7 @@ class RecoveryController extends Controller
{
$request->validate([
'account_id' => 'required',
'method' => 'in:phone,email',
'number_1' => 'required|digits:1',
'number_2' => 'required|digits:1',
'number_3' => 'required|digits:1',
@ -104,12 +106,13 @@ class RecoveryController extends Controller
$code = $request->get('number_1') . $request->get('number_2') . $request->get('number_3') . $request->get('number_4');
$account = Account::where('id', Crypt::decryptString($request->get('account_id')))->firstOrFail();
if ($account->recovery_code != $code) {
return redirect()->back()->withErrors([
'code' => 'Wrong code'
return redirect()->route($request->get('method') == 'phone'
? 'account.recovery.show.phone'
: 'account.recovery.show.email')->withErrors([
'code' => 'The code entered was not valid'
]);
}
@ -117,6 +120,6 @@ class RecoveryController extends Controller
$account->save();
Auth::login($account);
return redirect()->route('account.dashboard');
return redirect()->route('account.password.update');
}
}

View file

@ -38,20 +38,22 @@ class AccountContactController extends Controller
public function store(Request $request, int $id)
{
$request->validate([
'sip' => 'required',
]);
$account = Account::findOrFail($id);
$contact = Account::sip($request->get('sip'))->first();
if (!$contact) {
$request->session()->flash('error', 'The contact SIP address doesn\'t exists');
return redirect()->route('admin.account.contact.create', $account);
return redirect()->back()->withErrors([
'sip' => 'The contact SIP address doesn\'t exists'
]);
}
$account->contacts()->detach($contact->id);
$account->contacts()->attach($contact->id);
$request->session()->flash('success', 'Contact successfully added');
Log::channel('events')->info('Web Admin: Account contact added', ['id' => $account->identifier, 'contact' => $contact->identifier]);
return redirect()->route('admin.account.edit', $account);

View file

@ -35,12 +35,15 @@ class ContactsListContactController extends Controller
$accounts = $accounts->where('username', 'like', '%' . $request->get('search') . '%');
}
if ($request->has('domain')) {
$accounts = $accounts->where('domain', $request->get('domain'));
}
return view('admin.contacts_list.contacts.add', [
'domains' => Account::groupBy('domain')->pluck('domain'),
'contacts_list' => ContactsList::findOrFail($contactsListId),
'params' => [
'search' => $request->get('search'),
'contacts_list_id' => $contactsListId,
'updated_at_order' => $request->get('updated_at_order') == 'desc' ? 'asc' : 'desc'
'contacts_list_id' => $contactsListId
],
'accounts' => $accounts->whereNotIn('id', function ($query) use ($contactsListId) {
$query->select('contact_id')

View file

@ -19,6 +19,7 @@
namespace App\Http\Controllers\Admin;
use App\Account;
use App\ContactsList;
use App\Http\Controllers\Controller;
use Illuminate\Validation\Rule;
@ -67,10 +68,29 @@ class ContactsListController extends Controller
return redirect()->route('admin.contacts_lists.edit', $contactsList->id);
}
public function edit(int $id)
public function search(Request $request, int $contactsListId)
{
return redirect()->route('admin.contacts_lists.edit', ['contacts_list_id' => $contactsListId] + $request->except('_token'));
}
public function edit(Request $request, int $id)
{
$contacts = ContactsList::findOrFail($id)->contacts();
if ($request->has('search')) {
$contacts = $contacts->where('username', 'like', '%' . $request->get('search') . '%');
}
if ($request->has('domain')) {
$contact = $contacts->where('domain', $request->get('domain'));
}
$contacts = $contacts->get();
return view('admin.contacts_list.create_edit', [
'domains' => Account::groupBy('domain')->pluck('domain'),
'contacts_list' => ContactsList::findOrFail($id),
'contacts' => $contacts
]);
}

View file

@ -0,0 +1,4 @@
Username,Password,Role,Status,Phone,Email
john,number9,user,active,+12341234,john@lennon.com
paul,a_day_in_the_life,admin,active,,paul@apple.com
ringo,allUneedIsL3ve,user,unactove,+123456,ringo@star.co.uk
1 Username Password Role Status Phone Email
2 john number9 user active +12341234 john@lennon.com
3 paul a_day_in_the_life admin active paul@apple.com
4 ringo allUneedIsL3ve user unactove +123456 ringo@star.co.uk

View file

@ -304,7 +304,7 @@ header nav a#logo::before {
width: 3rem;
height: 3rem;
padding: 1rem;
background-image: url('/img/logo.svg');
background-image: url('../img/logo.svg');
background-color: var(--main-5);
background-size: 3rem;
background-position: center;
@ -387,7 +387,7 @@ content > nav {
background-size: auto 10rem;
background-position: bottom center;
background-repeat: repeat-x;
background-image: url('/img/footer.svg');
background-image: url('../img/footer.svg');
z-index: 1;
}
@ -465,7 +465,7 @@ content > nav a i {
body.welcome::after {
background-position: bottom center;
background-repeat: repeat-x;
background-image: url('/img/footer.svg');
background-image: url('../img/footer.svg');
display: block;
height: 10rem;
width: 100%;

View file

@ -89,6 +89,7 @@ form.inline {
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
margin-bottom: 2rem;
clear: both;
}
form div {

View file

@ -42,7 +42,7 @@ body > footer::before {
width: 100%;
background-size: 50rem;
content: '';
background-image: url('/img/footer.svg');
background-image: url('../img/footer.svg');
height: 9rem;
}

View file

@ -2,7 +2,7 @@
@section('content')
<div style="max-width: 40rem; width: 100%; padding: 1rem;">
<img style="float: right; margin-top: 1rem;" src="/img/logo_linphone.png">
<img style="float: right; margin-top: 1rem;" src="{{ asset('img/logo_linphone.png') }}">
<h2>About</h2>
<hr />

View file

@ -21,6 +21,8 @@
<p>The verification code is invalid.</p>
<p>Please enter again your email address to receive a new code.</p>
@endif
@include('parts.errors', ['name' => 'code'])
</div>
<div class="large">
@ -38,7 +40,7 @@
</section>
<section class="on_desktop">
<img src="/img/lock.svg">
<img src="{{ asset('img/lock.svg') }}">
</section>
@endsection

View file

@ -35,7 +35,7 @@
</section>
<section class="on_desktop">
<img src="/img/lock.svg">
<img src="{{ asset('img/lock.svg') }}">
</section>
@endsection

View file

@ -50,7 +50,7 @@
<section class="on_desktop" style="text-align: center;">
<span style="color: var(--main-5); font-size: 5rem; font-weight: 300;">{{ $count }}</span><br />
<p style="margin-bottom: 3rem;">users</p>
<img src="/img/login.svg">
<img src="{{ asset('img/login.svg') }}">
</section>
@endsection

View file

@ -12,34 +12,36 @@
</h1>
<form method="POST" action="{{ route('account.phone.request_change') }}" accept-charset="UTF-8">
@csrf
@csrf
<div class="large">
@if ($account->phone)
<p>Please enter the new phone number that you would like to link to your account.</p>
@else
<p>The verification code is invalid or you didn't receive it.</p>
<p>Please enter your phone number again to receive a new code.</p>
@endif
</div>
<div class="large">
@if ($account->phone)
<p>Please enter the new phone number that you would like to link to your account.</p>
@else
<p>The verification code is invalid or you didn't receive it.</p>
<p>Please enter your phone number again to receive a new code.</p>
@endif
<div class="large">
<input placeholder="+12345678" name="phone" type="text" value="">
<label for="phone">Phone</label>
@include('parts.errors', ['name' => 'phone'])
</div>
@include('parts.errors', ['name' => 'code'])
</div>
@include('parts.captcha')
<div class="large">
<input placeholder="+12345678" name="phone" type="text" value="">
<label for="phone">Phone</label>
@include('parts.errors', ['name' => 'phone'])
</div>
<div class="large">
<input class="btn oppose" type="submit" value="Verify">
</div>
@include('parts.captcha')
<div class="large">
<input class="btn oppose" type="submit" value="Verify">
</div>
</form>
</section>
<section class="on_desktop">
<img src="/img/lock.svg">
<img src="{{ asset('img/lock.svg') }}">
</section>
@endsection

View file

@ -35,7 +35,7 @@
</section>
<section class="on_desktop">
<img src="/img/lock.svg">
<img src="{{ asset('img/lock.svg') }}">
</section>
@endsection

View file

@ -13,8 +13,8 @@
<input oninput="digitFilled(this)" onfocus="this.value = ''" class="digit" name="number_2" type="number" min="0" max="9">
<input oninput="digitFilled(this)" onfocus="this.value = ''" class="digit" name="number_3" type="number" min="0" max="9">
<input oninput="digitFilled(this)" onfocus="this.value = ''" class="digit" name="number_4" type="number" min="0" max="9">
@include('parts.errors', ['name' => 'code'])
<input name="method" type="hidden" value="{{ $method }}">
<input name="account_id" type="hidden" value="{{ $account_id }}">
</div>
<div class="large">
@ -23,6 +23,6 @@
</form>
</section>
<section class="on_desktop">
<img src="/img/lock.svg">
<img src="{{ asset('img/lock.svg') }}">
</section>
@endsection

View file

@ -5,12 +5,15 @@
<h1><i class="material-icons-outlined">account_circle</i> Account recovery</h1>
<div>
<form method="POST" action="{{ route('account.recovery.send') }}" accept-charset="UTF-8">
@csrf
@csrf
@if ($method == 'email')
<p class="large">Enter your email account to recover it.</p>
<div class="large">
<input type="email" name="email" value="{{ old('email') }}" placeholder="bob@example.com" required>
<p class="large">Enter your email account to recover it.</p>
@include('parts.errors', ['name' => 'code'])
</div>
<div class="large">
<input type="email" name="email" value="{{ old('email') }}" placeholder="bob@example.com" required>
<label for="email">Email</label>
@include('parts.errors', ['name' => 'email'])
@include('parts.errors', ['name' => 'identifier'])
@ -44,6 +47,6 @@
</div>
</section>
<section class="on_desktop">
<img src="/img/lock.svg">
<img src="{{ asset('img/lock.svg') }}">
</section>
@endsection
@endsection

View file

@ -61,7 +61,7 @@
</section>
<section class="on_desktop">
<img src="/img/login.svg">
<img src="{{ asset('img/login.svg') }}">
</section>
@endsection

View file

@ -50,6 +50,6 @@
</section>
<section class="on_desktop">
<img src="/img/login.svg">
<img src="{{ asset('img/login.svg') }}">
</section>
@endsection

View file

@ -1,17 +1,25 @@
@extends('layouts.main')
@section('content')
<h2>Add a Contact to the Account</h2>
@section('breadcrumb')
<li class="breadcrumb-item">
<a href="{{ route('admin.account.index') }}">Accounts</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Add Contact</li>
@endsection
<form method="POST" action="{{ route('admin.account.contact.store', $account->id) }}" accept-charset="UTF-8">
@section('content')
<header>
<h1><i class="material-icons-outlined">person_add</i> Add a Contact</h1>
<a href="{{ route('admin.account.edit', $account->id) }}" class="btn btn-secondary oppose">Cancel</a>
<input form="add_contact" class="btn" type="submit" value="Add">
</header>
<form id="add_contact" method="POST" action="{{ route('admin.account.contact.store', $account->id) }}" accept-charset="UTF-8">
@csrf
@method('post')
<div>
<input placeholder="username@server.com" name="sip" type="text" id="sip">
<label for="sip">SIP Address</label>
</div>
<div>
<input class="btn" type="submit" value="Add">
<input placeholder="username@server.com" name="sip" type="text" id="sip" required>
<label for="sip">Local SIP Address</label>
@include('parts.errors', ['name' => 'sip'])
</div>
</form>
@endsection

View file

@ -20,7 +20,7 @@
<li>Import data</li>
</ol>
<p>Use this existing (.csv) template or create your own csv file.</p>
<p>Use this <a href="{{ route('account.home') }}/accounts_example.csv">existing example (.csv) template</a> or create your own csv file.</p>
<p>
This file MUST be in csv format and contain at least the following information:

View file

@ -16,10 +16,8 @@
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}" class="btn btn-secondary oppose">Cancel</a>
<form method="POST"
action="{{ route('admin.contacts_lists.contacts.store', $contacts_list->id) }}"
name="contacts_lists_contacts_store"
accept-charset="UTF-8">
<form method="POST" action="{{ route('admin.contacts_lists.contacts.store', $contacts_list->id) }}"
name="contacts_lists_contacts_store" accept-charset="UTF-8">
@csrf
@method('post')
@ -29,23 +27,37 @@
</header>
<div>
<form class="inline" method="POST" action="{{ route('admin.contacts_lists.contacts.search', $params) }}" accept-charset="UTF-8">
<form class="inline" method="POST" action="{{ route('admin.contacts_lists.contacts.search', $params) }}"
accept-charset="UTF-8">
@csrf
<div class="search large">
<input placeholder="Search by username: +1234, foo_bar…" name="search" type="text" value="{{ $params['search'] }}">
<div class="search">
<input placeholder="Search by username: +1234, foo_bar…" name="search" type="text"
value="{{ request()->get('search', '') }}">
<label for="search">Search</label>
</div>
<div class="select">
<select name="domain" onchange="this.form.submit()">
<option value="">
Select a domain
</option>
@foreach ($domains as $d)
<option value="{{ $d }}" @if (request()->get('domain', '') == $d) selected="selected" @endif>
{{ $d }}
</option>
@endforeach
</select>
<label for="domain">Domain</label>
</div>
<div>
<a href="{{ route('admin.contacts_lists.contacts.add', $contacts_list->id) }}" type="reset" class="btn btn-secondary">Reset</a>
<a href="{{ route('admin.contacts_lists.contacts.add', $contacts_list->id) }}" type="reset"
class="btn btn-secondary">Reset</a>
<button type="submit" class="btn">Search</button>
</div>
<div class="oppose">
<p style="display: inline-block; margin: 0 1rem;">
<span class="list_toggle" data-list-id="a{{ $contacts_list->id }}"></span> selected
</p>
<a class="btn" onclick="Utils.clearStorageList('a{{ $contacts_list->id }}'); document.querySelector('form[name=contacts_lists_contacts_store]').submit()">
<a class="btn"
onclick="Utils.clearStorageList('a{{ $contacts_list->id }}'); document.querySelector('form[name=contacts_lists_contacts_store]').submit()">
<i class="material-icons-outlined">add_circle</i>
Add
Add <span class="list_toggle" data-list-id="a{{ $contacts_list->id }}"></span> contacts
</a>
</div>
</form>
@ -58,16 +70,11 @@
<input type="checkbox" onchange="Utils.toggleAll(this)">
</th>
<th>Username</th>
<th>
<a href="{{ route('admin.contacts_lists.contacts.add', $params) }}">
Updated
@if ($params['updated_at_order'] == 'desc')
<i class="material-icons-outlined">expand_more</i>
@else
<i class="material-icons-outlined">expand_less</i>
@endif
</a>
</th>
@include('parts.column_sort', [
'key' => 'updated_at',
'title' => 'Updated',
'uriParams' => ['contacts_list_id' => $contacts_list->id],
])
</tr>
</thead>
<tbody>
@ -79,16 +86,17 @@
@foreach ($accounts as $account)
<tr>
<td>
<input class="list_toggle" type="checkbox" data-list-id="a{{ $contacts_list->id }}" data-id="{{ $account->id }}">
<input class="list_toggle" type="checkbox" data-list-id="a{{ $contacts_list->id }}"
data-id="{{ $account->id }}">
</td>
<td>
{{ $account->identifier }}
</td>
<td>{{ $account->updated_at}}</td>
<td>{{ $account->updated_at }}</td>
</tr>
@endforeach
</tbody>
</table>
{{ $accounts->links('pagination::bootstrap-4') }}
@endsection
@endsection

View file

@ -50,29 +50,56 @@
@if ($contacts_list->id)
<hr>
<header>
<p class="oppose">
<span class="list_toggle" data-list-id="d{{ $contacts_list->id }}"></span> selected
</p>
<a class="btn btn-secondary oppose" href="{{ route('admin.contacts_lists.contacts.add', $contacts_list->id) }}">
<i class="material-icons-outlined">add</i> Add contacts
</a>
<form method="POST" action="{{ route('admin.contacts_lists.contacts.destroy', $contacts_list->id) }}"
name="contacts_lists_contacts_destroy" accept-charset="UTF-8">
@csrf
@method('delete')
<form method="POST"
action="{{ route('admin.contacts_lists.contacts.destroy', $contacts_list->id) }}"
name="contacts_lists_contacts_destroy" accept-charset="UTF-8">
@csrf
@method('delete')
<select name="contacts_ids[]" class="list_toggle" data-list-id="d{{ $contacts_list->id }}"></select>
<input type="hidden" name="contacts_list_id" value="{{ $contacts_list->id }}">
<a class="btn btn-tertiary"
<select name="contacts_ids[]" class="list_toggle" data-list-id="d{{ $contacts_list->id }}"></select>
<input type="hidden" name="contacts_list_id" value="{{ $contacts_list->id }}">
</form>
<form class="inline" method="POST" action="{{ route('admin.contacts_lists.search', $contacts_list->id) }}"
name="contacts_lists_contacts_search" accept-charset="UTF-8">
@csrf
<div class="search">
<input placeholder="Search by username: +1234, foo_bar…" name="search" type="text"
value="{{ request()->get('search', '') }}">
<label for="search">Search</label>
</div>
<div class="select">
<select name="domain" onchange="this.form.submit()">
<option value="">
Select a domain
</option>
@foreach ($domains as $d)
<option value="{{ $d }}" @if (request()->get('domain', '') == $d) selected="selected" @endif>
{{ $d }}
</option>
@endforeach
</select>
<label for="domain">Domain</label>
</div>
<div>
<a href="{{ route('admin.contacts_lists.edit', $contacts_list->id) }}" type="reset"
class="btn btn-secondary">Reset</a>
<button type="submit" class="btn">Search</button>
</div>
<div>
<a class="btn btn-tertiary oppose"
onclick="Utils.clearStorageList('d{{ $contacts_list->id }}'); document.querySelector('form[name=contacts_lists_contacts_destroy]').submit()">
<i class="material-icons-outlined">delete</i>
Remove contacts
Remove <span class="list_toggle" data-list-id="d{{ $contacts_list->id }}"></span> contacts
</a>
</form>
<a class="btn btn-secondary" href="{{ route('admin.contacts_lists.contacts.add', $contacts_list->id) }}">
<i class="material-icons-outlined">add</i> Add contacts
</a>
</header>
</div>
</form>
<table class="large">
<thead>
@ -84,12 +111,12 @@
</tr>
</thead>
<tbody>
@if ($contacts_list->contacts->isEmpty())
@if ($contacts->isEmpty())
<tr class="empty">
<td colspan="2">No Contact</td>
</tr>
@endif
@foreach ($contacts_list->contacts as $contact)
@foreach ($contacts as $contact)
<tr>
<td>
<input class="list_toggle" type="checkbox" data-list-id="d{{ $contacts_list->id }}"

View file

@ -1,6 +1,10 @@
<th class="line">
@php
$uriParams = $uriParams ?? [];
@endphp
<a
href="{{ route(request()->route()->getName(), [
href="{{ route(request()->route()->getName(), $uriParams + [
'order_by' => $key,
'order_sort' => request()->get('order_sort', 'desc') == 'desc' ? 'asc' : 'desc'
] + request()->except('_token', 'query')) }}">

View file

@ -36,7 +36,7 @@ use App\Http\Controllers\Admin\ContactsListContactController;
use App\Http\Controllers\Admin\StatisticsController;
use Illuminate\Support\Facades\Route;
Route::redirect('/', '/login')->name('account.home');
Route::redirect('/', 'login')->name('account.home');
Route::get('documentation', 'Account\AccountController@documentation')->name('account.documentation');
Route::get('about', 'AboutController@about')->name('about');
@ -77,7 +77,7 @@ if (publicRegistrationEnabled()) {
}
if (config('app.web_panel')) {
Route::prefix('recover')->controller(RecoveryController::class)->group(function () {
Route::prefix('recovery')->controller(RecoveryController::class)->group(function () {
Route::get('phone', 'showPhone')->name('account.recovery.show.phone');
Route::get('email', 'showEmail')->name('account.recovery.show.email');
Route::post('/', 'send')->name('account.recovery.send');
@ -203,6 +203,7 @@ if (config('app.web_panel')) {
Route::get('/', 'index')->name('index');
Route::get('create', 'create')->name('create');
Route::post('/', 'store')->name('store');
Route::post('{contacts_list_id}/search', 'search')->name('search');
Route::get('{contacts_list_id}/edit', 'edit')->name('edit');
Route::put('{contacts_list_id}', 'update')->name('update');
Route::get('{contacts_list_id}/delete', 'delete')->name('delete');