6 | {{ inspect(flashMessages.all()) }}
7 |
8 |
Reset Your Password
9 |
10 | @if (isValid)
11 |
12 | Enter your new password below
13 |
14 |
15 |
22 | @else
23 |
24 | Your token is invalid or expired. Please try again
25 |
26 | @endif
27 |
28 |
29 | @endsection
--------------------------------------------------------------------------------
/contracts/env.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Contract source: https://git.io/JTm6U
3 | *
4 | * Feel free to let us know via PR, if you find something broken in this contract
5 | * file.
6 | */
7 |
8 | declare module '@ioc:Adonis/Core/Env' {
9 | /*
10 | |--------------------------------------------------------------------------
11 | | Getting types for validated environment variables
12 | |--------------------------------------------------------------------------
13 | |
14 | | The `default` export from the "../env.ts" file exports types for the
15 | | validated environment variables. Here we merge them with the `EnvTypes`
16 | | interface so that you can enjoy intellisense when using the "Env"
17 | | module.
18 | |
19 | */
20 |
21 | type CustomTypes = typeof import('../env').default
22 | interface EnvTypes extends CustomTypes {
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/migrations/1668806613838_tokens.ts:
--------------------------------------------------------------------------------
1 | import BaseSchema from '@ioc:Adonis/Lucid/Schema'
2 |
3 | export default class extends BaseSchema {
4 | protected tableName = 'tokens'
5 |
6 | public async up () {
7 | this.schema.createTable(this.tableName, (table) => {
8 | table.increments('id')
9 | table.integer('user_id').unsigned().references('id').inTable('users').onDelete('CASCADE')
10 | table.string('type').notNullable()
11 | table.string('token', 64).notNullable()
12 |
13 | /**
14 | * Uses timestamptz for PostgreSQL and DATETIME2 for MSSQL
15 | */
16 | table.timestamp('expires_at', { useTz: true })
17 | table.timestamp('created_at', { useTz: true })
18 | table.timestamp('updated_at', { useTz: true })
19 | })
20 | }
21 |
22 | public async down () {
23 | this.schema.dropTable(this.tableName)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "adonis-preset-ts/tsconfig.json",
3 | "include": [
4 | "**/*"
5 | ],
6 | "exclude": [
7 | "node_modules",
8 | "build"
9 | ],
10 | "compilerOptions": {
11 | "outDir": "build",
12 | "rootDir": "./",
13 | "sourceMap": true,
14 | "paths": {
15 | "App/*": [
16 | "./app/*"
17 | ],
18 | "Config/*": [
19 | "./config/*"
20 | ],
21 | "Contracts/*": [
22 | "./contracts/*"
23 | ],
24 | "Database/*": [
25 | "./database/*"
26 | ]
27 | },
28 | "types": [
29 | "@adonisjs/core",
30 | "@adonisjs/repl",
31 | "@adonisjs/session",
32 | "@adonisjs/view",
33 | "@adonisjs/shield",
34 | "@japa/preset-adonis/build/adonis-typings",
35 | "@adonisjs/lucid",
36 | "@adonisjs/auth",
37 | "@adonisjs/mail"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/contracts/events.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Contract source: https://git.io/JfefG
3 | *
4 | * Feel free to let us know via PR, if you find something broken in this contract
5 | * file.
6 | */
7 |
8 | declare module '@ioc:Adonis/Core/Event' {
9 | /*
10 | |--------------------------------------------------------------------------
11 | | Define typed events
12 | |--------------------------------------------------------------------------
13 | |
14 | | You can define types for events inside the following interface and
15 | | AdonisJS will make sure that all listeners and emit calls adheres
16 | | to the defined types.
17 | |
18 | | For example:
19 | |
20 | | interface EventsList {
21 | | 'new:user': UserModel
22 | | }
23 | |
24 | | Now calling `Event.emit('new:user')` will statically ensure that passed value is
25 | | an instance of the the UserModel only.
26 | |
27 | */
28 | interface EventsList {
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/database/migrations/1667756114567_roles.ts:
--------------------------------------------------------------------------------
1 | import BaseSchema from '@ioc:Adonis/Lucid/Schema'
2 | import Roles from 'App/Enums/Roles'
3 |
4 | export default class extends BaseSchema {
5 | protected tableName = 'roles'
6 |
7 | public async up () {
8 | this.schema.createTable(this.tableName, (table) => {
9 | table.increments('id')
10 | table.string('name', 50).notNullable()
11 |
12 | /**
13 | * Uses timestamptz for PostgreSQL and DATETIME2 for MSSQL
14 | */
15 | table.timestamp('created_at', { useTz: true })
16 | table.timestamp('updated_at', { useTz: true })
17 | })
18 |
19 | this.defer(async (db) => {
20 | await db.table(this.tableName).multiInsert([{
21 | id: Roles.USER,
22 | name: 'User'
23 | }, {
24 | id: Roles.ADMIN,
25 | name: 'Admin'
26 | }])
27 | })
28 | }
29 |
30 | public async down () {
31 | this.schema.dropTable(this.tableName)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.ts:
--------------------------------------------------------------------------------
1 | /*
2 | |--------------------------------------------------------------------------
3 | | Http Exception Handler
4 | |--------------------------------------------------------------------------
5 | |
6 | | AdonisJs will forward all exceptions occurred during an HTTP request to
7 | | the following class. You can learn more about exception handling by
8 | | reading docs.
9 | |
10 | | The exception handler extends a base `HttpExceptionHandler` which is not
11 | | mandatory, however it can do lot of heavy lifting to handle the errors
12 | | properly.
13 | |
14 | */
15 |
16 | import Logger from '@ioc:Adonis/Core/Logger'
17 | import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'
18 |
19 | export default class ExceptionHandler extends HttpExceptionHandler {
20 | protected statusPages = {
21 | '403': 'errors/unauthorized',
22 | '404': 'errors/not-found',
23 | '500..599': 'errors/server-error',
24 | }
25 |
26 | constructor () {
27 | super(Logger)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/database/migrations/1667756129692_users.ts:
--------------------------------------------------------------------------------
1 | import BaseSchema from '@ioc:Adonis/Lucid/Schema'
2 | import Roles from 'App/Enums/Roles'
3 |
4 | export default class extends BaseSchema {
5 | protected tableName = 'users'
6 |
7 | public async up() {
8 | this.schema.createTable(this.tableName, (table) => {
9 | table.increments('id').primary()
10 | table.integer('role_id').unsigned().references('id').inTable('roles').defaultTo(Roles.USER)
11 | table.string('email', 255).notNullable().unique()
12 | table.string('password', 180).notNullable()
13 | table.string('remember_me_token').nullable()
14 | table.boolean('is_email_verified').notNullable().defaultTo(false)
15 |
16 | /**
17 | * Uses timestampz for PostgreSQL and DATETIME2 for MSSQL
18 | */
19 | table.timestamp('created_at', { useTz: true }).notNullable()
20 | table.timestamp('updated_at', { useTz: true }).notNullable()
21 | })
22 | }
23 |
24 | public async down() {
25 | this.schema.dropTable(this.tableName)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "adonis-user-role-authentication",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "node ace serve --watch",
7 | "build": "node ace build --production",
8 | "start": "node server.js"
9 | },
10 | "devDependencies": {
11 | "@adonisjs/assembler": "^5.9.3",
12 | "@japa/preset-adonis": "^1.2.0",
13 | "@japa/runner": "^2.2.2",
14 | "adonis-preset-ts": "^2.1.0",
15 | "pino-pretty": "^9.1.1",
16 | "typescript": "~4.6",
17 | "youch": "^3.2.2",
18 | "youch-terminal": "^2.1.5"
19 | },
20 | "dependencies": {
21 | "@adonisjs/auth": "^8.2.3",
22 | "@adonisjs/core": "^5.8.8",
23 | "@adonisjs/lucid": "^18.2.0",
24 | "@adonisjs/mail": "^8.1.2",
25 | "@adonisjs/repl": "^3.1.11",
26 | "@adonisjs/session": "^6.4.0",
27 | "@adonisjs/shield": "^7.1.0",
28 | "@adonisjs/view": "^6.2.0",
29 | "luxon": "^3.1.0",
30 | "pg": "^8.8.0",
31 | "phc-argon2": "^1.1.3",
32 | "proxy-addr": "^2.0.7",
33 | "reflect-metadata": "^0.1.13",
34 | "source-map-support": "^0.5.21"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/resources/views/welcome.edge:
--------------------------------------------------------------------------------
1 | @layout('layouts/app')
2 |
3 | @section('content')
4 |
5 | @if (!auth.user)
6 |
30 | @if (auth.user.isAdmin)
31 |
Admin User {{ auth.user.email }}
32 |
37 | @else
38 | Regular User {{ auth.user.email }}
39 | @endif
40 |
Logout
41 |
42 | @endif
43 |
44 | @endsection
--------------------------------------------------------------------------------
/app/Mailers/VerifyEmail.ts:
--------------------------------------------------------------------------------
1 | import { BaseMailer, MessageContract } from '@ioc:Adonis/Addons/Mail'
2 | import User from 'App/Models/User'
3 | import Env from '@ioc:Adonis/Core/Env'
4 | import Route from '@ioc:Adonis/Core/Route'
5 |
6 | export default class VerifyEmail extends BaseMailer {
7 | constructor(private user: User, private token: string) {
8 | super()
9 | }
10 | /**
11 | * WANT TO USE A DIFFERENT MAILER?
12 | *
13 | * Uncomment the following line of code to use a different
14 | * mailer and chain the ".options" method to pass custom
15 | * options to the send method
16 | */
17 | // public mailer = this.mail.use()
18 |
19 | /**
20 | * The prepare method is invoked automatically when you run
21 | * "VerifyEmail.send".
22 | *
23 | * Use this method to prepare the email message. The method can
24 | * also be async.
25 | */
26 | public prepare(message: MessageContract) {
27 | const domain = Env.get('DOMAIN')
28 | const path = Route.makeUrl('verify.email.verify', [this.token])
29 | const url = domain + path
30 | message
31 | .subject('Please Verify Your Email')
32 | .from('noreply@adocasts.com')
33 | .to(this.user.email)
34 | .html(`
35 | Please click the following link to verify your email
36 |