mirror of
https://github.com/sergeyyarkov/educt-server.git
synced 2026-10-11 18:29:15 +03:00
added: MeService
This commit is contained in:
parent
a852e82451
commit
e6880e3e0e
@ -1,12 +1,10 @@
|
||||
import { Exception } from '@adonisjs/core/build/standalone';
|
||||
import { Exception, inject, Ioc } 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';
|
||||
|
||||
/**
|
||||
* Models
|
||||
* Services
|
||||
*/
|
||||
import Contact from 'App/Models/Contact';
|
||||
import MeService from 'App/Services/MeService';
|
||||
|
||||
/**
|
||||
* Validators
|
||||
@ -14,89 +12,60 @@ import Contact from 'App/Models/Contact';
|
||||
import ChangePasswordValidator from 'App/Validators/Password/ChangePasswordValidator';
|
||||
import UpdateContactsValidator from 'App/Validators/Contacts/UpdateContactsValidator';
|
||||
|
||||
export default class MeController {
|
||||
private readonly guard: 'api';
|
||||
import BaseController from '../../BaseController';
|
||||
|
||||
private readonly Contact: typeof Contact;
|
||||
@inject()
|
||||
export default class MeController extends BaseController {
|
||||
private meService: MeService;
|
||||
|
||||
constructor() {
|
||||
this.Contact = Contact;
|
||||
constructor(meService: MeService) {
|
||||
super();
|
||||
this.meService = meService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows user info of the access token resource owner.
|
||||
* GET /me
|
||||
*/
|
||||
public async show({ response, auth }: HttpContextContract) {
|
||||
const user = await auth.use(this.guard).authenticate();
|
||||
public async show(ctx: HttpContextContract) {
|
||||
const result = await this.meService.fetchUserContacts(ctx.auth);
|
||||
|
||||
await user.load('contacts');
|
||||
await user.load('roles');
|
||||
if (!result.success && result.error) {
|
||||
throw new Exception(result.message, result.status, result.error.code);
|
||||
}
|
||||
|
||||
return response.ok({
|
||||
message: 'Fetched data about me.',
|
||||
data: user,
|
||||
});
|
||||
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change password of authenticated user
|
||||
* PATCH /me/password
|
||||
*/
|
||||
public async changePassword({ request, response, auth }: HttpContextContract) {
|
||||
await request.validate(ChangePasswordValidator);
|
||||
public async changePassword(ctx: HttpContextContract) {
|
||||
const payload = await ctx.request.validate(ChangePasswordValidator);
|
||||
const result = await this.meService.changeUserPassword(payload.oldPassword, payload.newPassword, ctx.auth);
|
||||
|
||||
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');
|
||||
if (!result.success && result.error) {
|
||||
throw new Exception(result.message, result.status, result.error.code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.',
|
||||
});
|
||||
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update contacts of authenticated user
|
||||
* PATCH /me/contacts
|
||||
* PUT /me/contacts
|
||||
*/
|
||||
public async updateContacts({ request, response, auth }: HttpContextContract) {
|
||||
const payload = await request.validate(UpdateContactsValidator);
|
||||
const user = await auth.use(this.guard).authenticate();
|
||||
const contacts = await this.Contact.findByOrFail('user_id', user.id);
|
||||
public async updateContacts(ctx: HttpContextContract) {
|
||||
const payload = await ctx.request.validate(UpdateContactsValidator);
|
||||
const result = await this.meService.updateUserContacts(payload, ctx.auth);
|
||||
|
||||
/**
|
||||
* Update contacts
|
||||
*/
|
||||
if (payload.email) contacts.email = payload.email;
|
||||
contacts.phone_number = payload.phone_number ?? null;
|
||||
contacts.vk_id = payload.vk_id ?? null;
|
||||
contacts.twitter_id = payload.twitter_id ?? null;
|
||||
contacts.telegram_id = payload.telegram_id ?? null;
|
||||
if (!result.success && result.error) {
|
||||
throw new Exception(result.message, result.status, result.error.code);
|
||||
}
|
||||
|
||||
await contacts.save();
|
||||
|
||||
return response.ok({
|
||||
message: `Contacts has been successfully updated.`,
|
||||
data: contacts,
|
||||
});
|
||||
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||
}
|
||||
}
|
||||
|
||||
new Ioc().make(MeController);
|
||||
|
||||
12
app/Datatypes/Enums/StatusCodeEnum.ts
Normal file
12
app/Datatypes/Enums/StatusCodeEnum.ts
Normal file
@ -0,0 +1,12 @@
|
||||
enum StatusCodeEnum {
|
||||
OK = 200,
|
||||
CREATED = 201,
|
||||
NO_CONTENT = 204,
|
||||
BAD_REQUEST = 400,
|
||||
UNAUTHORIZED = 401,
|
||||
FORBIDDEN = 403,
|
||||
NOT_FOUND = 404,
|
||||
INTERNAL_SERVER = 500,
|
||||
}
|
||||
|
||||
export default StatusCodeEnum;
|
||||
@ -9,9 +9,6 @@ export default class Contact extends BaseModel {
|
||||
@column({ serializeAs: null })
|
||||
public user_id: string;
|
||||
|
||||
@column()
|
||||
public email: string;
|
||||
|
||||
@column()
|
||||
public phone_number: string | null;
|
||||
|
||||
|
||||
@ -30,6 +30,9 @@ export default class User extends BaseModel {
|
||||
@column({ serializeAs: null })
|
||||
public login: string;
|
||||
|
||||
@column()
|
||||
public email: string;
|
||||
|
||||
@column({ serializeAs: null })
|
||||
public password: string;
|
||||
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
/**
|
||||
* Models
|
||||
*/
|
||||
import Contact from 'App/Models/Contact';
|
||||
import User from 'App/Models/User';
|
||||
import CreateUserValidator from 'App/Validators/User/CreateUserValidator';
|
||||
import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
|
||||
|
||||
/**
|
||||
* Validators
|
||||
*/
|
||||
import CreateContactsValidator from 'App/Validators/Contacts/CreateContactsValidator';
|
||||
import UpdateContactsValidator from 'App/Validators/Contacts/UpdateContactsValidator';
|
||||
|
||||
export default class ContactRepository {
|
||||
private Contact: typeof Contact;
|
||||
@ -10,6 +17,17 @@ export default class ContactRepository {
|
||||
this.Contact = Contact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contacts by user id
|
||||
*
|
||||
* @param userId User id
|
||||
* @returns User contacts or null
|
||||
*/
|
||||
public async getByUser(userId: string | number): Promise<Contact | null> {
|
||||
const contacts = await this.Contact.query().where('user_id', userId).first();
|
||||
return contacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create user contacts in database
|
||||
*
|
||||
@ -17,10 +35,17 @@ export default class ContactRepository {
|
||||
* @param data Data contacts
|
||||
* @returns Created contacts
|
||||
*/
|
||||
public async create(user: User, data: Pick<CreateUserValidator['schema']['props'], 'email'>) {
|
||||
public async create(user: User, data: CreateContactsValidator['schema']['props']): Promise<Contact> {
|
||||
const contacts = await this.Contact.create(data);
|
||||
|
||||
/**
|
||||
* Associate user
|
||||
*/
|
||||
await contacts.related('user').associate(user);
|
||||
|
||||
/**
|
||||
* Load updated contacts to user
|
||||
*/
|
||||
await user.load('contacts');
|
||||
await user.load('roles');
|
||||
|
||||
@ -32,13 +57,16 @@ export default class ContactRepository {
|
||||
*
|
||||
* @param user User
|
||||
* @param data Data to update
|
||||
* @returns
|
||||
* @returns Updated contacts or null
|
||||
*/
|
||||
public async update(user: User, data: Pick<UpdateUserValidator['schema']['props'], 'email'>) {
|
||||
public async update(user: User, data: UpdateContactsValidator['schema']['props']): Promise<Contact | null> {
|
||||
const contacts = await this.Contact.query().where('user_id', user.id).first();
|
||||
|
||||
if (contacts) {
|
||||
contacts.email = data.email;
|
||||
contacts.phone_number = data.phone_number ?? null;
|
||||
contacts.telegram_id = data.telegram_id ?? null;
|
||||
contacts.twitter_id = data.twitter_id ?? null;
|
||||
contacts.vk_id = data.vk_id ?? null;
|
||||
|
||||
await contacts.save();
|
||||
await user.load('contacts');
|
||||
@ -46,15 +74,6 @@ export default class ContactRepository {
|
||||
return contacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new user contacts if contacts doesn't exist
|
||||
*/
|
||||
await user.related('contacts').create({
|
||||
email: data.email,
|
||||
});
|
||||
|
||||
await user.load('contacts');
|
||||
|
||||
return user.contacts;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* Models
|
||||
*/
|
||||
import Role from 'App/Models/Role';
|
||||
|
||||
export default class RoleRepository {
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import Hash from '@ioc:Adonis/Core/Hash';
|
||||
|
||||
/**
|
||||
* Models
|
||||
*/
|
||||
import User from 'App/Models/User';
|
||||
|
||||
/**
|
||||
* Validators
|
||||
*/
|
||||
import CreateUserValidator from 'App/Validators/User/CreateUserValidator';
|
||||
import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
|
||||
|
||||
@ -16,7 +26,7 @@ export default class UserRepository {
|
||||
* @param id User id
|
||||
* @returns User or null
|
||||
*/
|
||||
public async getById(id: string | number) {
|
||||
public async getById(id: string | number): Promise<User | null> {
|
||||
const data = await this.User.query().preload('contacts').preload('roles').where('id', id).first();
|
||||
return data;
|
||||
}
|
||||
@ -28,7 +38,7 @@ export default class UserRepository {
|
||||
* @param value Comparsion column
|
||||
* @returns User or null
|
||||
*/
|
||||
public async getByColumn(column: string, value: string | number) {
|
||||
public async getByColumn(column: string, value: string | number): Promise<User | null> {
|
||||
const data = await this.User.query().preload('contacts').preload('roles').where(column, value).first();
|
||||
return data;
|
||||
}
|
||||
@ -39,7 +49,7 @@ export default class UserRepository {
|
||||
* @param role Role
|
||||
* @returns Array of users with role
|
||||
*/
|
||||
public async getAllByRole(role: string) {
|
||||
public async getAllByRole(role: string): Promise<User[]> {
|
||||
const data = await this.User.query()
|
||||
.preload('contacts')
|
||||
.preload('roles')
|
||||
@ -53,7 +63,7 @@ export default class UserRepository {
|
||||
* @param params Params to find
|
||||
* @returns Array of users
|
||||
*/
|
||||
public async getAll(params?: any) {
|
||||
public async getAll(params?: any): Promise<User[]> {
|
||||
const { email, login, first_name, last_name, role }: any = params || {};
|
||||
const query = this.User.query();
|
||||
|
||||
@ -87,14 +97,8 @@ export default class UserRepository {
|
||||
* @param data Data for create user
|
||||
* @returns Created user
|
||||
*/
|
||||
public async create(data: CreateUserValidator['schema']['props']) {
|
||||
const createdUser = await this.User.create({
|
||||
first_name: data.first_name,
|
||||
last_name: data.last_name,
|
||||
login: data.login,
|
||||
password: data.password,
|
||||
});
|
||||
|
||||
public async create(data: CreateUserValidator['schema']['props']): Promise<User> {
|
||||
const createdUser = await this.User.create(data);
|
||||
return createdUser;
|
||||
}
|
||||
|
||||
@ -105,18 +109,11 @@ export default class UserRepository {
|
||||
* @param data Data to update
|
||||
* @returns User or null if user is not found
|
||||
*/
|
||||
public async update(id: number | string, data: UpdateUserValidator['schema']['props']) {
|
||||
public async update(id: number | string, data: UpdateUserValidator['schema']['props']): Promise<User | null> {
|
||||
const user = await this.User.query().preload('contacts').preload('roles').where('id', id).first();
|
||||
|
||||
if (user) {
|
||||
await user
|
||||
.merge({
|
||||
first_name: data.first_name,
|
||||
last_name: data.last_name,
|
||||
login: data.login,
|
||||
password: data.password,
|
||||
})
|
||||
.save();
|
||||
await user.merge(data).save();
|
||||
return user;
|
||||
}
|
||||
|
||||
@ -129,7 +126,7 @@ export default class UserRepository {
|
||||
* @param id User id
|
||||
* @returns Deleted user or null if user is not found
|
||||
*/
|
||||
public async delete(id: number | string) {
|
||||
public async delete(id: number | string): Promise<User | null> {
|
||||
const user = await this.User.query().preload('contacts').preload('roles').where('id', id).first();
|
||||
|
||||
if (user) {
|
||||
@ -139,4 +136,9 @@ export default class UserRepository {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async updatePassword(password: string, id: string | number): Promise<any> {
|
||||
const hashedPass = await Hash.make(password);
|
||||
return this.User.query().where('id', id).update({ password: hashedPass }).first();
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,11 @@ import Logger from '@ioc:Adonis/Core/Logger';
|
||||
import { AuthContract } from '@ioc:Adonis/Addons/Auth';
|
||||
import IResponse from 'App/Datatypes/Interfaces/IResponse';
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
import StatusCodeEnum from 'App/Datatypes/Enums/StatusCodeEnum';
|
||||
|
||||
/**
|
||||
* Reposirories
|
||||
*/
|
||||
@ -17,7 +22,7 @@ import UserRepository from 'App/Repositories/UserRepository';
|
||||
export default class AuthService {
|
||||
private userRepository: UserRepository;
|
||||
|
||||
private guard: 'api';
|
||||
private authGuard: 'api';
|
||||
|
||||
constructor(userRepository: UserRepository) {
|
||||
this.userRepository = userRepository;
|
||||
@ -37,11 +42,11 @@ export default class AuthService {
|
||||
if (!user) {
|
||||
return {
|
||||
success: false,
|
||||
status: 404,
|
||||
status: StatusCodeEnum.NOT_FOUND,
|
||||
message: 'User not found.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_USER_NOT_FOUND',
|
||||
code: 'E_NOT_FOUND',
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -52,7 +57,7 @@ export default class AuthService {
|
||||
if (!(await Hash.verify(user.password, password))) {
|
||||
return {
|
||||
success: false,
|
||||
status: 403,
|
||||
status: StatusCodeEnum.UNAUTHORIZED,
|
||||
message: 'Invalid credentials.',
|
||||
data: {},
|
||||
error: {
|
||||
@ -64,7 +69,7 @@ export default class AuthService {
|
||||
/**
|
||||
* Create new token
|
||||
*/
|
||||
const token = await auth.use(this.guard).generate(user, {
|
||||
const token = await auth.use(this.authGuard).generate(user, {
|
||||
expiresIn: '1d',
|
||||
userRoles: user.roles.map(role => role.slug),
|
||||
});
|
||||
@ -73,7 +78,7 @@ export default class AuthService {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Login success.',
|
||||
data: token.toJSON(),
|
||||
};
|
||||
@ -86,11 +91,11 @@ export default class AuthService {
|
||||
* @returns Logout message
|
||||
*/
|
||||
public async logout(auth: AuthContract): Promise<IResponse> {
|
||||
await auth.use(this.guard).revoke();
|
||||
await auth.use(this.authGuard).revoke();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Logout success.',
|
||||
data: {},
|
||||
};
|
||||
|
||||
134
app/Services/MeService.ts
Normal file
134
app/Services/MeService.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import { inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||
import { AuthContract } from '@ioc:Adonis/Addons/Auth';
|
||||
import Hash from '@ioc:Adonis/Core/Hash';
|
||||
import Logger from '@ioc:Adonis/Core/Logger';
|
||||
import StatusCodeEnum from 'App/Datatypes/Enums/StatusCodeEnum';
|
||||
import IResponse from 'App/Datatypes/Interfaces/IResponse';
|
||||
import ContactRepository from 'App/Repositories/ContactRepository';
|
||||
import UserRepository from 'App/Repositories/UserRepository';
|
||||
import UpdateContactsValidator from 'App/Validators/Contacts/UpdateContactsValidator';
|
||||
|
||||
@inject()
|
||||
export default class MeService {
|
||||
private userRepository: UserRepository;
|
||||
|
||||
private contactRepository: ContactRepository;
|
||||
|
||||
private authGuard: 'api';
|
||||
|
||||
constructor(userRepository: UserRepository, contactRepository: ContactRepository) {
|
||||
this.userRepository = userRepository;
|
||||
this.contactRepository = contactRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authorized user data
|
||||
*
|
||||
* @param auth AuthContract
|
||||
* @returns Response
|
||||
*/
|
||||
public async fetchUserContacts(auth: AuthContract): Promise<IResponse> {
|
||||
const user = await auth.use(this.authGuard).authenticate();
|
||||
|
||||
await user.load('roles');
|
||||
await user.load('contacts');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Fetched authorized user data.',
|
||||
data: user,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Change password of authorized user
|
||||
*
|
||||
* @param oldPassword Old password
|
||||
* @param newPassword New password
|
||||
* @param auth AuthContract
|
||||
* @returns Response
|
||||
*/
|
||||
public async changeUserPassword(oldPassword: string, newPassword: string, auth: AuthContract): Promise<IResponse> {
|
||||
const user = await auth.use(this.authGuard).authenticate();
|
||||
|
||||
/**
|
||||
* Verify old password
|
||||
*/
|
||||
if (!(await Hash.verify(user.password, oldPassword))) {
|
||||
return {
|
||||
success: false,
|
||||
status: StatusCodeEnum.UNAUTHORIZED,
|
||||
message: 'Invalid credentials.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_INVALID_CREDENTIALS',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update password
|
||||
*/
|
||||
const passwordUpdated = await this.userRepository.updatePassword(newPassword, user.id);
|
||||
|
||||
if (passwordUpdated) {
|
||||
Logger.info(`Password of user with id: "${user.id}" was updated.`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Password updated.',
|
||||
data: {},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
status: StatusCodeEnum.BAD_REQUEST,
|
||||
message: 'Unable to change password',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_BAD_REQUEST',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user conctact
|
||||
*
|
||||
* @param data Data to update
|
||||
* @param auth AuthContract
|
||||
* @returns Updated user contacts
|
||||
*/
|
||||
public async updateUserContacts(
|
||||
data: UpdateContactsValidator['schema']['props'],
|
||||
auth: AuthContract
|
||||
): Promise<IResponse> {
|
||||
const user = await auth.use(this.authGuard).authenticate();
|
||||
const contacts = await this.contactRepository.update(user, data);
|
||||
|
||||
if (contacts) {
|
||||
return {
|
||||
success: true,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'User contacts updated.',
|
||||
data: contacts,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create user contacts if they don't exist
|
||||
*/
|
||||
await this.contactRepository.create(user, data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'User contacts updated.',
|
||||
data: user.contacts,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
new Ioc().make(MeService);
|
||||
@ -5,6 +5,11 @@ import { inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||
*/
|
||||
import IResponse from 'App/Datatypes/Interfaces/IResponse';
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
import StatusCodeEnum from 'App/Datatypes/Enums/StatusCodeEnum';
|
||||
|
||||
/**
|
||||
* Models
|
||||
*/
|
||||
@ -13,7 +18,6 @@ import Role from 'App/Models/Role';
|
||||
/**
|
||||
* Repositories
|
||||
*/
|
||||
import ContactRepository from 'App/Repositories/ContactRepository';
|
||||
import RoleRepository from 'App/Repositories/RoleRepository';
|
||||
import UserRepository from 'App/Repositories/UserRepository';
|
||||
|
||||
@ -27,13 +31,10 @@ import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
|
||||
export default class UserService {
|
||||
private userRepository: UserRepository;
|
||||
|
||||
private contactRepository: ContactRepository;
|
||||
|
||||
private roleRepository: RoleRepository;
|
||||
|
||||
constructor(userRepository: UserRepository, contactRepository: ContactRepository, roleRepository: RoleRepository) {
|
||||
constructor(userRepository: UserRepository, roleRepository: RoleRepository) {
|
||||
this.userRepository = userRepository;
|
||||
this.contactRepository = contactRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
}
|
||||
|
||||
@ -49,18 +50,18 @@ export default class UserService {
|
||||
if (!user) {
|
||||
return {
|
||||
success: false,
|
||||
status: 404,
|
||||
status: StatusCodeEnum.NOT_FOUND,
|
||||
message: 'User not found.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_USER_NOT_FOUND',
|
||||
code: 'E_NOT_FOUND',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Fetched user.',
|
||||
data: user,
|
||||
};
|
||||
@ -77,7 +78,7 @@ export default class UserService {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Fetched all users.',
|
||||
data: users,
|
||||
};
|
||||
@ -92,12 +93,9 @@ export default class UserService {
|
||||
public async createUser(data: CreateUserValidator['schema']['props']): Promise<IResponse> {
|
||||
const user = await this.userRepository.create(data);
|
||||
|
||||
/* Associate user contacts */
|
||||
await this.contactRepository.create(user, { email: data.email });
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 201,
|
||||
status: StatusCodeEnum.CREATED,
|
||||
message: 'User created.',
|
||||
data: user,
|
||||
};
|
||||
@ -116,23 +114,18 @@ export default class UserService {
|
||||
if (!user) {
|
||||
return {
|
||||
success: false,
|
||||
status: 404,
|
||||
status: StatusCodeEnum.NOT_FOUND,
|
||||
message: 'User not found.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_USER_NOT_FOUND',
|
||||
code: 'E_NOT_FOUND',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user contacts
|
||||
*/
|
||||
await this.contactRepository.update(user, data);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'User updated.',
|
||||
data: user,
|
||||
};
|
||||
@ -150,18 +143,18 @@ export default class UserService {
|
||||
if (!user) {
|
||||
return {
|
||||
success: false,
|
||||
status: 404,
|
||||
status: StatusCodeEnum.NOT_FOUND,
|
||||
message: 'User not found.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_USER_NOT_FOUND',
|
||||
code: 'E_NOT_FOUND',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'User deleted.',
|
||||
data: user,
|
||||
};
|
||||
@ -180,11 +173,11 @@ export default class UserService {
|
||||
if (!user) {
|
||||
return {
|
||||
success: false,
|
||||
status: 404,
|
||||
status: StatusCodeEnum.NOT_FOUND,
|
||||
message: 'User not found.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_USER_NOT_FOUND',
|
||||
code: 'E_NOT_FOUND',
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -208,11 +201,11 @@ export default class UserService {
|
||||
if (attachedRole) {
|
||||
return {
|
||||
success: false,
|
||||
status: 404,
|
||||
status: StatusCodeEnum.BAD_REQUEST,
|
||||
message: `Role "${attachedRole.name}" already attached to that user.`,
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_ROLE_ATTACHED',
|
||||
code: 'E_BAD_REQUEST',
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -222,7 +215,7 @@ export default class UserService {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Roles attached.',
|
||||
data: user.roles,
|
||||
};
|
||||
@ -241,11 +234,11 @@ export default class UserService {
|
||||
if (!user) {
|
||||
return {
|
||||
success: false,
|
||||
status: 404,
|
||||
status: StatusCodeEnum.NOT_FOUND,
|
||||
message: 'User not found.',
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_USER_NOT_FOUND',
|
||||
code: 'E_NOT_FOUND',
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -266,11 +259,11 @@ export default class UserService {
|
||||
if (notAttachedRole) {
|
||||
return {
|
||||
success: false,
|
||||
status: 404,
|
||||
status: StatusCodeEnum.BAD_REQUEST,
|
||||
message: `Role "${notAttachedRole.name}" not attached to that user.`,
|
||||
data: {},
|
||||
error: {
|
||||
code: 'E_ROLE_NOT_ATTACHED',
|
||||
code: 'E_BAD_REQUEST',
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -280,7 +273,7 @@ export default class UserService {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
status: StatusCodeEnum.OK,
|
||||
message: 'Roles detached.',
|
||||
data: user.roles,
|
||||
};
|
||||
|
||||
20
app/Validators/Contacts/CreateContactsValidator.ts
Normal file
20
app/Validators/Contacts/CreateContactsValidator.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||
|
||||
export default class CreateContactsValidator {
|
||||
constructor(protected ctx: HttpContextContract) {}
|
||||
|
||||
public schema = schema.create({
|
||||
phone_number: schema.string.optional({}, [
|
||||
rules.mobile({
|
||||
locales: ['ru-RU', 'en-US'],
|
||||
strict: true,
|
||||
}),
|
||||
]),
|
||||
vk_id: schema.string.optional({}, [rules.regex(/^[a-zA-Z0-9_]+$/)]),
|
||||
twitter_id: schema.string.optional({}, [rules.regex(/^[a-zA-Z0-9_]+$/)]),
|
||||
telegram_id: schema.string.optional({}, [rules.regex(/^[a-zA-Z0-9_]+$/)]),
|
||||
});
|
||||
|
||||
public messages = {};
|
||||
}
|
||||
@ -5,7 +5,6 @@ export default class UpdateContactsValidator {
|
||||
constructor(protected ctx: HttpContextContract) {}
|
||||
|
||||
public schema = schema.create({
|
||||
email: schema.string.optional({}, [rules.email()]),
|
||||
phone_number: schema.string.optional({}, [
|
||||
rules.mobile({
|
||||
locales: ['ru-RU', 'en-US'],
|
||||
|
||||
@ -27,7 +27,7 @@ export default class CreateUserValidator {
|
||||
first_name: schema.string(),
|
||||
last_name: schema.string(),
|
||||
login: schema.string({}, [rules.maxLength(128), rules.unique({ table: 'users', column: 'login' })]),
|
||||
email: schema.string({}, [rules.email(), rules.unique({ table: 'contacts', column: 'email' })]),
|
||||
email: schema.string({}, [rules.email(), rules.unique({ table: 'users', column: 'email' })]),
|
||||
password: schema.string({}, [rules.minLength(6), rules.maxLength(128)]),
|
||||
});
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ export default class UpdateUserValidator {
|
||||
first_name: schema.string(),
|
||||
last_name: schema.string(),
|
||||
login: schema.string({}, [rules.unique({ table: 'users', column: 'login' })]),
|
||||
email: schema.string({}, [rules.email(), rules.unique({ table: 'contacts', column: 'email' })]),
|
||||
email: schema.string({}, [rules.email(), rules.unique({ table: 'users', column: 'email' })]),
|
||||
password: schema.string(),
|
||||
});
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import User from 'App/Models/User';
|
||||
|
||||
export const ContactFactory = Factory.define(Contact, ({ faker }) => {
|
||||
return {
|
||||
email: faker.internet.exampleEmail(),
|
||||
phone_number: faker.phone.phoneNumber(),
|
||||
};
|
||||
}).build();
|
||||
|
||||
@ -16,6 +16,7 @@ export const UserFactory = Factory.define(User, ({ faker }) => {
|
||||
first_name: faker.name.firstName(),
|
||||
last_name: faker.name.lastName(),
|
||||
login: `${faker.lorem.word(6)}${faker.datatype.number(10)}`,
|
||||
email: faker.internet.exampleEmail(),
|
||||
password: '12345',
|
||||
};
|
||||
})
|
||||
|
||||
@ -9,6 +9,7 @@ export default class Users extends BaseSchema {
|
||||
table.string('first_name', 24).notNullable();
|
||||
table.string('last_name', 24).notNullable();
|
||||
table.string('login', 128).notNullable().unique();
|
||||
table.string('email').notNullable().unique();
|
||||
table.string('password').notNullable();
|
||||
table.timestamp('created_at', { useTz: true });
|
||||
table.timestamp('updated_at', { useTz: true });
|
||||
|
||||
@ -7,7 +7,6 @@ export default class Contacts extends BaseSchema {
|
||||
this.schema.createTable(this.tableName, table => {
|
||||
table.increments('id');
|
||||
table.string('user_id', 21).unsigned().references('users.id').unique().onDelete('CASCADE');
|
||||
table.string('email').unique().notNullable();
|
||||
table.string('phone_number').unique();
|
||||
table.string('vk_id').unique();
|
||||
table.string('twitter_id').unique();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user