diff --git a/assets/reset_password.html b/assets/reset_password.html
new file mode 100644
index 0000000..36cc156
--- /dev/null
+++ b/assets/reset_password.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Reset Password BRI TL
+
+
+
+
+
+
+
+
+
+
+
+ | |
+
+
+
+ | |
+
+
+
+
+
+ | |
+
+
+
+
+ Hi {NAME}, You have requested to reset your password
+
+
+ We cannot simply send you your old password. A unique link to reset your
+ password has been generated for you. To reset your password, click the
+ following link and follow the instructions.
+
+ Reset
+ Password
+ |
+
+
+ | |
+
+
+ |
+
+ | |
+
+
+
+ | |
+
+
+ |
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/default.json b/config/default.json
index 2346631..695e002 100644
--- a/config/default.json
+++ b/config/default.json
@@ -29,6 +29,10 @@
},
"auth": {
"refresh_token_lifetime_day": 30,
- "access_token_lifetime": 300
+ "access_token_lifetime": 300,
+ "reset_password_url": "https://bri-dev.shiblysolution.id/reset-password/"
+ },
+ "service": {
+ "notification": "http://127.0.0.1:4008/"
}
}
diff --git a/config/stag.json b/config/stag.json
index 483342c..86e54ee 100644
--- a/config/stag.json
+++ b/config/stag.json
@@ -29,6 +29,10 @@
},
"auth": {
"refresh_token_lifetime_day": 30,
- "access_token_lifetime": 300
+ "access_token_lifetime": 300,
+ "reset_password_url": "https://bri-dev.shiblysolution.id/reset-password/"
+ },
+ "service": {
+ "notification": "http://127.0.0.1:4008/"
}
}
diff --git a/package.json b/package.json
index 5a02340..6b9175b 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,11 @@
{
- "name": "boilerplate-bri",
+ "name": "Service user",
"version": "1.0.0",
- "description": "This kind of project was built to present base application regarding BRI ERP Project",
+ "description": "Purpose of this service is to provide authorization, roles, user activity and etc",
"main": "src/index.ts",
"scripts": {
"dev": "nodemon",
- "build": "rimraf dist && tsc",
+ "build": "tsc",
"swagger": "node src/swagger/builder.js"
},
"keywords": [
@@ -14,11 +14,13 @@
"author": "STS",
"license": "ISC",
"dependencies": {
+ "axios": "^1.7.8",
"bcryptjs": "^2.4.3",
"compression": "^1.7.5",
"config": "^3.3.12",
"cors": "^2.8.5",
"dayjs": "^1.11.13",
+ "Entity": "file:../entity",
"express": "^4.21.1",
"express-jwt": "^8.4.1",
"fast-csv": "^5.0.2",
diff --git a/src/controllers/auth.ts b/src/controllers/auth.ts
index 719dff2..3c8f68e 100644
--- a/src/controllers/auth.ts
+++ b/src/controllers/auth.ts
@@ -2,18 +2,18 @@ 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 config from "config";
import { ILogObj, Logger } from "tslog";
import { Language } from "../langs/lang";
-import { UserRefreshToken } from "../entity/user_refresh_token";
import { UAParser } from 'ua-parser-js';
import dayjs from 'dayjs'
import jwt from 'jsonwebtoken';
import fs from 'fs';
-import { UserRole } from "../entity/users_roles";
import { v4 as uuidv4 } from 'uuid';
+import { EmailBody, User, UserRefreshToken, UserRole } from "Entity";
+import axios from 'axios';
+import CommonHelper from "../helpers/common";
const log: Logger = new Logger({ name: '[UserController]', type: 'pretty' });
@@ -170,8 +170,30 @@ export class AuthController {
await userRepository.save(user);
//send email reset password
+ const url = config.get("service.notification") + "api/email/send";
- return ReturnHelper.successResponseAny(res, 200, Language.lang.success, {});
+ console.log(url, 'url')
+
+ const template_raw = fs.readFileSync('assets/reset_password.html').toString();
+
+ const pairMap = {
+ 'LINK': config.get('auth.reset_password_url') + user.reset_token,
+ 'NAME': user.name
+ }
+
+ const template = CommonHelper.generateTemplate(template_raw, pairMap);
+
+ const email: EmailBody = {
+ subject: "Reset Password",
+ to: [user.email],
+ cc: [],
+ bcc: [],
+ html: template
+ }
+
+ const { data } = await axios.post(url, email);
+
+ return ReturnHelper.successResponseAny(res, 200, Language.lang.success, data);
// return ReturnHelper.errorResponse(res, 403, 401, Language.lang.failed_access);
diff --git a/src/controllers/user.ts b/src/controllers/user.ts
index 2c5d520..ed492f5 100644
--- a/src/controllers/user.ts
+++ b/src/controllers/user.ts
@@ -2,11 +2,11 @@ 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 { User } from "Entity";
import Joi from "joi";
import { ILogObj, Logger } from "tslog";
import { Language } from "../langs/lang";
-import { Paging } from "../types/paging";
+import { Paging } from "Entity";
import CommonHelper from "../helpers/common";
import * as fastcsv from 'fast-csv';
import dayjs from "dayjs";
diff --git a/src/controllers/user_activity.ts b/src/controllers/user_activity.ts
index 1da94a7..f6cfe3e 100644
--- a/src/controllers/user_activity.ts
+++ b/src/controllers/user_activity.ts
@@ -5,12 +5,12 @@ import { OrmHelper } from "../helpers/orm";
import Joi from "joi";
import { ILogObj, Logger } from "tslog";
import { Language } from "../langs/lang";
-import { Paging } from "../types/paging";
+import { Paging } from "Entity";
import CommonHelper from "../helpers/common";
-import { ActivityType } from "../types/action";
-import { UserActivity } from "../entity/user_activity";
+import { ActivityType } from "Entity";
import * as fastcsv from 'fast-csv';
import dayjs from "dayjs";
+import { UserActivity } from "Entity";
const log: Logger = new Logger({ name: '[UserActivityController]', type: 'pretty' });
diff --git a/src/controllers/user_refresh_token.ts b/src/controllers/user_refresh_token.ts
index 27fbdfe..d6c439b 100644
--- a/src/controllers/user_refresh_token.ts
+++ b/src/controllers/user_refresh_token.ts
@@ -5,9 +5,9 @@ import { OrmHelper } from "../helpers/orm";
import Joi from "joi";
import { ILogObj, Logger } from "tslog";
import { Language } from "../langs/lang";
-import { Paging } from "../types/paging";
+import { Paging } from "Entity";
import CommonHelper from "../helpers/common";
-import { UserRefreshToken } from "../entity/user_refresh_token";
+import { UserRefreshToken } from "Entity";
const log: Logger = new Logger({ name: '[UserRefreshTokenController]', type: 'pretty' });
diff --git a/src/controllers/user_roles.ts b/src/controllers/user_roles.ts
index 787ca44..30d41ab 100644
--- a/src/controllers/user_roles.ts
+++ b/src/controllers/user_roles.ts
@@ -4,13 +4,13 @@ import { OrmHelper } from "../helpers/orm";
import Joi from "joi";
import { ILogObj, Logger } from "tslog";
import { Language } from "../langs/lang";
-import { Paging } from "../types/paging";
+import { Paging } from "Entity";
import CommonHelper from "../helpers/common";
-import { Status } from "../types/status";
-import { UserRole } from "../entity/users_roles";
-import { RoleList } from "../types/role";
+import { Status } from "Entity";
+import { RoleList } from "Entity";
import * as fastcsv from 'fast-csv';
import dayjs from "dayjs";
+import { UserRole } from "Entity";
const log: Logger = new Logger({ name: '[UserRoleController]', type: 'pretty' });
diff --git a/src/entity/user_activity.ts b/src/entity/user_activity.ts
deleted file mode 100644
index 31fd37d..0000000
--- a/src/entity/user_activity.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, Index } from 'typeorm';
-
-import { ActivityType } from '../types/action';
-
-@Entity('user_activities')
-export class UserActivity {
- @PrimaryGeneratedColumn('uuid')
- id: string;
-
- @Index()
- @Column({
- type: 'uuid'
- })
- id_user: string;
-
- @Index()
- @Column({
- type: 'uuid'
- })
- refresh_token: string;
-
- @Index()
- @Column({
- nullable: false,
- length: 512
- })
- module: string;
-
- @Column({
- nullable: false,
- length: 2048
- })
- description: string;
-
- @Column({
- nullable: true,
- length: 1
- })
- action: ActivityType;
-
- @Column({
- nullable: false,
- length: 2048,
- })
- url: String;
-
- @Column({
- type: 'text',
- nullable: true,
- })
- data_body: String;
-
- @Column()
- @CreateDateColumn()
- created_at: Date;
-
- @Column({ nullable: true })
- @UpdateDateColumn()
- updated_at: Date;
-
- @Column({ nullable: true })
- @DeleteDateColumn()
- deleted_at: Date;
-}
\ No newline at end of file
diff --git a/src/entity/user_refresh_token.ts b/src/entity/user_refresh_token.ts
deleted file mode 100644
index cc3181e..0000000
--- a/src/entity/user_refresh_token.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, Index } from 'typeorm';
-
-@Entity('user_refresh_tokens')
-export class UserRefreshToken {
- @PrimaryGeneratedColumn('uuid')
- refresh_token: string;
-
- @Index()
- @Column({
- type: 'uuid'
- })
- id_user: string;
-
- @Column({
- nullable: false,
- length: 4096,
- })
- user_agent: string;
-
- @Column({
- nullable: true,
- length: 128
- })
- os: string;
-
- @Column({
- nullable: true,
- length: 256
- })
- device: string;
-
- @Column({
- nullable: true,
- length: 64
- })
- platform: string;
-
- @Column({
- nullable: true,
- length: 64
- })
- browser: string;
-
- @Column({
- nullable: true,
- length: 32
- })
- remote_addr: string;
-
- @Column('timestamp')
- expired_at: Date;
-
- @Column()
- @CreateDateColumn()
- created_at: Date;
-
- @Column({ nullable: true })
- @UpdateDateColumn()
- updated_at: Date;
-
- @Column({ nullable: true })
- @DeleteDateColumn()
- deleted_at: Date;
-}
\ No newline at end of file
diff --git a/src/entity/users.ts b/src/entity/users.ts
deleted file mode 100644
index 295e9b2..0000000
--- a/src/entity/users.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import bcrypt from 'bcryptjs';
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, Index } from 'typeorm';
-
-import { Status } from '../types/status';
-
-@Entity('users')
-export class User {
- @PrimaryGeneratedColumn('uuid')
- id: string;
-
- @Column({
- nullable: false,
- unique: true,
- length: 64
- })
- email: string;
-
- @Column({
- nullable: false,
- length: 64,
- select: false
- })
- password: string;
-
- @Column({
- nullable: false,
- unique: true,
- length: 64
- })
- username: string;
-
- @Column({
- nullable: true,
- length: 64
- })
- name: string;
-
- @Column({
- nullable: true,
- type: 'uuid'
- })
- id_role: string;
-
- @Index()
- @Column({
- nullable: true,
- type: 'uuid'
- })
- reset_token: string;
-
- @Column({
- nullable: false,
- length: 64
- })
- status: Status;
-
- @Column()
- @CreateDateColumn()
- created_at: Date;
-
- @Column({ nullable: true })
- @UpdateDateColumn()
- updated_at: Date;
-
- @Column({ nullable: true })
- @DeleteDateColumn()
- deleted_at: Date;
-
- hashPassword() {
- this.password = bcrypt.hashSync(this.password, 8);
- }
-
- checkIfPasswordMatch(unencryptedPassword: string) {
- return bcrypt.compareSync(unencryptedPassword, this.password);
- }
-}
\ No newline at end of file
diff --git a/src/entity/users_roles.ts b/src/entity/users_roles.ts
deleted file mode 100644
index 19dc98d..0000000
--- a/src/entity/users_roles.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, DeleteDateColumn } from 'typeorm';
-
-import { Status } from '../types/status';
-import { RoleList } from '../types/role';
-
-@Entity('user_roles')
-export class UserRole {
- @PrimaryGeneratedColumn('uuid')
- id: string;
-
- @Column({
- nullable: false,
- unique: true,
- length: 128
- })
- name: string;
-
- @Column({
- nullable: false,
- type: 'jsonb'
- })
- roles: RoleList[];
-
- @Column({
- nullable: false,
- length: 64
- })
- status: Status;
-
- @Column()
- @CreateDateColumn()
- created_at: Date;
-
- @Column({ nullable: true })
- @UpdateDateColumn()
- updated_at: Date;
-
- @Column({ nullable: true })
- @DeleteDateColumn()
- deleted_at: Date;
-}
\ No newline at end of file
diff --git a/src/helpers/common.ts b/src/helpers/common.ts
index 9af05a2..3075b15 100644
--- a/src/helpers/common.ts
+++ b/src/helpers/common.ts
@@ -81,4 +81,14 @@ export default class CommonHelper {
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
+ }
}
\ No newline at end of file
diff --git a/src/helpers/express/return.ts b/src/helpers/express/return.ts
index 92e9473..f14d74a 100644
--- a/src/helpers/express/return.ts
+++ b/src/helpers/express/return.ts
@@ -1,5 +1,5 @@
import { Response } from 'express';
-import { ErrorType, ErrorValidation } from '../../types/error';
+import { ErrorType, ErrorValidation } from 'Entity';
export class ReturnHelper {
static successResponseAny(
diff --git a/src/helpers/orm.ts b/src/helpers/orm.ts
index 395e79d..cf2bb7e 100644
--- a/src/helpers/orm.ts
+++ b/src/helpers/orm.ts
@@ -1,10 +1,7 @@
import config from 'config';
import { DataSource } from "typeorm";
-import { User } from "../entity/users";
+import { User, UserActivity, UserRefreshToken, UserRole } from "Entity";
import { ILogObj, Logger } from 'tslog';
-import { UserActivity } from '../entity/user_activity';
-import { UserRefreshToken } from '../entity/user_refresh_token';
-import { UserRole } from '../entity/users_roles';
export class OrmHelper {
static DB: DataSource = null
diff --git a/src/types/action.ts b/src/types/action.ts
deleted file mode 100644
index 314bcad..0000000
--- a/src/types/action.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export enum ActivityType {
- "Create" = "C",
- "View" = "V",
- "Update" = "U",
- "Delete" = "D",
- "Restore" = "T",
-};
\ No newline at end of file
diff --git a/src/types/error.ts b/src/types/error.ts
deleted file mode 100644
index 1415969..0000000
--- a/src/types/error.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export type ErrorType = 'General' | 'Raw' | 'Validation' | 'Unauthorized';
-
-export type ErrorValidation = { [key: string]: string };
\ No newline at end of file
diff --git a/src/types/paging.ts b/src/types/paging.ts
deleted file mode 100644
index ee83de9..0000000
--- a/src/types/paging.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export interface Paging {
- page: number,
- limit: number,
- filter: any,
- with_deleted: boolean,
- order_field: string,
- order_direction: 'ASC' | 'DESC'
-}
\ No newline at end of file
diff --git a/src/types/role.ts b/src/types/role.ts
deleted file mode 100644
index 18edd28..0000000
--- a/src/types/role.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-export enum RoleList {
- "Dashboard" = "dashboard",
- "Kinerja UKLN" = "ukln",
- "Dana Pihak Ketiga" = "dpk",
- "Posisi Outstanding Pinjaman" = "outstanding_loan",
- "Presentasi NPL" = "npl",
- "PPAP Amount NPL" = "ppap_amount",
- "Report Regulator Bulanan" = "regulator_bulanan",
- "Report Regulator Triwulan" = "regulator_triwulan",
- "Report Regulator Publikasi" = "regulator_publikasi",
- "Perhitungan Simulasi Perpajakan Per Bulan" = "pajak_per_bulan",
- "Perhitungan Simulasi Perpajakan Per Tahun" = "pajak_per_tahun",
- "Data Nasabah Potensial" = "nasabah_potensial",
- "Master Data User" = "master_user",
- "Master Data Product" = "master_product",
- "Master Data Tier" = "master_tier",
- "Master Klasifikasi Ekonomi" = "master_klasifikasi_ekonomi",
- "Master District" = "master_district",
- "Master Munisipu" = "master_munisipu",
- "Master Administrativu" = "master_administrativu",
- "Master Suco" = "master_suco",
- "Master Aldeia" = "master_aldeia",
-}
\ No newline at end of file
diff --git a/src/types/status.ts b/src/types/status.ts
deleted file mode 100644
index 7408c75..0000000
--- a/src/types/status.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export enum Status {
- "Active" = "Y",
- "Not Active" = "N"
-};
\ No newline at end of file