added me controller

This commit is contained in:
Sergey Yarkov 2021-07-25 19:03:15 +03:00
parent 49d6fe40ae
commit 6d32ca0857
5 changed files with 101 additions and 93 deletions

View File

@ -0,0 +1,73 @@
import { Exception } from '@adonisjs/core/build/standalone';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import Hash from '@ioc:Adonis/Core/Hash';
import Logger from '@ioc:Adonis/Core/Logger';
import ChangePasswordValidator from 'App/Validators/ChangePasswordValidator';
import Contact from 'App/Models/Contact';
export default class MeController {
private readonly guard: 'api';
private readonly contact: typeof Contact;
constructor() {
this.contact = Contact;
}
/**
* Shows user info of the access token resource owner.
* GET /me
*/
public async index({ response, auth }: HttpContextContract) {
const user = await auth.use(this.guard).authenticate();
await user.load('contacts');
await user.load('roles');
return response.ok({
message: 'Fetched data about me.',
data: user,
});
}
/**
* Change password of authenticated user
* PATCH /me/password
*/
public async changePassword({ request, response, auth }: HttpContextContract) {
await request.validate(ChangePasswordValidator);
const user = await auth.use(this.guard).authenticate();
const oldPassword: string = request.input('oldPassword');
const newPassword: string = request.input('newPassword');
if (oldPassword === newPassword) {
throw new Exception('The new password is the same as the old one.', 400, 'E_PASSWORD_VALUES');
}
/**
* Verify old password
*/
if (!(await Hash.verify(user.password, oldPassword))) {
throw new Exception('Invalid credentials.', 403, 'E_INVALID_CREDENTIALS');
}
/**
* Update user password
*/
user.password = newPassword;
await user.save();
Logger.info(`Password of user with id: "${user.id}" was updated.`);
return response.ok({
message: 'The password was successfully changed to the new value.',
});
}
/**
* Update contacts of authenticated user
* PATCH /me/contacts
*/
// public async updateContacts({ request, response, auth }: HttpContextContract) {}
}

View File

@ -1,17 +1,8 @@
import { AuthenticationException } from '@adonisjs/auth/build/standalone';
import { Exception } from '@adonisjs/core/build/standalone'; import { Exception } from '@adonisjs/core/build/standalone';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import Hash from '@ioc:Adonis/Core/Hash';
import Logger from '@ioc:Adonis/Core/Logger';
/* Models */
import Contact from 'App/Models/Contact';
import Role from 'App/Models/Role'; import Role from 'App/Models/Role';
import User from 'App/Models/User'; import User from 'App/Models/User';
/* Validators */
import AddRoleToUserValidator from 'App/Validators/AddRoleToUserValidator'; import AddRoleToUserValidator from 'App/Validators/AddRoleToUserValidator';
import ChangePasswordValidator from 'App/Validators/ChangePasswordValidator';
import CreateUserValidator from 'App/Validators/CreateUserValidator'; import CreateUserValidator from 'App/Validators/CreateUserValidator';
import DelRoleFromUserValidator from 'App/Validators/DelRoleFromUserValidator'; import DelRoleFromUserValidator from 'App/Validators/DelRoleFromUserValidator';
import UpdateUserValidator from 'App/Validators/UpdateUserValidator'; import UpdateUserValidator from 'App/Validators/UpdateUserValidator';
@ -21,36 +12,9 @@ export default class UsersController {
private readonly role: typeof Role; private readonly role: typeof Role;
private readonly contact: typeof Contact;
constructor() { constructor() {
this.user = User; this.user = User;
this.role = Role; this.role = Role;
this.contact = Contact;
}
/**
* Shows user info of the access token resource owner.
* GET /users/me
*/
public async showMe({ response, auth }: HttpContextContract) {
const userId = auth.use('api').token?.userId;
if (userId) {
const user = await this.user.findOrFail(userId);
await user.load('contacts');
await user.load('roles');
return response.ok({
message: 'Fetched data about me.',
data: user,
});
}
/**
* Unauthorized user
*/
throw new AuthenticationException('Unauthorized access', 'E_UNAUTHORIZED_ACCESS', 'api');
} }
/** /**
@ -58,7 +22,7 @@ export default class UsersController {
* GET /users * GET /users
*/ */
public async showAll({ response }: HttpContextContract) { public async index({ response }: HttpContextContract) {
const users = await this.user.query().preload('contacts').preload('roles'); const users = await this.user.query().preload('contacts').preload('roles');
return response.ok({ return response.ok({
@ -194,50 +158,6 @@ export default class UsersController {
}); });
} }
/**
* Change password of authenticated user
* PATCH /users/me/password
*/
public async changePassword({ request, response, auth }: HttpContextContract) {
await request.validate(ChangePasswordValidator);
const userId = auth.use('api').token?.userId;
if (userId) {
const user = await this.user.findOrFail(userId);
const oldPassword: string = request.input('oldPassword');
const newPassword: string = request.input('newPassword');
if (oldPassword === newPassword) {
throw new Exception('The new password is the same as the old one.', 400, 'E_PASSWORD_VALUES');
}
/**
* Verify old password
*/
if (!(await Hash.verify(user.password, oldPassword))) {
throw new Exception('Invalid credentials.', 403, 'E_INVALID_CREDENTIALS');
}
/**
* Update user password
*/
user.password = newPassword;
await user.save();
Logger.info(`Password of user with id: "${user.id}" was updated.`);
return response.ok({
message: 'The password was successfully changed to the new value.',
});
}
/**
* Unauthorized user
*/
throw new AuthenticationException('Unauthorized access', 'E_UNAUTHORIZED_ACCESS', 'api');
}
/** /**
* Finds roles by input value and throw error if role does not exist. * Finds roles by input value and throw error if role does not exist.
* *

View File

@ -0,0 +1,16 @@
import { schema, rules } from '@ioc:Adonis/Core/Validator';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
export default class UpdateContactsValidator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
email: schema.string.optional({}, [rules.email(), rules.unique({ table: 'contacts', column: 'email' })]),
phone_number: schema.string.optional(),
vk_id: schema.string.optional(),
twitter_id: schema.string.optional(),
telegram_id: schema.string.optional(),
});
public messages = {};
}

View File

@ -5,15 +5,10 @@ export default class UpdateUserValidator {
constructor(protected ctx: HttpContextContract) {} constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({ public schema = schema.create({
first_name: schema.string.optional({}, [ first_name: schema.string.optional({}, [rules.unique({ table: 'users', column: 'first_name' })]),
rules.unique({ table: 'users', column: 'first_name' }),
]),
last_name: schema.string.optional({}, [rules.unique({ table: 'users', column: 'last_name' })]), last_name: schema.string.optional({}, [rules.unique({ table: 'users', column: 'last_name' })]),
login: schema.string.optional({}, [rules.unique({ table: 'users', column: 'login' })]), login: schema.string.optional({}, [rules.unique({ table: 'users', column: 'login' })]),
email: schema.string.optional({}, [ email: schema.string.optional({}, [rules.email(), rules.unique({ table: 'contacts', column: 'email' })]),
rules.email(),
rules.unique({ table: 'contacts', column: 'email' }),
]),
password: schema.string.optional({}, [rules.unique({ table: 'users', column: 'password' })]), password: schema.string.optional({}, [rules.unique({ table: 'users', column: 'password' })]),
}); });

View File

@ -32,18 +32,22 @@ Route.group(() => {
/** /**
* Users controller * Users controller
*/ */
Route.get('users', 'UsersController.showAll').middleware('role:admin,teacher,student').as('showAllUsers'); Route.get('users', 'UsersController.index').middleware('role:admin,teacher,student').as('showAllUsers');
Route.get('users/:id', 'UsersController.show').middleware('role:admin,teacher,student').as('showUserById');
Route.post('users', 'UsersController.create').middleware('role:admin').as('createUser'); Route.post('users', 'UsersController.create').middleware('role:admin').as('createUser');
Route.get('users/:id', 'UsersController.show').middleware('role:admin,teacher,student').as('showUserById');
Route.patch('users/:id', 'UsersController.update').middleware('role:admin').as('updateUser'); Route.patch('users/:id', 'UsersController.update').middleware('role:admin').as('updateUser');
Route.delete('users/:id', 'UsersController.destroy').middleware('role:admin').as('deleteUser'); Route.delete('users/:id', 'UsersController.destroy').middleware('role:admin').as('deleteUser');
Route.post('users/:id/attach-roles', 'UsersController.attachRoles').middleware('role:admin').as('attachUserRole'); Route.post('users/:id/attach-roles', 'UsersController.attachRoles').middleware('role:admin').as('attachUserRole');
Route.delete('users/:id/detach-roles', 'UsersController.detachRoles').middleware('role:admin').as('detachUserRole'); Route.delete('users/:id/detach-roles', 'UsersController.detachRoles').middleware('role:admin').as('detachUserRole');
Route.get('users/me', 'UsersController.showMe').middleware('role:admin,teacher,student').as('showMe');
Route.patch('users/me/password', 'UsersController.changePassword') /**
* Me controller
*/
Route.get('me', 'MeController.index').middleware('role:admin,teacher,student').as('showMe');
Route.patch('me/password', 'MeController.changePassword')
.middleware('role:admin,teacher,student') .middleware('role:admin,teacher,student')
.as('changePassword'); .as('changePassword');
Route.patch('users/me/contacts', 'UsersController.updateContacts') Route.patch('me/contacts', 'MeController.updateContacts')
.middleware('role:admin,teacher,student') .middleware('role:admin,teacher,student')
.as('updateContacts'); .as('updateContacts');
}).middleware('auth'); }).middleware('auth');