-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
999 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,3 +11,4 @@ PG_PORT=5432 | |
PG_USER=lucid | ||
PG_PASSWORD= | ||
PG_DB_NAME=lucid | ||
SMTP_PORT=587 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' | ||
import Mail from '@ioc:Adonis/Addons/Mail' | ||
import Route from '@ioc:Adonis/Core/Route' | ||
import Env from '@ioc:Adonis/Core/Env' | ||
import { schema, rules } from '@ioc:Adonis/Core/Validator' | ||
import User from 'App/Models/User' | ||
import Token from 'App/Models/Token' | ||
|
||
export default class PasswordResetController { | ||
public async forgot({ view }: HttpContextContract) { | ||
return view.render('password.forgot') | ||
} | ||
|
||
public async send({ request, response, session }: HttpContextContract) { | ||
const emailSchema = schema.create({ | ||
email: schema.string([rules.email()]) | ||
}) | ||
|
||
const { email } = await request.validate({ schema: emailSchema }) | ||
const user = await User.findBy('email', email) | ||
const token = await Token.generatePasswordResetToken(user) | ||
const resetLink = Route.makeUrl('password.reset', [token]) | ||
|
||
if (user) { | ||
await Mail.sendLater(message => { | ||
message | ||
.from('[email protected]') | ||
.to(user.email) | ||
.subject('Reset Your Password') | ||
.html(`Reset your password by <a href="${Env.get('DOMAIN')}${resetLink}">clicking here</a>`) | ||
}) | ||
} | ||
|
||
session.flash('success', 'If an account matches the provided email, you will recieve a password reset link shortly') | ||
return response.redirect().back() | ||
} | ||
|
||
public async reset({ view, params }: HttpContextContract) { | ||
const token = params.token | ||
const isValid = await Token.verify(token) | ||
|
||
return view.render('password/reset', { isValid, token }) | ||
} | ||
|
||
public async store({ request, response, session, auth }: HttpContextContract) { | ||
const passwordSchema = schema.create({ | ||
token: schema.string(), | ||
password: schema.string([rules.minLength(8)]) | ||
}) | ||
|
||
const { token, password } = await request.validate({ schema: passwordSchema }) | ||
const user = await Token.getPasswordResetUser(token) | ||
|
||
if (!user) { | ||
session.flash('error', 'Token expired or associated user could not be found') | ||
return response.redirect().back() | ||
} | ||
|
||
await user.merge({ password }).save() | ||
await auth.login(user) | ||
await Token.expirePasswordResetTokens(user) | ||
|
||
return response.redirect().toPath('/') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { DateTime } from 'luxon' | ||
import { BaseModel, BelongsTo, belongsTo, column } from '@ioc:Adonis/Lucid/Orm' | ||
import { string } from '@ioc:Adonis/Core/Helpers' | ||
import User from './User' | ||
|
||
export default class Token extends BaseModel { | ||
@column({ isPrimary: true }) | ||
public id: number | ||
|
||
@column() | ||
public userId: number | null | ||
|
||
@column() | ||
public type: string | ||
|
||
@column() | ||
public token: string | ||
|
||
@column.dateTime() | ||
public expiresAt: DateTime | null | ||
|
||
@column.dateTime({ autoCreate: true }) | ||
public createdAt: DateTime | ||
|
||
@column.dateTime({ autoCreate: true, autoUpdate: true }) | ||
public updatedAt: DateTime | ||
|
||
@belongsTo(() => User) | ||
public user: BelongsTo<typeof User> | ||
|
||
public static async generatePasswordResetToken(user: User | null) { | ||
const token = string.generateRandom(64) | ||
|
||
if (!user) return token | ||
|
||
await Token.expirePasswordResetTokens(user) | ||
const record = await user.related('tokens').create({ | ||
type: 'PASSWORD_RESET', | ||
expiresAt: DateTime.now().plus({ hour: 1 }), | ||
token | ||
}) | ||
|
||
return record.token | ||
} | ||
|
||
public static async expirePasswordResetTokens(user: User) { | ||
await user.related('passwordResetTokens').query().update({ | ||
expiresAt: DateTime.now() | ||
}) | ||
} | ||
|
||
public static async getPasswordResetUser(token: string) { | ||
const record = await Token.query() | ||
.preload('user') | ||
.where('token', token) | ||
.where('expiresAt', '>', DateTime.now().toSQL()) | ||
.orderBy('createdAt', 'desc') | ||
.first() | ||
|
||
return record?.user | ||
} | ||
|
||
public static async verify(token: string) { | ||
const record = await Token.query() | ||
.where('expiresAt', '>', DateTime.now().toSQL()) | ||
.where('token', token) | ||
.first() | ||
|
||
return !!record | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* Config source: https://git.io/JvgAf | ||
* | ||
* Feel free to let us know via PR, if you find something broken in this contract | ||
* file. | ||
*/ | ||
|
||
import Env from '@ioc:Adonis/Core/Env' | ||
import { mailConfig } from '@adonisjs/mail/build/config' | ||
|
||
export default mailConfig({ | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Default mailer | ||
|-------------------------------------------------------------------------- | ||
| | ||
| The following mailer will be used to send emails, when you don't specify | ||
| a mailer | ||
| | ||
*/ | ||
mailer: 'smtp', | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| Mailers | ||
|-------------------------------------------------------------------------- | ||
| | ||
| You can define or more mailers to send emails from your application. A | ||
| single `driver` can be used to define multiple mailers with different | ||
| config. | ||
| | ||
| For example: Postmark driver can be used to have different mailers for | ||
| sending transactional and promotional emails | ||
| | ||
*/ | ||
mailers: { | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Smtp | ||
|-------------------------------------------------------------------------- | ||
| | ||
| Uses SMTP protocol for sending email | ||
| | ||
*/ | ||
smtp: { | ||
driver: 'smtp', | ||
host: Env.get('SMTP_HOST'), | ||
port: Env.get('SMTP_PORT'), | ||
auth: { | ||
user: Env.get('SMTP_USERNAME'), | ||
pass: Env.get('SMTP_PASSWORD'), | ||
type: 'login', | ||
} | ||
}, | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/** | ||
* Contract source: https://git.io/JvgAT | ||
* | ||
* Feel free to let us know via PR, if you find something broken in this contract | ||
* file. | ||
*/ | ||
|
||
import { InferMailersFromConfig } from '@adonisjs/mail/build/config' | ||
import mailConfig from '../config/mail' | ||
|
||
declare module '@ioc:Adonis/Addons/Mail' { | ||
interface MailersList extends InferMailersFromConfig<typeof mailConfig> {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import BaseSchema from '@ioc:Adonis/Lucid/Schema' | ||
|
||
export default class extends BaseSchema { | ||
protected tableName = 'tokens' | ||
|
||
public async up () { | ||
this.schema.createTable(this.tableName, (table) => { | ||
table.increments('id') | ||
table.integer('user_id').unsigned().references('id').inTable('users').onDelete('CASCADE') | ||
table.string('type').notNullable() | ||
table.string('token', 64).notNullable() | ||
|
||
/** | ||
* Uses timestamptz for PostgreSQL and DATETIME2 for MSSQL | ||
*/ | ||
table.timestamp('expires_at', { useTz: true }) | ||
table.timestamp('created_at', { useTz: true }) | ||
table.timestamp('updated_at', { useTz: true }) | ||
}) | ||
} | ||
|
||
public async down () { | ||
this.schema.dropTable(this.tableName) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.