Merge branch 'master' of https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0 into exchange-1-user-registration

This commit is contained in:
CheeSiong
2020-11-02 12:49:43 +08:00
13 changed files with 398 additions and 109 deletions
@@ -0,0 +1,71 @@
<?php
namespace App\Classes\Modules\Accounts\ControllersLogic;
use App\Classes\Modules\Accounts\DataTransferObjects\AuthenticationCredentialsObject;
use App\Classes\Modules\Accounts\Services\AuthenticatesUser;
use App\Classes\Modules\Accounts\Services\AuthenticationRedirect;
use App\Classes\Modules\Accounts\Standards\Rules\CanAuthenticateUser;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\ValueObjects\Constants\Notifications;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class AuthenticateUserLogic extends AbstractControllerLogic
{
protected function notification():array {
return [
'title' => 'Authentication',
'message' => 'You have successfully logged in to your account'
];
}
/** @var CanAuthenticateUser */
private $canAuthenticateUser;
/** @var AuthenticatesUser */
private $authenticatesUser;
/** @var AuthenticationRedirect */
private $authenticationRedirect;
/**
* AuthenticateUserLogic constructor.
* @param CanAuthenticateUser $canAuthenticateUser
* @param AuthenticatesUser $authenticatesUser
* @param AuthenticationRedirect $authenticationRedirect
*/
public function __construct(CanAuthenticateUser $canAuthenticateUser, AuthenticatesUser $authenticatesUser, AuthenticationRedirect $authenticationRedirect)
{
$this->canAuthenticateUser = $canAuthenticateUser;
$this->authenticatesUser = $authenticatesUser;
$this->authenticationRedirect = $authenticationRedirect;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
protected function logic(Request $request): JsonResponse {
try {
$object = new AuthenticationCredentialsObject($request->input('email'),
$request->input('password'), $request->input('remember_me'));
$this->canAuthenticateUser->passes($object);
$token = $this->authenticatesUser->execute($object);
return $this->response(['access_token' => $token, 'redirect_url' => $this->authenticationRedirect->url()]);
} catch (\Exception $exception){
throw new ErrorException($exception->getMessage(), $exception->getCode());
}
}
}
@@ -0,0 +1,59 @@
<?php
namespace App\Classes\Modules\Accounts\DataTransferObjects;
use App\Classes\Interfaces\DataTransferObject;
class AuthenticationCredentialsObject implements DataTransferObject
{
/** @var string */
private $email;
/** @var string */
private $password;
/** @var boolean */
private $rememberUser;
/**
* AuthenticationCredentials constructor.
* @param string $email
* @param string $password
* @param bool $rememberUser
*/
public function __construct(string $email, string $password, ?bool $rememberUser = false)
{
$this->email = $email;
$this->password = $password;
$this->rememberUser = $rememberUser;
}
/**
* @return string
*/
public function getEmail(): string
{
return $this->email;
}
/**
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* @return bool
*/
public function isRememberUser(): bool
{
return $this->rememberUser;
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
use App\Classes\Exceptions\AccessUnauthorisedException;
use App\Classes\Modules\Accounts\DataTransferObjects\AuthenticationCredentialsObject;
use Tymon\JWTAuth\Facades\JWTAuth;
class AuthenticatesUser
{
/**
* @param AuthenticationCredentialsObject $object
* @return false|string
* @throws AccessUnauthorisedException
*/
public function execute(AuthenticationCredentialsObject $object){
if (! $token = JWTAuth::attempt(['email' => $object->getEmail(), 'password' => $object->getPassword()])) {
throw new AccessUnauthorisedException('These credentials do not match our records.');
}
return $token;
}
}
@@ -0,0 +1,12 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
class AuthenticationRedirect
{
public function url(){
return route('dashboard');
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\Accounts\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Exceptions\RequestValidationException;
use App\Classes\Modules\Accounts\DataTransferObjects\AuthenticationCredentialsObject;
use App\Classes\Modules\Accounts\Standards\Validators\UserAuthenticationValidation;
class CanAuthenticateUser extends AbstractRule
{
/** @var UserAuthenticationValidation */
private $userAuthenticationValidation;
/**
* CanAuthenticateUser constructor.
* @param UserAuthenticationValidation $userAuthenticationValidation
*/
public function __construct(UserAuthenticationValidation $userAuthenticationValidation)
{
$this->userAuthenticationValidation = $userAuthenticationValidation;
}
/**
* @return bool
*/
protected function authorized(): bool
{
return true;
}
/**
* @param AuthenticationCredentialsObject $object
* @return bool
* @throws RequestValidationException
*/
protected function validators($object): bool
{
return $this->userAuthenticationValidation->validate($object);
}
/**
* @param AuthenticationCredentialsObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Classes\Modules\Accounts\Standards\Validators;
use App\Classes\General\Abstracts\AbstractValidation;
use App\Classes\Modules\Accounts\DataTransferObjects\AuthenticationCredentialsObject;
class UserAuthenticationValidation extends AbstractValidation
{
/**
* @param AuthenticationCredentialsObject $object
* @return array
*/
protected function data($object): array {
return [
'email' => $object->getEmail(),
'password' => $object->getPassword()
];
}
/**
* @return array
*/
protected function rules(): array {
return [
'email' => 'required|email',
'password' => 'required'
];
}
/**
* @return array
*/
protected function messages(): array {
return [];
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Account;
use App\Classes\Modules\Accounts\ControllersLogic\AuthenticateUserLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UserAuthenticationController
{
/**
* @param Request $request
* @param AuthenticateUserLogic $logic
* @return JsonResponse
*/
public function authenticate(Request $request, AuthenticateUserLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,99 @@
<template>
<div class="row">
<div class="col p-r-0">
<div class="row no-margin">
<div class="col">
<div class="row m-b-20 animated fadeInUpBig fast" v-if="error">
<div class="col p-l-50">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row animated fadeInDownBig">
<div class="col b-t b-b b-grey animated" :class="[{'shake': $v.parameters.email.$error}]" :style="[$v.parameters.email.$error ? {'border-bottom': 'solid 2px red !important'} : {}]">
<div class="row align-items-center">
<div class="col pl-md-0 pr-md-0 bg-white">
<div class="input-group transparent b-grey b-t">
<span class="input-group-addon no-border">
<i class="fa fa-user-o fa-fw p-l-15 p-t-20" style="padding-right: 18px;"></i>
</span>
<input v-model="parameters.email" placeholder="email" class="form-control no-border bg-white p-t-25 p-b-35 p-l-0 p-r-0">
<validation-error-component :validator="$v.parameters.email" class="absolute fs-12" style=" top: 10px; right: 15px; z-index: 99;"></validation-error-component>
</div>
</div>
</div>
</div>
</div>
<div class="row animated fadeInUpBig">
<div class="col bg-white b-b b-grey animated" :class="[{'shake': $v.parameters.password.$error}]" :style="[$v.parameters.password.$error ? {'border-bottom': 'solid 2px red !important'} : {}]">
<div class="row align-items-center">
<div class="col pl-md-0 pr-md-0 bg-white">
<div class="input-group transparent b-grey b-b">
<span class="input-group-addon no-border">
<i class="fa fa-lock fa-fw p-l-15 p-t-20" style="padding-right: 18px;"></i>
</span>
<input type="password" v-model="parameters.password" placeholder="Password" class="form-control no-border bg-white p-t-35 p-b-35 p-l-0 p-r-0">
<validation-error-component :validator="$v.parameters.password" class="absolute fs-12" style=" top: 10px; right: 15px; z-index: 99;"></validation-error-component>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row m-t-30 align-items-center">
<div class="col-auto animated fadeInLeftBig slow">
<div class="b-t b-b b-r b-primary bg-transparent all-caps text-primary p-t-15 p-b-15 p-l-50 p-r-50 bold font-lato pointer" style="letter-spacing: 8px;" @click="submit(route('api.account.authentication.authenticate.attempt'), 'post', section, false, false)">Login</div>
</div>
<div class="col animated fadeInRightBig slow">
<small class="font-lato muted fs-10 pointer" @click="$store.dispatch('toggleSection', {name: 'forgetPassword', status: true})" style=" letter-spacing: 2px; ">Forgot Password ?</small>
</div>
</div>
</div>
</div>
</template>
<script>
import { required, email } from "vuelidate/lib/validators";
export default {
props: {
section:{
type: String,
required: true
}
},
data() {
return {
error: '',
parameters: {
email: '',
password: ''
}
};
},
validations: {
parameters: {
email: { required, email },
password: { required }
}
},
methods:{
successHandler(response){
localStorage.setItem('user-token', response.payload.access_token);
this.$store.dispatch('userAuthentication', {access_token: response.payload.access_token});
this.error = '';
this.$store.dispatch('toggleSection', {name: 'loginSuccess', status: true})
setTimeout(function(){
window.location.href = response.payload.redirect_url;
}, 2000);
},
errorHandler(error){
this.$store.dispatch('userAuthentication', {access_token: ''});
localStorage.removeItem('user-token');
this.error = error.message;
}
}
}
</script>
@@ -1,93 +1,5 @@
@extends('layouts.base_login')
@section('inner_content')
<transition-component group enter-class="animated fadeInRightBig faster" leave-class="animated fadeOutRightBig" class="h-100">
<div class="row h-100 m-auto" key="1" v-show="!$store.getters.isShowing('loginSuccess') && !$store.getters.isShowing('forgetPasswordSuccess')">
<div class="col d-flex align-items-start flex-column">
<div class="row invisible" v-if="!$store.getters.isShowing('registrationForm')">
<div class="col-auto p-l-0 p-r-0 ml-auto" style="background-color: rgba(255,255,255,0.2);">
<div class="text-white font-lato lightest" style=" font-size: 150px; font-weight: 100; margin-right: -17px; margin-left: -183px; ">...</div>
</div>
</div>
<div class="row w-100">
<div class="col">
<div class="row">
<div class="col no-padding relative">
<transition-component group enter-class="animated fadeInUpBig faster" leave-class="animated fadeOutRightBig">
<loading-component style="height: 350px;" key="1" color="primary" v-show="$store.getters.isLoading('loginSection')"></loading-component>
<transition-component key="2" group enter-class="animated fadeInRightBig faster" leave-class="animated fadeOutUpBig" v-show="!$store.getters.isLoading('loginSection')">
<div class="row" key="1" v-show="!$store.getters.isShowing('forgetPassword')" >
<div class="col all-caps">
<login-section-component section="loginSection"></login-section-component>
</div>
</div>
<div class="row" key="2" v-show="$store.getters.isShowing('forgetPassword')" >
<div class="col all-caps">
<div class="row m-l-0">
<div class="col p-l-50">
<h5 class="font-lato light lh-40 animated fadeInLeftBig slow" style="letter-spacing: 5px; ">Did you forget your password?</h5>
</div>
</div>
<div class="row m-l-0 m-b-20 animated fadeInRightBig slow">
<div class="col p-l-50">
<p class="muted font-lato light lh-25" style="letter-spacing: 2px; ">Enter your email address you're using for your account below<br>and we will send you a password reset link</p>
</div>
</div>
<forget-password-form-component section="loginSection"></forget-password-form-component>
</div>
</div>
</transition-component>
</transition-component>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row align-items-center justify-content-center h-100 bg-white text-center" key="2" v-show="$store.getters.isShowing('loginSuccess')">
<div class="col">
<div class="row m-b-20 animated fadeInRightBig">
<div class="col">
<i class="fa fa-user-circle-o animated pulse slower infinite fs-60 text-success"></i>
</div>
</div>
<div class="row animated fadeInLeftBig" style="height: 50px;">
<div class="col">
<loading-component style="height: 40px;" key="1" color="success"></loading-component>
</div>
</div>
<div class="row animated fadeInUpBig fast">
<div class="col">
<h5 class="all-caps fs-35 m-b-15 text-success">Login Successful</h5>
</div>
</div>
<div class="row animated fadeInUpBig">
<div class="col">
<small class="muted font-lato all-caps">Please wait for redirect</small>
</div>
</div>
</div>
</div>
<div class="row align-items-center justify-content-center h-100 bg-white text-center" key="3" v-show="$store.getters.isShowing('forgetPasswordSuccess')">
<div class="col-10">
<div class="row m-b-20 animated fadeInDownBig">
<div class="col"><i class="fa fa-lock animated swing slower infinite fs-80 text-primary"></i></div>
</div>
<div class="row animated fadeInLeftBig">
<div class="col">
<h5 class="all-caps fs-35 m-b-15 text-primary" style="letter-spacing: 2px;">reset your password</h5>
</div>
</div>
<div class="row animated fadeInRightBig">
<div class="col"><small class="font-lato all-caps light" style="letter-spacing: 2px;">we have sent a reset password email to <span class="text-success" v-text="$store.getters.getResetPasswordEmail"></span><br>Please click the reset password link to set your new password.</small></div>
</div>
<div class="row m-t-30 animated fadeInUpBig slow">
<div class="col"><small class="hint-text font-lato all-caps fs-10" style="letter-spacing: 1px;"><span class="text-danger bold m-r-5">didn't receive the email yet ?</span> Please check your spam folder, or <span class="text-success text-underline bold pointer" @click="$store.dispatch('toggleSection', {name: 'forgetPasswordSuccess', status: false})">resend the email</span></small></div>
</div>
<div class="row m-t-50 animated fadeInUpBig slower">
<div class="col"><small class="hint-text font-lato all-caps fs-10" style="letter-spacing: 1px;">Did you remember your password? Go back to <span class="text-underline text-primary bold pointer" @click="$store.dispatch('toggleSection', {name: 'forgetPasswordSuccess', status: false});$store.dispatch('toggleSection', {name: 'forgetPassword', status: false})">login</span></small></div>
</div>
</div>
</div>
</transition-component>
<login-form-component ref="registration" :section="'RegistrationSection'"></login-form-component>
@endsection
@@ -1,15 +0,0 @@
@extends('layouts.base_portal')
@section('inner_content')
<registration-form-component ref="registration" :email="user@example.com" section="RegistrationSection"></registration-form-component>
<list-component :options="{active: true}" section="listUsersSection" endpoint="{{ route('api.account.user.list') }}">
<div class="row" slot="header">
<div class="col">
<div class="all-caps font-lato m-b-0 text-info bold fs-12">Active users</div>
<p class="fs-9 all-caps light font-lato muted m-b-0">List of the system currently active users</p>
</div>
</div>
<template slot="list" slot-scope="{data}">
<user-component :data="data"></user-component>
</template>
</list-component>
@endSection
@@ -1,4 +1,4 @@
@extends('layouts.base_portal')
@extends('layouts.base_login')
@section('inner_content')
<registration-form-component ref="registration" :section="'RegistrationSection'"></registration-form-component>
@endSection
+3 -4
View File
@@ -6,10 +6,9 @@ Route::group(['prefix' => 'account', 'namespace' => 'Accounts', 'as' => 'account
Route::group(['prefix' => 'authentication', 'as' => 'authentication.'], function () {
// Route::group(['prefix' => 'login', 'as' => 'authenticate.'], function () {
// Route::post('/attempt', 'UserAuthenticationController@authenticate')->name('attempt');
// Route::post('/check_email', 'CheckEmailController@check')->name('email.check');
// });
Route::group(['prefix' => 'login', 'as' => 'authenticate.'], function () {
Route::post('/attempt', 'UserAuthenticationController@authenticate')->name('attempt');
});
// Route::group(['prefix' => 'password', 'as' => 'password.'], function () {
// Route::post('/forget', 'GeneratePasswordResetController@generate')->name('forget');
+4
View File
@@ -25,3 +25,7 @@ Route::get('account/registration', function () {
Route::get('account/password/reset/{token}', function ($token){
return view('pages.accounts.authentication.reset_password',['token' => $token]);
})->name('account.password.reset');
route::get('dashboard/', function (){
return 'dashboard page here';
})->name('dashboard');