This commit is contained in:
2025-12-10 13:46:12 +07:00
commit eb34980465
36 changed files with 2780 additions and 0 deletions

505
src/controllers/event.ts Normal file
View File

@ -0,0 +1,505 @@
import config from "config";
// import { LogHikvision } from "entity";
import { NextFunction, Response } from "express";
import { Request } from 'express-jwt';
import moment from "moment";
import { ILogObj, Logger } from "tslog";
import { ReturnHelper } from "../helpers/express/return";
import { OrmHelper } from "../helpers/orm";
// import Thirdparty from "../helpers/thirdparty";
import { Language } from "../langs/lang";
import { Between, Or } from "typeorm";
import { AttendanceDoorInfo, AttendanceDoorLog } from "entity";
import Joi from "joi";
import { Employee } from "entity";
const log: Logger<ILogObj> = new Logger({ name: '[EventController]', type: 'pretty' });
export class EventController {
static async indexold(req: Request, res: Response, next: NextFunction): Promise<Response> {
/*
#swagger.tags = ['Event']
*/
try {
let param: any = req.body
let dtPost: any = {}
let data: any = null;
const attendancedoorlogrepo = OrmHelper.DB.getRepository(AttendanceDoorLog);
// console.log('Request : ', req)
// console.log('param : ', param)
let eventLog: any = {};
let dateTime: any = null;
let originalTimezone: string = null;
let originalDate: string = null;
let originalTime: string = null;
if (param.event_log) {
eventLog = JSON.parse(param.event_log)
// console.log('eventLog:', eventLog)
let employeeId = eventLog.AccessControllerEvent.employeeNoString
if (!employeeId) throw { message: 'NO_EMPLOYEE_NO_STRING_ON_EVENT' }
// 0|svc-hcmbridge | eventLog: {
// 0|svc-hcmbridge | ipAddress: '172.16.110.242',
// 0|svc-hcmbridge | ipv6Address: 'fe80::603:12ff:fe2e:4f8d',
// 0|svc-hcmbridge | portNo: 3000,
// 0|svc-hcmbridge | protocol: 'HTTP',
// 0|svc-hcmbridge | macAddress: '04:03:12:2e:4f:8d',
// 0|svc-hcmbridge | channelID: 1,
// 0|svc-hcmbridge | dateTime: '2025-05-29T09:22:40+08:00',
// 0|svc-hcmbridge | activePostCount: 1,
// 0|svc-hcmbridge | eventType: 'AccessControllerEvent',
// 0|svc-hcmbridge | eventState: 'active',
// 0|svc-hcmbridge | eventDescription: 'Access Controller Event',
// 0|svc-hcmbridge | AccessControllerEvent: {
// 0|svc-hcmbridge | deviceName: 'DeviceOut',
// 0|svc-hcmbridge | majorEventType: 5,
// 0|svc-hcmbridge | subEventType: 22,
// 0|svc-hcmbridge | cardReaderKind: 1,
// 0|svc-hcmbridge | doorNo: 1,
// 0|svc-hcmbridge | serialNo: 21403,
// 0|svc-hcmbridge | currentVerifyMode: 'invalid',
// 0|svc-hcmbridge | frontSerialNo: 21402,
// 0|svc-hcmbridge | attendanceStatus: 'undefined',
// 0|svc-hcmbridge | label: '',
// 0|svc-hcmbridge | statusValue: 0,
// 0|svc-hcmbridge | mask: 'unknown',
// 0|svc-hcmbridge | purePwdVerifyEnable: true
// 0|svc-hcmbridge | }
dateTime = moment.parseZone(eventLog.dateTime);
originalDate = dateTime.format("YYYY-MM-DD"); // Extract the date
originalTime = dateTime.format("HH:mm:ss"); // Extract the time
originalTimezone = dateTime.format("Z"); // Extract the timezone
dtPost = {
"accessdoorid": employeeId,
"datelogs": originalDate + ' ' + originalTime,
"ipaddress": eventLog.ipAddress,
"macaddress": eventLog.macAddress,
"devicename": eventLog.AccessControllerEvent.deviceName,
"doornumber": eventLog.AccessControllerEvent.doorNo,
"iby": 'system',
"idt": new Date()
}
// log.info('dtpost:', JSON.stringify(dtPost))
// let url = config.get('service.hrms') + 'api/sync-attendance'
// // log.info(url)
// let result = await Thirdparty.PostData(url, dtPost)
// // log.info('result:', JSON.stringify(result))
// const data = new LogHikvision()
// data.incoming = JSON.stringify(param.event_log)
// data.request = JSON.stringify(dtPost)
// data.url = url
// data.response = JSON.stringify(result)
// await OrmHelper.DB.manager.save(data);
}
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0);
const endOfToday = new Date();
endOfToday.setHours(23, 59, 59, 999);
// console.log('dtPost:', JSON.stringify(dtPost))
if (eventLog?.AccessControllerEvent?.deviceName === 'DeviceOut') {
const datalogsbefore = await attendancedoorlogrepo.findOne({
where: {
accessdoorid: dtPost.accessdoorid,
devicename: "DeviceIn",
datelogs: Between(startOfToday, endOfToday),
},
order: { datelogs: "DESC" },
});
// const datalogsbefore = await attendancedoorlogrepo
// .createQueryBuilder("log")
// .where("log.accessdoorid = :accessdoorid", { accessdoorid: dtPost.accessdoorid })
// .andWhere("log.devicename = :devicename", { devicename: "DeviceOut" })
// .andWhere("DATE(log.datelogs) = CURDATE()")
// .orderBy("log._idx", "DESC")
// .getOne();
if (datalogsbefore != null && datalogsbefore !== undefined) {
// data = await attendancedoorlogrepo.save(dtPost);
const previousDate = new Date(datalogsbefore.datelogs);
const timezone = new Date(originalDate + ' ' + originalTime);
const timeDiffSeconds = Math.floor((timezone.getTime() - previousDate.getTime()) / 1000);
// if(timeDiffSeconds<=50){
if ((timeDiffSeconds <= 50)) {
if (dtPost.accessdoorid == 34) {
if (dtPost.ipaddress == '172.16.110.245') {
console.log('datalogsbefore OUT:', datalogsbefore);
console.log("Interval (OUT) in seconds:", timeDiffSeconds);
}
}
return ReturnHelper.successResponseAny(res, 500, "Internal server error", {});
}
// data = await attendancedoorlogrepo.update({ idx: datalogsbefore.idx }, { datelogs: originalDate + ' ' + originalTime });
// }
// else {
// data = await attendancedoorlogrepo.save(dtPost);
}
}
// else {
// // const datalogsbefore = await attendancedoorlogrepo.findOne({
// // where: {
// // accessdoorid: dtPost.accessdoorid,
// // devicename: "DeviceOut",
// // datelogs : new Date(),
// // },
// // order: { idx: "DESC" },
// // });
// // const datalogsbefore = await attendancedoorlogrepo
// // .createQueryBuilder("log")
// // .where("log.accessdoorid = :accessdoorid", { accessdoorid: dtPost.accessdoorid })
// // .andWhere("log.devicename = :devicename", { devicename: "DeviceIn" })
// // .andWhere("DATE(log.datelogs) = CURDATE()")
// // .orderBy("log._idx", "DESC")
// // .getOne();
// const datalogsbefore = await attendancedoorlogrepo.findOne({
// where: {
// accessdoorid: dtPost.accessdoorid,
// // devicename: "DeviceOut",
// datelogs: Between(startOfToday, endOfToday),
// },
// order: { datelogs: "DESC" },
// });
// if (datalogsbefore != null && datalogsbefore !== undefined) {
// const previousDate = new Date(datalogsbefore.datelogs);
// const timezone = new Date(originalDate + ' ' + originalTime);
// const timeDiffSeconds = Math.floor((timezone.getTime() - previousDate.getTime()) / 1000);
// // if(timeDiffSeconds>=0 && timeDiffSeconds<=10){
// // if(timeDiffSeconds<=50){
// if ((datalogsbefore.devicename === 'DeviceOut' && timeDiffSeconds <= 50) || datalogsbefore.devicename === 'DeviceIn') {
// console.log("Interval (IN) in seconds:", timeDiffSeconds);
// return ReturnHelper.successResponseAny(res, 500, "Internal server error", {});
// }
// // console.log('datalogsbefore IN : ', datalogsbefore)
// // data = await attendancedoorlogrepo.update({ idx: datalogsbefore.idx }, { datelogs: originalDate + ' ' + originalTime });
// // }
// // else {
// // data = await attendancedoorlogrepo.save(dtPost);
// }
// // data = await attendancedoorlogrepo.save(dtPost);
// }
data = (dtPost ? await attendancedoorlogrepo.save(dtPost) : {});
return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
} catch (e: unknown) {
log.error(e);
const err = e as Error;
return ReturnHelper.successResponseAny(res, 200, Language.lang.failed, err.message);
}
}
static async index(req: Request, res: Response, next: NextFunction): Promise<Response> {
/*
#swagger.tags = ['Event']
*/
try {
let param: any = req.body
let dtPost: any = {}
let data: any = null;
// console.log('Request : ', req)
// console.log('param : ', param.event_log)
const attendancedoorlogrepo = OrmHelper.DB.getRepository(AttendanceDoorLog);
let eventLog: any = {};
let dateTime: any = null;
let originalTimezone: string = null;
let originalDate: string = null;
let originalTime: string = null;
let employeeId: string = null;
let formattedDuration = "00:00:00";
// const today = moment().format('YYYY-MM-DD');
let datalog = new AttendanceDoorLog();
// console.log(param);
if (param.event_log) {
eventLog = JSON.parse(param.event_log)
console.log('eventLog:', eventLog)
employeeId = eventLog.AccessControllerEvent.employeeNoString
if (!employeeId) throw { message: 'NO_EMPLOYEE_NO_STRING_ON_EVENT' }
// 0|svc-hcmbridge | eventLog: {
// 0|svc-hcmbridge | ipAddress: '172.16.110.242',
// 0|svc-hcmbridge | ipv6Address: 'fe80::603:12ff:fe2e:4f8d',
// 0|svc-hcmbridge | portNo: 3000,
// 0|svc-hcmbridge | protocol: 'HTTP',
// 0|svc-hcmbridge | macAddress: '04:03:12:2e:4f:8d',
// 0|svc-hcmbridge | channelID: 1,
// 0|svc-hcmbridge | dateTime: '2025-05-29T09:22:40+08:00',
// 0|svc-hcmbridge | activePostCount: 1,
// 0|svc-hcmbridge | eventType: 'AccessControllerEvent',
// 0|svc-hcmbridge | eventState: 'active',
// 0|svc-hcmbridge | eventDescription: 'Access Controller Event',
// 0|svc-hcmbridge | AccessControllerEvent: {
// 0|svc-hcmbridge | deviceName: 'DeviceOut',
// 0|svc-hcmbridge | majorEventType: 5,
// 0|svc-hcmbridge | subEventType: 22,
// 0|svc-hcmbridge | cardReaderKind: 1,
// 0|svc-hcmbridge | doorNo: 1,
// 0|svc-hcmbridge | serialNo: 21403,
// 0|svc-hcmbridge | currentVerifyMode: 'invalid',
// 0|svc-hcmbridge | frontSerialNo: 21402,
// 0|svc-hcmbridge | attendanceStatus: 'undefined',
// 0|svc-hcmbridge | label: '',
// 0|svc-hcmbridge | statusValue: 0,
// 0|svc-hcmbridge | mask: 'unknown',
// 0|svc-hcmbridge | purePwdVerifyEnable: true
// 0|svc-hcmbridge | }
dateTime = moment.parseZone(eventLog.dateTime);
originalDate = dateTime.format("YYYY-MM-DD"); // Extract the date
originalTime = dateTime.format("HH:mm:ss"); // Extract the time
originalTimezone = dateTime.format("Z"); // Extract the timezone
// dtPost = {
// "accessdoorid": employeeId,
// "datelogs": originalDate + ' ' + originalTime,
// "ipaddress": eventLog.ipAddress,
// "macaddress": eventLog.macAddress,
// "devicename": eventLog.AccessControllerEvent.deviceName,
// "doornumber": eventLog.AccessControllerEvent.doorNo,
// "duration" : formattedDuration,
// "iby": 'system',
// "idt": new Date()
// }
datalog.accessdoorid = parseInt(employeeId);
datalog.datelogs = moment.parseZone(eventLog.dateTime).toDate();
datalog.ipaddress = eventLog.ipAddress;
datalog.macaddress = eventLog.macAddress;
datalog.devicename = eventLog.AccessControllerEvent.deviceName;
datalog.doornumber = eventLog.AccessControllerEvent.doorNo;
datalog.duration = formattedDuration;
datalog.iby = 'system';
datalog.idt = new Date();
// datalog.dura
// log.info('dtpost:', JSON.stringify(dtPost))
// let url = config.get('service.hrms') + 'api/sync-attendance'
// // log.info(url)
// let result = await Thirdparty.PostData(url, dtPost)
// // log.info('result:', JSON.stringify(result))
// const data = new LogHikvision()
// data.incoming = JSON.stringify(param.event_log)
// data.request = JSON.stringify(dtPost)
// data.url = url
// data.response = JSON.stringify(result)
// await OrmHelper.DB.manager.save(data);
}
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0);
const endOfToday = new Date();
endOfToday.setHours(23, 59, 59, 999);
// console.log(dtPost);
if (employeeId == '34') {
console.log('dtPost: ', JSON.stringify(dtPost))
}
if (eventLog?.AccessControllerEvent?.deviceName === 'DeviceIn') {
const datalogsbefore = await attendancedoorlogrepo
.createQueryBuilder("log")
.where("log.accessdoorid = :accessdoorid", { accessdoorid: datalog.accessdoorid })
.andWhere("log.devicename = :devicename", { devicename: "DeviceOut" })
.andWhere("DATE(log.datelogs) = CURDATE()")
.orderBy("log._idx", "DESC")
.getOne();
if (datalogsbefore != null && datalogsbefore !== undefined) {
let dateTimeIn = moment.parseZone(eventLog.dateTime);
let dateTimeOut = moment(datalogsbefore.datelogs);
let duration = moment.duration(dateTimeIn.diff(dateTimeOut));
formattedDuration = moment.utc(duration.asMilliseconds()).format("HH:mm:ss");
datalog.duration = formattedDuration;
}
}
// if (eventLog?.AccessControllerEvent?.deviceName === 'DeviceOut') {
// // console.log("line 300 : ",dtPost);
// // const datalogsbefore = await attendancedoorlogrepo.findOne({
// // where: {
// // accessdoorid: dtPost.accessdoorid,
// // devicename: "DeviceIn",
// // datelogs: Between(startOfToday, endOfToday),
// // },
// // order: { datelogs: "DESC" },
// // });
// const datalogsbefore = await attendancedoorlogrepo.createQueryBuilder("tbl_attendancedoorlogs")
// .where("DATE_FORMAT(tbl_attendancedoorlogs.datelogs, '%Y-%m-%d')= :d", { d: today.toString() })
// .andWhere("accessdoorid= :a", { a: employeeId })
// .andWhere("devicename= :b", { b: "DeviceIn" })
// .orderBy("tbl_attendancedoorlogs.datelogs", "DESC")
// .getOne()
// // const datalogsbefore = await attendancedoorlogrepo
// // .createQueryBuilder("log")
// // .where("log.accessdoorid = :accessdoorid", { accessdoorid: dtPost.accessdoorid })
// // .andWhere("log.devicename = :devicename", { devicename: "DeviceOut" })
// // .andWhere("DATE(log.datelogs) = CURDATE()")
// // .orderBy("log._idx", "DESC")
// // .getOne();
// if (datalogsbefore != null && datalogsbefore !== undefined) {
// // data = await attendancedoorlogrepo.save(dtPost);
// const previousDate = new Date(datalogsbefore.datelogs);
// const timezone = new Date(originalDate + ' ' + originalTime);
// const timeDiffSeconds = Math.floor((timezone.getTime() - previousDate.getTime()) / 1000);
// if(employeeId==="34"){
// console.log('Accessdoor Id : ',employeeId,' ',datalogsbefore.devicename,' Prev Time : ',previousDate,' TimeDoor : ',timezone,' ===> Time Diff : ', timeDiffSeconds);
// }
// // if(timeDiffSeconds<=50){
// // if ((timeDiffSeconds <= 50)) {
// if (datalogsbefore.devicename == 'DeviceIn'&&(timeDiffSeconds>50)) {
// // console.log("Accessdoorid : ", employeeId, ", dates : ", timezone, ", dates checkin before : ", previousDate, ", diff second : ", timeDiffSeconds)
// // const datetimelogs = new Date(`${originalDate}T${originalTime}`);
// // data = await attendancedoorlogrepo.save(dtPost);
// // return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
// }
// else{
// // console.log("interval : ",timeDiffSeconds);
// // if ((timeDiffSeconds >= 0 && timeDiffSeconds <= 7)){
// // return ReturnHelper.successResponseAny(res, 500, "Internal server error", {});
// // }
// }
// }
// }
// console.log(datalog);
data = (datalog ? await attendancedoorlogrepo.save(datalog) : {});
console.log(data);
return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
} catch (e: unknown) {
log.error(e);
const err = e as Error;
return ReturnHelper.successResponseAny(res, 200, Language.lang.failed, err.message);
}
}
static async logrekon(req: Request, res: Response, next: NextFunction): Promise<Response> {
/*
#swagger.tags = ['Event']
#swagger.parameters['datelogs'] = {
description: 'Entry Date Logs',
in: 'query',
type: 'string'
}
*/
try {
// let data: any = null;
const schema = Joi.object().keys({
datelogs: Joi.string().required().label('Date Logs'),
});
const param = await schema.validateAsync(req.query);
const employeerepo = OrmHelper.DB.getRepository(Employee);
const attendancedoorinfo = OrmHelper.DB.getRepository(AttendanceDoorInfo);
const data = await employeerepo.createQueryBuilder("tbl_employee")
.innerJoin(
"tbl_attendancedoorlogs",
"attlog",
"tbl_employee.accessdoorid = attlog.accessdoorid"
)
.select("attlog.accessdoorid", "accessdoorid")
.addSelect("tbl_employee.nik", "nik")
.addSelect("tbl_employee.employeename", "employeename")
.addSelect("DATE_FORMAT(attlog.datelogs, '%Y-%m-%d')", "logdate")
.addSelect(`COUNT(CASE WHEN attlog.devicename = 'DeviceIn' THEN 1 END)`, "total_in")
.addSelect(`COUNT(CASE WHEN attlog.devicename = 'DeviceOut' THEN 1 END)`, "total_out")
// .select([
// "tbl_employee._idx AS idx",
// "tbl_employee.accessdoorid AS accessdoorid",
// "tbl_employee.nik AS nik",
// "tbl_employee.employeename AS employeename",
// "DATE_FORMAT(attlog.datelogs, '%Y-%m-%d') AS log_date",
// "attlog.devicename AS deviceevent",
// "COUNT(attlog.devicename) AS total_event"
// ])
.where("DATE_FORMAT(attlog.datelogs, '%Y-%m-%d') = :d", { d: param.datelogs })
// .andWhere("tbl_employee.accessdoorid = :e", { e: "219" })
.groupBy("tbl_employee.accessdoorid")
.addGroupBy("tbl_employee.nik")
.addGroupBy("tbl_employee.employeename")
.addGroupBy("DATE_FORMAT(attlog.datelogs, '%Y-%m-%d')")
.orderBy("accessdoorid", "ASC")
.getRawMany();
// console.log(data);
for (const row of data) {
const doorinfo = await attendancedoorinfo.createQueryBuilder("tbl_attendancedoorinfo")
.where("DATE_FORMAT(tbl_attendancedoorinfo.datelogs, '%Y-%m-%d')= :d", { d: param.datelogs })
.andWhere("accessdoorid= :a", { a: row.accessdoorid })
.getOne()
let datadoorinfo: any = {};
// console.log(doorinfo);
if (doorinfo == null) {
datadoorinfo = {
"accessdoorid": row.accessdoorid,
"nik": row.nik,
"employeename": row.employeename,
"datelogs": param.datelogs,
"totalin": row.total_in,
"totalout": row.total_out,
"iby": 'sys',
"idt": new Date()
}
await attendancedoorinfo.save(datadoorinfo);
}
else {
datadoorinfo = {
"accessdoorid": row.accessdoorid,
"nik": row.nik,
"employeename": row.employeename,
"datelogs": param.datelogs,
"totalin": row.total_in,
"totalout": row.total_out,
"uby": "sys",
"udt": new Date()
}
// console.log("update ; ", datadoorinfo);
// console.log("doorinfo ; ", doorinfo);
await attendancedoorinfo.update({ idx: doorinfo.idx }, datadoorinfo)
// if (row.deviceevent == 'deviceIn') {
// data['totalin'] = row.total_event + doorinfo.totalin;
// }
// else {
// data['totalout'] = row.total_event + ;
// }
}
// console.log("Access Door ID:", row.accessdoorid);
// console.log("Employee Name:", row.employeename);
// console.log("Log Date:", row.log_date);
// console.log("Device Event:", row.deviceevent);
// console.log("Total Events:", row.total_event);
// console.log("-----");
}
// data.map(row => ({
// ...row,
// log_date: (row.log_date).toISOString().split('T')[0],
// }));
return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
} catch (e: unknown) {
log.error(e);
const err = e as Error;
return ReturnHelper.successResponseAny(res, 200, Language.lang.failed, err.message);
}
}
}

514
src/controllers/eventold.ts Normal file
View File

@ -0,0 +1,514 @@
import config from "config";
// import { LogHikvision } from "entity";
import { NextFunction, Response } from "express";
import { Request } from 'express-jwt';
import moment from "moment";
import { ILogObj, Logger } from "tslog";
import { ReturnHelper } from "../helpers/express/return";
import { OrmHelper } from "../helpers/orm";
// import Thirdparty from "../helpers/thirdparty";
import { Language } from "../langs/lang";
import { Between, Or } from "typeorm";
import { AttendanceDoorInfo, AttendanceDoorLog } from "entity";
import Joi from "joi";
import { Employee } from "entity";
const log: Logger<ILogObj> = new Logger({ name: '[EventController]', type: 'pretty' });
export class EventController {
static async indexold(req: Request, res: Response, next: NextFunction): Promise<Response> {
/*
#swagger.tags = ['Event']
*/
try {
let param: any = req.body
let dtPost: any = {}
let data: any = null;
const attendancedoorlogrepo = OrmHelper.DB.getRepository(AttendanceDoorLog);
// console.log('Request : ', req)
// console.log('param : ', param)
let eventLog: any = {};
let dateTime: any = null;
let originalTimezone: string = null;
let originalDate: string = null;
let originalTime: string = null;
if (param.event_log) {
eventLog = JSON.parse(param.event_log)
// console.log('eventLog:', eventLog)
let employeeId = eventLog.AccessControllerEvent.employeeNoString
if (!employeeId) throw { message: 'NO_EMPLOYEE_NO_STRING_ON_EVENT' }
// 0|svc-hcmbridge | eventLog: {
// 0|svc-hcmbridge | ipAddress: '172.16.110.242',
// 0|svc-hcmbridge | ipv6Address: 'fe80::603:12ff:fe2e:4f8d',
// 0|svc-hcmbridge | portNo: 3000,
// 0|svc-hcmbridge | protocol: 'HTTP',
// 0|svc-hcmbridge | macAddress: '04:03:12:2e:4f:8d',
// 0|svc-hcmbridge | channelID: 1,
// 0|svc-hcmbridge | dateTime: '2025-05-29T09:22:40+08:00',
// 0|svc-hcmbridge | activePostCount: 1,
// 0|svc-hcmbridge | eventType: 'AccessControllerEvent',
// 0|svc-hcmbridge | eventState: 'active',
// 0|svc-hcmbridge | eventDescription: 'Access Controller Event',
// 0|svc-hcmbridge | AccessControllerEvent: {
// 0|svc-hcmbridge | deviceName: 'DeviceOut',
// 0|svc-hcmbridge | majorEventType: 5,
// 0|svc-hcmbridge | subEventType: 22,
// 0|svc-hcmbridge | cardReaderKind: 1,
// 0|svc-hcmbridge | doorNo: 1,
// 0|svc-hcmbridge | serialNo: 21403,
// 0|svc-hcmbridge | currentVerifyMode: 'invalid',
// 0|svc-hcmbridge | frontSerialNo: 21402,
// 0|svc-hcmbridge | attendanceStatus: 'undefined',
// 0|svc-hcmbridge | label: '',
// 0|svc-hcmbridge | statusValue: 0,
// 0|svc-hcmbridge | mask: 'unknown',
// 0|svc-hcmbridge | purePwdVerifyEnable: true
// 0|svc-hcmbridge | }
dateTime = moment.parseZone(eventLog.dateTime);
originalDate = dateTime.format("YYYY-MM-DD"); // Extract the date
originalTime = dateTime.format("HH:mm:ss"); // Extract the time
originalTimezone = dateTime.format("Z"); // Extract the timezone
dtPost = {
"accessdoorid": employeeId,
"datelogs": originalDate + ' ' + originalTime,
"ipaddress": eventLog.ipAddress,
"macaddress": eventLog.macAddress,
"devicename": eventLog.AccessControllerEvent.deviceName,
"doornumber": eventLog.AccessControllerEvent.doorNo,
"iby": 'system',
"idt": new Date()
}
// log.info('dtpost:', JSON.stringify(dtPost))
// let url = config.get('service.hrms') + 'api/sync-attendance'
// // log.info(url)
// let result = await Thirdparty.PostData(url, dtPost)
// // log.info('result:', JSON.stringify(result))
// const data = new LogHikvision()
// data.incoming = JSON.stringify(param.event_log)
// data.request = JSON.stringify(dtPost)
// data.url = url
// data.response = JSON.stringify(result)
// await OrmHelper.DB.manager.save(data);
}
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0);
const endOfToday = new Date();
endOfToday.setHours(23, 59, 59, 999);
// console.log('dtPost:', JSON.stringify(dtPost))
if (eventLog?.AccessControllerEvent?.deviceName === 'DeviceOut') {
const datalogsbefore = await attendancedoorlogrepo.findOne({
where: {
accessdoorid: dtPost.accessdoorid,
devicename: "DeviceIn",
datelogs: Between(startOfToday, endOfToday),
},
order: { datelogs: "DESC" },
});
// const datalogsbefore = await attendancedoorlogrepo
// .createQueryBuilder("log")
// .where("log.accessdoorid = :accessdoorid", { accessdoorid: dtPost.accessdoorid })
// .andWhere("log.devicename = :devicename", { devicename: "DeviceOut" })
// .andWhere("DATE(log.datelogs) = CURDATE()")
// .orderBy("log._idx", "DESC")
// .getOne();
if (datalogsbefore != null && datalogsbefore !== undefined) {
// data = await attendancedoorlogrepo.save(dtPost);
const previousDate = new Date(datalogsbefore.datelogs);
const timezone = new Date(originalDate + ' ' + originalTime);
const timeDiffSeconds = Math.floor((timezone.getTime() - previousDate.getTime()) / 1000);
// if(timeDiffSeconds<=50){
if ((timeDiffSeconds <= 50)) {
if (dtPost.accessdoorid == 34) {
if (dtPost.ipaddress == '172.16.110.245') {
console.log('datalogsbefore OUT:', datalogsbefore);
console.log("Interval (OUT) in seconds:", timeDiffSeconds);
}
}
return ReturnHelper.successResponseAny(res, 500, "Internal server error", {});
}
// data = await attendancedoorlogrepo.update({ idx: datalogsbefore.idx }, { datelogs: originalDate + ' ' + originalTime });
// }
// else {
// data = await attendancedoorlogrepo.save(dtPost);
}
}
// else {
// // const datalogsbefore = await attendancedoorlogrepo.findOne({
// // where: {
// // accessdoorid: dtPost.accessdoorid,
// // devicename: "DeviceOut",
// // datelogs : new Date(),
// // },
// // order: { idx: "DESC" },
// // });
// // const datalogsbefore = await attendancedoorlogrepo
// // .createQueryBuilder("log")
// // .where("log.accessdoorid = :accessdoorid", { accessdoorid: dtPost.accessdoorid })
// // .andWhere("log.devicename = :devicename", { devicename: "DeviceIn" })
// // .andWhere("DATE(log.datelogs) = CURDATE()")
// // .orderBy("log._idx", "DESC")
// // .getOne();
// const datalogsbefore = await attendancedoorlogrepo.findOne({
// where: {
// accessdoorid: dtPost.accessdoorid,
// // devicename: "DeviceOut",
// datelogs: Between(startOfToday, endOfToday),
// },
// order: { datelogs: "DESC" },
// });
// if (datalogsbefore != null && datalogsbefore !== undefined) {
// const previousDate = new Date(datalogsbefore.datelogs);
// const timezone = new Date(originalDate + ' ' + originalTime);
// const timeDiffSeconds = Math.floor((timezone.getTime() - previousDate.getTime()) / 1000);
// // if(timeDiffSeconds>=0 && timeDiffSeconds<=10){
// // if(timeDiffSeconds<=50){
// if ((datalogsbefore.devicename === 'DeviceOut' && timeDiffSeconds <= 50) || datalogsbefore.devicename === 'DeviceIn') {
// console.log("Interval (IN) in seconds:", timeDiffSeconds);
// return ReturnHelper.successResponseAny(res, 500, "Internal server error", {});
// }
// // console.log('datalogsbefore IN : ', datalogsbefore)
// // data = await attendancedoorlogrepo.update({ idx: datalogsbefore.idx }, { datelogs: originalDate + ' ' + originalTime });
// // }
// // else {
// // data = await attendancedoorlogrepo.save(dtPost);
// }
// // data = await attendancedoorlogrepo.save(dtPost);
// }
data = (dtPost ? await attendancedoorlogrepo.save(dtPost) : {});
return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
} catch (e: unknown) {
log.error(e);
const err = e as Error;
return ReturnHelper.successResponseAny(res, 200, Language.lang.failed, err.message);
}
}
static async index(req: Request, res: Response, next: NextFunction): Promise<Response> {
/*
#swagger.tags = ['Event']
*/
try {
let param: any = req.body
let dtPost: any = {}
let data: any = null;
// console.log('Request : ', req)
// console.log('param : ', param.event_log)
const attendancedoorlogrepo = OrmHelper.DB.getRepository(AttendanceDoorLog);
let eventLog: any = {};
let dateTime: any = null;
let originalTimezone: string = null;
let originalDate: string = null;
let originalTime: string = null;
let employeeId: string = null;
const today = moment().format('YYYY-MM-DD');
// console.log(param);
if (param.event_log) {
eventLog = JSON.parse(param.event_log)
// console.log('eventLog:', eventLog)
employeeId = eventLog.AccessControllerEvent.employeeNoString
if (!employeeId) throw { message: 'NO_EMPLOYEE_NO_STRING_ON_EVENT' }
// 0|svc-hcmbridge | eventLog: {
// 0|svc-hcmbridge | ipAddress: '172.16.110.242',
// 0|svc-hcmbridge | ipv6Address: 'fe80::603:12ff:fe2e:4f8d',
// 0|svc-hcmbridge | portNo: 3000,
// 0|svc-hcmbridge | protocol: 'HTTP',
// 0|svc-hcmbridge | macAddress: '04:03:12:2e:4f:8d',
// 0|svc-hcmbridge | channelID: 1,
// 0|svc-hcmbridge | dateTime: '2025-05-29T09:22:40+08:00',
// 0|svc-hcmbridge | activePostCount: 1,
// 0|svc-hcmbridge | eventType: 'AccessControllerEvent',
// 0|svc-hcmbridge | eventState: 'active',
// 0|svc-hcmbridge | eventDescription: 'Access Controller Event',
// 0|svc-hcmbridge | AccessControllerEvent: {
// 0|svc-hcmbridge | deviceName: 'DeviceOut',
// 0|svc-hcmbridge | majorEventType: 5,
// 0|svc-hcmbridge | subEventType: 22,
// 0|svc-hcmbridge | cardReaderKind: 1,
// 0|svc-hcmbridge | doorNo: 1,
// 0|svc-hcmbridge | serialNo: 21403,
// 0|svc-hcmbridge | currentVerifyMode: 'invalid',
// 0|svc-hcmbridge | frontSerialNo: 21402,
// 0|svc-hcmbridge | attendanceStatus: 'undefined',
// 0|svc-hcmbridge | label: '',
// 0|svc-hcmbridge | statusValue: 0,
// 0|svc-hcmbridge | mask: 'unknown',
// 0|svc-hcmbridge | purePwdVerifyEnable: true
// 0|svc-hcmbridge | }
dateTime = moment.parseZone(eventLog.dateTime);
originalDate = dateTime.format("YYYY-MM-DD"); // Extract the date
originalTime = dateTime.format("HH:mm:ss"); // Extract the time
originalTimezone = dateTime.format("Z"); // Extract the timezone
dtPost = {
"accessdoorid": employeeId,
"datelogs": originalDate + ' ' + originalTime,
"ipaddress": eventLog.ipAddress,
"macaddress": eventLog.macAddress,
"devicename": eventLog.AccessControllerEvent.deviceName,
"doornumber": eventLog.AccessControllerEvent.doorNo,
"iby": 'system',
"idt": new Date()
}
// log.info('dtpost:', JSON.stringify(dtPost))
// let url = config.get('service.hrms') + 'api/sync-attendance'
// // log.info(url)
// let result = await Thirdparty.PostData(url, dtPost)
// // log.info('result:', JSON.stringify(result))
// const data = new LogHikvision()
// data.incoming = JSON.stringify(param.event_log)
// data.request = JSON.stringify(dtPost)
// data.url = url
// data.response = JSON.stringify(result)
// await OrmHelper.DB.manager.save(data);
}
const startOfToday = new Date();
startOfToday.setHours(0, 0, 0, 0);
const endOfToday = new Date();
endOfToday.setHours(23, 59, 59, 999);
// console.log(dtPost);
// if (eventLog.ipAddress == '172.16.110.245' && employeeId == '34') {
// console.log('dtPost: ', JSON.stringify(dtPost))
// }
if (eventLog?.AccessControllerEvent?.deviceName === 'DeviceOut') {
// console.log(dtPost);
// const datalogsbefore = await attendancedoorlogrepo.findOne({
// where: {
// accessdoorid: dtPost.accessdoorid,
// devicename: "DeviceIn",
// datelogs: Between(startOfToday, endOfToday),
// },
// order: { datelogs: "DESC" },
// });
const datalogsbefore = await attendancedoorlogrepo.createQueryBuilder("tbl_attendancedoorlogs")
.where("DATE_FORMAT(tbl_attendancedoorlogs.datelogs, '%Y-%m-%d')= :d", { d: today })
.andWhere("accessdoorid= :a", { a: employeeId })
.andWhere("devicename= :b", { b: "DeviceIn" })
.orderBy("tbl_attendancedoorlogs.datelogs", "DESC")
.getOne()
// const datalogsbefore = await attendancedoorlogrepo
// .createQueryBuilder("log")
// .where("log.accessdoorid = :accessdoorid", { accessdoorid: dtPost.accessdoorid })
// .andWhere("log.devicename = :devicename", { devicename: "DeviceOut" })
// .andWhere("DATE(log.datelogs) = CURDATE()")
// .orderBy("log._idx", "DESC")
// .getOne();
if (datalogsbefore != null && datalogsbefore !== undefined) {
// data = await attendancedoorlogrepo.save(dtPost);
const previousDate = new Date(datalogsbefore.datelogs);
const timezone = new Date(originalDate + ' ' + originalTime);
const timeDiffSeconds = Math.floor((timezone.getTime() - previousDate.getTime()) / 1000);
// if(timeDiffSeconds<=50){
if ((timeDiffSeconds <= 50)) {
console.log("Accessdoorid : ", employeeId, ", dates : ", timezone, ", dates checkin before : ", previousDate, ", diff second : ", timeDiffSeconds)
// if (dtPost.accessdoorid == 34) {
// if (dtPost.ipaddress == '172.16.110.245') {
// console.log('datalogsbefore OUT:', datalogsbefore);
// console.log("Interval (OUT) in seconds:", timeDiffSeconds);
// }
// }
return ReturnHelper.successResponseAny(res, 500, "Internal server error", {});
}
// data = await attendancedoorlogrepo.update({ idx: datalogsbefore.idx }, { datelogs: originalDate + ' ' + originalTime });
// }
// else {
// data = await attendancedoorlogrepo.save(dtPost);
}
}
// else {
// // const datalogsbefore = await attendancedoorlogrepo.findOne({
// // where: {
// // accessdoorid: dtPost.accessdoorid,
// // devicename: "DeviceOut",
// // datelogs : new Date(),
// // },
// // order: { idx: "DESC" },
// // });
// // const datalogsbefore = await attendancedoorlogrepo
// // .createQueryBuilder("log")
// // .where("log.accessdoorid = :accessdoorid", { accessdoorid: dtPost.accessdoorid })
// // .andWhere("log.devicename = :devicename", { devicename: "DeviceIn" })
// // .andWhere("DATE(log.datelogs) = CURDATE()")
// // .orderBy("log._idx", "DESC")
// // .getOne();
// const datalogsbefore = await attendancedoorlogrepo.findOne({
// where: {
// accessdoorid: dtPost.accessdoorid,
// // devicename: "DeviceOut",
// datelogs: Between(startOfToday, endOfToday),
// },
// order: { datelogs: "DESC" },
// });
// if (datalogsbefore != null && datalogsbefore !== undefined) {
// const previousDate = new Date(datalogsbefore.datelogs);
// const timezone = new Date(originalDate + ' ' + originalTime);
// const timeDiffSeconds = Math.floor((timezone.getTime() - previousDate.getTime()) / 1000);
// // if(timeDiffSeconds>=0 && timeDiffSeconds<=10){
// // if(timeDiffSeconds<=50){
// if ((datalogsbefore.devicename === 'DeviceOut' && timeDiffSeconds <= 50) || datalogsbefore.devicename === 'DeviceIn') {
// console.log("Interval (IN) in seconds:", timeDiffSeconds);
// return ReturnHelper.successResponseAny(res, 500, "Internal server error", {});
// }
// // console.log('datalogsbefore IN : ', datalogsbefore)
// // data = await attendancedoorlogrepo.update({ idx: datalogsbefore.idx }, { datelogs: originalDate + ' ' + originalTime });
// // }
// // else {
// // data = await attendancedoorlogrepo.save(dtPost);
// }
// // data = await attendancedoorlogrepo.save(dtPost);
// }
data = (dtPost ? await attendancedoorlogrepo.save(dtPost) : {});
return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
} catch (e: unknown) {
log.error(e);
const err = e as Error;
return ReturnHelper.successResponseAny(res, 200, Language.lang.failed, err.message);
}
}
static async logrekon(req: Request, res: Response, next: NextFunction): Promise<Response> {
/*
#swagger.tags = ['Event']
#swagger.parameters['datelogs'] = {
description: 'Entry Date Logs',
in: 'query',
type: 'string'
}
*/
try {
// let data: any = null;
const schema = Joi.object().keys({
datelogs: Joi.string().required().label('Date Logs'),
});
const param = await schema.validateAsync(req.query);
const employeerepo = OrmHelper.DB.getRepository(Employee);
const attendancedoorinfo = OrmHelper.DB.getRepository(AttendanceDoorInfo);
const data = await employeerepo.createQueryBuilder("tbl_employee")
.innerJoin(
"tbl_attendancedoorlogs",
"attlog",
"tbl_employee.accessdoorid = attlog.accessdoorid"
)
.select("attlog.accessdoorid", "accessdoorid")
.addSelect("tbl_employee.nik", "nik")
.addSelect("tbl_employee.employeename", "employeename")
.addSelect("DATE_FORMAT(attlog.datelogs, '%Y-%m-%d')", "logdate")
.addSelect(`COUNT(CASE WHEN attlog.devicename = 'DeviceIn' THEN 1 END)`, "total_in")
.addSelect(`COUNT(CASE WHEN attlog.devicename = 'DeviceOut' THEN 1 END)`, "total_out")
// .select([
// "tbl_employee._idx AS idx",
// "tbl_employee.accessdoorid AS accessdoorid",
// "tbl_employee.nik AS nik",
// "tbl_employee.employeename AS employeename",
// "DATE_FORMAT(attlog.datelogs, '%Y-%m-%d') AS log_date",
// "attlog.devicename AS deviceevent",
// "COUNT(attlog.devicename) AS total_event"
// ])
.where("DATE_FORMAT(attlog.datelogs, '%Y-%m-%d') = :d", { d: param.datelogs })
// .andWhere("tbl_employee.accessdoorid = :e", { e: "219" })
.groupBy("tbl_employee.accessdoorid")
.addGroupBy("tbl_employee.nik")
.addGroupBy("tbl_employee.employeename")
.addGroupBy("DATE_FORMAT(attlog.datelogs, '%Y-%m-%d')")
.orderBy("accessdoorid", "ASC")
.getRawMany();
// console.log(data);
for (const row of data) {
const doorinfo = await attendancedoorinfo.createQueryBuilder("tbl_attendancedoorinfo")
.where("DATE_FORMAT(tbl_attendancedoorinfo.datelogs, '%Y-%m-%d')= :d", { d: param.datelogs })
.andWhere("accessdoorid= :a", { a: row.accessdoorid })
.getOne()
let datadoorinfo: any = {};
// console.log(doorinfo);
if (doorinfo == null) {
datadoorinfo = {
"accessdoorid": row.accessdoorid,
"nik": row.nik,
"employeename": row.employeename,
"datelogs": param.datelogs,
"totalin": row.total_in,
"totalout": row.total_out,
"iby": 'sys',
"idt": new Date()
}
await attendancedoorinfo.save(datadoorinfo);
}
else {
datadoorinfo = {
"accessdoorid": row.accessdoorid,
"nik": row.nik,
"employeename": row.employeename,
"datelogs": param.datelogs,
"totalin": row.total_in,
"totalout": row.total_out,
"uby": "sys",
"udt": new Date()
}
// console.log("update ; ", datadoorinfo);
// console.log("doorinfo ; ", doorinfo);
await attendancedoorinfo.update({ idx: doorinfo.idx }, datadoorinfo)
// if (row.deviceevent == 'deviceIn') {
// data['totalin'] = row.total_event + doorinfo.totalin;
// }
// else {
// data['totalout'] = row.total_event + ;
// }
}
// console.log("Access Door ID:", row.accessdoorid);
// console.log("Employee Name:", row.employeename);
// console.log("Log Date:", row.log_date);
// console.log("Device Event:", row.deviceevent);
// console.log("Total Events:", row.total_event);
// console.log("-----");
}
// data.map(row => ({
// ...row,
// log_date: (row.log_date).toISOString().split('T')[0],
// }));
return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
} catch (e: unknown) {
log.error(e);
const err = e as Error;
return ReturnHelper.successResponseAny(res, 200, Language.lang.failed, err.message);
}
}
}

37
src/cron-task.ts Normal file
View File

@ -0,0 +1,37 @@
import cron from 'node-cron';
import { AxiosApi } from "./helpers/express/axiosapi";
import config, { util } from "config";
import moment from 'moment-timezone';
let isRunning = false;
export function startCronJob() {
const job = cron.schedule('0 */1 * * * *', async () => {
if (isRunning) {
console.log('crlogrekon is still running. Skipping this schedule.');
return;
}
console.log('Running scheduled task at :', new Date().toLocaleString());
isRunning = true;
try {
await crlogrekon();
} catch (error) {
console.error('crlogrekon failed:', error);
} finally {
isRunning = false;
}
});
// job.stop();
console.log('Cron task initialized');
}
export async function crlogrekon() {
const today = moment().tz('Asia/Dili').format('YYYY-MM-DD');
console.log(today);
// let res = await AxiosApi.get("http://" + config.get("server.host") + ":" + config.get("server.port") + "/api/dooraccess/logrekon?datelogs=" + today, '');
await AxiosApi.get("http://" + config.get("server.host") + ":" + config.get("server.port") + "/api/dooraccess/logrekon?datelogs=" + today, '');
console.log('Process done At :', new Date().toLocaleString());
// return res;
}

225
src/helpers/common.ts Normal file
View File

@ -0,0 +1,225 @@
import { Logger, ILogObj } from 'tslog';
import { validate } from 'uuid';
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 objectFlip(obj: any): any {
const ret = {};
Object.keys(obj).forEach(key => {
ret[obj[key]] = key;
});
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 '';
}
static getKeyEnum(obj: any, key: any): any {
try {
return Object.values(obj)[Object.keys(obj)[key]]
} catch (e: any) {
return '';
}
}
static generateTemplate(template: string, pairMap: any): string {
for (let p in pairMap) {
let v = pairMap[p];
template = template.split('{' + p + '}').join(v);
}
return template
}
static handleFilter(param: { filter: any, col_any_eq: string[], col_any_like: string[], additional_where?: string }): any {
const whereAttrPre = [];
const whereVal: any = {};
if (param.filter) {
try {
param.filter = JSON.parse(param.filter);
let filter_any = false;
let filter_any_val = '';
for (let p in param.filter) {
let f = String(param.filter[p])
let fr = param.filter[p]
if (p != 'any') {
if (!validate(f)) {
let found = false;
if (fr['from']) {
whereAttrPre.push(p + " >= :" + p + '_from');
whereVal[p + '_from'] = fr['from'];
found = true;
}
if (fr['to']) {
whereAttrPre.push(p + " <= :" + p + '_to');
whereVal[p + '_to'] = fr['to'];
found = true;
}
if (fr['in']) {
whereAttrPre.push(p + " in (:..." + p + '_in)');
whereVal[p + '_in'] = fr['in'];
found = true;
}
if (fr['like']) {
whereAttrPre.push('LOWER(' + p + ') like :' + p + '_like');
whereVal[p + '_like'] = '%' + fr['like'].toLowerCase() + '%';;
found = true;
}
if (!found) {
whereAttrPre.push("LOWER(" + p + ") = :" + p);
f = f.toLowerCase();
whereVal[p] = f;
}
} else {//uuid only
whereAttrPre.push(p + " = :" + p);
whereVal[p] = f;
}
} else {
filter_any = true;
filter_any_val = f;
}
}
if (filter_any) {
let wtp = []
if (param.col_any_eq.length > 0) {
const eqr = [];
for (let c of param.col_any_eq) {
eqr.push('LOWER(' + c + ') = :filter_eq');
}
const eq = '(' + eqr.join(' or ') + ')';
wtp.push(eq);
}
if (param.col_any_like.length > 0) {
const liker = [];
for (let c of param.col_any_like) {
liker.push('LOWER(' + c + ') like :filter_like');
}
const like = '(' + liker.join(' or ') + ')';
wtp.push(like);
}
if (wtp.length > 0) {
whereAttrPre.push('(' + wtp.join(' or ') + ')');
}
if (param.col_any_eq.length > 0) {
whereVal['filter_eq'] = filter_any_val;
}
if (param.col_any_like.length > 0) {
whereVal['filter_like'] = '%' + filter_any_val + '%';
}
}
} catch (e: any) {
let wtp = []
if (param.col_any_eq.length > 0) {
const eqr = [];
for (let c of param.col_any_eq) {
eqr.push('LOWER(' + c + ') = :filter_eq');
}
const eq = '(' + eqr.join(' or ') + ')';
wtp.push(eq);
}
if (param.col_any_like.length > 0) {
const liker = [];
for (let c of param.col_any_like) {
liker.push(c + ' like :filter_like');
}
const like = '(' + liker.join(' or ') + ')';
wtp.push(like);
}
if (wtp.length > 0) {
whereAttrPre.push('(' + wtp.join(' or ') + ')');
}
if (param.col_any_eq.length > 0) {
whereVal['filter_eq'] = param.filter.toLowerCase();
}
if (param.col_any_like.length > 0) {
whereVal['filter_like'] = '%' + param.filter + '%';
}
}
}
const whereAttr = whereAttrPre.join(' and ') + (whereAttrPre.length > 0 && param.additional_where && param.additional_where != '' ? ' and ' : '') + (param.additional_where ?? '');
return { whereAttr, whereVal };
}
}

View File

@ -0,0 +1,72 @@
import axios from 'axios';
let header = {
'accept': '*/*',
'Content-Type': 'application/json',
}
export class AxiosApi {
static async get(url: string, token: any): Promise<any> {
try {
if (token) header['Authorization'] = `Bearer ${token}`;
header['Content-Type'] = 'application/json';
return await axios.get(url, {
headers: header
})
.then(response => {
// console.log('Response sms:', response.data);
return response.data;
})
.catch(error => {
// console.error('Error:', error);
throw error;
});
} catch (e: unknown) {
throw e;
}
}
static async post(url: string, data: any, token: any): Promise<any> {
try {
// console.log(token);
if (token) header['Authorization'] = `Bearer ${token}`;
header['Content-Type'] = 'application/json';
return await axios.post(url, data, {
headers: header
})
.then(response => {
// console.log('Response sms:', response.data);
return response.data;
})
.catch(error => {
// console.error('Error:', error);
throw error;
});
} catch (e: unknown) {
throw e;
}
}
async postparams(url: string, data: any): Promise<any> {
try {
return await axios.post(url, new URLSearchParams(data).toString(), {
headers: {
'accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(response => {
// console.log('Response sms:', response.data);
return response.data;
})
.catch(error => {
// console.error('Error:', error);
throw error;
});
} catch (e: unknown) {
throw e;
}
}
}

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

View File

@ -0,0 +1,16 @@
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'),
methods: 'GET,POST,PUT,DELETE,OPTIONS',
allowedHeaders: ['Content-Type', 'Authorization'],
optionsSuccessStatus: 200,
};
app.use(cors(corsOptions));
}
}

View File

@ -0,0 +1,124 @@
import crypto from 'crypto';
export default class EncryptionPINHelper {
static alphaNum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static defaultEncKey = [
's'.charCodeAt(0) << 1, 't'.charCodeAt(0) << 2, '9'.charCodeAt(0) << 3, '4'.charCodeAt(0) << 4,
'v'.charCodeAt(0) << 1, '1'.charCodeAt(0) << 2, 'b'.charCodeAt(0) << 3, '0'.charCodeAt(0) << 4,
'a'.charCodeAt(0) << 1, 'b'.charCodeAt(0) << 2, 'C'.charCodeAt(0) << 3, 'F'.charCodeAt(0) << 4,
'x'.charCodeAt(0) << 1, 'u'.charCodeAt(0) << 2, 'T'.charCodeAt(0) << 3, 'z'.charCodeAt(0) << 4
];
static getDefaultEncryptionKey() {
const key = new Uint8Array(EncryptionPINHelper.defaultEncKey.length);
for (let i = 0; i < key.length; i++) {
key[i] = EncryptionPINHelper.defaultEncKey[i] >> (i % 4) + 1;
}
return key;
}
static Generate128BitsKey() {
return EncryptionPINHelper.GetRandomSecureBytes(16);
}
static AES128EncryptToBase64(key, plainText) {
const ivSeed = EncryptionPINHelper.GenerateIVSeed();
const iv = EncryptionPINHelper.GenerateIV(ivSeed);
const cipher = crypto.createCipheriv('aes-128-cbc', Buffer.from(key), Buffer.from(iv));
cipher.setAutoPadding(true); // PKCS7 is default
let cipherText = cipher.update(plainText);
cipherText = Buffer.concat([cipherText, cipher.final()]);
const base64CipherText = cipherText.toString('base64');
return base64CipherText + ivSeed;
}
static AES128DecryptFromBase64(key, base64CipherText) {
const ivSeed = base64CipherText.slice(-2);
base64CipherText = base64CipherText.slice(0, -2);
const cipherText = Buffer.from(base64CipherText, 'base64');
const iv = EncryptionPINHelper.GenerateIV(ivSeed);
const decipher = crypto.createDecipheriv('aes-128-cbc', Buffer.from(key), Buffer.from(iv));
decipher.setAutoPadding(true);
let plainText = decipher.update(cipherText);
plainText = Buffer.concat([plainText, decipher.final()]);
return plainText;
}
static Decrypt_with_shared_key(msg) {
try {
const decrypted = EncryptionPINHelper.AES128DecryptFromBase64(EncryptionPINHelper.getDefaultEncryptionKey(), msg);
return decrypted.toString('utf8');
} catch (error) {
console.error("Decryption error:", error);
return null;
}
}
static Encrypt_with_shared_key(msg) {
try {
return EncryptionPINHelper.AES128EncryptToBase64(EncryptionPINHelper.getDefaultEncryptionKey(), Buffer.from(msg, 'utf8'));
} catch (error) {
console.error("Encryption error:", error);
return null;
}
}
static GenerateIVSeed() {
var length = 2;
let result = "";
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * EncryptionPINHelper.alphaNum.length);
result += EncryptionPINHelper.alphaNum.charAt(randomIndex);
}
return result;
}
static GenerateIV(seed) {
const ivSeed = Buffer.from(seed, 'utf8');
return new Uint8Array([
ivSeed[0], ivSeed[1], 1, 2, ivSeed[0], ivSeed[1], 3, 4, ivSeed[0], ivSeed[1], 5, 6, ivSeed[0], ivSeed[1], 7, 8
]);
}
static GetRandomSecureBytes(size: number) {
return crypto.randomBytes(size);
}
// static encryptDefaultUTF8(texto) {
// try {
// let encrypted = EncryptionPINHelper.AES128EncryptToBase64(EncryptionPINHelper.getDefaultEncryptionKey(), Buffer.from(texto, 'utf8'));
// return (encrypted);
// } catch (error) {
// console.error("Encryption error:", error);
// return null; // Or handle the error as needed
// }
// }
// static Decrypt_with_key(msg, keyEncriptedWithSeven) {
// try {
// const key = EncryptionPINHelper.AES128DecryptFromBase64(EncryptionPINHelper.getDefaultEncryptionKey(), keyEncriptedWithSeven);
// const decrypted = EncryptionPINHelper.AES128DecryptFromBase64(key, msg);
// return decrypted.toString('utf8');
// } catch (error) {
// console.error("Decryption error:", error);
// return null;
// }
// }
// static Encrypt_with_key(msg, keyEncriptedWithSeven) {
// try {
// const key = EncryptionPINHelper.AES128DecryptFromBase64(EncryptionPINHelper.getDefaultEncryptionKey(), keyEncriptedWithSeven);
// return EncryptionPINHelper.AES128EncryptToBase64(key, Buffer.from(msg, 'utf8'));
// } catch (error) {
// console.error("Encryption error:", error);
// return null;
// }
// }
}

View 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'),
})
);
}
}

View File

@ -0,0 +1,15 @@
import config from 'config';
import morgan from 'morgan';
import express from 'express';
export class MorganHelper {
static setup(app: express.Application) {
if (process.env.NODE_ENV == 'prod') {
app.use(morgan(config.get('server.morgan'), {
skip: function (req, res) { return res.statusCode < 400 }
}));
} else {
app.use(morgan(config.get('server.morgan')));
}
}
}

View File

@ -0,0 +1,58 @@
import { Response } from 'express';
import { ErrorType, ErrorValidation } from 'entity';
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 || "failed",
error: error,
});
};
}

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

View File

@ -0,0 +1,7 @@
import express from 'express';
export class TrustProxyHelper {
static setup(app: express.Application) {
app.set('trust proxy', true);
}
}

View 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'),
})
);
}
}

View File

@ -0,0 +1,103 @@
import moment from 'moment-timezone';
import crypto from 'crypto';
import config from "config";
import { AxiosApi } from "../../helpers/express/axiosapi";
const algorithm = config.get("auth.algorithm").toString();
const keyString = config.get("auth.keystring").toString(); // Must be 32 characters for AES-256
const iv = crypto.randomBytes(16); // Secure random IV
const axiosapi = new AxiosApi();
export enum TimeLocation {
"local" = "L",
"GMT" = "G"
}
export class Utility {
static isMobile(): boolean {
try {
const userAgent = navigator.userAgent.toLowerCase();
// List of mobile device keywords
const mobileDevices = [
'iphone', 'ipod', 'ipad', 'android', 'blackberry', 'windows phone', 'mobile'
];
// Check if the userAgent matches any mobile device keyword
return mobileDevices.some(device => userAgent.includes(device));
} catch (error) {
return false;
}
}
static getTimeStamp(d: string): Date {
var dobj = moment.tz(d, "YYYY-MM-DD HH:mm:ss", 'Asia/Jakarta').toDate();
return new Date(dobj.getFullYear() + '-' + (dobj.getMonth() + 1) + '-' + dobj.getDate() + ' ' + dobj.getHours() + ':' + dobj.getMinutes() + ':' + dobj.getSeconds());
}
static hashData(data: string, salt: string): string {
const hash = crypto.createHmac("sha256", salt).update(data).digest("hex");
return hash;
}
static generateSalt(length: number = 16): string {
return crypto.randomBytes(length).toString("hex");
}
static encrypt(text: string): string {
const key = Buffer.from(keyString, 'utf8');
const cipher = crypto.createCipheriv(algorithm, key, iv);
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
return `${iv.toString('hex')}:${encrypted.toString('hex')}`;
}
static decrypt(encryptedData: string): string {
const [ivHex, encryptedHex] = encryptedData.split(':');
const ivBuffer = Buffer.from(ivHex, 'hex');
const key = Buffer.from(keyString, 'utf8');
const encryptedBuffer = Buffer.from(encryptedHex, 'hex');
const decipher = crypto.createDecipheriv(algorithm, key, ivBuffer);
const decrypted = Buffer.concat([decipher.update(encryptedBuffer), decipher.final()]);
return decrypted.toString();
}
static expired_at(location: TimeLocation): any {
return location === TimeLocation.GMT
? moment.tz("Asia/Jakarta").add(config.get("auth.expired_otp"), "minute").add(7, "hours").toDate()
: moment.tz("Asia/Jakarta").add(config.get("auth.expired_otp"), "minute").toDate();
}
static expired_attoken(location: TimeLocation): any {
return location === TimeLocation.GMT
? moment.tz("Asia/Jakarta").add(24 * parseInt(config.get("auth.refresh_token_lifetime_day")), "hours").toDate()
: moment.tz("Asia/Jakarta").add(config.get("auth.refresh_token_lifetime_day"), "days").toDate();
}
// static expired_atdb() : any{
// return moment.tz("Asia/Jakarta").add(config.get("auth.expired_otp"), "minute").toDate();
// }
static suspend_until(location: TimeLocation): any {
return location === TimeLocation.GMT
? moment.tz("Asia/Jakarta").add(config.get("auth.suspend_otp"), "minute").add(7, "hours").toDate()
: moment.tz("Asia/Jakarta").add(config.get("auth.suspend_otp"), "minute").toDate();
// return moment.tz("Asia/Jakarta").add(config.get("auth.suspend_otp"), "minute").toDate();
}
// static suspend_untildb() : any{
// return moment.tz("Asia/Jakarta").add(config.get("auth.suspend_otp"), "minute").toDate();
// }
static async getwording(code: string, lang: string): Promise<any> {
try {
const respwording = await axiosapi.postparams(
config.get("service.wording"), { code: code }
);
let getcontentmsg = respwording.data[0].name[lang];
return getcontentmsg;
} catch (error) {
throw error;
}
}
}

50
src/helpers/jwt.ts Normal file
View File

@ -0,0 +1,50 @@
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';
import { Utility } from './express/utility';
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"],
getToken: function fromHeaderOrQuerystring(req): any {
// log.info(req.query);
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.token) {
return req.query.token;
}
return null;
},
}).unless({ path: ["/token"] }),
function (req: Request, res: Response, next: NextFunction) {
// log.info(req.auth.data);
req.auth.data.id = Utility.decrypt(req.auth.data.id);
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();
});
}
}

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

View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtLHXJ3mO1t9sRPIW4xT0
ePwGRXbUKsEN5RLLlBXLGIdikdMD9LpqrSDBi5Xt+tN5YUPwDFw5SgQSbSAD9UiT
bxmGOn1HZvgGdDRZrLdwgohbMOzeRfilyhFtYP71DvTiidh4PZV7jpGAIQ2L/ndE
eZ7B7uZe1gHrB7a3LjcHs5hDXgMI4FjXs5cCZn+eLKDa1fhBO8z8U8sntbHt2/C4
zIAf8w0xdlJHa761bpabIRtCTLw8tZ+0Bv/it7twXBmpEcLORmbuy2boOGTXVEWo
y9KKjfW8T0EVkefu41aptYGDURkHzybgV1IqnfwF2vmqdDNETwRVn6Jo38Z9tUKX
VQIDAQAB
-----END PUBLIC KEY-----

44
src/helpers/orm.ts Normal file
View File

@ -0,0 +1,44 @@
import config from "config";
import { DataSource } from "typeorm";
import { entities } from "entity";
import { ILogObj, Logger } from "tslog";
export class OrmHelper {
static DB: DataSource = null;
static setup() {
const log: Logger<ILogObj> = new Logger({
name: "[OrmHelper]",
type: "pretty",
});
log.settings.prettyLogTimeZone = "local";
const engine: "mysql" = config.get("database.hcm.engine");
OrmHelper.DB = new DataSource({
type: engine,
host: config.get("database.hcm.host"),
port: Number(config.get("database.hcm.port")),
username: String(config.get("database.hcm.username")),
password: String(config.get("database.hcm.password")),
database: String(config.get("database.hcm.database")),
synchronize: config.get("database.hcm.sync"),
logging: config.get("database.hcm.logging"),
entities: entities,
subscribers: [],
migrations: [],
extra: {
// Set the timezone for the session
query: "SET TIMEZONE='Asia/Jakarta';",
},
});
OrmHelper.DB.initialize()
.then(async () => {
// await OrmHelper.DB.query("SET TIMEZONE='Asia/Jakarta';");
log.info("Database initialized successfully and created default data");
// here you can start to work with your database
})
.catch((error: any) => log.error(error));
}
}

150
src/helpers/thirdparty.ts Normal file
View File

@ -0,0 +1,150 @@
import axios from "axios";
import { ILogObj, Logger } from "tslog"
const log: Logger<ILogObj> = new Logger({
name: "[AppliactionFileController]",
type: "pretty",
})
export default class Thirdparty {
static async GetData(url: string, field: any, token?: string) {
try {
const headers: Record<string, string> = {};
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const response = await axios.get(url, { params: field, headers });
const result = response.data;
if (!result.status) throw response
return result
} catch (error: any) {
const { response } = error;
throw {
status: false,
message: response?.data?.error ?? response?.data?.message ?? 'Unknown error',
error: error
};
}
}
static async PostData(url: string, field: any, token?: string) {
try {
const headers: Record<string, string> = {};
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const response = await axios.post(url, field, { headers });
const result = response.data;
// if (!result.status) throw response
return result
} catch (error: any) {
const { response } = error;
throw {
status: false,
message: response?.data.message || 'Unknown error',
data: null
};
}
}
static async PutDate(url: string, field: any, token?: string) {
try {
const headers: Record<string, string> = {};
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const response = await axios.put(url, field, { headers });
// log.info(response.data || response)
const result = response.data;
if (!result.status) throw response
return result
} catch (error: any) {
const { response } = error;
throw {
status: false,
message: response?.data?.error ?? response?.data?.message ?? 'Unknown error',
data: null
};
}
}
static async UploadFile(url: string, field: any, token?: string) {
try {
const headers: Record<string, string> = {};
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const formData = new FormData();
// Append the file and other fields to FormData
for (const key in field) {
if (field.hasOwnProperty(key)) {
const value = field[key];
if (value instanceof Object && value.data && value.mimetype) {
// Convert file-like object to a Blob
const blob = new Blob([value.data], { type: value.mimetype });
formData.append(key, blob, value.name); // Use name as filename
} else {
formData.append(key, value); // Append non-file fields
}
}
}
// console.log('formData :', formData);
const response = await axios.post(url, formData, {
headers: { ...headers, "Content-Type": "multipart/form-data" }
});
// log.info(response.data || response)
const result = response.data;
if (!result.status) throw response
return result
} catch (error: any) {
log.error(error)
const { response } = error;
throw {
status: false,
message: response?.data?.error ?? response?.data?.message ?? 'Unknown error',
data: null
};
}
}
static async DownloadFile(url: string, field: any, token?: string) {
try {
const headers: Record<string, string> = {};
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const response = await axios.get(url, { params: field, headers, responseType: 'arraybuffer' });
// log.info(response.data || response)
const result = response.data;
return Buffer.from(result)
} catch (error: any) {
log.error(error)
const { response } = error;
throw {
status: false,
message: response?.data?.error ?? response?.data?.message ?? 'Unknown error',
data: null
};
}
}
}

44
src/index.ts Normal file
View File

@ -0,0 +1,44 @@
import { Logger, ILogObj } from "tslog";
import { app } from "./server";
import config from 'config'
import https from 'https';
import fs from 'fs';
import moment from 'moment-timezone';
import { startCronJob } from './cron-task';
// Set a global timezone for all dates
moment.tz.setDefault('Asia/Dili');
const log: Logger<ILogObj> = new Logger({ name: '[Index]', type: 'pretty' });
log.settings.prettyLogTimeZone = 'local';
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}`);
// === Start cron
startCronJob();
});
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);

45
src/langs/json/en.json Normal file
View File

@ -0,0 +1,45 @@
{
"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_userexists": "User Exists",
"otp_success_login": "OTP Has been Verified, Login Successfully",
"pin_success_login": "PIN Has been Verified, Login Successfully",
"success_valid_otp": "Operation has been success, valid for 1 minutes",
"success_logout": "Logout has been success",
"failed": "Operation has been failed",
"failed_access": "You're not allowed to access",
"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",
"failed_usernot_found": "Username not found, please provide valid username",
"failed_usernotorotp_found": "Username not found or wrong OTP, please provide valid username",
"failed_otpfailedattempt_found": "OTP 3 Failed attempt, please try again",
"failed_userorpin_notfound": "Username not found or wrong PIN, please provide valid username",
"failed_forgotpin_notfound": "Username, Mother Full name, birth of date do not match",
"failed_pinfailedattempt_found": "Pin 3 Failed attempts, Your account will be suspend",
"failed_userorpasswordnot_found": "Username not found or wrong password, please provide valid username",
"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",
"failed_logout": "Logout has been failed, please try again later",
"failed_related": "Data has been NOT successfully saved, please check related data"
}

79
src/langs/lang.ts Normal file
View File

@ -0,0 +1,79 @@
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;
success_logout?: string;
pin_success_login?: 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_usernot_found?: string;
failed_forgotpin_notfound?: string;
failed_pinfailedattempt_found?: string;
failed_usernotorotp_found?: string;
failed_otpfailedattempt_found?: string;
failed_userorpin_notfound?: string;
failed_userorpasswordnot_found?: string;
failed_limit_otp?: string;
failed_limit_link_code?: string;
failed_expired_token?: string;
failed_token?: string;
failed_add_point?: string;
failed_logout?: string;
failed_related?: string;
//login
otp_success_login?: string;
success_login?: string;
success_userexists?: 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 = 'en';
// req.params.language = acceptLanguageHeader.substring(0, 2).toLowerCase();
}
Language.lang = Language.lang_init[req.params.language];
return next();
}
}

25
src/routes/private.ts Normal file
View File

@ -0,0 +1,25 @@
import express from 'express';
import { Language } from '../langs/lang';
import JwtHelper from '../helpers/jwt';
// import { EventController } from '../controllers/event';
export class RoutePrivate {
static setup(app: express.Application) {
app.use(Language.apply)
JwtHelper.secure(app);
// app.get('/api/auth/getprofile', AuthController.getprofile)
// app.get('/api/reguler/list', RegulersController.list)
// app.get('/api/reguler/export', RegulersController.export)
// app.post('/api/reguler/create', RegulersController.create)
// // app.put('/api/reguler/update/:id', RegulersController.update)
// app.put('/api/reguler/update_profile', RegulersController.updateProfile)
// app.put('/api/reguler/update_password', RegulersController.updatePassword)
// app.get('/api/reguler/detail/:id', RegulersController.detail)
// app.delete('/api/reguler/delete/:id/:hard', RegulersController.delete)
// app.put('/api/reguler/restore/:id', RegulersController.restore)
}
}

19
src/routes/public.ts Normal file
View File

@ -0,0 +1,19 @@
import express from 'express';
import { EventController } from '../controllers/event';
import { Language } from '../langs/lang';
import multer from 'multer';
const upload = multer({ storage: multer.memoryStorage() });
export class RoutePublic {
static setup(app: express.Application) {
app.use(Language.apply);
app.post('/api/dooraccess/logs', upload.any(), EventController.index)
app.get('/api/dooraccess/logrekon', EventController.logrekon)
}
}

29
src/server.ts Normal file
View File

@ -0,0 +1,29 @@
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';
import { TrustProxyHelper } from './helpers/express/trust_proxy';
const app = express();
CorsHelper.setup(app);
CompressionHelper.setup(app);
MorganHelper.setup(app);
JsonHelper.setup(app);
UrlencodedHelper.setup(app);
OrmHelper.setup();
Language.setup();
TrustProxyHelper.setup(app);
SwaggerHelper.setup(app);
RoutePublic.setup(app);
RoutePrivate.setup(app);
export { app };

78
src/swagger/builder.js Normal file
View File

@ -0,0 +1,78 @@
const swaggerAutogen = require('swagger-autogen')({ openapi: '3.0.0' });
const config = require('config');
const { verify } = require('jsonwebtoken');
const doc = {
info: {
title: config.get('app.name'),
description: config.get('app.description'),
version: config.get('app.version')
},
servers: [
{
url: config.get('server.host_swagger'),
description: 'Environtment ' + config.get('app.env')
},
],
schemas: ['http', 'https'],
components: {
schemas: {
username: {
$username: "Users"
},
loginagent: {
$username: "67075666667",
$password: "87654321"
},
loginreguler: {
$msisdn: "67075666666",
$otp: "12345"
},
verifyotp: {
$msisdn: "67074254072",
$otp: "12345",
$code: "d8ecef150ab78ccf1823a399b12b55264369164b45eb87e4eec6a5b94405f699"
},
verifypin: {
$customerid: "d8ecef150ab78ccf1823a399b12b55264369164b45eb87e4eec6a5b94405f699",
$fcmtoken: "d8ecef150ab78ccf1823a399b12b55264369164b45eb87e4eec6a5b94405f699",
$lng: "20.470202",
$lat: "11.867351",
$os: "Android",
$uniqueid: "d8ecef150ab78ccf1823a399b12b55264369164b45eb87e4eec6a5b94405f699",
$pin: "123456"
},
changepin: {
$customerid: "d8ecef150ab78ccf1823a399b12b55264369164b45eb87e4eec6a5b94405f699",
$pin: "123456"
},
forgotpin: {
$fullname: "Fatih",
$mother_fullname: "Yana",
$date_birth: "2000-01-01",
$msisdn: "67074254072"
}
},
parameters: {
},
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
format: 'JWT'
},
}
},
security: [
{
bearerAuth: []
}
]
};
const outputFile = './swagger.json';
const routes = ['../routes/private.ts', '../routes/public.ts'];
swaggerAutogen(outputFile, routes, doc);