@hedhog/admin 0.12.1 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/{hedhog.yaml → bkp.hedhog.yaml} +1012 -814
  2. package/dist/auth/consts/body.js +23 -23
  3. package/package.json +43 -43
  4. package/src/admin.module.ts +37 -37
  5. package/src/auth/auth.controller.ts +72 -72
  6. package/src/auth/auth.module.ts +39 -39
  7. package/src/auth/auth.service.spec.ts +196 -196
  8. package/src/auth/auth.service.ts +234 -234
  9. package/src/auth/consts/body.ts +26 -26
  10. package/src/auth/consts/subject.ts +1 -1
  11. package/src/auth/dto/forget.dto.ts +6 -6
  12. package/src/auth/dto/login.dto.ts +15 -15
  13. package/src/auth/dto/otp.dto.ts +11 -11
  14. package/src/auth/dto/reset.dto.ts +14 -14
  15. package/src/auth/enums/multifactor-type.enum.ts +4 -4
  16. package/src/auth/guards/auth.guard.ts +50 -50
  17. package/src/auth/types/user.type.ts +8 -8
  18. package/src/dto/delete.dto.ts +8 -8
  19. package/src/dto/update-ids.dto.ts +9 -9
  20. package/src/index.ts +20 -20
  21. package/src/menu/dto/create.dto.ts +25 -25
  22. package/src/menu/dto/order.dto.ts +8 -8
  23. package/src/menu/dto/update.dto.ts +19 -19
  24. package/src/menu/menu.controller.ts +105 -105
  25. package/src/menu/menu.module.ts +18 -18
  26. package/src/menu/menu.service.spec.ts +247 -247
  27. package/src/menu/menu.service.ts +263 -263
  28. package/src/role/dto/create.dto.ts +7 -7
  29. package/src/role/dto/update.dto.ts +4 -4
  30. package/src/role/guards/role.guard.ts +123 -123
  31. package/src/role/role.controller.ts +126 -126
  32. package/src/role/role.module.ts +28 -28
  33. package/src/role/role.service.spec.ts +417 -417
  34. package/src/role/role.service.ts +289 -289
  35. package/src/route/dto/create.dto.ts +13 -13
  36. package/src/route/dto/update.dto.ts +15 -15
  37. package/src/route/route.controller.ts +91 -91
  38. package/src/route/route.module.ts +18 -18
  39. package/src/route/route.service.spec.ts +300 -300
  40. package/src/route/route.service.ts +164 -164
  41. package/src/screen/dto/create.dto.ts +11 -11
  42. package/src/screen/dto/update.dto.ts +19 -19
  43. package/src/screen/screen.controller.ts +93 -93
  44. package/src/screen/screen.module.ts +18 -18
  45. package/src/screen/screen.service.spec.ts +298 -298
  46. package/src/screen/screen.service.ts +179 -179
  47. package/src/types/http-method.ts +8 -8
  48. package/src/user/constants/user.constants.ts +1 -1
  49. package/src/user/dto/create.dto.ts +24 -24
  50. package/src/user/dto/update.dto.ts +41 -41
  51. package/src/user/user.controller.ts +75 -75
  52. package/src/user/user.module.ts +18 -18
  53. package/src/user/user.service.spec.ts +294 -294
  54. package/src/user/user.service.ts +129 -129
@@ -1,234 +1,234 @@
1
- import { MailService } from '@hedhog/mail';
2
- import { PrismaService } from '@hedhog/prisma';
3
- import {
4
- forwardRef,
5
- Inject,
6
- Injectable,
7
- NotFoundException,
8
- BadRequestException,
9
- } from '@nestjs/common';
10
- import { JwtService } from '@nestjs/jwt';
11
- import { compare, genSalt, hash } from 'bcrypt';
12
- import { ForgetDTO } from './dto/forget.dto';
13
- import { LoginDTO } from './dto/login.dto';
14
- import { OtpDTO } from './dto/otp.dto';
15
- import { MultifactorType } from './enums/multifactor-type.enum';
16
- import { User } from 'hcode-core';
17
- import { SUBJECT_RECOVERY } from './consts/subject';
18
- import { getBody } from './consts/body';
19
-
20
- @Injectable()
21
- export class AuthService {
22
- constructor(
23
- @Inject(forwardRef(() => PrismaService))
24
- private readonly prisma: PrismaService,
25
- @Inject(forwardRef(() => JwtService))
26
- private readonly jwt: JwtService,
27
- @Inject(forwardRef(() => MailService))
28
- private readonly mail: MailService,
29
- ) {}
30
-
31
- async verifyToken(token: string) {
32
- return this.jwt.verifyAsync(token, {
33
- secret: String(process.env.JWT_SECRET),
34
- });
35
- }
36
-
37
- generateRandomString(length: number): string {
38
- const characters =
39
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
40
- let result = '';
41
- for (let i = 0; i < length; i++) {
42
- const randomIndex = Math.floor(Math.random() * characters.length);
43
- result += characters.charAt(randomIndex);
44
- }
45
- return result;
46
- }
47
-
48
- generateRandomNumber(): number {
49
- const min = 100000;
50
- const max = 999999;
51
- return Math.floor(Math.random() * (max - min + 1)) + min;
52
- }
53
-
54
- async loginWithEmailAndPassword(email: string, password: string) {
55
- const user = await this.prisma.user.findFirst({
56
- where: {
57
- email,
58
- },
59
- });
60
- if (!user) {
61
- throw new NotFoundException('User not found');
62
- }
63
-
64
- const isPasswordValid = await compare(password, user.password);
65
-
66
- if (!isPasswordValid) {
67
- throw new NotFoundException('Invalid password');
68
- }
69
-
70
- if (!user.multifactor_id) {
71
- return this.getToken(user);
72
- } else {
73
- if (user.multifactor_id === MultifactorType.EMAIL) {
74
- const code = this.generateRandomNumber();
75
-
76
- await this.prisma.user.update({
77
- where: {
78
- id: user.id,
79
- },
80
- data: {
81
- code: String(code),
82
- },
83
- });
84
-
85
- await this.mail.send({
86
- to: user.email,
87
- subject: 'Login code',
88
- body: `Your login code is ${code}`,
89
- });
90
- }
91
-
92
- return {
93
- token: this.jwt.sign({
94
- id: user.id,
95
- mfa: user.multifactor_id,
96
- }),
97
- mfa: true,
98
- };
99
- }
100
- }
101
-
102
- async getToken(user) {
103
- delete user.password;
104
-
105
- const payload = { user };
106
-
107
- return {
108
- token: this.jwt.sign(payload),
109
- };
110
- }
111
-
112
- async forget({
113
- email,
114
- subject,
115
- body,
116
- }: ForgetDTO & {
117
- subject?: string;
118
- body?: string;
119
- }) {
120
- const user = await this.prisma.user.findFirst({
121
- where: {
122
- email,
123
- },
124
- select: {
125
- id: true,
126
- },
127
- });
128
-
129
- if (!user) {
130
- throw new NotFoundException('User not found');
131
- }
132
-
133
- const payload = {
134
- ...user,
135
- };
136
-
137
- const code = this.jwt.sign(payload);
138
-
139
- await this.prisma.user.update({
140
- where: {
141
- id: user.id,
142
- },
143
- data: {
144
- code,
145
- },
146
- });
147
-
148
- await this.mail.send({
149
- to: email,
150
- subject: subject ?? SUBJECT_RECOVERY,
151
- body:
152
- body ??
153
- getBody(`${process.env.FRONTEND_URL}/password-recovery/${code}`),
154
- });
155
-
156
- return true;
157
- }
158
-
159
- async resetPassword({
160
- code,
161
- newPassword,
162
- confirmNewPassword,
163
- }: {
164
- code: string;
165
- newPassword: string;
166
- confirmNewPassword: string;
167
- }) {
168
- if (newPassword !== confirmNewPassword) {
169
- throw new BadRequestException("Passwords don't match");
170
- }
171
-
172
- const { id } = this.jwt.decode(code) as User;
173
-
174
- const user = await this.prisma.user.findFirst({
175
- where: {
176
- id,
177
- code,
178
- },
179
- });
180
-
181
- if (user) {
182
- const salt = await genSalt();
183
- const password = await hash(confirmNewPassword, salt);
184
-
185
- await this.prisma.user.update({
186
- where: {
187
- id: user.id,
188
- },
189
- data: {
190
- password,
191
- code: null,
192
- },
193
- });
194
-
195
- return this.getToken(user);
196
- }
197
-
198
- return false;
199
- }
200
-
201
- async otp({ token, code }: OtpDTO) {
202
- const data = this.jwt.decode(token);
203
-
204
- const user = await this.prisma.user.findFirst({
205
- where: {
206
- id: data['id'],
207
- code: String(code),
208
- },
209
- });
210
-
211
- if (!user) {
212
- throw new NotFoundException('Invalid code');
213
- }
214
-
215
- await this.prisma.user.update({
216
- where: {
217
- id: user.id,
218
- },
219
- data: {
220
- code: null,
221
- },
222
- });
223
-
224
- return this.getToken(user);
225
- }
226
-
227
- login({ email, password }: LoginDTO) {
228
- return this.loginWithEmailAndPassword(email, password);
229
- }
230
-
231
- verify(id: number) {
232
- return this.prisma.user.findUnique({ where: { id } });
233
- }
234
- }
1
+ import { MailService } from '@hedhog/mail';
2
+ import { PrismaService } from '@hedhog/prisma';
3
+ import {
4
+ forwardRef,
5
+ Inject,
6
+ Injectable,
7
+ NotFoundException,
8
+ BadRequestException,
9
+ } from '@nestjs/common';
10
+ import { JwtService } from '@nestjs/jwt';
11
+ import { compare, genSalt, hash } from 'bcrypt';
12
+ import { ForgetDTO } from './dto/forget.dto';
13
+ import { LoginDTO } from './dto/login.dto';
14
+ import { OtpDTO } from './dto/otp.dto';
15
+ import { MultifactorType } from './enums/multifactor-type.enum';
16
+ import { User } from 'hcode-core';
17
+ import { SUBJECT_RECOVERY } from './consts/subject';
18
+ import { getBody } from './consts/body';
19
+
20
+ @Injectable()
21
+ export class AuthService {
22
+ constructor(
23
+ @Inject(forwardRef(() => PrismaService))
24
+ private readonly prisma: PrismaService,
25
+ @Inject(forwardRef(() => JwtService))
26
+ private readonly jwt: JwtService,
27
+ @Inject(forwardRef(() => MailService))
28
+ private readonly mail: MailService,
29
+ ) {}
30
+
31
+ async verifyToken(token: string) {
32
+ return this.jwt.verifyAsync(token, {
33
+ secret: String(process.env.JWT_SECRET),
34
+ });
35
+ }
36
+
37
+ generateRandomString(length: number): string {
38
+ const characters =
39
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
40
+ let result = '';
41
+ for (let i = 0; i < length; i++) {
42
+ const randomIndex = Math.floor(Math.random() * characters.length);
43
+ result += characters.charAt(randomIndex);
44
+ }
45
+ return result;
46
+ }
47
+
48
+ generateRandomNumber(): number {
49
+ const min = 100000;
50
+ const max = 999999;
51
+ return Math.floor(Math.random() * (max - min + 1)) + min;
52
+ }
53
+
54
+ async loginWithEmailAndPassword(email: string, password: string) {
55
+ const user = await this.prisma.user.findFirst({
56
+ where: {
57
+ email,
58
+ },
59
+ });
60
+ if (!user) {
61
+ throw new NotFoundException('User not found');
62
+ }
63
+
64
+ const isPasswordValid = await compare(password, user.password);
65
+
66
+ if (!isPasswordValid) {
67
+ throw new NotFoundException('Invalid password');
68
+ }
69
+
70
+ if (!user.multifactor_id) {
71
+ return this.getToken(user);
72
+ } else {
73
+ if (user.multifactor_id === MultifactorType.EMAIL) {
74
+ const code = this.generateRandomNumber();
75
+
76
+ await this.prisma.user.update({
77
+ where: {
78
+ id: user.id,
79
+ },
80
+ data: {
81
+ code: String(code),
82
+ },
83
+ });
84
+
85
+ await this.mail.send({
86
+ to: user.email,
87
+ subject: 'Login code',
88
+ body: `Your login code is ${code}`,
89
+ });
90
+ }
91
+
92
+ return {
93
+ token: this.jwt.sign({
94
+ id: user.id,
95
+ mfa: user.multifactor_id,
96
+ }),
97
+ mfa: true,
98
+ };
99
+ }
100
+ }
101
+
102
+ async getToken(user) {
103
+ delete user.password;
104
+
105
+ const payload = { user };
106
+
107
+ return {
108
+ token: this.jwt.sign(payload),
109
+ };
110
+ }
111
+
112
+ async forget({
113
+ email,
114
+ subject,
115
+ body,
116
+ }: ForgetDTO & {
117
+ subject?: string;
118
+ body?: string;
119
+ }) {
120
+ const user = await this.prisma.user.findFirst({
121
+ where: {
122
+ email,
123
+ },
124
+ select: {
125
+ id: true,
126
+ },
127
+ });
128
+
129
+ if (!user) {
130
+ throw new NotFoundException('User not found');
131
+ }
132
+
133
+ const payload = {
134
+ ...user,
135
+ };
136
+
137
+ const code = this.jwt.sign(payload);
138
+
139
+ await this.prisma.user.update({
140
+ where: {
141
+ id: user.id,
142
+ },
143
+ data: {
144
+ code,
145
+ },
146
+ });
147
+
148
+ await this.mail.send({
149
+ to: email,
150
+ subject: subject ?? SUBJECT_RECOVERY,
151
+ body:
152
+ body ??
153
+ getBody(`${process.env.FRONTEND_URL}/password-recovery/${code}`),
154
+ });
155
+
156
+ return true;
157
+ }
158
+
159
+ async resetPassword({
160
+ code,
161
+ newPassword,
162
+ confirmNewPassword,
163
+ }: {
164
+ code: string;
165
+ newPassword: string;
166
+ confirmNewPassword: string;
167
+ }) {
168
+ if (newPassword !== confirmNewPassword) {
169
+ throw new BadRequestException("Passwords don't match");
170
+ }
171
+
172
+ const { id } = this.jwt.decode(code) as User;
173
+
174
+ const user = await this.prisma.user.findFirst({
175
+ where: {
176
+ id,
177
+ code,
178
+ },
179
+ });
180
+
181
+ if (user) {
182
+ const salt = await genSalt();
183
+ const password = await hash(confirmNewPassword, salt);
184
+
185
+ await this.prisma.user.update({
186
+ where: {
187
+ id: user.id,
188
+ },
189
+ data: {
190
+ password,
191
+ code: null,
192
+ },
193
+ });
194
+
195
+ return this.getToken(user);
196
+ }
197
+
198
+ return false;
199
+ }
200
+
201
+ async otp({ token, code }: OtpDTO) {
202
+ const data = this.jwt.decode(token);
203
+
204
+ const user = await this.prisma.user.findFirst({
205
+ where: {
206
+ id: data['id'],
207
+ code: String(code),
208
+ },
209
+ });
210
+
211
+ if (!user) {
212
+ throw new NotFoundException('Invalid code');
213
+ }
214
+
215
+ await this.prisma.user.update({
216
+ where: {
217
+ id: user.id,
218
+ },
219
+ data: {
220
+ code: null,
221
+ },
222
+ });
223
+
224
+ return this.getToken(user);
225
+ }
226
+
227
+ login({ email, password }: LoginDTO) {
228
+ return this.loginWithEmailAndPassword(email, password);
229
+ }
230
+
231
+ verify(id: number) {
232
+ return this.prisma.user.findUnique({ where: { id } });
233
+ }
234
+ }
@@ -1,26 +1,26 @@
1
- export const getBody = (url: string): string => {
2
- return `
3
- <body style="font-family: Arial, sans-serif; background-color: #eef2f7; color: #333; margin: 0; padding: 0;">
4
- <div style="max-width: 600px; margin: 40px auto; background-color: #ffffff; border: 1px solid #dcdfe6; border-radius: 10px; padding: 40px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);">
5
- <div style="text-align: center; margin-bottom: 30px;">
6
- <h1 style="color: #2c3e50; font-size: 26px; margin: 0;">Recuperação de Senha</h1>
7
- </div>
8
- <div style="line-height: 1.8; font-size: 16px; color: #555; text-align: justify;">
9
- <p>Olá,</p>
10
- <p>Recebemos uma solicitação para redefinir sua senha em nossa plataforma. Para garantir que você é o proprietário desta conta, criamos um link exclusivo para redefinir sua senha.</p>
11
- <p>Se você não fez essa solicitação, entre em contato conosco imediatamente para garantir a segurança de sua conta.</p>
12
- <p>Para redefinir sua senha, clique no botão abaixo:</p>
13
- </div>
14
- <div style="text-align: center; margin: 30px 0;">
15
- <a href="${url}" style="display: inline-block; padding: 15px 30px; background-color: #3498db; color: #ffffff; text-decoration: none; font-size: 16px; font-weight: bold; border-radius: 8px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);">Redefinir Senha</a>
16
- </div>
17
- <div style="font-size: 14px; line-height: 1.7; color: #666;">
18
- <p>Por razões de segurança, evite compartilhar suas informações de login ou clicar em links suspeitos.</p>
19
- <p>Agradecemos por escolher nossa plataforma!</p>
20
- </div>
21
- <div style="text-align: center; font-size: 13px; color: #95a5a6; margin-top: 40px; border-top: 1px solid #ecf0f1; padding-top: 20px;">
22
- <p>Este email foi enviado automaticamente. Por favor, não responda.</p>
23
- </div>
24
- </div>
25
- </body>`;
26
- };
1
+ export const getBody = (url: string): string => {
2
+ return `
3
+ <body style="font-family: Arial, sans-serif; background-color: #eef2f7; color: #333; margin: 0; padding: 0;">
4
+ <div style="max-width: 600px; margin: 40px auto; background-color: #ffffff; border: 1px solid #dcdfe6; border-radius: 10px; padding: 40px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);">
5
+ <div style="text-align: center; margin-bottom: 30px;">
6
+ <h1 style="color: #2c3e50; font-size: 26px; margin: 0;">Recuperação de Senha</h1>
7
+ </div>
8
+ <div style="line-height: 1.8; font-size: 16px; color: #555; text-align: justify;">
9
+ <p>Olá,</p>
10
+ <p>Recebemos uma solicitação para redefinir sua senha em nossa plataforma. Para garantir que você é o proprietário desta conta, criamos um link exclusivo para redefinir sua senha.</p>
11
+ <p>Se você não fez essa solicitação, entre em contato conosco imediatamente para garantir a segurança de sua conta.</p>
12
+ <p>Para redefinir sua senha, clique no botão abaixo:</p>
13
+ </div>
14
+ <div style="text-align: center; margin: 30px 0;">
15
+ <a href="${url}" style="display: inline-block; padding: 15px 30px; background-color: #3498db; color: #ffffff; text-decoration: none; font-size: 16px; font-weight: bold; border-radius: 8px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);">Redefinir Senha</a>
16
+ </div>
17
+ <div style="font-size: 14px; line-height: 1.7; color: #666;">
18
+ <p>Por razões de segurança, evite compartilhar suas informações de login ou clicar em links suspeitos.</p>
19
+ <p>Agradecemos por escolher nossa plataforma!</p>
20
+ </div>
21
+ <div style="text-align: center; font-size: 13px; color: #95a5a6; margin-top: 40px; border-top: 1px solid #ecf0f1; padding-top: 20px;">
22
+ <p>Este email foi enviado automaticamente. Por favor, não responda.</p>
23
+ </div>
24
+ </div>
25
+ </body>`;
26
+ };
@@ -1 +1 @@
1
- export const SUBJECT_RECOVERY = 'Recuperação de Senha';
1
+ export const SUBJECT_RECOVERY = 'Recuperação de Senha';
@@ -1,6 +1,6 @@
1
- import { IsEmail } from 'class-validator';
2
-
3
- export class ForgetDTO {
4
- @IsEmail()
5
- email: string;
6
- }
1
+ import { IsEmail } from 'class-validator';
2
+
3
+ export class ForgetDTO {
4
+ @IsEmail()
5
+ email: string;
6
+ }
@@ -1,15 +1,15 @@
1
- import { IsEmail, IsStrongPassword } from 'class-validator';
2
-
3
- export class LoginDTO {
4
- @IsEmail()
5
- email: string;
6
-
7
- @IsStrongPassword({
8
- minLength: 6,
9
- minLowercase: 1,
10
- minUppercase: 0,
11
- minNumbers: 0,
12
- minSymbols: 0,
13
- })
14
- password: string;
15
- }
1
+ import { IsEmail, IsStrongPassword } from 'class-validator';
2
+
3
+ export class LoginDTO {
4
+ @IsEmail()
5
+ email: string;
6
+
7
+ @IsStrongPassword({
8
+ minLength: 6,
9
+ minLowercase: 1,
10
+ minUppercase: 0,
11
+ minNumbers: 0,
12
+ minSymbols: 0,
13
+ })
14
+ password: string;
15
+ }
@@ -1,11 +1,11 @@
1
- import { IsInt, IsJWT, Max, Min } from 'class-validator';
2
-
3
- export class OtpDTO {
4
- @Min(0)
5
- @Max(999999)
6
- @IsInt()
7
- code: number;
8
-
9
- @IsJWT()
10
- token: string;
11
- }
1
+ import { IsInt, IsJWT, Max, Min } from 'class-validator';
2
+
3
+ export class OtpDTO {
4
+ @Min(0)
5
+ @Max(999999)
6
+ @IsInt()
7
+ code: number;
8
+
9
+ @IsJWT()
10
+ token: string;
11
+ }
@@ -1,14 +1,14 @@
1
- import { IsNotEmpty, MinLength } from 'class-validator';
2
-
3
- export class ResetDTO {
4
- @IsNotEmpty()
5
- @MinLength(8)
6
- newPassword: string;
7
-
8
- @IsNotEmpty()
9
- @MinLength(8)
10
- confirmNewPassword: string;
11
-
12
- @IsNotEmpty()
13
- code: string;
14
- }
1
+ import { IsNotEmpty, MinLength } from 'class-validator';
2
+
3
+ export class ResetDTO {
4
+ @IsNotEmpty()
5
+ @MinLength(8)
6
+ newPassword: string;
7
+
8
+ @IsNotEmpty()
9
+ @MinLength(8)
10
+ confirmNewPassword: string;
11
+
12
+ @IsNotEmpty()
13
+ code: string;
14
+ }
@@ -1,4 +1,4 @@
1
- export enum MultifactorType {
2
- EMAIL = 1,
3
- APP = 2,
4
- }
1
+ export enum MultifactorType {
2
+ EMAIL = 1,
3
+ APP = 2,
4
+ }