initial
This commit is contained in:
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
.vscode/
|
||||
.DS_Store
|
||||
|
||||
node_modules/
|
||||
build/
|
||||
dist/
|
||||
temp/
|
||||
package-lock.json
|
||||
src/swagger/swagger.json
|
||||
swagger.json
|
||||
29
config/default.json
Normal file
29
config/default.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"app": {
|
||||
"name": "Service Master Data",
|
||||
"description": "Purpose of this service is to provide master data product, master data suco and etc",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"server": {
|
||||
"port": "4001",
|
||||
"host": "0.0.0.0",
|
||||
"host_swagger": "127.0.0.1",
|
||||
"max_body": "50mb",
|
||||
"max_upload": 104857600,
|
||||
"morgan": "combined",
|
||||
"cors": "*",
|
||||
"ssl": {
|
||||
"enable": false,
|
||||
"cert": "",
|
||||
"key": ""
|
||||
}
|
||||
},
|
||||
"database": {
|
||||
"engine": "postgres",
|
||||
"host": "127.0.0.1",
|
||||
"port": "5432",
|
||||
"username": "postgres",
|
||||
"password": "123",
|
||||
"database": "bri_erp"
|
||||
}
|
||||
}
|
||||
0
config/prod.json
Normal file
0
config/prod.json
Normal file
29
config/stag.json
Normal file
29
config/stag.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"app": {
|
||||
"name": "Service Master Data",
|
||||
"description": "Purpose of this service is to provide master data product, master data suco and etc",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"server": {
|
||||
"port": "4001",
|
||||
"host": "0.0.0.0",
|
||||
"host_swagger": "127.0.0.1",
|
||||
"max_body": "50mb",
|
||||
"max_upload": 104857600,
|
||||
"morgan": "combined",
|
||||
"cors": "*",
|
||||
"ssl": {
|
||||
"enable": false,
|
||||
"cert": "/etc/letsencrypt/live/bri-dev.shiblysolution.id/fullchain.pem",
|
||||
"key": "/etc/letsencrypt/live/bri-dev.shiblysolution.id/privkey.pem"
|
||||
}
|
||||
},
|
||||
"database": {
|
||||
"engine": "postgres",
|
||||
"host": "127.0.0.1",
|
||||
"port": "5432",
|
||||
"username": "postgres",
|
||||
"password": "r00t@dm1n05",
|
||||
"database": "bri_erp"
|
||||
}
|
||||
}
|
||||
46
package.json
Normal file
46
package.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "Service master data",
|
||||
"version": "1.0.0",
|
||||
"description": "Purpose of this service is to provide master data product, master data suco and etc",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"dev": "nodemon",
|
||||
"build": "rimraf dist && tsc",
|
||||
"swagger": "node src/swagger/builder.js"
|
||||
},
|
||||
"keywords": [
|
||||
"BRI"
|
||||
],
|
||||
"author": "STS",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^2.4.3",
|
||||
"compression": "^1.7.5",
|
||||
"config": "^3.3.12",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.21.1",
|
||||
"express-jwt": "^8.4.1",
|
||||
"fast-csv": "^5.0.2",
|
||||
"helmet": "^8.0.0",
|
||||
"i": "^0.3.7",
|
||||
"joi": "^17.13.3",
|
||||
"morgan": "^1.10.0",
|
||||
"npm": "^10.9.1",
|
||||
"pg": "^8.13.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"swagger-autogen": "^2.23.7",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"tslog": "^4.9.3",
|
||||
"typeorm": "^0.3.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/compression": "^1.7.5",
|
||||
"@types/config": "^3.3.5",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/morgan": "^1.9.9",
|
||||
"@types/swagger-ui-express": "^4.1.7"
|
||||
}
|
||||
}
|
||||
526
src/controllers/user.ts
Normal file
526
src/controllers/user.ts
Normal file
@ -0,0 +1,526 @@
|
||||
import { Response, NextFunction, Application } from "express";
|
||||
import { Request } from "express-jwt";
|
||||
import { ReturnHelper } from "../helpers/express/return";
|
||||
import { OrmHelper } from "../helpers/orm";
|
||||
import { User } from "../entity/users";
|
||||
import Joi from "joi";
|
||||
import { ILogObj, Logger } from "tslog";
|
||||
import { Language } from "../langs/lang";
|
||||
import { Paging } from "../types/paging";
|
||||
import CommonHelper from "../helpers/common";
|
||||
import * as fastcsv from 'fast-csv';
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const log: Logger<ILogObj> = new Logger({ name: '[UserController]', type: 'pretty' });
|
||||
|
||||
export class UserController {
|
||||
static async list(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
||||
/*
|
||||
#swagger.tags = ['User']
|
||||
#swagger.parameters['filter'] = {
|
||||
in: 'query',
|
||||
type: 'string'
|
||||
}
|
||||
#swagger.parameters['limit'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
type: 'number'
|
||||
}
|
||||
#swagger.parameters['page'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
type: 'number'
|
||||
}
|
||||
#swagger.parameters['with_deleted'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
type: 'boolean'
|
||||
}
|
||||
#swagger.parameters['order_field'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
type: 'string'
|
||||
}
|
||||
#swagger.parameters['order_direction'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: {
|
||||
'@enum': ['ASC', 'DESC']
|
||||
}
|
||||
}
|
||||
#swagger.parameters['token'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
type: 'string'
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
filter: Joi.string().allow('').optional().label('Filter'),
|
||||
page: Joi.number().required().min(1).label('Page'),
|
||||
limit: Joi.number().required().min(1).label('Limit'),
|
||||
with_deleted: Joi.bool().required().label('With Deleted'),
|
||||
order_field: Joi.string().required().label('Order Field'),
|
||||
order_direction: Joi.string().allow('asc', 'desc').required().label('Order Direction'),
|
||||
token: Joi.string().required().label('Token'),
|
||||
});
|
||||
|
||||
const param: Paging = await schema.validateAsync(req.query);
|
||||
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
|
||||
const offset = (param.page - 1) * param.limit
|
||||
|
||||
let whereAttr = '';
|
||||
let whereVal: any = {};
|
||||
|
||||
if (param.filter) {
|
||||
whereAttr = 'name like :filter_like or username like :filter_like or email = :filter ';
|
||||
whereVal['filter'] = param.filter
|
||||
whereVal['filter_like'] = '%' + param.filter + '%'
|
||||
}
|
||||
|
||||
const res_count = userRepository.createQueryBuilder()
|
||||
.where(whereAttr, whereVal);
|
||||
const res_list = userRepository.createQueryBuilder()
|
||||
.where(whereAttr, whereVal)
|
||||
.orderBy(param.order_field, param.order_direction)
|
||||
.offset(offset)
|
||||
.limit(param.limit);
|
||||
|
||||
if (param.with_deleted) {
|
||||
res_count.withDeleted();
|
||||
res_list.withDeleted();
|
||||
}
|
||||
|
||||
const current_page = param.page;
|
||||
const total_count_data = await res_count.getCount();
|
||||
const list_data = await res_list.getMany();
|
||||
const count_data = CommonHelper.countObject(list_data);
|
||||
|
||||
return ReturnHelper.successResponselist(res, 200, Language.lang.success_view, count_data, current_page, total_count_data, list_data);
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
|
||||
return ReturnHelper.errorResponse(res, 400, 401, Language.lang.failed_view, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
static async export(req: Request, res: Response, next: NextFunction): Promise<void | Response> {
|
||||
/*
|
||||
#swagger.tags = ['User']
|
||||
#swagger.parameters['filter'] = {
|
||||
in: 'query',
|
||||
type: 'string'
|
||||
}
|
||||
#swagger.parameters['filter'] = {
|
||||
in: 'query',
|
||||
type: 'string'
|
||||
}
|
||||
#swagger.parameters['order_field'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
type: 'string'
|
||||
}
|
||||
#swagger.parameters['order_direction'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
schema: {
|
||||
'@enum': ['ASC', 'DESC']
|
||||
}
|
||||
}
|
||||
#swagger.parameters['token'] = {
|
||||
in: 'query',
|
||||
required: true,
|
||||
type: 'string'
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
filter: Joi.string().allow('').optional().label('Filter'),
|
||||
order_field: Joi.string().required().label('Order Field'),
|
||||
order_direction: Joi.string().allow('asc', 'desc').required().label('Order Direction'),
|
||||
token: Joi.string().required().label('Token'),
|
||||
});
|
||||
|
||||
const param: Paging = await schema.validateAsync(req.query);
|
||||
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
|
||||
let whereAttr = '';
|
||||
let whereVal: any = {};
|
||||
|
||||
if (param.filter) {
|
||||
whereAttr = 'name like :filter_like or username like :filter_like or email = :filter ';
|
||||
whereVal['filter'] = param.filter
|
||||
whereVal['filter_like'] = '%' + param.filter + '%'
|
||||
}
|
||||
|
||||
const filename = "user.csv";
|
||||
|
||||
res.setHeader('Content-Type', 'text/csv');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=' + filename);
|
||||
|
||||
const csvStream = fastcsv.format({
|
||||
headers: true,
|
||||
writeHeaders: true,
|
||||
transform: (row: User): any => ({
|
||||
...row,
|
||||
created_at: dayjs(row.created_at).format('DD-MM-YYYY HH:MM:ss'),
|
||||
})
|
||||
});
|
||||
csvStream.pipe(res);
|
||||
|
||||
const limit = 50;
|
||||
|
||||
const fetchAndWrite = async (page: any) => {
|
||||
const offset = (page - 1) * limit
|
||||
|
||||
const data = await userRepository.createQueryBuilder()
|
||||
.where(whereAttr, whereVal)
|
||||
.select([
|
||||
'id',
|
||||
'name',
|
||||
'email',
|
||||
'username',
|
||||
'status',
|
||||
'created_at'])
|
||||
.addSelect('(select role.name from user_roles role where role.id=User.id_role )', 'role_name')
|
||||
.orderBy(param.order_field, param.order_direction)
|
||||
.offset(offset)
|
||||
.limit(limit).getRawMany();
|
||||
|
||||
if (CommonHelper.countObject(data) === 0) {
|
||||
csvStream.end();
|
||||
} else {
|
||||
data.forEach((item: any) => csvStream.write(item));
|
||||
|
||||
if (CommonHelper.countObject(data) == limit) {
|
||||
fetchAndWrite(page + 1);
|
||||
} else {
|
||||
csvStream.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchAndWrite(1);
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
|
||||
return ReturnHelper.errorResponse(res, 400, 401, Language.lang.failed_view, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
static async create(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
||||
/*
|
||||
#swagger.tags = ['User']
|
||||
#swagger.security = [{
|
||||
"bearerAuth": []
|
||||
}]
|
||||
|
||||
#swagger.requestBody = {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
$ref: "#/components/schemas/user"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
email: Joi.string().email().max(64).required().label('Email'),
|
||||
username: Joi.string().max(64).required().label('Username'),
|
||||
password: Joi.string().alphanum().min(6).required().label('Password'),
|
||||
retype_password: Joi.ref('password'),
|
||||
name: Joi.string().max(64).required().label('Name'),
|
||||
id_role: Joi.string().uuid().required().label('Role'),
|
||||
status: Joi.string().required().label('Status'),
|
||||
});
|
||||
|
||||
const param: User = await schema.validateAsync(req.body);
|
||||
|
||||
const data = new User()
|
||||
data.name = param.name
|
||||
data.username = param.username
|
||||
data.password = param.password
|
||||
data.email = param.email
|
||||
data.id_role = param.id_role
|
||||
data.status = param.status
|
||||
|
||||
data.hashPassword();
|
||||
|
||||
await OrmHelper.DB.manager.save(data);
|
||||
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_insert, data);
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
|
||||
return ReturnHelper.errorResponse(res, 500, 401, Language.lang.failed_insert, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
static async updateProfile(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
||||
/*
|
||||
#swagger.tags = ['User']
|
||||
#swagger.security = [{
|
||||
"bearerAuth": []
|
||||
}]
|
||||
|
||||
#swagger.requestBody = {
|
||||
required: true,
|
||||
description: "This action will effect to user related token JWT logged",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
$ref: "#/components/schemas/user_profile"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
id: Joi.string().uuid().required().label('ID'),
|
||||
email: Joi.string().email().max(64).required().label('Email'),
|
||||
username: Joi.string().max(64).required().label('Username'),
|
||||
name: Joi.string().max(64).required().label('Name'),
|
||||
});
|
||||
|
||||
req.body.id = req.auth.data.id;
|
||||
|
||||
const param: User = await schema.validateAsync(req.body);
|
||||
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
|
||||
const data = await userRepository.findOneBy({ id: param.id });
|
||||
|
||||
if (data != null) {
|
||||
data.name = param.name
|
||||
data.username = param.username
|
||||
data.email = param.email
|
||||
|
||||
await userRepository.save(data);
|
||||
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_update, data);
|
||||
} else {
|
||||
return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, "");
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
|
||||
return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_update, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
static async updatePassword(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
||||
/*
|
||||
#swagger.tags = ['User']
|
||||
#swagger.security = [{
|
||||
"bearerAuth": []
|
||||
}]
|
||||
|
||||
#swagger.requestBody = {
|
||||
required: true,
|
||||
description: "This action will effect to user related token JWT logged",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
$ref: "#/components/schemas/user_password"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
id: Joi.string().uuid().required().label('ID'),
|
||||
password: Joi.string().required().label('Password'),
|
||||
retype_password: Joi.ref('password'),
|
||||
});
|
||||
|
||||
req.body.id = req.auth.data.id;
|
||||
|
||||
const param: User = await schema.validateAsync(req.body);
|
||||
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
|
||||
const data = await userRepository.findOneBy({ id: param.id });
|
||||
|
||||
if (data != null) {
|
||||
if (param.password) {
|
||||
data.password = param.password
|
||||
data.hashPassword();
|
||||
}
|
||||
|
||||
await userRepository.save(data);
|
||||
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_update, data);
|
||||
} else {
|
||||
return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, "");
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
|
||||
return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_update, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
static async update(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
||||
/*
|
||||
#swagger.tags = ['User']
|
||||
#swagger.security = [{
|
||||
"bearerAuth": []
|
||||
}]
|
||||
#swagger.parameters['id'] = {
|
||||
in: 'path',
|
||||
description: 'User ID.',
|
||||
required: true,
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
#swagger.requestBody = {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
$ref: "#/components/schemas/user"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
id: Joi.string().uuid().required().label('ID'),
|
||||
email: Joi.string().email().max(64).required().label('Email'),
|
||||
username: Joi.string().max(64).required().label('Username'),
|
||||
password: Joi.string().allow('').optional().label('Password'),
|
||||
retype_password: Joi.ref('password'),
|
||||
name: Joi.string().max(64).required().label('Name'),
|
||||
id_role: Joi.string().uuid().required().label('Role'),
|
||||
status: Joi.string().required().label('Status'),
|
||||
});
|
||||
|
||||
req.body.id = req.params['id'];
|
||||
|
||||
const param: User = await schema.validateAsync(req.body);
|
||||
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
|
||||
const data = await userRepository.findOneBy({ id: param.id });
|
||||
|
||||
if (data != null) {
|
||||
data.name = param.name
|
||||
data.username = param.username
|
||||
data.email = param.email
|
||||
data.id_role = param.id_role
|
||||
data.status = param.status
|
||||
|
||||
if (param.password) {
|
||||
data.password = param.password
|
||||
data.hashPassword();
|
||||
}
|
||||
|
||||
await userRepository.save(data);
|
||||
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_update, data);
|
||||
} else {
|
||||
return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, "");
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
|
||||
return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_update, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
static async delete(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
||||
/*
|
||||
#swagger.tags = ['User']
|
||||
#swagger.security = [{
|
||||
"bearerAuth": []
|
||||
}]
|
||||
#swagger.parameters['id'] = {
|
||||
in: 'path',
|
||||
description: 'User ID.',
|
||||
required: true,
|
||||
type: 'string'
|
||||
}
|
||||
*/
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
id: Joi.string().uuid().required().label('ID')
|
||||
});
|
||||
|
||||
const param: User = await schema.validateAsync(req.params);
|
||||
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
|
||||
const affected = (await userRepository.softDelete({ id: param.id })).affected;
|
||||
|
||||
if (affected > 0) {
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_delete, {});
|
||||
} else {
|
||||
return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, "");
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
|
||||
return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_delete, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
static async restore(req: Request, res: Response, next: NextFunction): Promise<Response> {
|
||||
/*
|
||||
#swagger.tags = ['User']
|
||||
#swagger.security = [{
|
||||
"bearerAuth": []
|
||||
}]
|
||||
|
||||
#swagger.parameters['id'] = {
|
||||
in: 'path',
|
||||
description: 'User ID.',
|
||||
required: true,
|
||||
type: 'string'
|
||||
}
|
||||
*/
|
||||
try {
|
||||
const schema = Joi.object().keys({
|
||||
id: Joi.string().uuid().required().label('ID')
|
||||
});
|
||||
|
||||
const param: User = await schema.validateAsync(req.params);
|
||||
|
||||
const userRepository = OrmHelper.DB.getRepository(User);
|
||||
|
||||
const affected = (await userRepository.restore({ id: param.id })).affected;
|
||||
|
||||
if (affected > 0) {
|
||||
return ReturnHelper.successResponseAny(res, 200, Language.lang.success_restore, {});
|
||||
} else {
|
||||
return ReturnHelper.errorResponse(res, 404, 401, Language.lang.failed_not_found, "");
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
log.error(e);
|
||||
const err = e as Error;
|
||||
|
||||
return ReturnHelper.errorResponse(res, 500, 402, Language.lang.failed_restore, err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/helpers/common.ts
Normal file
66
src/helpers/common.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { Logger, ILogObj } from 'tslog';
|
||||
|
||||
const log: Logger<ILogObj> = new Logger({ name: '[CommonHelper]', type: 'pretty' });
|
||||
|
||||
export default class CommonHelper {
|
||||
static randomInteger(min: number, max: number): number | null {
|
||||
if (min > 0 && max > 0) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
} else {
|
||||
log.error(new Error('Min & Max must be > 0'));
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
static inArray(array: string[], keyword: string): boolean {
|
||||
for (let val of array) {
|
||||
if (val === keyword) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static async sleep(seconds: number): Promise<void> {
|
||||
if (seconds > 0) {
|
||||
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
|
||||
} else {
|
||||
log.error(new Error('Second must be > 0'));
|
||||
}
|
||||
}
|
||||
|
||||
static convertArrayToObject(object: any, key: string, val = ''): any {
|
||||
const ret: any = {};
|
||||
|
||||
for (let i in object) {
|
||||
const d = object[i];
|
||||
|
||||
if (val) {
|
||||
ret[d[key]] = d[val];
|
||||
} else {
|
||||
ret[d[key]] = d;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static countObject(obj: any): number {
|
||||
let c = 0;
|
||||
|
||||
for (let s in obj) {
|
||||
c++;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static capitalizeFirstLetter(str: string): string {
|
||||
if (str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
14
src/helpers/express/compression.ts
Normal file
14
src/helpers/express/compression.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import cors from 'cors';
|
||||
import express from 'express';
|
||||
import compression from 'compression';
|
||||
|
||||
export class CompressionHelper {
|
||||
static setup(app: express.Application) {
|
||||
const compressionOptions: compression.CompressionOptions = {
|
||||
level: 6,
|
||||
memLevel: 8
|
||||
};
|
||||
|
||||
app.use(compression(compressionOptions));
|
||||
}
|
||||
}
|
||||
14
src/helpers/express/cors.ts
Normal file
14
src/helpers/express/cors.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import config from 'config';
|
||||
import cors from 'cors';
|
||||
import express from 'express';
|
||||
|
||||
export class CorsHelper {
|
||||
static setup(app: express.Application) {
|
||||
const corsOptions: cors.CorsOptions = {
|
||||
origin: config.get('server.cors'),
|
||||
optionsSuccessStatus: 200,
|
||||
};
|
||||
|
||||
app.use(cors(corsOptions));
|
||||
}
|
||||
}
|
||||
12
src/helpers/express/json.ts
Normal file
12
src/helpers/express/json.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import config from 'config';
|
||||
import express from 'express';
|
||||
|
||||
export class JsonHelper {
|
||||
static setup(app: express.Application) {
|
||||
app.use(
|
||||
express.json({
|
||||
limit: config.get('server.max_body'),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
9
src/helpers/express/morgan.ts
Normal file
9
src/helpers/express/morgan.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import config from 'config';
|
||||
import morgan from 'morgan';
|
||||
import express from 'express';
|
||||
|
||||
export class MorganHelper {
|
||||
static setup(app: express.Application) {
|
||||
app.use(morgan(config.get('server.morgan')));
|
||||
}
|
||||
}
|
||||
58
src/helpers/express/return.ts
Normal file
58
src/helpers/express/return.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { Response } from 'express';
|
||||
import { ErrorType, ErrorValidation } from '../../types/error';
|
||||
|
||||
export class ReturnHelper {
|
||||
static successResponseAny(
|
||||
res: Response,
|
||||
status_code: number,
|
||||
message: string,
|
||||
data: any = null
|
||||
): Response {
|
||||
|
||||
return res.status(status_code || 200).json({
|
||||
status: true,
|
||||
code: status_code || 200,
|
||||
message: message || "success",
|
||||
data: data || {},
|
||||
});
|
||||
};
|
||||
|
||||
static successResponselist(
|
||||
res: Response,
|
||||
status_code: number,
|
||||
message: string,
|
||||
count_data: number = 0,
|
||||
current_page: number = 0,
|
||||
total_count_data: number = 0,
|
||||
list_data: any = null
|
||||
): Response {
|
||||
|
||||
return res.status(status_code || 200).json({
|
||||
status: true,
|
||||
code: status_code || 200,
|
||||
message: message || "success",
|
||||
data: {
|
||||
count: count_data,
|
||||
page: current_page,
|
||||
total_count: total_count_data,
|
||||
list: list_data
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
static errorResponse(
|
||||
res: Response,
|
||||
status_code: number,
|
||||
error_code: number,
|
||||
message: string,
|
||||
error: any = null
|
||||
): Response {
|
||||
|
||||
return res.status(status_code || 200).json({
|
||||
status: false,
|
||||
error_code: error_code || 400,
|
||||
message: message || "success",
|
||||
error: error,
|
||||
});
|
||||
};
|
||||
}
|
||||
14
src/helpers/express/swagger.ts
Normal file
14
src/helpers/express/swagger.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import config from 'config';
|
||||
import express from 'express';
|
||||
import swaggerUi from 'swagger-ui-express';
|
||||
import swaggerDocument from '../../swagger/swagger.json';
|
||||
|
||||
export class SwaggerHelper {
|
||||
static setup(app: express.Application) {
|
||||
var options = {
|
||||
explorer: false
|
||||
};
|
||||
|
||||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
|
||||
}
|
||||
}
|
||||
13
src/helpers/express/urlencoded.ts
Normal file
13
src/helpers/express/urlencoded.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import config from 'config';
|
||||
import express from 'express';
|
||||
|
||||
export class UrlencodedHelper {
|
||||
static setup(app: express.Application) {
|
||||
app.use(
|
||||
express.urlencoded({
|
||||
extended: true,
|
||||
limit: config.get('server.max_body'),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
38
src/helpers/jwt.ts
Normal file
38
src/helpers/jwt.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { NextFunction, Response } from 'express';
|
||||
import { Logger, ILogObj } from 'tslog';
|
||||
import { Request, expressjwt } from "express-jwt";
|
||||
import fs from 'fs';
|
||||
import { Language } from '../langs/lang';
|
||||
import { ReturnHelper } from './express/return';
|
||||
import express from 'express';
|
||||
|
||||
const log: Logger<ILogObj> = new Logger({ name: '[JwtHelper]', type: 'pretty' });
|
||||
|
||||
export default class JwtHelper {
|
||||
static secure = (app: express.Application) => {
|
||||
|
||||
var publicKey = fs.readFileSync("src/helpers/key/public.key");
|
||||
|
||||
app.use(
|
||||
expressjwt({
|
||||
secret: publicKey, algorithms: ["RS256"]
|
||||
}).unless({ path: ["/token"] }),
|
||||
function (req: Request, res: Response, next: NextFunction) {
|
||||
if (!req.auth?.data.id) {
|
||||
return ReturnHelper.errorResponse(res, 403, 666, Language.lang.failed_access);
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
)
|
||||
|
||||
app.use(function (err: any, req: Request, res: Response, next: NextFunction) {
|
||||
if (err.name === 'UnauthorizedError') {
|
||||
return ReturnHelper.errorResponse(res, 403, 666, Language.lang.failed_access);
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
28
src/helpers/key/private.key
Normal file
28
src/helpers/key/private.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC0sdcneY7W32xE
|
||||
8hbjFPR4/AZFdtQqwQ3lEsuUFcsYh2KR0wP0umqtIMGLle3603lhQ/AMXDlKBBJt
|
||||
IAP1SJNvGYY6fUdm+AZ0NFmst3CCiFsw7N5F+KXKEW1g/vUO9OKJ2Hg9lXuOkYAh
|
||||
DYv+d0R5nsHu5l7WAesHtrcuNwezmENeAwjgWNezlwJmf54soNrV+EE7zPxTyye1
|
||||
se3b8LjMgB/zDTF2UkdrvrVulpshG0JMvDy1n7QG/+K3u3BcGakRws5GZu7LZug4
|
||||
ZNdURajL0oqN9bxPQRWR5+7jVqm1gYNRGQfPJuBXUiqd/AXa+ap0M0RPBFWfomjf
|
||||
xn21QpdVAgMBAAECggEAKUMRHCEMhrG3YhkcM9fFqdj3P6aOdYLnPt+nYFYHrj7A
|
||||
OgeDOD/Xe1hnCg5/LQ9cgOMILnJi3K2IXaX5cWoUzMJ53eJcyz0pECEiNygeh5hG
|
||||
pqn4aecJSNbo8MTXxgYSsyKc9ocrk1dTeHjE9qNaniEsLPcrQdhnSLgnJWUIm7Bv
|
||||
HqFFhgINdbZmE3Wx0a1Y71jGePcm3Zqx0a5sZDmZN2Vh7fNs1X8y2rnNvsKOBG5T
|
||||
RmB8zlnj5SkjtD9RKkis0gGDVGjtkfskClY6wARUgSajfJnBAwpbdqrR0bmOox5k
|
||||
T39aL6dxcPBQc8L0HX1sYW4yCIba1snxOUXtLEjdkQKBgQDwepPKv09waBlp7Q5W
|
||||
c7Fn5dLBJ8ungbeDf83jZbIUs2I0wJ0v/UJiUegVP/h005kpEyY9NjFhcN5GXnTo
|
||||
Ru1jmZ2w0UC+iOa7+JplXsS7kZfieaPIWHcmg0IkQpWHXRjoeWrd2dA+unc+6BGf
|
||||
ZvUlb9XPZBATShARnjHu1z5CiQKBgQDAW3PBjLwgrT7NlRkpjuLMEvzimso1yTKa
|
||||
yYdTNhJYkz5YnlPeu197seqqeGQPuRuR9KlMjfe7IQOvo0AGNB7VMxCxfF0Obyb9
|
||||
hBT5fFci5dweKqgN3bR/+ppj/bpLS0veMwYNKzhaHsMrwRQzaxrRypRkri2rT7dx
|
||||
jZAI0ilrbQKBgGmk//5m80gng1qkmNLj+oDxVxgiGnbZJryvTczjZUtwzujr4WIu
|
||||
uZYl83Y6ZzUzrCp+TiNABouPISb64hMU7b7+wmbmVrIdxHe5rGJyMq1QNdB5rbkb
|
||||
HCUgLtNtKPGRtZqTlJ4nzTNxiWdqXiuP+IxcyCpXBDTlKZAD1l3d0205AoGBAJTk
|
||||
NO2UKeqBLyOiTR/F4fdkmyor9mk7m1gEtiLKr9iv4IpnwzOchYQRazsYhRtGhPit
|
||||
EH6ZRTArldbV3jDvFw6fwEQhp0YM83k4S6PxguEYWxFeo0ZYXebR67+KHjE5zzfm
|
||||
9sAqvCvFs/yiLyi9try8ubBUwjTgN3ZFxT+OrVDhAoGAUhFkd/Fy0FCsMROPKK5l
|
||||
uadRukj5zKLMw+JJegXO+0AntV2vWPam73x2ulvVig9TqrJLqtOfqYNNX789Fzri
|
||||
PBcqDaMJKfMc6ac7YgZTNP6vk7avjqWUpoJqlj1g8y3suAYkm/xfLd1HvAqQh0p8
|
||||
i3/cmSzkc1MCE2YxYop0gpc=
|
||||
-----END PRIVATE KEY-----
|
||||
9
src/helpers/key/public.key
Normal file
9
src/helpers/key/public.key
Normal file
@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtLHXJ3mO1t9sRPIW4xT0
|
||||
ePwGRXbUKsEN5RLLlBXLGIdikdMD9LpqrSDBi5Xt+tN5YUPwDFw5SgQSbSAD9UiT
|
||||
bxmGOn1HZvgGdDRZrLdwgohbMOzeRfilyhFtYP71DvTiidh4PZV7jpGAIQ2L/ndE
|
||||
eZ7B7uZe1gHrB7a3LjcHs5hDXgMI4FjXs5cCZn+eLKDa1fhBO8z8U8sntbHt2/C4
|
||||
zIAf8w0xdlJHa761bpabIRtCTLw8tZ+0Bv/it7twXBmpEcLORmbuy2boOGTXVEWo
|
||||
y9KKjfW8T0EVkefu41aptYGDURkHzybgV1IqnfwF2vmqdDNETwRVn6Jo38Z9tUKX
|
||||
VQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
37
src/helpers/orm.ts
Normal file
37
src/helpers/orm.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import config from 'config';
|
||||
import { DataSource } from "typeorm";
|
||||
import { User } from "../entity/users";
|
||||
import { TrialBalance } from '../entity/trial_balance';
|
||||
import { ILogObj, Logger } from 'tslog';
|
||||
import { LNKOLEK } from '../entity/lnkolek';
|
||||
import { CifAccount } from '../entity/cif_account';
|
||||
|
||||
export class OrmHelper {
|
||||
static DB: DataSource = null
|
||||
|
||||
static setup() {
|
||||
const log: Logger<ILogObj> = new Logger({ name: '[OrmHelper]', type: 'pretty' });
|
||||
|
||||
const engine: 'mysql' | 'postgres' = config.get("database.engine")
|
||||
|
||||
OrmHelper.DB = new DataSource({
|
||||
type: engine,
|
||||
host: config.get("database.host"),
|
||||
port: Number(config.get("database.port")),
|
||||
username: String(config.get("database.username")),
|
||||
password: String(config.get("database.password")),
|
||||
database: String(config.get("database.database")),
|
||||
synchronize: true,
|
||||
logging: true,
|
||||
entities: [User, TrialBalance, LNKOLEK, CifAccount],
|
||||
subscribers: [],
|
||||
migrations: [],
|
||||
})
|
||||
|
||||
OrmHelper.DB.initialize()
|
||||
.then(() => {
|
||||
// here you can start to work with your database
|
||||
})
|
||||
.catch((error: any) => log.error(error))
|
||||
}
|
||||
}
|
||||
36
src/index.ts
Normal file
36
src/index.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { Logger, ILogObj } from "tslog";
|
||||
import { app } from "./server";
|
||||
import config from 'config'
|
||||
import https from 'https';
|
||||
import fs from 'fs';
|
||||
|
||||
|
||||
const log: Logger<ILogObj> = new Logger({ name: '[Index]', type: 'pretty' });
|
||||
|
||||
const HOST = config.get('server.host')
|
||||
const PORT = Number(config.get('server.port'))
|
||||
|
||||
const server = app.listen(config.get('server.ssl.enable') ? PORT + 1000 : PORT, String(HOST), () => {
|
||||
log.info(`Server ${config.get('app.name')} running on port http://${HOST}:${PORT}`);
|
||||
});
|
||||
|
||||
if (config.get('server.ssl.enable')) {
|
||||
const options = {
|
||||
cert: fs.readFileSync(config.get('server.ssl.cert')),
|
||||
key: fs.readFileSync(config.get('server.ssl.key'))
|
||||
};
|
||||
|
||||
https.createServer(options, app).listen(PORT);
|
||||
}
|
||||
|
||||
const onCloseSignal = () => {
|
||||
log.info("sigint received, shutting down");
|
||||
server.close(() => {
|
||||
log.info("server closed");
|
||||
process.exit();
|
||||
});
|
||||
setTimeout(() => process.exit(1), 10000).unref(); // Force shutdown after 10s
|
||||
};
|
||||
|
||||
process.on("SIGINT", onCloseSignal);
|
||||
process.on("SIGTERM", onCloseSignal);
|
||||
32
src/langs/json/en.json
Normal file
32
src/langs/json/en.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"success_insert": "Data has been successfully inserted",
|
||||
"success_update": "Data has been successfully updated",
|
||||
"success_delete": "Data has been successfully deleted",
|
||||
"success_restore": "Data has been successfully restored",
|
||||
"success_view": "Data has been successfully fetched",
|
||||
"success": "Operation has been success",
|
||||
"success_valid_otp": "Operation has been success, valid for 1 minutes",
|
||||
"failed": "Operation has been failed",
|
||||
"failed_access": "You're not allowed to acces",
|
||||
"failed_access_otp": "Please provide valid OTP code",
|
||||
"failed_expired_otp": "Your OTP has been expired, Please provide valid OTP code",
|
||||
"failed_access_pin": "Please provide valid PIN code",
|
||||
"failed_try_pin": "Maximum try has been reached, please re-login MyTelkomcel",
|
||||
"failed_insert": "Data has been NOT successfully inserted",
|
||||
"failed_update": "Data has been NOT successfully updated",
|
||||
"failed_delete": "Data has been NOT successfully deleted",
|
||||
"failed_restore": "Data has been NOT successfully restored",
|
||||
"failed_save": "Data has been NOT successfully saved",
|
||||
"failed_view": "Data has been NOT successfully fetched",
|
||||
"failed_empty": "Data empty",
|
||||
"failed_data": "Please provide valid data",
|
||||
"failed_duplicate": "Duplicate data, please provide valid data",
|
||||
"failed_not_found": "Data not found, please provide valid data",
|
||||
"success_login": "Login Successfully",
|
||||
"failed_password": "Please provide valid password",
|
||||
"failed_limit_otp": "Please send OTP 1 minutes later",
|
||||
"failed_limit_link_code": "Please send verification link 1 minutes later",
|
||||
"failed_expired_token": "Token has been expired",
|
||||
"failed_token": "Your session has been expired, please re-login",
|
||||
"failed_add_point": "Add point failed, please try again later"
|
||||
}
|
||||
65
src/langs/lang.ts
Normal file
65
src/langs/lang.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
|
||||
interface LanguageValue {
|
||||
success_insert?: string;
|
||||
success_update?: string;
|
||||
success_delete?: string;
|
||||
success_restore?: string;
|
||||
success_view?: string;
|
||||
success?: string;
|
||||
success_valid_otp?: string;
|
||||
|
||||
failed?: string;
|
||||
failed_access?: string;
|
||||
failed_access_otp?: string;
|
||||
failed_expired_otp?: string;
|
||||
failed_access_pin?: string;
|
||||
failed_try_pin?: string;
|
||||
failed_insert?: string;
|
||||
failed_update?: string;
|
||||
failed_delete?: string;
|
||||
failed_restore?: string;
|
||||
failed_save?: string;
|
||||
failed_view?: string;
|
||||
failed_empty?: string;
|
||||
failed_data?: string;
|
||||
failed_duplicate?: string;
|
||||
failed_not_found?: string;
|
||||
failed_limit_otp?: string;
|
||||
failed_limit_link_code?: string;
|
||||
failed_expired_token?: string;
|
||||
failed_token?: string;
|
||||
failed_add_point?: string;
|
||||
|
||||
//login
|
||||
success_login?: string;
|
||||
failed_password?: string;
|
||||
}
|
||||
|
||||
export class Language {
|
||||
static lang_init: LanguageValue = {};
|
||||
static lang: LanguageValue = {};
|
||||
|
||||
static setup() {
|
||||
const fileLang: any = fs.readFileSync(
|
||||
path.join(__dirname, '../langs/json/en.json')
|
||||
);
|
||||
Language.lang_init['en'] = JSON.parse(fileLang.toString('utf8'));
|
||||
}
|
||||
|
||||
static apply = (req: Request, res: Response, next: NextFunction) => {
|
||||
const acceptLanguageHeader = req.get('Accept-Language') as string | null;
|
||||
if (!acceptLanguageHeader) {
|
||||
//default
|
||||
req.params.language = 'en';
|
||||
} else {
|
||||
req.params.language = acceptLanguageHeader.substring(0, 2).toLowerCase();
|
||||
}
|
||||
|
||||
Language.lang = Language.lang_init[req.params.language];
|
||||
|
||||
return next();
|
||||
}
|
||||
}
|
||||
12
src/routes/private.ts
Normal file
12
src/routes/private.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import express from 'express';
|
||||
import { Language } from '../langs/lang';
|
||||
import JwtHelper from '../helpers/jwt';
|
||||
|
||||
export class RoutePrivate {
|
||||
static setup(app: express.Application) {
|
||||
|
||||
// app.use(Language.apply)
|
||||
|
||||
JwtHelper.secure(app);
|
||||
}
|
||||
}
|
||||
17
src/routes/public.ts
Normal file
17
src/routes/public.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import express from 'express';
|
||||
import { UserController } from '../controllers/user';
|
||||
import { Language } from '../langs/lang';
|
||||
|
||||
export class RoutePublic {
|
||||
static setup(app: express.Application) {
|
||||
|
||||
app.use(Language.apply)
|
||||
|
||||
app.get('/api/user/list', UserController.list)
|
||||
app.get('/api/user/export', UserController.export)
|
||||
app.post('/api/user/create', UserController.create)
|
||||
app.put('/api/user/update/:id', UserController.update)
|
||||
app.delete('/api/user/delete/:id', UserController.delete)
|
||||
app.put('/api/user/restore/:id', UserController.restore)
|
||||
}
|
||||
}
|
||||
26
src/server.ts
Normal file
26
src/server.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import express from 'express';
|
||||
import { CorsHelper } from './helpers/express/cors';
|
||||
import { CompressionHelper } from './helpers/express/compression';
|
||||
import { MorganHelper } from './helpers/express/morgan';
|
||||
import { JsonHelper } from './helpers/express/json';
|
||||
import { UrlencodedHelper } from './helpers/express/urlencoded';
|
||||
import { OrmHelper } from './helpers/orm';
|
||||
import { RoutePrivate } from './routes/private';
|
||||
import { RoutePublic } from './routes/public';
|
||||
import { Language } from './langs/lang';
|
||||
import { SwaggerHelper } from './helpers/express/swagger';
|
||||
|
||||
const app = express();
|
||||
|
||||
CorsHelper.setup(app);
|
||||
CompressionHelper.setup(app);
|
||||
MorganHelper.setup(app);
|
||||
JsonHelper.setup(app);
|
||||
UrlencodedHelper.setup(app);
|
||||
OrmHelper.setup();
|
||||
Language.setup();
|
||||
SwaggerHelper.setup(app);
|
||||
RoutePublic.setup(app);
|
||||
RoutePrivate.setup(app);
|
||||
|
||||
export { app };
|
||||
17
src/swagger/builder.js
Normal file
17
src/swagger/builder.js
Normal file
@ -0,0 +1,17 @@
|
||||
const swaggerAutogen = require('swagger-autogen')();
|
||||
const config = require('config');
|
||||
|
||||
const doc = {
|
||||
info: {
|
||||
title: config.get('app.name'),
|
||||
description: config.get('app.description'),
|
||||
version: config.get('app.version')
|
||||
},
|
||||
host: config.get('server.host_swagger') + ':' + config.get('server.port'),
|
||||
};
|
||||
|
||||
const outputFile = './swagger.json';
|
||||
const routes = ['../routes/private.ts', '../routes/public.ts'];
|
||||
|
||||
swaggerAutogen(outputFile, routes, doc);
|
||||
|
||||
3
src/types/error.ts
Normal file
3
src/types/error.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export type ErrorType = 'General' | 'Raw' | 'Validation' | 'Unauthorized';
|
||||
|
||||
export type ErrorValidation = { [key: string]: string };
|
||||
8
src/types/paging.ts
Normal file
8
src/types/paging.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface Paging {
|
||||
page: number,
|
||||
limit: number,
|
||||
filter: any,
|
||||
with_deleted: boolean,
|
||||
order_field: string,
|
||||
order_direction: 'ASC' | 'DESC'
|
||||
}
|
||||
1
src/types/role.ts
Normal file
1
src/types/role.ts
Normal file
@ -0,0 +1 @@
|
||||
export type Role = 'ADMINISTRATOR' | 'HR' | 'STAFF';
|
||||
4
src/types/status.ts
Normal file
4
src/types/status.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum Status {
|
||||
"Active" = "Y",
|
||||
"Not Active" = "N"
|
||||
};
|
||||
23
tsconfig.json
Normal file
23
tsconfig.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"lib": ["dom", "es6", "es2017", "esnext.asynciterable"],
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./",
|
||||
"moduleResolution": "node",
|
||||
"removeComments": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"resolveJsonModule": true,
|
||||
"typeRoots": ["./src/types", "./node_modules/@types"],
|
||||
// "baseUrl": "src/",
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src/swagger-output.json", "src/langs/json/*.json", "./src/**/*.tsx", "./src/**/*.ts"],
|
||||
"exclude": ["node_modules", "test/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user