refactor: UsersController

This commit is contained in:
Sergey Yarkov 2021-08-06 19:26:47 +03:00
parent 419495d39c
commit f8e3417f1f
23 changed files with 610 additions and 226 deletions

View File

@ -4,7 +4,7 @@ import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
/**
* Datatype
*/
import Role from 'App/Datatype/Role';
import Role from 'App/Datatypes/Enums/RoleEnum';
/**
* Models

View File

@ -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';
/**
* Models
* Services
*/
import Role from 'App/Models/Role';
import User from 'App/Models/User';
import UserService from 'App/Services/UserService';
/**
* Validators
@ -17,15 +16,13 @@ import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
import BaseController from '../../BaseController';
@inject()
export default class UsersController extends BaseController {
private readonly User: typeof User;
private userService: UserService;
private readonly Role: typeof Role;
constructor() {
constructor(userService: UserService) {
super();
this.User = User;
this.Role = Role;
this.userService = userService;
}
/**
@ -33,13 +30,14 @@ export default class UsersController extends BaseController {
* GET /users
*/
public async list({ response }: HttpContextContract) {
const users = await this.User.query().preload('contacts').preload('roles');
public async list(ctx: HttpContextContract) {
const result = await this.userService.fetchUsers(ctx.request.qs());
return response.ok({
message: 'Fetched all users.',
data: users,
});
if (!result.success && result.error) {
throw new Exception(result.message, result.status, result.error.code);
}
return this.sendResponse(ctx, result.data, result.message, result.status);
}
/**
@ -47,16 +45,14 @@ export default class UsersController extends BaseController {
* GET /users/:id
*/
public async show({ response, params }: HttpContextContract) {
const user = await this.User.findOrFail(params.id);
public async show(ctx: HttpContextContract) {
const result = await this.userService.fetchUser(ctx.params.id);
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 user with id: "${user.id}"`,
data: user,
});
return this.sendResponse(ctx, result.data, result.message, result.status);
}
/**
@ -64,20 +60,15 @@ export default class UsersController extends BaseController {
* POST /users
*/
public async create({ response, request }: HttpContextContract) {
await request.validate(CreateUserValidator);
public async create(ctx: HttpContextContract) {
const payload = await ctx.request.validate(CreateUserValidator);
const result = await this.userService.createUser(payload);
const user = await this.User.create({
first_name: request.input('first_name'),
last_name: request.input('last_name'),
login: request.input('login'),
password: request.input('password'),
});
if (!result.success && result.error) {
throw new Exception(result.message, result.status, result.error.code);
}
await user.related('contacts').create({ email: request.input('email') });
await user.load('contacts');
return response.created({ message: 'Successfully created.', data: user });
return this.sendResponse(ctx, result.data, result.message, result.status);
}
/**
@ -85,34 +76,15 @@ export default class UsersController extends BaseController {
* PATCH /users/:id
*/
public async update({ request, response, params }: HttpContextContract) {
await request.validate(UpdateUserValidator);
public async update(ctx: HttpContextContract) {
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);
const input: Pick<User, 'first_name' | 'last_name' | 'login' | 'password'> = {
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];
if (!result.success && result.error) {
throw new Exception(result.message, result.status, result.error.code);
}
});
await user.save();
await user.load('roles');
await user.load('contacts');
return response.ok({
message: `User with id: "${user.id}" was successfully updated.`,
data: user,
});
return this.sendResponse(ctx, result.data, result.message, result.status);
}
/**
@ -120,74 +92,45 @@ export default class UsersController extends BaseController {
* DELETE /users/:id
*/
public async delete({ response, params }: HttpContextContract) {
const user = await this.User.query().preload('contacts').preload('roles').where('id', params.id).firstOrFail();
public async delete(ctx: HttpContextContract) {
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({
message: `Used with id: "${user.id}" was successfully deleted.`,
data: user,
});
return this.sendResponse(ctx, result.data, result.message, result.status);
}
/**
* Attach array of roles to user
* POST /users/:id/attach-roles
*/
public async attachRoles({ request, response, params }: HttpContextContract) {
await request.validate(AddRoleToUserValidator);
public async attachRoles(ctx: HttpContextContract) {
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');
const user = await this.User.query().preload('roles').where('id', params.id).firstOrFail();
const roles = await this.findRolesBySlug(input);
if (!result.success && result.error) {
throw new Exception(result.message, result.status, result.error.code);
}
await this.User.attachRoles(user, roles);
return response.ok({
message: 'Roles attached',
data: user.roles,
});
return this.sendResponse(ctx, result.data, result.message, result.status);
}
/**
* Detach array of roles from user
* DELETE /users/:id/detach-roles
*/
public async detachRoles({ request, response, params }: HttpContextContract) {
await request.validate(DelRoleFromUserValidator);
public async detachRoles(ctx: HttpContextContract) {
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');
const user = await this.User.query().preload('roles').where('id', params.id).firstOrFail();
const roles = await this.findRolesBySlug(input);
await this.User.detachRoles(user, roles);
return response.ok({
message: 'Roles detached',
data: user.roles,
});
if (!result.success && result.error) {
throw new Exception(result.message, result.status, result.error.code);
}
/**
* 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);
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;
return this.sendResponse(ctx, result.data, result.message, result.status);
}
}
new Ioc().make(UsersController);

View File

@ -1,7 +1,7 @@
enum Role {
enum RoleEnum {
ADMIN = 'admin',
TEACHER = 'teacher',
STUDENT = 'student',
}
export default Role;
export default RoleEnum;

View File

@ -0,0 +1,9 @@
export default interface IResponse {
success: boolean;
status: number;
message: string;
data: object;
error?: {
code: string;
};
}

View File

@ -1,5 +1,6 @@
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 {
@column({ isPrimary: true })
@ -23,6 +24,11 @@ export default class Contact extends BaseModel {
@column()
public telegram_id: string | null;
@belongsTo(() => User, {
foreignKey: 'user_id',
})
public user: BelongsTo<typeof User>;
@column.dateTime({ autoCreate: true, serializeAs: null })
public createdAt: DateTime;

View File

@ -1,7 +1,6 @@
/* eslint-disable import/no-cycle */
/* eslint-disable no-param-reassign */
import { DateTime } from 'luxon';
import { Exception } from '@adonisjs/core/build/standalone';
import {
BaseModel,
beforeCreate,
@ -55,45 +54,6 @@ export default class User extends BaseModel {
@column.dateTime({ autoCreate: true, autoUpdate: true, serializeAs: null })
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.
* @param user User

View 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;
}
}

View 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;
}
}

View 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
View 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);

View File

@ -1,11 +1,12 @@
import { schema } from '@ioc:Adonis/Core/Validator';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import RoleEnum from 'App/Datatypes/Enums/RoleEnum';
export default class AddRoleToUserValidator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
roles: schema.array().members(schema.string()),
roles: schema.array().members(schema.enum(Object.values(RoleEnum))),
});
public messages = {};

View File

@ -1,11 +1,12 @@
import { schema } from '@ioc:Adonis/Core/Validator';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import RoleEnum from 'App/Datatypes/Enums/RoleEnum';
export default class DelRoleFromUserValidator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
roles: schema.array().members(schema.string()),
roles: schema.array().members(schema.enum(Object.values(RoleEnum))),
});
public messages = {};

View File

@ -5,11 +5,11 @@ export default class UpdateUserValidator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
first_name: schema.string.optional({}, [rules.unique({ table: 'users', column: 'first_name' })]),
last_name: schema.string.optional({}, [rules.unique({ table: 'users', column: 'last_name' })]),
login: schema.string.optional({}, [rules.unique({ table: 'users', column: 'login' })]),
email: schema.string.optional({}, [rules.email(), rules.unique({ table: 'contacts', column: 'email' })]),
password: schema.string.optional({}, [rules.unique({ table: 'users', column: 'password' })]),
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' })]),
password: schema.string(),
});
public messages = {};

View File

@ -17,6 +17,4 @@ import Application from '@ioc:Adonis/Core/Application';
|
*/
export default listDirectoryFiles(__dirname, Application.appRoot, [
'./commands/index',
]);
export default listDirectoryFiles(__dirname, Application.appRoot, ['./commands/index']);

View File

@ -32,12 +32,7 @@ const bodyParserConfig: BodyParserConfig = {
encoding: 'utf-8',
limit: '1mb',
strict: true,
types: [
'application/json',
'application/json-patch+json',
'application/vnd.api+json',
'application/csp-report',
],
types: ['application/json', 'application/json-patch+json', 'application/vnd.api+json', 'application/csp-report'],
},
/*

View File

@ -41,6 +41,7 @@ const redisConfig: RedisConfig = {
password: Env.get('REDIS_PASSWORD', ''),
db: 0,
keyPrefix: '',
healthCheck: true,
},
},
};

View File

@ -5,7 +5,7 @@
* file.
*/
import User from 'App/Models/User'
import User from 'App/Models/User';
declare module '@ioc:Adonis/Addons/Auth' {
/*
@ -34,9 +34,9 @@ declare module '@ioc:Adonis/Addons/Auth' {
|
*/
user: {
implementation: LucidProviderContract<typeof User>,
config: LucidProviderConfig<typeof User>,
},
implementation: LucidProviderContract<typeof User>;
config: LucidProviderConfig<typeof User>;
};
}
/*
@ -65,8 +65,8 @@ declare module '@ioc:Adonis/Addons/Auth' {
|
*/
api: {
implementation: OATGuardContract<'user', 'api'>,
config: OATGuardConfig<'user'>,
},
implementation: OATGuardContract<'user', 'api'>;
config: OATGuardConfig<'user'>;
};
}
}

38
package-lock.json generated
View File

@ -145,11 +145,41 @@
}
},
"@adonisjs/fold": {
"version": "8.1.4",
"resolved": "https://registry.npmjs.org/@adonisjs/fold/-/fold-8.1.4.tgz",
"integrity": "sha512-+B56Lxb19TZ2DkK2deZH1kTfqyXVUKwrfNirVZ3JfGeO6RbXjW3IYeUTJ7MWzcbiSTqmHXw2HC+TTIpE/EEDpg==",
"version": "8.1.5",
"resolved": "https://registry.npmjs.org/@adonisjs/fold/-/fold-8.1.5.tgz",
"integrity": "sha512-eqbq0zQd0TV7AoN/RP4vUUg442BP4GSc0U1CsNYGKJ3YBhxfgThVLDlgn1K4/nadC1lv4/Gf3ZSnLj1Rx5OzFA==",
"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": {

View File

@ -3,19 +3,11 @@ import { ApplicationContract } from '@ioc:Adonis/Core/Application';
export default class AppProvider {
constructor(protected app: ApplicationContract) {}
public register() {
// Register your own bindings
}
public register() {}
public async boot() {
// IoC container is ready
}
public async boot() {}
public async ready() {
// App is ready
}
public async ready() {}
public async shutdown() {
// Cleanup, since app is going down
}
public async shutdown() {}
}

11
routes/apis/v1/health.ts Normal file
View 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');

View File

@ -12,6 +12,13 @@ Route.group(() => {
require('./auth');
Route.group(() => {
/**
*
* Health check
*
*/
require('./health');
/**
*
* Users module

View File

@ -2,14 +2,14 @@ import Route from '@ioc:Adonis/Core/Route';
Route.group(() => {
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.patch('/:id', 'Api/v1/UsersController.update').middleware('role:admin').as('users.update');
Route.delete('/:id', 'Api/v1/UsersController.delete').middleware('role:admin').as('users.delete');
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,student,teacher').as('users.delete');
Route.post('/:id/attach-roles', 'Api/v1/UsersController.attachRoles')
.middleware('role:admin')
.middleware('role:admin,student,teacher')
.as('users.attach-role');
Route.delete('/:id/detach-roles', 'Api/v1/UsersController.detachRoles')
.middleware('role:admin')
.middleware('role:admin,student,teacher')
.as('users.detach-role');
}).prefix('users');

View File

@ -1,36 +1,17 @@
{
"extends": "./node_modules/adonis-preset-ts/tsconfig",
"include": [
"**/*"
],
"exclude": [
"node_modules",
"build"
],
"include": ["**/*"],
"exclude": ["node_modules", "build"],
"compilerOptions": {
"outDir": "build",
"rootDir": "./",
"sourceMap": true,
"paths": {
"App/*": [
"./app/*"
],
"Config/*": [
"./config/*"
],
"Contracts/*": [
"./contracts/*"
],
"Database/*": [
"./database/*"
]
"App/*": ["./app/*"],
"Config/*": ["./config/*"],
"Contracts/*": ["./contracts/*"],
"Database/*": ["./database/*"]
},
"types": [
"@adonisjs/core",
"@adonisjs/repl",
"@adonisjs/lucid",
"@adonisjs/auth",
"@adonisjs/redis"
]
"types": ["@adonisjs/core", "@adonisjs/repl", "@adonisjs/lucid", "@adonisjs/auth", "@adonisjs/redis"]
}
}