feat: Implement forgotPassword mutation

This commit is contained in:
Faruk AYDIN
2023-02-18 16:54:01 +01:00
parent e4021bf830
commit 90dcbadc52
7 changed files with 70 additions and 2 deletions

View File

@@ -0,0 +1,13 @@
import { Knex } from 'knex';
export async function up(knex: Knex): Promise<void> {
return knex.schema.table('users', (table) => {
table.string('reset_password_token');
});
}
export async function down(knex: Knex): Promise<void> {
return knex.schema.table('users', (table) => {
table.dropColumn('reset_password_token');
});
}

View File

@@ -0,0 +1,13 @@
import { Knex } from 'knex';
export async function up(knex: Knex): Promise<void> {
return knex.schema.table('users', (table) => {
table.timestamp('reset_password_token_sent_at');
});
}
export async function down(knex: Knex): Promise<void> {
return knex.schema.table('users', (table) => {
table.dropColumn('reset_password_token_sent_at');
});
}

View File

@@ -14,6 +14,7 @@ import updateStep from './mutations/update-step';
import deleteStep from './mutations/delete-step'; import deleteStep from './mutations/delete-step';
import createUser from './mutations/create-user.ee'; import createUser from './mutations/create-user.ee';
import updateUser from './mutations/update-user'; import updateUser from './mutations/update-user';
import forgotPassword from './mutations/forgot-password.ee';
import login from './mutations/login'; import login from './mutations/login';
const mutationResolvers = { const mutationResolvers = {
@@ -33,6 +34,7 @@ const mutationResolvers = {
deleteStep, deleteStep,
createUser, createUser,
updateUser, updateUser,
forgotPassword,
login, login,
}; };

View File

@@ -0,0 +1,24 @@
import User from '../../models/user';
type Params = {
input: {
email: string;
};
};
const forgotPassword = async (_parent: unknown, params: Params) => {
const { email } = params.input;
const user = await User.query().findOne({ email });
if (!user) {
throw new Error('Email address not found!');
}
await user.generateResetPasswordToken();
// TODO: Send email with reset password link
return;
};
export default forgotPassword;

View File

@@ -50,6 +50,7 @@ type Mutation {
deleteStep(input: DeleteStepInput): Step deleteStep(input: DeleteStepInput): Step
createUser(input: CreateUserInput): User createUser(input: CreateUserInput): User
updateUser(input: UpdateUserInput): User updateUser(input: UpdateUserInput): User
forgotPassword(input: ForgotPasswordInput): Boolean
login(input: LoginInput): Auth login(input: LoginInput): Auth
} }
@@ -302,8 +303,8 @@ input DeleteStepInput {
} }
input CreateUserInput { input CreateUserInput {
email: String email: String!
password: String password: String!
} }
input UpdateUserInput { input UpdateUserInput {
@@ -311,6 +312,10 @@ input UpdateUserInput {
password: String password: String
} }
input ForgotPasswordInput {
email: String
}
input LoginInput { input LoginInput {
email: String! email: String!
password: String! password: String!

View File

@@ -30,6 +30,7 @@ const authentication = shield(
'*': isAuthenticated, '*': isAuthenticated,
login: allow, login: allow,
createUser: allow, createUser: allow,
forgotPassword: allow,
}, },
}, },
{ {

View File

@@ -5,12 +5,15 @@ import Flow from './flow';
import Step from './step'; import Step from './step';
import Execution from './execution'; import Execution from './execution';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
import crypto from 'crypto';
class User extends Base { class User extends Base {
id!: string; id!: string;
email!: string; email!: string;
password!: string; password!: string;
role: string; role: string;
resetPasswordToken: string;
resetPasswordTokenSentAt: string;
connections?: Connection[]; connections?: Connection[];
flows?: Flow[]; flows?: Flow[];
steps?: Step[]; steps?: Step[];
@@ -77,6 +80,13 @@ class User extends Base {
return bcrypt.compare(password, this.password); return bcrypt.compare(password, this.password);
} }
async generateResetPasswordToken() {
const resetPasswordToken = crypto.randomBytes(64).toString('hex');
const resetPasswordTokenSentAt = new Date().toISOString();
await this.$query().patch({ resetPasswordToken, resetPasswordTokenSentAt });
}
async generateHash() { async generateHash() {
this.password = await bcrypt.hash(this.password, 10); this.password = await bcrypt.hash(this.password, 10);
} }