In this lesson, we'll learn how to create a user management screen that'll allow administrators to change any of our registered user's roles. For this, we'll create a role middleware, allowing us to restrict actions to admins. We'll also add the ability to delete users from our application as well.
👍 If You Enjoy This Video, Consider Hitting The Like Button!
🥁 Subscribe To Stay Notified For New Lessons
📺 View on YouTube
👨💻 Find The Code For This Lesson Here
📚 Chapters:
- Creating Files
- User Management Route Handler
- Creating A Layout
- User Management View
- Updating A User's Role
- Creating A Role Middleware
- Handling Self-Demotion
- Deleting Users
- Wrapping Up
📜 Transcript:
in this lesson we're going to expand
upon our last list in just a little bit
by adding a user management screen that
will allow us to alter the role of any
user and delete users as well so let's
go ahead and dive in and get the view
set up for this first so let's jump into
our terminal and do node Ace make
controller and we'll call this users and
then let's also do node Ace make View
and let's put this inside of a user's
directory but call the actual file
manage next let's dive into that
controller so let's jump into our code
base go to users controller uncomment
the HTTP context and let's do public
async manage we should just need view
out of this grab our HTTP context
contract for that and first let's go
ahead and grab all of our users so let's
do const users equals await user query
and let's order them by their email now
we could also do pagination here but we
will have a specific lesson on
pagination coming up so we'll skip over
that for right now and let's also grab
our roles as well so let's do const
rolls equals await role query and let's
order those by their name lastly let's
return that to our view so View render
users slash manage and provided the
users and the roles give that a save now
we can jump into our role page so let's
go users manage and let's actually set
up a layout for these two views so let's
copy what we have within our welcome
page under views let's do a new file
call a directory layouts and then we'll
just do app.edge within that layouts
directory let's paste all of our welcome
page in and then get rid of everything
inside of main then inside of main let's
do section content next let's jump back
into our welcome page and let's actually
rig that up so grab everything inside of
main cut that out and then get rid of
everything inside of the file and we can
do at layout is layout so slash app at
section is content and then let's end
our section pasting our contents of main
back inside of here give that a save we
can boot our server up real quick just
to make sure that everything went okay
with that jump back into the browser and
refresh okay looks like that one okay
now let's do the same for manage so at
layout is layouts at section is content
and then at end our section inside of
our section I'll put an extra div here
and then we'll do an H1 specifying that
this is our user management screen then
we'll want a table with a t head and a
table row and then our th for the First
Column will be our email our second th
will be the user's role third will be
when they joined and then lastly we will
have an actions column then we could do
a t body and let's Loop over each of our
users so each user and users at and each
will do a table Row for each one of our
users TD the first one will be our
user.email second for right now let's
just print out their role ID so roll ID
third user dot created at dot two Locale
string and then lastly we will put a to
do on our actions and we'll break that
up to delete here in a bit let's
actually jump back into our welcome page
and add a link for this as well so we'll
ultimately want this to be restricted to
administrators So within in our is admin
check we can put the link inside of
there so let's do a href route and we
need to actually create this route but
it will be users.manage and we can call
this manage users all right let's go and
create that route as well so route dot
get users slash manage users controller
dot manage as users.manage actually
let's put this inside of a group so
route.group.prefix users as users and
then get rid of that user's prefix there
and here okay good so now we should be
able to jump back into our browser give
it a refresh let's log in with an
administrator so that should be Test
Plus admin all right cool there we go
and here we have manage users and log
out let's actually grab that inside of a
separate div so that everything flows so
let's wrap this section here inside of a
div and each one of these as well there
we go that's a little bit better all
right now let's jump into our manage
user screen and we can see our user
management with our table of four users
I did go ahead and register two extra
users here so that we can test our
deletion and we can see at the present
moment we only have one user with a roll
ID of two so only one administrator so
next let's go ahead and rig up our roll
column here to a select and then anytime
that select box changes we want to
persist the user's role change so let's
jump back into that page and for our row
column here we can get rid of everything
that we have so far and let's put this
inside of a form the action here we will
create in a second method for that will
be post and then all we need inside of
this form is a single select name of
role ID and then we'll want to Loop over
each of our roles so at each row in
rolls and then we'll want to put our
option with the value of that role ID
and then the contents will be the
rule.name and then we also want to add
an additional check here so if the roll
dot ID equals the user.roll ID then we
want to mark this as selected otherwise
we can just put an empty string there so
let's give that a save jump back into
our browser and we should now see a
select box looks like they are all
defined oh you know what we forgot to do
in our last lesson was actually rig up
the name column to our role so let's do
column public name String for some
reason I completely forgot about
everything inside of the models last
lesson but we did actually Circle back
and fill out our user I just forgot that
role name needed to be created there as
well so now that we have that saved
let's jump back into our browser refresh
and there we go so now we see our actual
role names with user user admin and user
so next whenever we actually change a
role for a user we want that to persist
so right now if I refresh that's just
going to reset back to user so let's
jump back into our code base and take
the care of that let's go ahead and just
do an inline on change equals this dot
parentelement dot submit I know some
people don't like putting their event
handlers directly on as attributes but
if we imported Alpine it would look
pretty much the same so we're just going
to move forward with that for right now
and then we need to set up our forms
action so that that actually has
something to submit to so let's jump
back into our users controller and let's
do public now you can call this
something like change rolls roll change
I'm just going to call it roll we'll
want our request response and params and
we're also going to want to import the
validator so let's import schema and
rules from at ioc Adonis or validator
for this validator we will do const row
schema equals schema.create role ID ish
schema.number and then we'll do rules
dot exists so that we can check whether
or not the role ID provided actually
exists within our database table roles
column of ID that should be all that we
need for our schema we'll grab the
actual user's ID off of the params so
then we can do const user equals await
user dot find or fail and then just
provide it the params.id oh we also want
to validate our data so data equals 08
request validate schema is roll schema
and then we could do a weight user.merge
data and save lastly let's return
response Dot redirect and redirect them
directly back to the form give that a
save and let's break that up to a route
so routes inside of our group here let's
do route Dot and we'll set this up as a
patch and we'll want this to have a
param of ID and then we'll suffix it
with Slash role and then this will be
users controller dot roll as roll and
then we need to rig it up to our form so
jump back into manage for our action
let's do route users dot roll and then
the ID will be user dot ID then we also
need to specify that the query string
underscore method should be patch and
then lastly let's go enable method
spoofing so let's jump into our app.ts
right here where we have allow method
spoofing change that from false to true
and we should be good to test this out
so let's jump back into our browser give
this a refresh to pick up those changes
and let's change Butters here from user
to admin all right we did see that that
did do a soft Refresh on us and it is
still admin let's give it a hard refresh
just to test it out and it is still
admin we can jump into our actual
database here give that a refresh and
test that out and you can see Butters is
indeed a roll ID of two so he is
officially an admin we can test it again
by changing them back to a user refresh
once more and he's back to one so that
is working A-Okay now before we go any
further we want to restrict this page
and that action to administrators only
it doesn't make sense to allow just any
old user to pop into this page see all
of our users and be able to change all
of their roles so we'll want to create a
middleware for that action now if you're
using bouncer that would be a perfectly
valid solution but I think we can do
this one check within a single
middleware so let's go ahead and stop
our server and let's do node Ace make
middleware and let's call this roll so
we're not going to call this admin or
user we'll just call this roll and then
we'll be able to provide a role into
this middleware so that we can check
against it to see whether or not our
user has it to allow or disallow the
particular action so let's go ahead and
register that role real quick so let's
jump down to our kernel underneath auth
here let's do roll and import app
middleware and roll give that a save and
then let's jump into our roll middleware
and we'll want to accept in the
particular roles that we want to allow
into this middleware check as the third
argument we can call this guards and
this will come through as a string array
and so the guards that we'll want to
provide here will look something like
this so we'll have dot middleware to
actually apply in the middleware
probably have off prior to it and then
we would have our roll middleware which
is this one here colon and then a list
of any roles that we want to allow into
this particular route so we would want
admin for this one and say in the future
we were to add a moderator role we could
allow them in here by doing a comma
delimited list and just adding them in
there like that so this is on the route
registration this is what it would look
like so what we need to do here is
change our guards string array from a
string array of admin moderator or
whatever into a list of IDs for those
roles that they represent so we can do
const roll IDs equals then we can Loop
over our guards as guard import our
rolls enum and then try to find that
guard key and we also want to make this
to uppercase so that it changes from
lowercase admin to the uppercase admin
that would match our roll key and then
let's also grab our response and auth
out of our HTTP context if not our role
IDs includes our auth user role ID then
we want to stop this request for the
user and kick them out now you can
either redirect them to a page that
they're allowed at and give them some
session message or you can just end the
request with an error so let's return
response Dot and let's do unauthorized
here to just kick them out with an error
and we can say this is restricted to
guards.join make that a common delimited
list there oop I should have an s on it
there we go users so whenever we
restrict our route to a roll of just
admins if the user is not an
administrator this will kick them out
with an unauthorized error otherwise if
they are an admin they will bypass that
if statement and go directly to next
allow them into the request Handler so
this should be all that we need to do
here let's give that a save jump back
into our routes and rig that up to our
user group so we can do middleware
provided off first and then roll and
specify that we only want to allow
admins give that a save and let's change
one more thing so within our users
controller if a currently authenticated
administrator demotes themselves to a
user we don't want to just redirect them
back because now since this page is
restricted to just administrators
whenever we actually try to redirect
them back since they're no longer an
admin they would just be reached with an
error so let's go ahead and change this
so let's grab our auth off of our HTTP
contract as well all right and let's do
const is auth user equals user.id equals
our auth.user ID and then we can do a
ternary check here is auth user and
user.roll ID does not equal roles dot
admin otherwise we can redirect them
back so here we would want to do
response redirect and and then two and
we'll just do path and point them back
to the home page so if the auth user is
changing their role and that role is not
to an admin which in this current point
in time would be true for anything since
we only have two roles then we would
want to kick them back to the home page
otherwise we're okay to just return them
back so let's give this a save jump back
into our terminal boot back up our
server and let's jump back into our
browser give that a refresh and let's
try changing a role that is not our
currently authenticated user first so
let's change apples to admin okay good
so we got redirected back to this page
just like we should have been and now
let's change our test admin from an
admin to a user and there we go we got
redirected back to the home page
preventing an error for us and you can
note that we also do not see manage
users as a link here either let's try to
manually go into that page now so let's
go users manage and we are greeted by an
error so this is being successfully
restricted to just administrators let's
log out and let's log in as our admin so
that I think that's apples at test.com
okay and let's begin manage our users
again and give test admin administrator
capabilities once more there we go and
next let's go ahead and register up the
deletion So within our manage page we
will want to take out this to do replace
this with a form action which we will
again fill out here in a second method
of post and instead of a select or
anything in here all that we want is a
button type equals and let's actually
set this to a button inside of here
let's just put delete and then similar
to our previous one we're just going to
do an inline event handler here and
instead of just directly submitting
which is why we've set this to a button
let's actually do on click equals and
let's provide a confirm and let's say
are you sure you want to delete this
user and then if that comes back truthy
we can do and and this dot parent
element dot submit so if the user
confirms that they want to delete the
user then this will come back truthy and
we'll move on to our and check which
would be our submission of our form
otherwise if this comes back falsy the
and check would be just bypassed so this
will never run and let's next go ahead
and set up that route Handler so inside
of our user's controller public async
destroy we'll want our response params
and auth out of here as well so let's
grab our user first so const user equals
await user.find or fail rams.id let's do
our is auth user check again so is auth
user equals user.id off user ID and then
we can do await user dot delete and then
return is off user and we don't need to
do any additional check here so if it's
the auth user deleting themselves then
we just want to return them back to the
home page so response redirect to path
home otherwise we can just return them
back so response dot redirect back and
that should be all that we need to do
there since we don't have any additional
relationships bound off of our user we
don't need to worry about deleting those
out prior to our user installation so at
this point it should be pretty
simplistic just as we have it let's go
ahead and rig up that route so routes
route delete ID and then users
controller.destroy as destroy give that
a save and let's go rig that up to our
form so action route users dot destroy
provided the ID of user.id and then our
query string of underscore method is
delete and you can put these different
methods buffing forms into actual Edge
components we have a lesson on that
specifically if you are interested in
learning about that approach but for
right now we will just leave this as is
and let's go ahead and give this a test
so let's jump back into our browser give
this a refresh and we should now see
delete buttons which we do now we're
logged in as Apple so let's not delete
him quite yet and let's actually try to
delete Butters instead so let's click on
delete we are greeted with our are you
sure you want to delete this user
message let's first try cancel to make
sure that that works okay refresh to
make sure Butters is still there and he
is so let's try deleting again click OK
and buy those Butters now we can try
that again with apples which we are
logged in as actually we can do one more
thing here before we delete out off user
of apples let's jump back into our page
and where we have user email Let's do an
additional check here so let's plop this
down onto its own line and let's do at
if user.id equals auth user ID and if
and then we can put in parentheses U so
we can specify that this is the
authenticated user by telling them this
is you and there we go so you can see
apples has U so now we can tell that
this is us and we can try to delete hit
OK and we are redirected back to the
login or the home page just fine so
that's working A-Okay so that gives you
an idea on how to start out a user
management screen it's at its very
simplistic State at this point in time
but we'll expand upon this further in
later lessons particularly next we'll go
in and add user blocking so that we can
restrict users from being able to log in
or access our application
[Music]
thank you
Join The Discussion! (2 Comments)
Please sign in or sign up for free to join in on the dicussion.
ahmed-besara-(besara-media)
you are hero man
Please sign in or sign up for free to reply
tomgobich
Thank you!! 😊
Please sign in or sign up for free to reply