Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
laravel-adminpanel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
laravel-adminpanel
Commits
0fc48c64
Commit
0fc48c64
authored
Nov 30, 2017
by
Viral Solani
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
API Boilerplate
parent
1b4b4b6f
Changes
18
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
652 additions
and
634 deletions
+652
-634
APIController.php
app/Http/Controllers/Api/V1/APIController.php
+80
-34
AuthController.php
app/Http/Controllers/Api/V1/AuthController.php
+29
-208
ForgotPasswordController.php
app/Http/Controllers/Api/V1/ForgotPasswordController.php
+57
-0
RegisterController.php
app/Http/Controllers/Api/V1/RegisterController.php
+63
-0
UsersController.php
app/Http/Controllers/Api/V1/UsersController.php
+70
-0
Kernel.php
app/Http/Kernel.php
+4
-3
UserResource.php
app/Http/Resources/UserResource.php
+25
-0
User.php
app/Models/Access/User/User.php
+22
-1
BaseRepository.php
app/Repositories/BaseRepository.php
+22
-0
UserRepository.php
app/Repositories/Frontend/Access/User/UserRepository.php
+0
-1
composer.lock
composer.lock
+85
-73
api.php
config/api.php
+10
-212
api_validation.php
config/api_validation.php
+0
-49
auth.php
config/auth.php
+1
-1
jwt.php
config/jwt.php
+137
-43
api.php
resources/lang/en/api.php
+30
-0
footer.blade.php
resources/views/backend/includes/footer.blade.php
+1
-1
api.php
routes/api.php
+16
-8
No files found.
app/Http/Controllers/Api/V1/APIController.php
View file @
0fc48c64
...
@@ -33,7 +33,7 @@ class APIController extends Controller
...
@@ -33,7 +33,7 @@ class APIController extends Controller
*
*
* @param [type] $statusCode [description]
* @param [type] $statusCode [description]
*
*
* @return
mix
* @return
statuscode
*/
*/
public
function
setStatusCode
(
$statusCode
)
public
function
setStatusCode
(
$statusCode
)
{
{
...
@@ -42,37 +42,13 @@ class APIController extends Controller
...
@@ -42,37 +42,13 @@ class APIController extends Controller
return
$this
;
return
$this
;
}
}
/**
* responsd not found.
*
* @param string $message
*
* @return mix
*/
public
function
respondNotFound
(
$message
=
'Not Found'
)
{
return
$this
->
setStatusCode
(
IlluminateResponse
::
HTTP_NOT_FOUND
)
->
respondWithError
(
$message
);
}
/**
* Respond with error.
*
* @param string $message
*
* @return mix
*/
public
function
respondInternalError
(
$message
=
'Internal Error'
)
{
return
$this
->
setStatusCode
(
'500'
)
->
respondWithError
(
$message
);
}
/**
/**
* Respond.
* Respond.
*
*
* @param array $data
* @param array $data
* @param array $headers
* @param array $headers
*
*
* @return
mix
* @return
\Illuminate\Http\JsonResponse
*/
*/
public
function
respond
(
$data
,
$headers
=
[])
public
function
respond
(
$data
,
$headers
=
[])
{
{
...
@@ -85,7 +61,7 @@ class APIController extends Controller
...
@@ -85,7 +61,7 @@ class APIController extends Controller
* @param Paginator $items
* @param Paginator $items
* @param array $data
* @param array $data
*
*
* @return
mix
* @return
\Illuminate\Http\JsonResponse
*/
*/
public
function
respondWithPagination
(
$items
,
$data
)
public
function
respondWithPagination
(
$items
,
$data
)
{
{
...
@@ -101,12 +77,38 @@ class APIController extends Controller
...
@@ -101,12 +77,38 @@ class APIController extends Controller
return
$this
->
respond
(
$data
);
return
$this
->
respond
(
$data
);
}
}
/**
* Respond Created.
*
* @param string $message
*
* @return \Illuminate\Http\JsonResponse
*/
public
function
respondCreated
(
$data
)
{
return
$this
->
setStatusCode
(
201
)
->
respond
([
'data'
=>
$data
,
]);
}
/**
* Respond Created with data.
*
* @param string $message
*
* @return \Illuminate\Http\JsonResponse
*/
public
function
respondCreatedWithData
(
$data
)
{
return
$this
->
setStatusCode
(
201
)
->
respond
(
$data
);
}
/**
/**
* respond with error.
* respond with error.
*
*
* @param $message
* @param $message
*
*
* @return
mix
* @return
\Illuminate\Http\JsonResponse
*/
*/
public
function
respondWithError
(
$message
)
public
function
respondWithError
(
$message
)
{
{
...
@@ -119,17 +121,61 @@ class APIController extends Controller
...
@@ -119,17 +121,61 @@ class APIController extends Controller
}
}
/**
/**
*
Respond Create
d.
*
responsd not foun
d.
*
*
* @param string $message
* @param string $message
*
*
* @return
mix
* @return
\Illuminate\Http\JsonResponse
*/
*/
public
function
respond
Created
(
$message
)
public
function
respond
NotFound
(
$message
=
'Not Found'
)
{
{
return
$this
->
setStatusCode
(
201
)
->
respond
([
return
$this
->
setStatusCode
(
IlluminateResponse
::
HTTP_NOT_FOUND
)
->
respondWithError
(
$message
);
'message'
=>
$message
,
}
]);
/**
* Respond with error.
*
* @param string $message
*
* @return \Illuminate\Http\JsonResponse
*/
public
function
respondInternalError
(
$message
=
'Internal Error'
)
{
return
$this
->
setStatusCode
(
500
)
->
respondWithError
(
$message
);
}
/**
* Respond with unauthorized.
*
* @param string $message
*
* @return \Illuminate\Http\JsonResponse
*/
protected
function
respondUnauthorized
(
$message
=
'Unauthorized'
)
{
return
$this
->
setStatusCode
(
401
)
->
respondWithError
(
$message
);
}
/**
* Respond with forbidden.
*
* @param string $message
*
* @return \Illuminate\Http\JsonResponse
*/
protected
function
respondForbidden
(
$message
=
'Forbidden'
)
{
return
$this
->
setStatusCode
(
403
)
->
respondWithError
(
$message
);
}
/**
* Respond with no content.
*
* @return \Illuminate\Http\JsonResponse
*/
protected
function
respondWithNoContent
()
{
return
$this
->
setStatusCode
(
204
)
->
respond
(
null
);
}
}
/**
/**
...
...
app/Http/Controllers/Api/V1/AuthController.php
View file @
0fc48c64
...
@@ -2,74 +2,49 @@
...
@@ -2,74 +2,49 @@
namespace
App\Http\Controllers\Api\V1
;
namespace
App\Http\Controllers\Api\V1
;
use
App\Models\Access\User\User
;
use
App\Notifications\Activated
;
use
App\Notifications\Activation
;
use
App\Notifications\PasswordReset
;
use
App\Notifications\PasswordResetted
;
use
Illuminate\Http\Request
;
use
Illuminate\Http\Request
;
use
JWTAuth
;
use
JWTAuth
;
use
Tymon\JWTAuth\Exceptions\JWTException
;
use
Tymon\JWTAuth\Exceptions\JWTException
;
use
Validator
;
use
Validator
;
/**
* AuthController.
*/
class
AuthController
extends
APIController
class
AuthController
extends
APIController
{
{
/**
/**
*
Authenticate User
.
*
Log the user in
.
*
*
* @param Request $request
* @param Request $request
*
*
* @return \Illuminate\Http\JsonResponse
* @return \Illuminate\Http\JsonResponse
*/
*/
public
function
authenticate
(
Request
$request
)
public
function
login
(
Request
$request
)
{
{
$credentials
=
$request
->
only
(
'email'
,
'password'
);
$validation
=
Validator
::
make
(
$request
->
all
(),
[
'email'
=>
'required|email'
,
try
{
'password'
=>
'required|min:4'
,
if
(
!
$token
=
JWTAuth
::
attempt
(
$credentials
))
{
]);
return
$this
->
throwValidation
(
'Invalid Credentials! Please try again.'
);
}
}
catch
(
JWTException
$e
)
{
return
$this
->
respondInternalError
(
'This is something wrong. Please try again!'
);
}
$user
=
User
::
whereEmail
(
request
(
'email'
))
->
first
();
if
(
$
user
->
status
!=
1
)
{
if
(
$
validation
->
fails
()
)
{
return
$this
->
throwValidation
(
'Your account hasn\'t been activated. Please check your email & activate account.'
);
return
$this
->
throwValidation
(
$validation
->
messages
()
->
first
()
);
}
}
return
$this
->
respond
([
$credentials
=
$request
->
only
([
'email'
,
'password'
]);
'message'
=>
'You are successfully logged in!'
,
'token'
=>
$token
,
]);
}
/**
* Check if user is authenticated or not.
*
* @return \Illuminate\Http\JsonResponse
*/
public
function
check
()
{
try
{
try
{
JWTAuth
::
parseToken
()
->
authenticate
();
if
(
!
$token
=
JWTAuth
::
attempt
(
$credentials
))
{
return
$this
->
throwValidation
(
trans
(
'api.messages.login.failed'
));
}
}
catch
(
JWTException
$e
)
{
}
catch
(
JWTException
$e
)
{
return
$this
->
respond
([
return
$this
->
respondInternalError
(
$e
->
getMessage
());
'authenticated'
=>
false
,
]);
}
}
return
$this
->
respond
([
return
$this
->
respond
([
'authenticated'
=>
true
,
'message'
=>
trans
(
'api.messages.login.success'
),
'token'
=>
$token
,
]);
]);
}
}
/**
/**
* Log
Out
.
* Log
the user out (Invalidate the token)
.
*
*
* @return \Illuminate\Http\JsonResponse
* @return \Illuminate\Http\JsonResponse
*/
*/
...
@@ -82,190 +57,36 @@ class AuthController extends APIController
...
@@ -82,190 +57,36 @@ class AuthController extends APIController
JWTAuth
::
invalidate
(
$token
);
JWTAuth
::
invalidate
(
$token
);
}
}
}
catch
(
JWTException
$e
)
{
}
catch
(
JWTException
$e
)
{
return
$this
->
respondInternalError
(
'This is something wrong. Please try again!'
);
return
$this
->
respondInternalError
(
$e
->
getMessage
()
);
}
}
return
$this
->
respond
([
return
$this
->
respond
([
'message'
=>
'You are successfully logged out!'
,
'message'
=>
trans
(
'api.messages.logout.success'
),
]);
}
/**
* Register User.
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public
function
register
(
Request
$request
)
{
$validation
=
Validator
::
make
(
$request
->
all
(),
[
'first_name'
=>
'required'
,
'last_name'
=>
'required'
,
'email'
=>
'required|email|unique:users'
,
'password'
=>
'required|min:6'
,
'password_confirmation'
=>
'required|same:password'
,
]);
if
(
$validation
->
fails
())
{
return
$this
->
throwValidation
(
$validation
->
messages
()
->
first
());
}
$user
=
User
::
create
([
'first_name'
=>
request
(
'first_name'
),
'last_name'
=>
request
(
'last_name'
),
'email'
=>
request
(
'email'
),
'status'
=>
'0'
,
'password'
=>
bcrypt
(
request
(
'password'
)),
'country_id'
=>
1
,
'state_id'
=>
1
,
'city_id'
=>
1
,
'zip_code'
=>
1
,
'ssn'
=>
123456789
,
'created_by'
=>
1
,
]);
$user
->
confirmation_code
=
generateUuid
();
$user
->
save
();
$user
->
notify
(
new
Activation
(
$user
));
return
$this
->
respondCreated
([
'You have registered successfully. Please check your email for activation!'
,
]);
]);
}
}
/**
/**
* Activate User.
* Refresh a token.
*
* @param $activation_token [description]
*
*
* @return \Illuminate\Http\JsonResponse
* @return \Illuminate\Http\JsonResponse
*/
*/
public
function
activate
(
$activation_token
)
public
function
refresh
(
)
{
{
$
user
=
User
::
whereConfirmationCode
(
$activation_token
)
->
first
();
$
token
=
JWTAuth
::
getToken
();
if
(
!
$
user
)
{
if
(
!
$
token
)
{
return
$this
->
throwValidation
(
'Invalid activation token!'
);
$this
->
respondUnauthorized
(
trans
(
'api.messages.refresh.token.not_provided'
)
);
}
}
if
(
$user
->
status
==
1
)
{
try
{
return
$this
->
throwValidation
(
'Your account has already been activated!'
);
$refreshedToken
=
JWTAuth
::
refresh
(
$token
);
}
catch
(
JWTException
$e
)
{
return
$this
->
respondInternalError
(
$e
->
getMessage
());
}
}
$user
->
confirmed
=
1
;
$user
->
status
=
1
;
$user
->
save
();
$user
->
notify
(
new
Activated
(
$user
));
return
$this
->
respond
([
return
$this
->
respond
([
'message'
=>
'Your account has been activated!'
,
'status'
=>
trans
(
'api.messages.refresh.status'
),
]);
'token'
=>
$refreshedToken
,
}
public
function
password
(
Request
$request
)
{
$validation
=
Validator
::
make
(
$request
->
all
(),
[
'email'
=>
'required|email'
,
]);
if
(
$validation
->
fails
())
{
return
response
()
->
json
([
'message'
=>
$validation
->
messages
()
->
first
()],
422
);
}
$user
=
User
::
whereEmail
(
request
(
'email'
))
->
first
();
if
(
!
$user
)
{
return
response
()
->
json
([
'message'
=>
'We couldn\'t found any user with this email. Please try again!'
],
422
);
}
$token
=
generateUuid
();
\DB
::
table
(
'password_resets'
)
->
insert
([
'email'
=>
request
(
'email'
),
'token'
=>
$token
,
]);
$user
->
notify
(
new
PasswordReset
(
$user
,
$token
));
return
response
()
->
json
([
'message'
=>
'We have sent reminder email. Please check your inbox!'
]);
}
public
function
validatePasswordReset
(
Request
$request
)
{
$validate_password_request
=
\DB
::
table
(
'password_resets'
)
->
where
(
'token'
,
'='
,
request
(
'token'
))
->
first
();
if
(
!
$validate_password_request
)
{
return
response
()
->
json
([
'message'
=>
'Invalid password reset token!'
],
422
);
}
if
(
date
(
'Y-m-d H:i:s'
,
strtotime
(
$validate_password_request
->
created_at
.
'+30 minutes'
))
<
date
(
'Y-m-d H:i:s'
))
{
return
response
()
->
json
([
'message'
=>
'Password reset token is expired. Please request reset password again!'
],
422
);
}
return
response
()
->
json
([
'message'
=>
''
]);
}
public
function
reset
(
Request
$request
)
{
$validation
=
Validator
::
make
(
$request
->
all
(),
[
'email'
=>
'required|email'
,
'password'
=>
'required|min:6'
,
'password_confirmation'
=>
'required|same:password'
,
]);
if
(
$validation
->
fails
())
{
return
response
()
->
json
([
'message'
=>
$validation
->
messages
()
->
first
()],
422
);
}
$user
=
User
::
whereEmail
(
request
(
'email'
))
->
first
();
if
(
!
$user
)
{
return
response
()
->
json
([
'message'
=>
'We couldn\'t found any user with this email. Please try again!'
],
422
);
}
$validate_password_request
=
\DB
::
table
(
'password_resets'
)
->
where
(
'email'
,
'='
,
request
(
'email'
))
->
where
(
'token'
,
'='
,
request
(
'token'
))
->
first
();
if
(
!
$validate_password_request
)
{
return
response
()
->
json
([
'message'
=>
'Invalid password reset token!'
],
422
);
}
if
(
date
(
'Y-m-d H:i:s'
,
strtotime
(
$validate_password_request
->
created_at
.
'+30 minutes'
))
<
date
(
'Y-m-d H:i:s'
))
{
return
response
()
->
json
([
'message'
=>
'Password reset token is expired. Please request reset password again!'
],
422
);
}
$user
->
password
=
bcrypt
(
request
(
'password'
));
$user
->
save
();
$user
->
notify
(
new
PasswordResetted
(
$user
));
return
response
()
->
json
([
'message'
=>
'Your password has been reset. Please login again!'
]);
}
public
function
changePassword
(
Request
$request
)
{
if
(
env
(
'IS_DEMO'
))
{
return
response
()
->
json
([
'message'
=>
'You are not allowed to perform this action in this mode.'
],
422
);
}
$validation
=
Validator
::
make
(
$request
->
all
(),
[
'current_password'
=>
'required'
,
'new_password'
=>
'required|confirmed|different:current_password|min:6'
,
'new_password_confirmation'
=>
'required|same:new_password'
,
]);
]);
if
(
$validation
->
fails
())
{
return
response
()
->
json
([
'message'
=>
$validation
->
messages
()
->
first
()],
422
);
}
$user
=
JWTAuth
::
parseToken
()
->
authenticate
();
if
(
!
\Hash
::
check
(
request
(
'current_password'
),
$user
->
password
))
{
return
response
()
->
json
([
'message'
=>
'Old password does not match! Please try again!'
],
422
);
}
$user
->
password
=
bcrypt
(
request
(
'new_password'
));
$user
->
save
();
return
response
()
->
json
([
'message'
=>
'Your password has been changed successfully!'
]);
}
}
}
}
app/Http/Controllers/Api/V1/ForgotPasswordController.php
0 → 100644
View file @
0fc48c64
<?php
namespace
App\Http\Controllers\Api\V1
;
use
Validator
;
use
App\Models\User\User
;
use
Illuminate\Http\Request
;
use
App\Http\Controllers\Controller
;
use
App\Repositories\UserRepository
;
use
Illuminate\Support\Facades\Password
;
use
App\Notifications\UserNeedsPasswordReset
;
class
ForgotPasswordController
extends
APIController
{
/**
* __construct.
*
* @param $repository
*/
public
function
__construct
(
UserRepository
$repository
)
{
$this
->
repository
=
$repository
;
}
/**
* Send a reset link to the given user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public
function
sendResetLinkEmail
(
Request
$request
)
{
$validation
=
Validator
::
make
(
$request
->
all
(),
[
'email'
=>
'required|email'
,
]);
if
(
$validation
->
fails
())
{
return
$this
->
throwValidation
(
$validation
->
messages
()
->
first
());
}
$user
=
$this
->
repository
->
getUserByEmail
(
$request
);
if
(
!
$user
)
{
return
$this
->
respondNotFound
(
trans
(
'api.messages.forgot_password.validation.email_not_found'
));
}
$token
=
$this
->
repository
->
createNewToken
();
$user
->
notify
(
new
UserNeedsPasswordReset
(
$token
));
return
$this
->
respond
([
'status'
=>
'ok'
,
'message'
=>
trans
(
'api.messages.forgot_password.success'
),
]);
}
}
app/Http/Controllers/Api/V1/RegisterController.php
0 → 100644
View file @
0fc48c64
<?php
namespace
App\Http\Controllers\Api\V1
;
use
Config
;
use
JWTAuth
;
use
Validator
;
use
App\Models\User\User
;
use
Illuminate\Http\Request
;
use
App\Repositories\Frontend\Access\User\UserRepository
;
class
RegisterController
extends
APIController
{
protected
$repository
;
/**
* __construct.
*
* @param $repository
*/
public
function
__construct
(
UserRepository
$repository
)
{
$this
->
repository
=
$repository
;
}
/**
* Register User.
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public
function
register
(
Request
$request
)
{
$validation
=
Validator
::
make
(
$request
->
all
(),
[
'first_name'
=>
'required'
,
'last_name'
=>
'required'
,
'email'
=>
'required|email|unique:users'
,
'password'
=>
'required|min:4'
,
'password_confirmation'
=>
'required|same:password'
,
'is_term_accept'
=>
'required'
]);
if
(
$validation
->
fails
())
{
return
$this
->
throwValidation
(
$validation
->
messages
()
->
first
());
}
$user
=
$this
->
repository
->
create
(
$request
->
all
());
if
(
!
Config
::
get
(
'api.register.release_token'
))
{
return
$this
->
respondCreated
([
'message'
=>
trans
(
'api.messages.registeration.success'
),
]);
}
$token
=
JWTAuth
::
fromUser
(
$user
);
return
$this
->
respondCreated
([
'message'
=>
trans
(
'api.messages.registeration.success'
),
'token'
=>
$token
,
]);
}
}
app/Http/Controllers/Api/V1/UsersController.php
0 → 100644
View file @
0fc48c64
<?php
namespace
App\Http\Controllers\Api\V1
;
use
Validator
;
use
App\Models\User\User
;
use
Illuminate\Http\Request
;
use
App\Http\Resources\UserResource
;
use
App\Repositories\Backend\Access\User\UserRepository
;
class
UsersController
extends
APIController
{
protected
$repository
;
/**
* __construct.
*
* @param $repository
*/
public
function
__construct
(
UserRepository
$repository
)
{
$this
->
repository
=
$repository
;
}
/**
* Return the users.
*
* @return \Illuminate\Http\Response
*/
public
function
index
(
Request
$request
)
{
$limit
=
$request
->
get
(
'paginate'
)
?
$request
->
get
(
'paginate'
)
:
25
;
return
UserResource
::
collection
(
$this
->
repository
->
getPaginated
(
$limit
)
);
}
/**
* Return the specified resource.
*
* @param User $user
*
* @return \Illuminate\Http\Response
*/
public
function
show
(
User
$user
)
{
return
new
UserResource
(
$user
);
}
/**
* Update the specified resource in storage.
*/
public
function
update
(
Request
$request
,
User
$user
)
{
$validation
=
Validator
::
make
(
$request
->
all
(),
[
'name'
=>
'required'
,
'email'
=>
'email|unique:users,email,'
.
$user
->
id
,
'password'
=>
'nullable|confirmed'
,
]);
if
(
$validation
->
fails
())
{
return
$this
->
throwValidation
(
$validation
->
messages
()
->
first
());
}
$user
=
$this
->
repository
->
update
(
$user
->
id
,
$request
->
all
());
return
new
UserResource
(
$user
);
}
}
app/Http/Kernel.php
View file @
0fc48c64
...
@@ -3,6 +3,8 @@
...
@@ -3,6 +3,8 @@
namespace
App\Http
;
namespace
App\Http
;
use
Illuminate\Foundation\Http\Kernel
as
HttpKernel
;
use
Illuminate\Foundation\Http\Kernel
as
HttpKernel
;
use
Tymon\JWTAuth\Middleware\GetUserFromToken
;
use
Tymon\JWTAuth\Middleware\RefreshToken
;
/**
/**
* Class Kernel.
* Class Kernel.
...
@@ -73,8 +75,7 @@ class Kernel extends HttpKernel
...
@@ -73,8 +75,7 @@ class Kernel extends HttpKernel
*/
*/
'access.routeNeedsRole'
=>
\App\Http\Middleware\RouteNeedsRole
::
class
,
'access.routeNeedsRole'
=>
\App\Http\Middleware\RouteNeedsRole
::
class
,
'access.routeNeedsPermission'
=>
\App\Http\Middleware\RouteNeedsPermission
::
class
,
'access.routeNeedsPermission'
=>
\App\Http\Middleware\RouteNeedsPermission
::
class
,
//'jwt.auth' => \App\Http\Middleware\VerifyJWTToken::class,
'jwt.auth'
=>
GetUserFromToken
::
class
,
'jwt.auth'
=>
\Tymon\JWTAuth\Middleware\GetUserFromToken
::
class
,
'jwt.refresh'
=>
RefreshToken
::
class
,
'jwt.refresh'
=>
\Tymon\JWTAuth\Middleware\RefreshToken
::
class
,
];
];
}
}
app/Http/Resources/UserResource.php
0 → 100644
View file @
0fc48c64
<?php
namespace
App\Http\Resources
;
use
Illuminate\Http\Resources\Json\Resource
;
class
UserResource
extends
Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
*
* @return array
*/
public
function
toArray
(
$request
)
{
return
[
'id'
=>
$this
->
id
,
'name'
=>
$this
->
name
,
'email'
=>
$this
->
email
,
'registered_at'
=>
$this
->
created_at
->
toIso8601String
(),
];
}
}
app/Models/Access/User/User.php
View file @
0fc48c64
...
@@ -9,12 +9,13 @@ use App\Models\Access\User\Traits\UserAccess;
...
@@ -9,12 +9,13 @@ use App\Models\Access\User\Traits\UserAccess;
use
App\Models\Access\User\Traits\UserSendPasswordReset
;
use
App\Models\Access\User\Traits\UserSendPasswordReset
;
use
Illuminate\Database\Eloquent\SoftDeletes
;
use
Illuminate\Database\Eloquent\SoftDeletes
;
use
Illuminate\Foundation\Auth\User
as
Authenticatable
;
use
Illuminate\Foundation\Auth\User
as
Authenticatable
;
use
Tymon\JWTAuth\Contracts\JWTSubject
;
use
Illuminate\Notifications\Notifiable
;
use
Illuminate\Notifications\Notifiable
;
/**
/**
* Class User.
* Class User.
*/
*/
class
User
extends
Authenticatable
class
User
extends
Authenticatable
implements
JWTSubject
{
{
use
UserScope
,
use
UserScope
,
UserAccess
,
UserAccess
,
...
@@ -67,4 +68,24 @@ class User extends Authenticatable
...
@@ -67,4 +68,24 @@ class User extends Authenticatable
parent
::
__construct
(
$attributes
);
parent
::
__construct
(
$attributes
);
$this
->
table
=
config
(
'access.users_table'
);
$this
->
table
=
config
(
'access.users_table'
);
}
}
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public
function
getJWTIdentifier
()
{
return
$this
->
getKey
();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public
function
getJWTCustomClaims
()
{
return
[];
}
}
}
app/Repositories/BaseRepository.php
View file @
0fc48c64
...
@@ -15,6 +15,28 @@ class BaseRepository
...
@@ -15,6 +15,28 @@ class BaseRepository
return
$this
->
query
()
->
get
();
return
$this
->
query
()
->
get
();
}
}
/**
* Get Paginated.
*
* @param $per_page
* @param string $active
* @param string $order_by
* @param string $sort
*
* @return mixed
*/
public
function
getPaginated
(
$per_page
,
$active
=
''
,
$order_by
=
'id'
,
$sort
=
'asc'
)
{
if
(
$active
)
{
return
$this
->
query
()
->
where
(
'status'
,
$active
)
->
orderBy
(
$order_by
,
$sort
)
->
paginate
(
$per_page
);
}
else
{
return
$this
->
query
()
->
orderBy
(
$order_by
,
$sort
)
->
paginate
(
$per_page
);
}
}
/**
/**
* @return mixed
* @return mixed
*/
*/
...
...
app/Repositories/Frontend/Access/User/UserRepository.php
View file @
0fc48c64
...
@@ -95,7 +95,6 @@ class UserRepository extends BaseRepository
...
@@ -95,7 +95,6 @@ class UserRepository extends BaseRepository
$user
->
password
=
$provider
?
null
:
bcrypt
(
$data
[
'password'
]);
$user
->
password
=
$provider
?
null
:
bcrypt
(
$data
[
'password'
]);
$user
->
confirmed
=
$provider
?
1
:
(
config
(
'access.users.confirm_email'
)
?
0
:
1
);
$user
->
confirmed
=
$provider
?
1
:
(
config
(
'access.users.confirm_email'
)
?
0
:
1
);
$user
->
is_term_accept
=
$data
[
'is_term_accept'
];
$user
->
is_term_accept
=
$data
[
'is_term_accept'
];
$user
->
created_by
=
1
;
DB
::
transaction
(
function
()
use
(
$user
)
{
DB
::
transaction
(
function
()
use
(
$user
)
{
if
(
$user
->
save
())
{
if
(
$user
->
save
())
{
...
...
composer.lock
View file @
0fc48c64
This diff is collapsed.
Click to expand it.
config/api.php
View file @
0fc48c64
<?php
<?php
return
[
return
[
/*
// these options are related to the sign-up procedure
|--------------------------------------------------------------------------
'register'
=>
[
| Standards Tree
|--------------------------------------------------------------------------
|
| Versioning an API with Dingo revolves around content negotiation and
| custom MIME types. A custom type will belong to one of three
| standards trees, the Vendor tree (vnd), the Personal tree
| (prs), and the Unregistered tree (x).
|
| By default the Unregistered tree (x) is used, however, should you wish
| to you can register your type with the IANA. For more details:
| https://tools.ietf.org/html/rfc6838
|
*/
'standardsTree'
=>
env
(
'API_STANDARDS_TREE'
,
'x'
),
/*
|--------------------------------------------------------------------------
| API Subtype
|--------------------------------------------------------------------------
|
| Your subtype will follow the standards tree you use when used in the
| "Accept" header to negotiate the content type and version.
|
| For example: Accept: application/x.SUBTYPE.v1+json
|
*/
'subtype'
=>
env
(
'API_SUBTYPE'
,
''
),
/*
|--------------------------------------------------------------------------
| Default API Version
|--------------------------------------------------------------------------
|
| This is the default version when strict mode is disabled and your API
| is accessed via a web browser. It's also used as the default version
| when generating your APIs documentation.
|
*/
'version'
=>
env
(
'API_VERSION'
,
'v1'
),
/*
|--------------------------------------------------------------------------
| Default API Prefix
|--------------------------------------------------------------------------
|
| A default prefix to use for your API routes so you don't have to
| specify it for each group.
|
*/
'prefix'
=>
env
(
'API_PREFIX'
,
null
),
/*
|--------------------------------------------------------------------------
| Default API Domain
|--------------------------------------------------------------------------
|
| A default domain to use for your API routes so you don't have to
| specify it for each group.
|
*/
'domain'
=>
env
(
'API_DOMAIN'
,
null
),
/*
|--------------------------------------------------------------------------
| Name
|--------------------------------------------------------------------------
|
| When documenting your API using the API Blueprint syntax you can
| configure a default name to avoid having to manually specify
| one when using the command.
|
*/
'name'
=>
env
(
'API_NAME'
,
null
),
/*
|--------------------------------------------------------------------------
| Conditional Requests
|--------------------------------------------------------------------------
|
| Globally enable conditional requests so that an ETag header is added to
| any successful response. Subsequent requests will perform a check and
| will return a 304 Not Modified. This can also be enabled or disabled
| on certain groups or routes.
|
*/
'conditionalRequest'
=>
env
(
'API_CONDITIONAL_REQUEST'
,
true
),
/*
|--------------------------------------------------------------------------
| Strict Mode
|--------------------------------------------------------------------------
|
| Enabling strict mode will require clients to send a valid Accept header
| with every request. This also voids the default API version, meaning
| your API will not be browsable via a web browser.
|
*/
'strict'
=>
env
(
'API_STRICT'
,
false
),
/*
|--------------------------------------------------------------------------
| Debug Mode
|--------------------------------------------------------------------------
|
| Enabling debug mode will result in error responses caused by thrown
| exceptions to have a "debug" key that will be populated with
| more detailed information on the exception.
|
*/
'debug'
=>
env
(
'API_DEBUG'
,
false
),
/*
|--------------------------------------------------------------------------
| Generic Error Format
|--------------------------------------------------------------------------
|
| When some HTTP exceptions are not caught and dealt with the API will
| generate a generic error response in the format provided. Any
| keys that aren't replaced with corresponding values will be
| removed from the final response.
|
*/
'errorFormat'
=>
[
'message'
=>
':message'
,
'errors'
=>
':errors'
,
'code'
=>
':code'
,
'status_code'
=>
':status_code'
,
'debug'
=>
':debug'
,
],
/*
|--------------------------------------------------------------------------
| API Middleware
|--------------------------------------------------------------------------
|
| Middleware that will be applied globally to all API requests.
|
*/
'middleware'
=>
[
// this option must be set to true if you want to release a token
// when your user successfully terminates the sign-in procedure
'release_token'
=>
env
(
'SIGN_UP_RELEASE_TOKEN'
,
true
),
],
],
/*
// these options are related to the password recovery procedure
|--------------------------------------------------------------------------
'reset_password'
=>
[
| Authentication Providers
|--------------------------------------------------------------------------
|
| The authentication providers that should be used when attempting to
| authenticate an incoming API request.
|
*/
'auth'
=>
[
'jwt'
=>
'Dingo\Api\Auth\Provider\JWT'
,
],
/*
|--------------------------------------------------------------------------
| Throttling / Rate Limiting
|--------------------------------------------------------------------------
|
| Consumers of your API can be limited to the amount of requests they can
| make. You can create your own throttles or simply change the default
| throttles.
|
*/
'throttling'
=>
[
],
/*
|--------------------------------------------------------------------------
| Response Transformer
|--------------------------------------------------------------------------
|
| Responses can be transformed so that they are easier to format. By
| default a Fractal transformer will be used to transform any
| responses prior to formatting. You can easily replace
| this with your own transformer.
|
*/
'transformer'
=>
env
(
'API_TRANSFORMER'
,
Dingo\Api\Transformer\Adapter\Fractal
::
class
),
/*
|--------------------------------------------------------------------------
| Response Formats
|--------------------------------------------------------------------------
|
| Responses can be returned in multiple formats by registering different
| response formatters. You can also customize an existing response
| formatter.
|
*/
'defaultFormat'
=>
env
(
'API_DEFAULT_FORMAT'
,
'json'
),
'formats'
=>
[
'json'
=>
Dingo\Api\Http\Response\Format\Json
::
class
,
// this option must be set to true if you want to release a token
// when your user successfully terminates the password reset procedure
'release_token'
=>
env
(
'PASSWORD_RESET_RELEASE_TOKEN'
,
false
),
],
],
];
];
config/api_validation.php
deleted
100755 → 0
View file @
1b4b4b6f
<?php
return
[
/*
* Validation rules for all api.
*/
'login'
=>
[
'rules'
=>
[
'email'
=>
'required|email'
,
'password'
=>
'required'
,
],
],
'forgotpassword'
=>
[
'rules'
=>
[
'email'
=>
'required|email'
,
],
],
'resetpassword'
=>
[
'rules'
=>
[
'email'
=>
'required|email'
,
'password_confirmation'
=>
'required'
,
'password'
=>
'required|confirmed'
,
'token'
=>
'required'
,
],
],
'register'
=>
[
'rules'
=>
[
'first_name'
=>
'required|max:255'
,
'last_name'
=>
'required|max:255'
,
'email'
=>
'required|email|max:255|unique:users'
,
'password'
=>
'required|min:6|confirmed'
,
'state_id'
=>
'required'
,
'city_id'
=>
'required'
,
'zip_code'
=>
'required'
,
'ssn'
=>
'required'
,
],
],
'confirmaccount'
=>
[
'rules'
=>
[
'email'
=>
'required|email'
,
'otp'
=>
'required'
,
],
],
];
config/auth.php
View file @
0fc48c64
...
@@ -44,7 +44,7 @@ return [
...
@@ -44,7 +44,7 @@ return [
],
],
'api'
=>
[
'api'
=>
[
'driver'
=>
'
token
'
,
'driver'
=>
'
jwt
'
,
'provider'
=>
'users'
,
'provider'
=>
'users'
,
],
],
],
],
...
...
config/jwt.php
View file @
0fc48c64
...
@@ -16,76 +16,124 @@ return [
...
@@ -16,76 +16,124 @@ return [
| JWT Authentication Secret
| JWT Authentication Secret
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Don't forget to set this, as it will be used to sign your tokens.
| Don't forget to set this in your .env file, as it will be used to sign
| A helper command is provided for this: `php artisan jwt:generate`
| your tokens. A helper command is provided for this:
| `php artisan jwt:secret`
|
| Note: This will be used for Symmetric algorithms only (HMAC),
| since RSA and ECDSA use a private/public key combo (See below).
|
|
*/
*/
'secret'
=>
env
(
'JWT_SECRET'
,
'3M0tGfsEolZsrst5wrJgUOWk5Zkqzx5A'
),
'secret'
=>
env
(
'JWT_SECRET'
),
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
| JWT
time to live
| JWT
Authentication Keys
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Specify the length of time (in minutes) that the token will be valid for.
| The algorithm you are using, will determine whether your tokens are
| Defaults to 1 hour
| signed with a random string (defined in `JWT_SECRET`) or using the
| following public & private keys.
|
| Symmetric Algorithms:
| HS256, HS384 & HS512 will use `JWT_SECRET`.
|
| Asymmetric Algorithms:
| RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below.
|
|
*/
*/
'
ttl'
=>
60
,
'
keys'
=>
[
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
| Refresh time to live
| Public Key
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Specify the length of time (in minutes) that the token can be refreshed
| A path or resource to your public key.
| within. I.E. The user can refresh their token within a 2 week window of
|
| the original token being created until they must re-authenticate.
| E.g. 'file://path/to/public/key'
| Defaults to 2 weeks
|
|
*/
*/
'refresh_ttl'
=>
20160
,
'public'
=>
env
(
'JWT_PUBLIC_KEY'
)
,
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
| JWT hashing algorithm
| Private Key
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Specify the hashing algorithm that will be used to sign the token.
| A path or resource to your private key.
|
| E.g. 'file://path/to/private/key'
|
*/
'private'
=>
env
(
'JWT_PRIVATE_KEY'
),
/*
|--------------------------------------------------------------------------
| Passphrase
|--------------------------------------------------------------------------
|
| The passphrase for your private key. Can be null if none set.
|
*/
'passphrase'
=>
env
(
'JWT_PASSPHRASE'
),
],
/*
|--------------------------------------------------------------------------
| JWT time to live
|--------------------------------------------------------------------------
|
| Specify the length of time (in minutes) that the token will be valid for.
| Defaults to 1 hour.
|
|
| See here: https://github.com/namshi/jose/tree/2.2.0/src/Namshi/JOSE/Signer
| You can also set this to null, to yield a never expiring token.
| for possible values
| Some people may want this behaviour for e.g. a mobile app.
| This is not particularly recommended, so make sure you have appropriate
| systems in place to revoke the token if necessary.
|
|
*/
*/
'
algo'
=>
'HS256'
,
'
ttl'
=>
env
(
'JWT_TTL'
,
60
)
,
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
User Model namespac
e
|
Refresh time to liv
e
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Specify the full namespace to your User model.
| Specify the length of time (in minutes) that the token can be refreshed
| e.g. 'Acme\Entities\User'
| within. I.E. The user can refresh their token within a 2 week window of
| the original token being created until they must re-authenticate.
| Defaults to 2 weeks.
|
| You can also set this to null, to yield an infinite refresh time.
| Some may want this instead of never expiring tokens for e.g. a mobile app.
| This is not particularly recommended, so make sure you have appropriate
| systems in place to revoke the token if necessary.
|
|
*/
*/
'
user'
=>
'App\Models\Access\User\User'
,
'
refresh_ttl'
=>
env
(
'JWT_REFRESH_TTL'
,
20160
)
,
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
User identifier
|
JWT hashing algorithm
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Specify a unique property of the user that will be added as the 'sub'
| Specify the hashing algorithm that will be used to sign the token.
| claim of the token payload.
|
| See here: https://github.com/namshi/jose/tree/master/src/Namshi/JOSE/Signer/OpenSSL
| for possible values.
|
|
*/
*/
'
identifier'
=>
'id'
,
'
algo'
=>
env
(
'JWT_ALGO'
,
'HS256'
)
,
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
...
@@ -98,7 +146,32 @@ return [
...
@@ -98,7 +146,32 @@ return [
|
|
*/
*/
'required_claims'
=>
[
'iss'
,
'iat'
,
'exp'
,
'nbf'
,
'sub'
,
'jti'
],
'required_claims'
=>
[
'iss'
,
'iat'
,
'exp'
,
'nbf'
,
'sub'
,
'jti'
,
],
/*
|--------------------------------------------------------------------------
| Persistent Claims
|--------------------------------------------------------------------------
|
| Specify the claim keys to be persisted when refreshing a token.
| `sub` and `iat` will automatically be persisted, in
| addition to the these claims.
|
| Note: If a claim does not exist then it will be ignored.
|
*/
'persistent_claims'
=>
[
// 'foo',
// 'bar',
],
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
...
@@ -112,28 +185,49 @@ return [
...
@@ -112,28 +185,49 @@ return [
'blacklist_enabled'
=>
env
(
'JWT_BLACKLIST_ENABLED'
,
true
),
'blacklist_enabled'
=>
env
(
'JWT_BLACKLIST_ENABLED'
,
true
),
/*
| -------------------------------------------------------------------------
| Blacklist Grace Period
| -------------------------------------------------------------------------
|
| When multiple concurrent requests are made with the same JWT,
| it is possible that some of them fail, due to token regeneration
| on every request.
|
| Set grace period in seconds to prevent parallel request failure.
|
*/
'blacklist_grace_period'
=>
env
(
'JWT_BLACKLIST_GRACE_PERIOD'
,
0
),
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
Providers
|
Cookies encryption
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Specify the various providers used throughout the package.
| By default Laravel encrypt cookies for security reason.
| If you decide to not decrypt cookies, you will have to configure Laravel
| to not encrypt your cookie token by adding its name into the $except
| array available in the middleware "EncryptCookies" provided by Laravel.
| see https://laravel.com/docs/master/responses#cookies-and-encryption
| for details.
|
| Set it to false if you don't want to decrypt cookies.
|
|
*/
*/
'
providers'
=>
[
'
decrypt_cookies'
=>
true
,
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
| User Provider
| Providers
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Specify the provider that is used to find the user based
| Specify the various providers used throughout the package.
| on the subject claim
|
|
*/
*/
'user'
=>
'Tymon\JWTAuth\Providers\User\EloquentUserAdapter'
,
'providers'
=>
[
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
...
@@ -144,7 +238,7 @@ return [
...
@@ -144,7 +238,7 @@ return [
|
|
*/
*/
'jwt'
=>
'Tymon\JWTAuth\Providers\JWT\NamshiAdapter'
,
'jwt'
=>
Tymon\JWTAuth\Providers\JWT\Namshi
::
class
,
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
...
@@ -155,18 +249,18 @@ return [
...
@@ -155,18 +249,18 @@ return [
|
|
*/
*/
'auth'
=>
'Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter'
,
'auth'
=>
Tymon\JWTAuth\Providers\Auth\Illuminate
::
class
,
/*
/*
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
| Storage Provider
| Storage Provider
|--------------------------------------------------------------------------
|--------------------------------------------------------------------------
|
|
| Specify the provider that is used to store tokens in the blacklist
| Specify the provider that is used to store tokens in the blacklist
.
|
|
*/
*/
'storage'
=>
'Tymon\JWTAuth\Providers\Storage\IlluminateCacheAdapter'
,
'storage'
=>
Tymon\JWTAuth\Providers\Storage\Illuminate
::
class
,
],
],
...
...
resources/lang/en/api.php
0 → 100644
View file @
0fc48c64
<?php
return
[
'messages'
=>
[
'registeration'
=>
[
'success'
=>
'You have registered successfully. Please check your email for activation!'
,
],
'login'
=>
[
'success'
=>
'Login Successfull.'
,
'failed'
=>
'Invalid Credentials! Please try again.'
,
],
'logout'
=>
[
'success'
=>
'Successfully logged out.'
,
],
'forgot_password'
=>
[
'success'
=>
'We have sent email with reset password link. Please check your inbox!.'
,
'validation'
=>
[
'email_not_found'
=>
'This email address is not registered.'
,
],
],
'refresh'
=>
[
'token'
=>
[
'not_provided'
=>
'Token not provided.'
,
],
'status'
=>
'Ok'
,
],
],
];
resources/views/backend/includes/footer.blade.php
View file @
0fc48c64
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
<footer
class=
"main-footer"
>
<footer
class=
"main-footer"
>
<!-- To the right -->
<!-- To the right -->
<div
class=
"pull-right hidden-xs"
>
<div
class=
"pull-right hidden-xs"
>
<a
href=
"http://laravel-
boilerplate
.com"
target=
"_blank"
>
{{ trans('strings.backend.general.boilerplate_link') }}
</a>
<a
href=
"http://laravel-
admin
.com"
target=
"_blank"
>
{{ trans('strings.backend.general.boilerplate_link') }}
</a>
</div>
</div>
<!-- Default to the left -->
<!-- Default to the left -->
<strong>
Copyright
©
{{ date('Y') }}
<a
href=
"#"
>
{{ app_name() }}
</a>
.
</strong>
{{ trans('strings.backend.general.all_rights_reserved') }}
<strong>
Copyright
©
{{ date('Y') }}
<a
href=
"#"
>
{{ app_name() }}
</a>
.
</strong>
{{ trans('strings.backend.general.all_rights_reserved') }}
...
...
routes/api.php
View file @
0fc48c64
...
@@ -14,13 +14,21 @@
...
@@ -14,13 +14,21 @@
Route
::
group
([
'namespace'
=>
'Api\V1'
,
'prefix'
=>
'v1'
,
'as'
=>
'v1.'
],
function
()
{
Route
::
group
([
'namespace'
=>
'Api\V1'
,
'prefix'
=>
'v1'
,
'as'
=>
'v1.'
],
function
()
{
Route
::
group
([
'prefix'
=>
'auth'
],
function
()
{
Route
::
group
([
'prefix'
=>
'auth'
],
function
()
{
Route
::
post
(
'/login'
,
'AuthController@authenticate'
);
Route
::
post
(
'register'
,
'RegisterController@register'
);
Route
::
post
(
'/logout'
,
'AuthController@logout'
);
Route
::
post
(
'login'
,
'AuthController@login'
);
Route
::
post
(
'/check'
,
'AuthController@check'
);
});
Route
::
post
(
'/register'
,
'AuthController@register'
);
Route
::
get
(
'/activate/{token}'
,
'AuthController@activate'
);
Route
::
group
([
'middleware'
=>
[
'jwt.auth'
]],
function
()
{
Route
::
post
(
'/password'
,
'AuthController@password'
);
Route
::
group
([
'prefix'
=>
'auth'
],
function
()
{
Route
::
post
(
'/validate-password-reset'
,
'AuthController@validatePasswordReset'
);
Route
::
post
(
'logout'
,
'AuthController@logout'
);
Route
::
post
(
'/reset'
,
'AuthController@reset'
);
Route
::
post
(
'refresh'
,
'AuthController@refresh'
);
// Password Reset Routes
Route
::
post
(
'password/email'
,
'ForgotPasswordController@sendResetLinkEmail'
);
Route
::
post
(
'password/reset'
,
'ResetPasswordController@reset'
)
->
name
(
'password.reset'
);
});
// Users
Route
::
resource
(
'users'
,
'UsersController'
);
});
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment