AdonisJS User Role Management

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

Published
Nov 13, 22
Duration
17m 5s

Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.

Adocasts

Burlington, KY

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:
00:00 - Creating Files
00:28 - User Management Route Handler
01:08 - Creating A Layout
02:04 - User Management View
04:08 - Updating A User's Role
08:15 - Creating A Role Middleware
11:16 - Handling Self-Demotion
13:04 - Deleting Users
16:30 - Wrapping Up


📜 Transcript:

0:00

in this lesson we're going to expand

0:01

upon our last list in just a little bit

0:02

by adding a user management screen that

0:04

will allow us to alter the role of any

0:06

user and delete users as well so let's

0:08

go ahead and dive in and get the view

0:10

set up for this first so let's jump into

0:12

our terminal and do node Ace make

0:14

controller and we'll call this users and

0:16

then let's also do node Ace make View

0:18

and let's put this inside of a user's

0:20

directory but call the actual file

0:21

manage next let's dive into that

0:23

controller so let's jump into our code

0:24

base go to users controller uncomment

0:26

the HTTP context and let's do public

0:28

async manage we should just need view

0:31

out of this grab our HTTP context

0:33

contract for that and first let's go

0:35

ahead and grab all of our users so let's

0:36

do const users equals await user query

0:40

and let's order them by their email now

0:43

we could also do pagination here but we

0:45

will have a specific lesson on

0:46

pagination coming up so we'll skip over

0:48

that for right now and let's also grab

0:50

our roles as well so let's do const

0:52

rolls equals await role query and let's

0:56

order those by their name lastly let's

0:58

return that to our view so View render

1:01

users slash manage and provided the

1:04

users and the roles give that a save now

1:06

we can jump into our role page so let's

1:09

go users manage and let's actually set

1:11

up a layout for these two views so let's

1:12

copy what we have within our welcome

1:13

page under views let's do a new file

1:16

call a directory layouts and then we'll

1:18

just do app.edge within that layouts

1:20

directory let's paste all of our welcome

1:22

page in and then get rid of everything

1:23

inside of main then inside of main let's

1:26

do section content next let's jump back

1:29

into our welcome page and let's actually

1:30

rig that up so grab everything inside of

1:32

main cut that out and then get rid of

1:34

everything inside of the file and we can

1:36

do at layout is layout so slash app at

1:40

section is content and then let's end

1:43

our section pasting our contents of main

1:46

back inside of here give that a save we

1:48

can boot our server up real quick just

1:49

to make sure that everything went okay

1:50

with that jump back into the browser and

1:52

refresh okay looks like that one okay

1:54

now let's do the same for manage so at

1:57

layout is layouts at section is content

2:01

and then at end our section inside of

2:05

our section I'll put an extra div here

2:07

and then we'll do an H1 specifying that

2:08

this is our user management screen then

2:11

we'll want a table with a t head and a

2:14

table row and then our th for the First

2:17

Column will be our email our second th

2:20

will be the user's role third will be

2:23

when they joined and then lastly we will

2:25

have an actions column then we could do

2:27

a t body and let's Loop over each of our

2:29

users so each user and users at and each

2:33

will do a table Row for each one of our

2:36

users TD the first one will be our

2:38

user.email second for right now let's

2:40

just print out their role ID so roll ID

2:43

third user dot created at dot two Locale

2:48

string and then lastly we will put a to

2:50

do on our actions and we'll break that

2:52

up to delete here in a bit let's

2:54

actually jump back into our welcome page

2:55

and add a link for this as well so we'll

2:58

ultimately want this to be restricted to

2:59

administrators So within in our is admin

3:01

check we can put the link inside of

3:03

there so let's do a href route and we

3:05

need to actually create this route but

3:07

it will be users.manage and we can call

3:09

this manage users all right let's go and

3:11

create that route as well so route dot

3:13

get users slash manage users controller

3:17

dot manage as users.manage actually

3:20

let's put this inside of a group so

3:24

route.group.prefix users as users and

3:28

then get rid of that user's prefix there

3:29

and here okay good so now we should be

3:32

able to jump back into our browser give

3:34

it a refresh let's log in with an

3:36

administrator so that should be Test

3:37

Plus admin all right cool there we go

3:39

and here we have manage users and log

3:42

out let's actually grab that inside of a

3:43

separate div so that everything flows so

3:46

let's wrap this section here inside of a

3:48

div and each one of these as well there

3:51

we go that's a little bit better all

3:52

right now let's jump into our manage

3:54

user screen and we can see our user

3:56

management with our table of four users

3:58

I did go ahead and register two extra

4:00

users here so that we can test our

4:02

deletion and we can see at the present

4:03

moment we only have one user with a roll

4:05

ID of two so only one administrator so

4:08

next let's go ahead and rig up our roll

4:10

column here to a select and then anytime

4:12

that select box changes we want to

4:14

persist the user's role change so let's

4:16

jump back into that page and for our row

4:20

column here we can get rid of everything

4:21

that we have so far and let's put this

4:23

inside of a form the action here we will

4:25

create in a second method for that will

4:27

be post and then all we need inside of

4:29

this form is a single select name of

4:32

role ID and then we'll want to Loop over

4:34

each of our roles so at each row in

4:37

rolls and then we'll want to put our

4:39

option with the value of that role ID

4:41

and then the contents will be the

4:43

rule.name and then we also want to add

4:45

an additional check here so if the roll

4:47

dot ID equals the user.roll ID then we

4:51

want to mark this as selected otherwise

4:54

we can just put an empty string there so

4:56

let's give that a save jump back into

4:57

our browser and we should now see a

4:59

select box looks like they are all

5:01

defined oh you know what we forgot to do

5:03

in our last lesson was actually rig up

5:05

the name column to our role so let's do

5:08

column public name String for some

5:11

reason I completely forgot about

5:12

everything inside of the models last

5:13

lesson but we did actually Circle back

5:15

and fill out our user I just forgot that

5:17

role name needed to be created there as

5:19

well so now that we have that saved

5:21

let's jump back into our browser refresh

5:22

and there we go so now we see our actual

5:24

role names with user user admin and user

5:27

so next whenever we actually change a

5:29

role for a user we want that to persist

5:30

so right now if I refresh that's just

5:32

going to reset back to user so let's

5:34

jump back into our code base and take

5:36

the care of that let's go ahead and just

5:37

do an inline on change equals this dot

5:40

parentelement dot submit I know some

5:43

people don't like putting their event

5:44

handlers directly on as attributes but

5:47

if we imported Alpine it would look

5:48

pretty much the same so we're just going

5:49

to move forward with that for right now

5:51

and then we need to set up our forms

5:53

action so that that actually has

5:54

something to submit to so let's jump

5:56

back into our users controller and let's

5:58

do public now you can call this

5:59

something like change rolls roll change

6:01

I'm just going to call it roll we'll

6:03

want our request response and params and

6:06

we're also going to want to import the

6:08

validator so let's import schema and

6:10

rules from at ioc Adonis or validator

6:15

for this validator we will do const row

6:18

schema equals schema.create role ID ish

6:22

schema.number and then we'll do rules

6:24

dot exists so that we can check whether

6:26

or not the role ID provided actually

6:28

exists within our database table roles

6:31

column of ID that should be all that we

6:34

need for our schema we'll grab the

6:36

actual user's ID off of the params so

6:38

then we can do const user equals await

6:41

user dot find or fail and then just

6:44

provide it the params.id oh we also want

6:47

to validate our data so data equals 08

6:50

request validate schema is roll schema

6:54

and then we could do a weight user.merge

6:56

data and save lastly let's return

6:59

response Dot redirect and redirect them

7:02

directly back to the form give that a

7:04

save and let's break that up to a route

7:05

so routes inside of our group here let's

7:08

do route Dot and we'll set this up as a

7:10

patch and we'll want this to have a

7:11

param of ID and then we'll suffix it

7:13

with Slash role and then this will be

7:15

users controller dot roll as roll and

7:19

then we need to rig it up to our form so

7:21

jump back into manage for our action

7:23

let's do route users dot roll and then

7:25

the ID will be user dot ID then we also

7:28

need to specify that the query string

7:30

underscore method should be patch and

7:34

then lastly let's go enable method

7:36

spoofing so let's jump into our app.ts

7:38

right here where we have allow method

7:40

spoofing change that from false to true

7:42

and we should be good to test this out

7:43

so let's jump back into our browser give

7:45

this a refresh to pick up those changes

7:47

and let's change Butters here from user

7:49

to admin all right we did see that that

7:51

did do a soft Refresh on us and it is

7:54

still admin let's give it a hard refresh

7:56

just to test it out and it is still

7:58

admin we can jump into our actual

8:00

database here give that a refresh and

8:02

test that out and you can see Butters is

8:03

indeed a roll ID of two so he is

8:06

officially an admin we can test it again

8:08

by changing them back to a user refresh

8:09

once more and he's back to one so that

8:12

is working A-Okay now before we go any

8:14

further we want to restrict this page

8:16

and that action to administrators only

8:19

it doesn't make sense to allow just any

8:20

old user to pop into this page see all

8:23

of our users and be able to change all

8:24

of their roles so we'll want to create a

8:26

middleware for that action now if you're

8:28

using bouncer that would be a perfectly

8:29

valid solution but I think we can do

8:32

this one check within a single

8:33

middleware so let's go ahead and stop

8:36

our server and let's do node Ace make

8:39

middleware and let's call this roll so

8:41

we're not going to call this admin or

8:42

user we'll just call this roll and then

8:45

we'll be able to provide a role into

8:46

this middleware so that we can check

8:48

against it to see whether or not our

8:49

user has it to allow or disallow the

8:52

particular action so let's go ahead and

8:54

register that role real quick so let's

8:56

jump down to our kernel underneath auth

8:58

here let's do roll and import app

9:01

middleware and roll give that a save and

9:04

then let's jump into our roll middleware

9:05

and we'll want to accept in the

9:08

particular roles that we want to allow

9:09

into this middleware check as the third

9:12

argument we can call this guards and

9:14

this will come through as a string array

9:15

and so the guards that we'll want to

9:17

provide here will look something like

9:18

this so we'll have dot middleware to

9:20

actually apply in the middleware

9:21

probably have off prior to it and then

9:24

we would have our roll middleware which

9:25

is this one here colon and then a list

9:28

of any roles that we want to allow into

9:31

this particular route so we would want

9:33

admin for this one and say in the future

9:34

we were to add a moderator role we could

9:36

allow them in here by doing a comma

9:38

delimited list and just adding them in

9:40

there like that so this is on the route

9:41

registration this is what it would look

9:43

like so what we need to do here is

9:44

change our guards string array from a

9:46

string array of admin moderator or

9:49

whatever into a list of IDs for those

9:52

roles that they represent so we can do

9:54

const roll IDs equals then we can Loop

9:57

over our guards as guard import our

10:00

rolls enum and then try to find that

10:02

guard key and we also want to make this

10:04

to uppercase so that it changes from

10:07

lowercase admin to the uppercase admin

10:09

that would match our roll key and then

10:11

let's also grab our response and auth

10:14

out of our HTTP context if not our role

10:18

IDs includes our auth user role ID then

10:23

we want to stop this request for the

10:25

user and kick them out now you can

10:26

either redirect them to a page that

10:28

they're allowed at and give them some

10:29

session message or you can just end the

10:31

request with an error so let's return

10:33

response Dot and let's do unauthorized

10:36

here to just kick them out with an error

10:38

and we can say this is restricted to

10:41

guards.join make that a common delimited

10:44

list there oop I should have an s on it

10:46

there we go users so whenever we

10:48

restrict our route to a roll of just

10:50

admins if the user is not an

10:52

administrator this will kick them out

10:53

with an unauthorized error otherwise if

10:56

they are an admin they will bypass that

10:58

if statement and go directly to next

10:59

allow them into the request Handler so

11:02

this should be all that we need to do

11:03

here let's give that a save jump back

11:04

into our routes and rig that up to our

11:07

user group so we can do middleware

11:09

provided off first and then roll and

11:12

specify that we only want to allow

11:13

admins give that a save and let's change

11:16

one more thing so within our users

11:18

controller if a currently authenticated

11:20

administrator demotes themselves to a

11:22

user we don't want to just redirect them

11:24

back because now since this page is

11:25

restricted to just administrators

11:27

whenever we actually try to redirect

11:28

them back since they're no longer an

11:30

admin they would just be reached with an

11:32

error so let's go ahead and change this

11:34

so let's grab our auth off of our HTTP

11:36

contract as well all right and let's do

11:39

const is auth user equals user.id equals

11:43

our auth.user ID and then we can do a

11:46

ternary check here is auth user and

11:50

user.roll ID does not equal roles dot

11:54

admin otherwise we can redirect them

11:56

back so here we would want to do

11:58

response redirect and and then two and

12:01

we'll just do path and point them back

12:03

to the home page so if the auth user is

12:05

changing their role and that role is not

12:07

to an admin which in this current point

12:09

in time would be true for anything since

12:10

we only have two roles then we would

12:12

want to kick them back to the home page

12:13

otherwise we're okay to just return them

12:15

back so let's give this a save jump back

12:17

into our terminal boot back up our

12:18

server and let's jump back into our

12:20

browser give that a refresh and let's

12:22

try changing a role that is not our

12:24

currently authenticated user first so

12:26

let's change apples to admin okay good

12:29

so we got redirected back to this page

12:30

just like we should have been and now

12:32

let's change our test admin from an

12:34

admin to a user and there we go we got

12:36

redirected back to the home page

12:38

preventing an error for us and you can

12:40

note that we also do not see manage

12:41

users as a link here either let's try to

12:44

manually go into that page now so let's

12:45

go users manage and we are greeted by an

12:49

error so this is being successfully

12:51

restricted to just administrators let's

12:53

log out and let's log in as our admin so

12:56

that I think that's apples at test.com

12:58

okay and let's begin manage our users

13:00

again and give test admin administrator

13:03

capabilities once more there we go and

13:05

next let's go ahead and register up the

13:07

deletion So within our manage page we

13:10

will want to take out this to do replace

13:12

this with a form action which we will

13:14

again fill out here in a second method

13:16

of post and instead of a select or

13:18

anything in here all that we want is a

13:20

button type equals and let's actually

13:22

set this to a button inside of here

13:24

let's just put delete and then similar

13:26

to our previous one we're just going to

13:28

do an inline event handler here and

13:30

instead of just directly submitting

13:31

which is why we've set this to a button

13:33

let's actually do on click equals and

13:36

let's provide a confirm and let's say

13:38

are you sure you want to delete this

13:42

user and then if that comes back truthy

13:44

we can do and and this dot parent

13:47

element dot submit so if the user

13:50

confirms that they want to delete the

13:51

user then this will come back truthy and

13:53

we'll move on to our and check which

13:55

would be our submission of our form

13:57

otherwise if this comes back falsy the

13:59

and check would be just bypassed so this

14:01

will never run and let's next go ahead

14:03

and set up that route Handler so inside

14:05

of our user's controller public async

14:08

destroy we'll want our response params

14:11

and auth out of here as well so let's

14:13

grab our user first so const user equals

14:16

await user.find or fail rams.id let's do

14:20

our is auth user check again so is auth

14:22

user equals user.id off user ID and then

14:27

we can do await user dot delete and then

14:30

return is off user and we don't need to

14:33

do any additional check here so if it's

14:35

the auth user deleting themselves then

14:37

we just want to return them back to the

14:39

home page so response redirect to path

14:41

home otherwise we can just return them

14:43

back so response dot redirect back and

14:46

that should be all that we need to do

14:47

there since we don't have any additional

14:49

relationships bound off of our user we

14:51

don't need to worry about deleting those

14:52

out prior to our user installation so at

14:54

this point it should be pretty

14:55

simplistic just as we have it let's go

14:57

ahead and rig up that route so routes

14:59

route delete ID and then users

15:03

controller.destroy as destroy give that

15:06

a save and let's go rig that up to our

15:08

form so action route users dot destroy

15:12

provided the ID of user.id and then our

15:16

query string of underscore method is

15:19

delete and you can put these different

15:21

methods buffing forms into actual Edge

15:24

components we have a lesson on that

15:26

specifically if you are interested in

15:27

learning about that approach but for

15:29

right now we will just leave this as is

15:30

and let's go ahead and give this a test

15:32

so let's jump back into our browser give

15:34

this a refresh and we should now see

15:36

delete buttons which we do now we're

15:37

logged in as Apple so let's not delete

15:39

him quite yet and let's actually try to

15:41

delete Butters instead so let's click on

15:43

delete we are greeted with our are you

15:44

sure you want to delete this user

15:45

message let's first try cancel to make

15:47

sure that that works okay refresh to

15:49

make sure Butters is still there and he

15:50

is so let's try deleting again click OK

15:52

and buy those Butters now we can try

15:55

that again with apples which we are

15:56

logged in as actually we can do one more

15:58

thing here before we delete out off user

16:00

of apples let's jump back into our page

16:02

and where we have user email Let's do an

16:04

additional check here so let's plop this

16:06

down onto its own line and let's do at

16:08

if user.id equals auth user ID and if

16:13

and then we can put in parentheses U so

16:16

we can specify that this is the

16:17

authenticated user by telling them this

16:19

is you and there we go so you can see

16:20

apples has U so now we can tell that

16:22

this is us and we can try to delete hit

16:25

OK and we are redirected back to the

16:28

login or the home page just fine so

16:30

that's working A-Okay so that gives you

16:32

an idea on how to start out a user

16:34

management screen it's at its very

16:35

simplistic State at this point in time

16:37

but we'll expand upon this further in

16:38

later lessons particularly next we'll go

16:41

in and add user blocking so that we can

16:43

restrict users from being able to log in

16:45

or access our application

16:47

[Music]

17:03

thank you

Join The Discussion! (2 Comments)

Please sign in or sign up for free to join in on the dicussion.

  1. Commented 1 year ago

    you are hero man

    1

    Please sign in or sign up for free to reply

    1. Commented 1 year ago

      Thank you!! 😊

      1

      Please sign in or sign up for free to reply

Playing Next Lesson In
seconds