mirror of
https://github.com/sergeyyarkov/educt-server.git
synced 2026-10-11 02:09:07 +03:00
refactor: UsersController
This commit is contained in:
parent
419495d39c
commit
f8e3417f1f
@ -4,7 +4,7 @@ import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
|||||||
/**
|
/**
|
||||||
* Datatype
|
* Datatype
|
||||||
*/
|
*/
|
||||||
import Role from 'App/Datatype/Role';
|
import Role from 'App/Datatypes/Enums/RoleEnum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models
|
* Models
|
||||||
|
|||||||
@ -1,11 +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 { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models
|
* Services
|
||||||
*/
|
*/
|
||||||
import Role from 'App/Models/Role';
|
import UserService from 'App/Services/UserService';
|
||||||
import User from 'App/Models/User';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validators
|
* Validators
|
||||||
@ -17,15 +16,13 @@ import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
|
|||||||
|
|
||||||
import BaseController from '../../BaseController';
|
import BaseController from '../../BaseController';
|
||||||
|
|
||||||
|
@inject()
|
||||||
export default class UsersController extends BaseController {
|
export default class UsersController extends BaseController {
|
||||||
private readonly User: typeof User;
|
private userService: UserService;
|
||||||
|
|
||||||
private readonly Role: typeof Role;
|
constructor(userService: UserService) {
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
super();
|
||||||
this.User = User;
|
this.userService = userService;
|
||||||
this.Role = Role;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,13 +30,14 @@ export default class UsersController extends BaseController {
|
|||||||
* GET /users
|
* GET /users
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public async list({ response }: HttpContextContract) {
|
public async list(ctx: HttpContextContract) {
|
||||||
const users = await this.User.query().preload('contacts').preload('roles');
|
const result = await this.userService.fetchUsers(ctx.request.qs());
|
||||||
|
|
||||||
return response.ok({
|
if (!result.success && result.error) {
|
||||||
message: 'Fetched all users.',
|
throw new Exception(result.message, result.status, result.error.code);
|
||||||
data: users,
|
}
|
||||||
});
|
|
||||||
|
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,16 +45,14 @@ export default class UsersController extends BaseController {
|
|||||||
* GET /users/:id
|
* GET /users/:id
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public async show({ response, params }: HttpContextContract) {
|
public async show(ctx: HttpContextContract) {
|
||||||
const user = await this.User.findOrFail(params.id);
|
const result = await this.userService.fetchUser(ctx.params.id);
|
||||||
|
|
||||||
await user.load('contacts');
|
if (!result.success && result.error) {
|
||||||
await user.load('roles');
|
throw new Exception(result.message, result.status, result.error.code);
|
||||||
|
}
|
||||||
|
|
||||||
return response.ok({
|
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||||
message: `Fetched user with id: "${user.id}"`,
|
|
||||||
data: user,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,20 +60,15 @@ export default class UsersController extends BaseController {
|
|||||||
* POST /users
|
* POST /users
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public async create({ response, request }: HttpContextContract) {
|
public async create(ctx: HttpContextContract) {
|
||||||
await request.validate(CreateUserValidator);
|
const payload = await ctx.request.validate(CreateUserValidator);
|
||||||
|
const result = await this.userService.createUser(payload);
|
||||||
|
|
||||||
const user = await this.User.create({
|
if (!result.success && result.error) {
|
||||||
first_name: request.input('first_name'),
|
throw new Exception(result.message, result.status, result.error.code);
|
||||||
last_name: request.input('last_name'),
|
}
|
||||||
login: request.input('login'),
|
|
||||||
password: request.input('password'),
|
|
||||||
});
|
|
||||||
|
|
||||||
await user.related('contacts').create({ email: request.input('email') });
|
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||||
await user.load('contacts');
|
|
||||||
|
|
||||||
return response.created({ message: 'Successfully created.', data: user });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,34 +76,15 @@ export default class UsersController extends BaseController {
|
|||||||
* PATCH /users/:id
|
* PATCH /users/:id
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public async update({ request, response, params }: HttpContextContract) {
|
public async update(ctx: HttpContextContract) {
|
||||||
await request.validate(UpdateUserValidator);
|
const payload = await ctx.request.validate(UpdateUserValidator);
|
||||||
|
const result = await this.userService.updateUser(ctx.params.id, payload);
|
||||||
|
|
||||||
const user = await this.User.findOrFail(params.id);
|
if (!result.success && result.error) {
|
||||||
const input: Pick<User, 'first_name' | 'last_name' | 'login' | 'password'> = {
|
throw new Exception(result.message, result.status, result.error.code);
|
||||||
first_name: request.input('first_name'),
|
|
||||||
last_name: request.input('last_name'),
|
|
||||||
login: request.input('login'),
|
|
||||||
password: request.input('password'),
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update roles
|
|
||||||
*/
|
|
||||||
Object.keys(input).forEach(k => {
|
|
||||||
if (input[k] !== undefined) {
|
|
||||||
user[k] = input[k];
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
await user.save();
|
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||||
await user.load('roles');
|
|
||||||
await user.load('contacts');
|
|
||||||
|
|
||||||
return response.ok({
|
|
||||||
message: `User with id: "${user.id}" was successfully updated.`,
|
|
||||||
data: user,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,74 +92,45 @@ export default class UsersController extends BaseController {
|
|||||||
* DELETE /users/:id
|
* DELETE /users/:id
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public async delete({ response, params }: HttpContextContract) {
|
public async delete(ctx: HttpContextContract) {
|
||||||
const user = await this.User.query().preload('contacts').preload('roles').where('id', params.id).firstOrFail();
|
const result = await this.userService.deleteUser(ctx.params.id);
|
||||||
|
|
||||||
await user.delete();
|
if (!result.success && result.error) {
|
||||||
|
throw new Exception(result.message, result.status, result.error.code);
|
||||||
|
}
|
||||||
|
|
||||||
return response.ok({
|
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||||
message: `Used with id: "${user.id}" was successfully deleted.`,
|
|
||||||
data: user,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach array of roles to user
|
* Attach array of roles to user
|
||||||
* POST /users/:id/attach-roles
|
* POST /users/:id/attach-roles
|
||||||
*/
|
*/
|
||||||
public async attachRoles({ request, response, params }: HttpContextContract) {
|
public async attachRoles(ctx: HttpContextContract) {
|
||||||
await request.validate(AddRoleToUserValidator);
|
const payload = await ctx.request.validate(AddRoleToUserValidator);
|
||||||
|
const result = await this.userService.attachRolesToUser(ctx.params.id, payload.roles);
|
||||||
|
|
||||||
const input: string[] | undefined = request.input('roles');
|
if (!result.success && result.error) {
|
||||||
const user = await this.User.query().preload('roles').where('id', params.id).firstOrFail();
|
throw new Exception(result.message, result.status, result.error.code);
|
||||||
const roles = await this.findRolesBySlug(input);
|
}
|
||||||
|
|
||||||
await this.User.attachRoles(user, roles);
|
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||||
|
|
||||||
return response.ok({
|
|
||||||
message: 'Roles attached',
|
|
||||||
data: user.roles,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detach array of roles from user
|
* Detach array of roles from user
|
||||||
* DELETE /users/:id/detach-roles
|
* DELETE /users/:id/detach-roles
|
||||||
*/
|
*/
|
||||||
public async detachRoles({ request, response, params }: HttpContextContract) {
|
public async detachRoles(ctx: HttpContextContract) {
|
||||||
await request.validate(DelRoleFromUserValidator);
|
const payload = await ctx.request.validate(DelRoleFromUserValidator);
|
||||||
|
const result = await this.userService.detachRolesFromUser(ctx.params.id, payload.roles);
|
||||||
|
|
||||||
const input: string[] | undefined = request.input('roles');
|
if (!result.success && result.error) {
|
||||||
const user = await this.User.query().preload('roles').where('id', params.id).firstOrFail();
|
throw new Exception(result.message, result.status, result.error.code);
|
||||||
const roles = await this.findRolesBySlug(input);
|
|
||||||
|
|
||||||
await this.User.detachRoles(user, roles);
|
|
||||||
|
|
||||||
return response.ok({
|
|
||||||
message: 'Roles detached',
|
|
||||||
data: user.roles,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return this.sendResponse(ctx, result.data, result.message, result.status);
|
||||||
* Finds roles by input value and throw error if role does not exist.
|
}
|
||||||
*
|
|
||||||
* @param input Array of roles to find them
|
|
||||||
* @returns Finded roles
|
|
||||||
*/
|
|
||||||
private async findRolesBySlug(input: string[] | undefined): Promise<Role[]> {
|
|
||||||
if (!input) {
|
|
||||||
throw new Exception('Unable to find "roles" field in input.', 400, 'E_ROLES_FIELD_NOT_PROVIDED');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const roles = await this.Role.query().whereIn('slug', input);
|
new Ioc().make(UsersController);
|
||||||
|
|
||||||
input.forEach(val => {
|
|
||||||
if (!roles.map(r => r.slug).includes(val)) {
|
|
||||||
throw new Exception(`Unable to find role: "${val}" using input value "roles"`, 404, 'E_ROLE_NOT_FOUND');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
enum Role {
|
enum RoleEnum {
|
||||||
ADMIN = 'admin',
|
ADMIN = 'admin',
|
||||||
TEACHER = 'teacher',
|
TEACHER = 'teacher',
|
||||||
STUDENT = 'student',
|
STUDENT = 'student',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Role;
|
export default RoleEnum;
|
||||||
9
app/Datatypes/Interfaces/IResponse.ts
Normal file
9
app/Datatypes/Interfaces/IResponse.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default interface IResponse {
|
||||||
|
success: boolean;
|
||||||
|
status: number;
|
||||||
|
message: string;
|
||||||
|
data: object;
|
||||||
|
error?: {
|
||||||
|
code: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm';
|
import { BaseModel, BelongsTo, belongsTo, column } from '@ioc:Adonis/Lucid/Orm';
|
||||||
|
import User from './User';
|
||||||
|
|
||||||
export default class Contact extends BaseModel {
|
export default class Contact extends BaseModel {
|
||||||
@column({ isPrimary: true })
|
@column({ isPrimary: true })
|
||||||
@ -23,6 +24,11 @@ export default class Contact extends BaseModel {
|
|||||||
@column()
|
@column()
|
||||||
public telegram_id: string | null;
|
public telegram_id: string | null;
|
||||||
|
|
||||||
|
@belongsTo(() => User, {
|
||||||
|
foreignKey: 'user_id',
|
||||||
|
})
|
||||||
|
public user: BelongsTo<typeof User>;
|
||||||
|
|
||||||
@column.dateTime({ autoCreate: true, serializeAs: null })
|
@column.dateTime({ autoCreate: true, serializeAs: null })
|
||||||
public createdAt: DateTime;
|
public createdAt: DateTime;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
/* eslint-disable import/no-cycle */
|
/* eslint-disable import/no-cycle */
|
||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { Exception } from '@adonisjs/core/build/standalone';
|
|
||||||
import {
|
import {
|
||||||
BaseModel,
|
BaseModel,
|
||||||
beforeCreate,
|
beforeCreate,
|
||||||
@ -55,45 +54,6 @@ export default class User extends BaseModel {
|
|||||||
@column.dateTime({ autoCreate: true, autoUpdate: true, serializeAs: null })
|
@column.dateTime({ autoCreate: true, autoUpdate: true, serializeAs: null })
|
||||||
public updatedAt: DateTime;
|
public updatedAt: DateTime;
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the input role is already attached, and if so, throws an error,
|
|
||||||
* otherwise it attaches the role to the user.
|
|
||||||
*
|
|
||||||
* @param user User
|
|
||||||
* @param inputRoles Array of roles to attach
|
|
||||||
*/
|
|
||||||
public static async attachRoles(user: User, inputRoles: Role[]): Promise<void> {
|
|
||||||
const currentRolesSlugs: string[] = user.roles.map(r => r.slug);
|
|
||||||
const inputRolesSlugs: string[] = inputRoles.map(r => r.slug);
|
|
||||||
|
|
||||||
currentRolesSlugs.forEach(s => {
|
|
||||||
if (inputRolesSlugs.includes(s)) {
|
|
||||||
throw new Exception(`Role "${s}" already attached to that user.`, 400, 'E_ROLE_ATTACHED');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await user.related('roles').attach(inputRoles.map(r => r.id));
|
|
||||||
await user.load('roles');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Before detach, checks if input role is attached to that user and
|
|
||||||
* if not, throws an error.
|
|
||||||
*
|
|
||||||
* @param user User
|
|
||||||
* @param inputRoles Array of roles to detach
|
|
||||||
*/
|
|
||||||
public static async detachRoles(user: User, inputRoles: Role[]): Promise<void> {
|
|
||||||
inputRoles.forEach(role => {
|
|
||||||
if (!user.roles.map(r => r.id).includes(role.id)) {
|
|
||||||
throw new Exception(`Role "${role.slug}" not attached to that user.`, 400, 'E_ROLE_NOT_ATTACHED');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
user.related('roles').detach(inputRoles.map(r => r.id));
|
|
||||||
await user.load('roles');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign id to user by nanoid.
|
* Assign id to user by nanoid.
|
||||||
* @param user User
|
* @param user User
|
||||||
|
|||||||
56
app/Repositories/ContactRepository.ts
Normal file
56
app/Repositories/ContactRepository.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
export default class ContactRepository {
|
||||||
|
private Contact: typeof Contact;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.Contact = Contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates user contacts in database
|
||||||
|
*
|
||||||
|
* @param user User for associate the contacts
|
||||||
|
* @param data Data contacts
|
||||||
|
* @returns Created contacts
|
||||||
|
*/
|
||||||
|
public async create(user: User, data: Pick<CreateUserValidator['schema']['props'], 'email'>) {
|
||||||
|
const contacts = await this.Contact.create(data);
|
||||||
|
|
||||||
|
await contacts.related('user').associate(user);
|
||||||
|
await user.load('contacts');
|
||||||
|
await user.load('roles');
|
||||||
|
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async update(user: User, data: Pick<UpdateUserValidator['schema']['props'], 'email'>) {
|
||||||
|
const contacts = await this.Contact.query().where('user_id', user.id).first();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user contacts
|
||||||
|
*/
|
||||||
|
if (contacts) {
|
||||||
|
contacts.email = data.email;
|
||||||
|
|
||||||
|
await contacts.save();
|
||||||
|
await user.load('contacts');
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Repositories/RoleRepository.ts
Normal file
26
app/Repositories/RoleRepository.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Role from 'App/Models/Role';
|
||||||
|
|
||||||
|
export default class RoleRepository {
|
||||||
|
private Role: typeof Role;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.Role = Role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAll(params?: any) {
|
||||||
|
const { roles }: any = params || {};
|
||||||
|
const query = this.Role.query();
|
||||||
|
|
||||||
|
if (roles) {
|
||||||
|
query.whereIn('slug', roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await query;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBySlug(slug: string) {
|
||||||
|
const role = await this.Role.query().where('slug', slug);
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
}
|
||||||
106
app/Repositories/UserRepository.ts
Normal file
106
app/Repositories/UserRepository.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import User from 'App/Models/User';
|
||||||
|
import CreateUserValidator from 'App/Validators/User/CreateUserValidator';
|
||||||
|
import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
|
||||||
|
|
||||||
|
export default class UserRepository {
|
||||||
|
private User: typeof User;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.User = User;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getById(id: string | number) {
|
||||||
|
const data = await this.User.query().preload('contacts').preload('roles').where('id', id).first();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAllByRole(role: string) {
|
||||||
|
const data = await this.User.query()
|
||||||
|
.preload('contacts')
|
||||||
|
.preload('roles')
|
||||||
|
.whereHas('roles', q => q.where('slug', role));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAll(params?: any) {
|
||||||
|
const { email, login, first_name, last_name, role }: any = params || {};
|
||||||
|
const query = this.User.query();
|
||||||
|
|
||||||
|
if (email) {
|
||||||
|
query.preload('contacts').whereHas('contacts', q => q.where('email', 'like', `%${email}%`));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (login) {
|
||||||
|
query.where('login', 'like', `%${login}%`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first_name) {
|
||||||
|
query.where('first_name', 'like', `%${first_name}%`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_name) {
|
||||||
|
query.where('last_name', 'like', `%${last_name}%`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role) {
|
||||||
|
query.preload('roles').whereHas('roles', q => q.where('slug', role));
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await query.preload('contacts').preload('roles');
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
|
||||||
|
return createdUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user
|
||||||
|
*
|
||||||
|
* @param id User id
|
||||||
|
* @param data Data to update
|
||||||
|
* @returns User or null if user is not found
|
||||||
|
*/
|
||||||
|
public async update(id: number | string, data: UpdateUserValidator['schema']['props']) {
|
||||||
|
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();
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete user
|
||||||
|
*
|
||||||
|
* @param id User id
|
||||||
|
* @returns Deleted user or null if user is not found
|
||||||
|
*/
|
||||||
|
public async delete(id: number | string) {
|
||||||
|
const user = await this.User.query().preload('contacts').preload('roles').where('id', id).first();
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
await user.delete();
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
261
app/Services/UserService.ts
Normal file
261
app/Services/UserService.ts
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
import { inject, Ioc } from '@adonisjs/core/build/standalone';
|
||||||
|
import IResponse from 'App/Datatypes/Interfaces/IResponse';
|
||||||
|
import Role from 'App/Models/Role';
|
||||||
|
import ContactRepository from 'App/Repositories/ContactRepository';
|
||||||
|
import RoleRepository from 'App/Repositories/RoleRepository';
|
||||||
|
import UserRepository from 'App/Repositories/UserRepository';
|
||||||
|
import CreateUserValidator from 'App/Validators/User/CreateUserValidator';
|
||||||
|
import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
|
||||||
|
|
||||||
|
@inject()
|
||||||
|
export default class UserService {
|
||||||
|
private userRepository: UserRepository;
|
||||||
|
|
||||||
|
private contactRepository: ContactRepository;
|
||||||
|
|
||||||
|
private roleRepository: RoleRepository;
|
||||||
|
|
||||||
|
constructor(userRepository: UserRepository, contactRepository: ContactRepository, roleRepository: RoleRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.contactRepository = contactRepository;
|
||||||
|
this.roleRepository = roleRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch one user by id
|
||||||
|
*
|
||||||
|
* @param id Id of user
|
||||||
|
* @returns Response data
|
||||||
|
*/
|
||||||
|
public async fetchUser(id: string | number): Promise<IResponse> {
|
||||||
|
const user = await this.userRepository.getById(id);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 404,
|
||||||
|
message: 'User not found.',
|
||||||
|
data: {},
|
||||||
|
error: {
|
||||||
|
code: 'USER_NOT_FOUND',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
status: 200,
|
||||||
|
message: 'Fetched user.',
|
||||||
|
data: user,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch list of users
|
||||||
|
*
|
||||||
|
* @param params Params for finding user
|
||||||
|
* @returns Response data
|
||||||
|
*/
|
||||||
|
public async fetchUsers(params?: any): Promise<IResponse> {
|
||||||
|
const users = await this.userRepository.getAll(params);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
status: 200,
|
||||||
|
message: 'Fetched all users.',
|
||||||
|
data: users,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new user
|
||||||
|
*
|
||||||
|
* @param data Input for create new user
|
||||||
|
* @returns Response data
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
message: 'User created.',
|
||||||
|
data: user,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateUser(id: string | number, data: UpdateUserValidator['schema']['props']): Promise<IResponse> {
|
||||||
|
const user = await this.userRepository.update(id, data);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 404,
|
||||||
|
message: 'User not found.',
|
||||||
|
data: {},
|
||||||
|
error: {
|
||||||
|
code: 'E_USER_NOT_FOUND',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user contacts
|
||||||
|
*/
|
||||||
|
await this.contactRepository.update(user, data);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
status: 200,
|
||||||
|
message: 'User updated.',
|
||||||
|
data: user,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deleteUser(id: string | number): Promise<IResponse> {
|
||||||
|
const user = await this.userRepository.delete(id);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 404,
|
||||||
|
message: 'User not found.',
|
||||||
|
data: {},
|
||||||
|
error: {
|
||||||
|
code: 'E_USER_NOT_FOUND',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
status: 200,
|
||||||
|
message: 'User deleted.',
|
||||||
|
data: user,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach array of roles to user
|
||||||
|
*
|
||||||
|
* @param id User id
|
||||||
|
* @param input Roles
|
||||||
|
* @returns Result
|
||||||
|
*/
|
||||||
|
public async attachRolesToUser(id: string | number, input: string[]): Promise<IResponse> {
|
||||||
|
const user = await this.userRepository.getById(id);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 404,
|
||||||
|
message: 'User not found.',
|
||||||
|
data: {},
|
||||||
|
error: {
|
||||||
|
code: 'E_USER_NOT_FOUND',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const roles = await this.roleRepository.getAll({ roles: input });
|
||||||
|
let attachedRole: Role | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set attachedRole variable if some role already
|
||||||
|
* attached to user.
|
||||||
|
*/
|
||||||
|
roles.some(inputRole => {
|
||||||
|
const existed = user.roles.find(role => role.slug === inputRole.slug);
|
||||||
|
if (existed) {
|
||||||
|
attachedRole = inputRole;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (attachedRole) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 404,
|
||||||
|
message: `Role "${attachedRole.name}" already attached to that user.`,
|
||||||
|
data: {},
|
||||||
|
error: {
|
||||||
|
code: 'E_ROLE_ATTACHED',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await user.related('roles').attach([...roles.map(r => r.id)]);
|
||||||
|
await user.load('roles');
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
status: 200,
|
||||||
|
message: 'Roles attached.',
|
||||||
|
data: user.roles,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach array of role from user
|
||||||
|
*
|
||||||
|
* @param id User id
|
||||||
|
* @param input Roles
|
||||||
|
* @returns Result
|
||||||
|
*/
|
||||||
|
public async detachRolesFromUser(id: string | number, input: string[]): Promise<IResponse> {
|
||||||
|
const user = await this.userRepository.getById(id);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 404,
|
||||||
|
message: 'User not found.',
|
||||||
|
data: {},
|
||||||
|
error: {
|
||||||
|
code: 'E_USER_NOT_FOUND',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const roles = await this.roleRepository.getAll({ roles: input });
|
||||||
|
let notAttachedRole: Role | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set notAttachedRole variable if some role
|
||||||
|
* not attached to user.
|
||||||
|
*/
|
||||||
|
roles.forEach(role => {
|
||||||
|
if (!user.roles.map(r => r.id).includes(role.id)) {
|
||||||
|
notAttachedRole = role;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (notAttachedRole) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 404,
|
||||||
|
message: `Role "${notAttachedRole.name}" not attached to that user.`,
|
||||||
|
data: {},
|
||||||
|
error: {
|
||||||
|
code: 'E_ROLE_NOT_ATTACHED',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
await user.related('roles').detach([...roles.map(r => r.id)]);
|
||||||
|
await user.load('roles');
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
status: 200,
|
||||||
|
message: 'Roles detached.',
|
||||||
|
data: user.roles,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Ioc().make(UserService);
|
||||||
@ -1,11 +1,12 @@
|
|||||||
import { schema } from '@ioc:Adonis/Core/Validator';
|
import { schema } from '@ioc:Adonis/Core/Validator';
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||||
|
import RoleEnum from 'App/Datatypes/Enums/RoleEnum';
|
||||||
|
|
||||||
export default class AddRoleToUserValidator {
|
export default class AddRoleToUserValidator {
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
constructor(protected ctx: HttpContextContract) {}
|
||||||
|
|
||||||
public schema = schema.create({
|
public schema = schema.create({
|
||||||
roles: schema.array().members(schema.string()),
|
roles: schema.array().members(schema.enum(Object.values(RoleEnum))),
|
||||||
});
|
});
|
||||||
|
|
||||||
public messages = {};
|
public messages = {};
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { schema } from '@ioc:Adonis/Core/Validator';
|
import { schema } from '@ioc:Adonis/Core/Validator';
|
||||||
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||||
|
import RoleEnum from 'App/Datatypes/Enums/RoleEnum';
|
||||||
|
|
||||||
export default class DelRoleFromUserValidator {
|
export default class DelRoleFromUserValidator {
|
||||||
constructor(protected ctx: HttpContextContract) {}
|
constructor(protected ctx: HttpContextContract) {}
|
||||||
|
|
||||||
public schema = schema.create({
|
public schema = schema.create({
|
||||||
roles: schema.array().members(schema.string()),
|
roles: schema.array().members(schema.enum(Object.values(RoleEnum))),
|
||||||
});
|
});
|
||||||
|
|
||||||
public messages = {};
|
public messages = {};
|
||||||
|
|||||||
@ -5,11 +5,11 @@ 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({}, [rules.unique({ table: 'users', column: 'first_name' })]),
|
first_name: schema.string(),
|
||||||
last_name: schema.string.optional({}, [rules.unique({ table: 'users', column: 'last_name' })]),
|
last_name: schema.string(),
|
||||||
login: schema.string.optional({}, [rules.unique({ table: 'users', column: 'login' })]),
|
login: schema.string({}, [rules.unique({ table: 'users', column: 'login' })]),
|
||||||
email: schema.string.optional({}, [rules.email(), rules.unique({ table: 'contacts', column: 'email' })]),
|
email: schema.string({}, [rules.email(), rules.unique({ table: 'contacts', column: 'email' })]),
|
||||||
password: schema.string.optional({}, [rules.unique({ table: 'users', column: 'password' })]),
|
password: schema.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
public messages = {};
|
public messages = {};
|
||||||
|
|||||||
@ -17,6 +17,4 @@ import Application from '@ioc:Adonis/Core/Application';
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default listDirectoryFiles(__dirname, Application.appRoot, [
|
export default listDirectoryFiles(__dirname, Application.appRoot, ['./commands/index']);
|
||||||
'./commands/index',
|
|
||||||
]);
|
|
||||||
|
|||||||
@ -32,12 +32,7 @@ const bodyParserConfig: BodyParserConfig = {
|
|||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
limit: '1mb',
|
limit: '1mb',
|
||||||
strict: true,
|
strict: true,
|
||||||
types: [
|
types: ['application/json', 'application/json-patch+json', 'application/vnd.api+json', 'application/csp-report'],
|
||||||
'application/json',
|
|
||||||
'application/json-patch+json',
|
|
||||||
'application/vnd.api+json',
|
|
||||||
'application/csp-report',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -41,6 +41,7 @@ const redisConfig: RedisConfig = {
|
|||||||
password: Env.get('REDIS_PASSWORD', ''),
|
password: Env.get('REDIS_PASSWORD', ''),
|
||||||
db: 0,
|
db: 0,
|
||||||
keyPrefix: '',
|
keyPrefix: '',
|
||||||
|
healthCheck: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
* file.
|
* file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import User from 'App/Models/User'
|
import User from 'App/Models/User';
|
||||||
|
|
||||||
declare module '@ioc:Adonis/Addons/Auth' {
|
declare module '@ioc:Adonis/Addons/Auth' {
|
||||||
/*
|
/*
|
||||||
@ -34,9 +34,9 @@ declare module '@ioc:Adonis/Addons/Auth' {
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
user: {
|
user: {
|
||||||
implementation: LucidProviderContract<typeof User>,
|
implementation: LucidProviderContract<typeof User>;
|
||||||
config: LucidProviderConfig<typeof User>,
|
config: LucidProviderConfig<typeof User>;
|
||||||
},
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -65,8 +65,8 @@ declare module '@ioc:Adonis/Addons/Auth' {
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
api: {
|
api: {
|
||||||
implementation: OATGuardContract<'user', 'api'>,
|
implementation: OATGuardContract<'user', 'api'>;
|
||||||
config: OATGuardConfig<'user'>,
|
config: OATGuardConfig<'user'>;
|
||||||
},
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
package-lock.json
generated
38
package-lock.json
generated
@ -145,11 +145,41 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@adonisjs/fold": {
|
"@adonisjs/fold": {
|
||||||
"version": "8.1.4",
|
"version": "8.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@adonisjs/fold/-/fold-8.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@adonisjs/fold/-/fold-8.1.5.tgz",
|
||||||
"integrity": "sha512-+B56Lxb19TZ2DkK2deZH1kTfqyXVUKwrfNirVZ3JfGeO6RbXjW3IYeUTJ7MWzcbiSTqmHXw2HC+TTIpE/EEDpg==",
|
"integrity": "sha512-eqbq0zQd0TV7AoN/RP4vUUg442BP4GSc0U1CsNYGKJ3YBhxfgThVLDlgn1K4/nadC1lv4/Gf3ZSnLj1Rx5OzFA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@poppinss/utils": "^3.1.3"
|
"@poppinss/utils": "^3.1.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@poppinss/utils": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@poppinss/utils/-/utils-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-gnqlrxE4zMvqW+LpviyCWCg4+RShCYCFyBdVTyg9ZZEEgPBV9bEY+YB5r/2klFrKx30k9nfClHVI2n8ZKmXgsw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/bytes": "^3.1.1",
|
||||||
|
"@types/he": "^1.1.2",
|
||||||
|
"buffer-alloc": "^1.2.0",
|
||||||
|
"bytes": "^3.1.0",
|
||||||
|
"change-case": "^4.1.2",
|
||||||
|
"cuid": "^2.1.8",
|
||||||
|
"fs-readdir-recursive": "^1.1.0",
|
||||||
|
"he": "^1.2.0",
|
||||||
|
"kind-of": "^6.0.3",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"ms": "^2.1.3",
|
||||||
|
"pluralize": "^8.0.0",
|
||||||
|
"require-all": "^3.0.0",
|
||||||
|
"resolve-from": "^5.0.0",
|
||||||
|
"slugify": "^1.6.0",
|
||||||
|
"truncatise": "0.0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slugify": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-FkMq+MQc5hzYgM86nLuHI98Acwi3p4wX+a5BO9Hhw4JdK4L7WueIiZ4tXEobImPqBz2sVcV0+Mu3GRB30IGang=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@adonisjs/hash": {
|
"@adonisjs/hash": {
|
||||||
|
|||||||
@ -3,19 +3,11 @@ import { ApplicationContract } from '@ioc:Adonis/Core/Application';
|
|||||||
export default class AppProvider {
|
export default class AppProvider {
|
||||||
constructor(protected app: ApplicationContract) {}
|
constructor(protected app: ApplicationContract) {}
|
||||||
|
|
||||||
public register() {
|
public register() {}
|
||||||
// Register your own bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
public async boot() {
|
public async boot() {}
|
||||||
// IoC container is ready
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ready() {
|
public async ready() {}
|
||||||
// App is ready
|
|
||||||
}
|
|
||||||
|
|
||||||
public async shutdown() {
|
public async shutdown() {}
|
||||||
// Cleanup, since app is going down
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
routes/apis/v1/health.ts
Normal file
11
routes/apis/v1/health.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import Route from '@ioc:Adonis/Core/Route';
|
||||||
|
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||||
|
import HealthCheck from '@ioc:Adonis/Core/HealthCheck';
|
||||||
|
|
||||||
|
Route.group(() => {
|
||||||
|
Route.get('/', async (ctx: HttpContextContract) => {
|
||||||
|
const report = await HealthCheck.getReport();
|
||||||
|
|
||||||
|
return report.healthy ? ctx.response.ok(report) : ctx.response.badRequest(report);
|
||||||
|
}).as('health');
|
||||||
|
}).prefix('health');
|
||||||
@ -12,6 +12,13 @@ Route.group(() => {
|
|||||||
require('./auth');
|
require('./auth');
|
||||||
|
|
||||||
Route.group(() => {
|
Route.group(() => {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Health check
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
require('./health');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Users module
|
* Users module
|
||||||
|
|||||||
@ -2,14 +2,14 @@ import Route from '@ioc:Adonis/Core/Route';
|
|||||||
|
|
||||||
Route.group(() => {
|
Route.group(() => {
|
||||||
Route.get('/', 'Api/v1/UsersController.list').middleware('role:admin,teacher,student').as('users.list');
|
Route.get('/', 'Api/v1/UsersController.list').middleware('role:admin,teacher,student').as('users.list');
|
||||||
Route.post('/', 'Api/v1/UsersController.create').middleware('role:admin').as('users.create');
|
Route.post('/', 'Api/v1/UsersController.create').middleware('role:admin,student').as('users.create');
|
||||||
Route.get('/:id', 'Api/v1/UsersController.show').middleware('role:admin,teacher,student').as('users.show');
|
Route.get('/:id', 'Api/v1/UsersController.show').middleware('role:admin,teacher,student').as('users.show');
|
||||||
Route.patch('/:id', 'Api/v1/UsersController.update').middleware('role:admin').as('users.update');
|
Route.put('/:id', 'Api/v1/UsersController.update').middleware('role:admin,student,teacher').as('users.update');
|
||||||
Route.delete('/:id', 'Api/v1/UsersController.delete').middleware('role:admin').as('users.delete');
|
Route.delete('/:id', 'Api/v1/UsersController.delete').middleware('role:admin,student,teacher').as('users.delete');
|
||||||
Route.post('/:id/attach-roles', 'Api/v1/UsersController.attachRoles')
|
Route.post('/:id/attach-roles', 'Api/v1/UsersController.attachRoles')
|
||||||
.middleware('role:admin')
|
.middleware('role:admin,student,teacher')
|
||||||
.as('users.attach-role');
|
.as('users.attach-role');
|
||||||
Route.delete('/:id/detach-roles', 'Api/v1/UsersController.detachRoles')
|
Route.delete('/:id/detach-roles', 'Api/v1/UsersController.detachRoles')
|
||||||
.middleware('role:admin')
|
.middleware('role:admin,student,teacher')
|
||||||
.as('users.detach-role');
|
.as('users.detach-role');
|
||||||
}).prefix('users');
|
}).prefix('users');
|
||||||
|
|||||||
@ -1,36 +1,17 @@
|
|||||||
{
|
{
|
||||||
"extends": "./node_modules/adonis-preset-ts/tsconfig",
|
"extends": "./node_modules/adonis-preset-ts/tsconfig",
|
||||||
"include": [
|
"include": ["**/*"],
|
||||||
"**/*"
|
"exclude": ["node_modules", "build"],
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
"build"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "build",
|
"outDir": "build",
|
||||||
"rootDir": "./",
|
"rootDir": "./",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"App/*": [
|
"App/*": ["./app/*"],
|
||||||
"./app/*"
|
"Config/*": ["./config/*"],
|
||||||
],
|
"Contracts/*": ["./contracts/*"],
|
||||||
"Config/*": [
|
"Database/*": ["./database/*"]
|
||||||
"./config/*"
|
|
||||||
],
|
|
||||||
"Contracts/*": [
|
|
||||||
"./contracts/*"
|
|
||||||
],
|
|
||||||
"Database/*": [
|
|
||||||
"./database/*"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"types": [
|
"types": ["@adonisjs/core", "@adonisjs/repl", "@adonisjs/lucid", "@adonisjs/auth", "@adonisjs/redis"]
|
||||||
"@adonisjs/core",
|
|
||||||
"@adonisjs/repl",
|
|
||||||
"@adonisjs/lucid",
|
|
||||||
"@adonisjs/auth",
|
|
||||||
"@adonisjs/redis"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user