rez_core 2.2.168 → 2.2.170
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.
- package/dist/module/listmaster/service/list-master.service.js +3 -1
- package/dist/module/listmaster/service/list-master.service.js.map +1 -1
- package/dist/module/notification/controller/notification.controller.d.ts +2 -1
- package/dist/module/notification/controller/notification.controller.js +15 -2
- package/dist/module/notification/controller/notification.controller.js.map +1 -1
- package/dist/module/notification/controller/otp.controller.d.ts +2 -1
- package/dist/module/notification/controller/otp.controller.js +2 -2
- package/dist/module/notification/controller/otp.controller.js.map +1 -1
- package/dist/module/notification/entity/notification.entity.d.ts +1 -0
- package/dist/module/notification/entity/notification.entity.js +4 -0
- package/dist/module/notification/entity/notification.entity.js.map +1 -1
- package/dist/module/notification/firebase-admin.config.d.ts +6 -1
- package/dist/module/notification/firebase-admin.config.js +20 -6
- package/dist/module/notification/firebase-admin.config.js.map +1 -1
- package/dist/module/notification/notification.module.js +17 -3
- package/dist/module/notification/notification.module.js.map +1 -1
- package/dist/module/notification/service/notification.service.d.ts +19 -0
- package/dist/module/notification/service/notification.service.js +88 -0
- package/dist/module/notification/service/notification.service.js.map +1 -0
- package/dist/module/notification/service/otp.service.d.ts +2 -1
- package/dist/module/notification/service/otp.service.js +8 -3
- package/dist/module/notification/service/otp.service.js.map +1 -1
- package/dist/module/user/controller/login.controller.js +16 -4
- package/dist/module/user/controller/login.controller.js.map +1 -1
- package/dist/module/user/controller/user.controller.d.ts +1 -9
- package/dist/module/user/controller/user.controller.js +10 -4
- package/dist/module/user/controller/user.controller.js.map +1 -1
- package/dist/module/user/entity/user.entity.d.ts +1 -0
- package/dist/module/user/entity/user.entity.js +4 -0
- package/dist/module/user/entity/user.entity.js.map +1 -1
- package/dist/module/user/service/login.service.d.ts +17 -3
- package/dist/module/user/service/login.service.js +14 -5
- package/dist/module/user/service/login.service.js.map +1 -1
- package/dist/module/user/service/user.service.d.ts +7 -10
- package/dist/module/user/service/user.service.js +23 -8
- package/dist/module/user/service/user.service.js.map +1 -1
- package/dist/module/workflow/service/task.service.d.ts +3 -1
- package/dist/module/workflow/service/task.service.js +6 -2
- package/dist/module/workflow/service/task.service.js.map +1 -1
- package/dist/module/workflow/workflow.module.js +2 -0
- package/dist/module/workflow/workflow.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/module/listmaster/service/list-master.service.ts +3 -1
- package/src/module/notification/controller/notification.controller.ts +10 -2
- package/src/module/notification/controller/otp.controller.ts +3 -2
- package/src/module/notification/entity/notification.entity.ts +3 -0
- package/src/module/notification/firebase-admin.config.ts +20 -6
- package/src/module/notification/notification.module.ts +18 -4
- package/src/module/notification/service/notification.service.ts +90 -0
- package/src/module/notification/service/otp.service.ts +9 -3
- package/src/module/user/controller/login.controller.ts +26 -11
- package/src/module/user/controller/user.controller.ts +7 -2
- package/src/module/user/entity/user.entity.ts +3 -0
- package/src/module/user/service/login.service.ts +24 -8
- package/src/module/user/service/user.service.ts +32 -6
- package/src/module/workflow/service/task.service.ts +7 -0
- package/src/module/workflow/workflow.module.ts +2 -0
- package/src/resources/dev.properties.yaml +11 -7
- package/dist/module/notification/firebase-admin.json +0 -13
- package/dist/module/notification/service/firebase.service.d.ts +0 -11
- package/dist/module/notification/service/firebase.service.js +0 -40
- package/dist/module/notification/service/firebase.service.js.map +0 -1
- package/src/module/notification/firebase-admin.json +0 -13
- package/src/module/notification/service/firebase.service.ts +0 -31
package/package.json
CHANGED
|
@@ -296,14 +296,16 @@ export class ListMasterService {
|
|
|
296
296
|
async createEntity(entityData: any, loggedInUser: UserData): Promise<any> {
|
|
297
297
|
// Trim and validate name and code
|
|
298
298
|
const name = entityData.name?.trim();
|
|
299
|
+
const code = entityData.code?.trim();
|
|
299
300
|
|
|
300
|
-
if (!name) {
|
|
301
|
+
if (!name || !code) {
|
|
301
302
|
throw new BadRequestException(
|
|
302
303
|
'Name and Code are required and cannot be empty',
|
|
303
304
|
);
|
|
304
305
|
}
|
|
305
306
|
|
|
306
307
|
entityData.name = name;
|
|
308
|
+
entityData.code = code;
|
|
307
309
|
entityData.is_factory = entityData.is_factory || 0;
|
|
308
310
|
entityData.source = entityData.source || 'master';
|
|
309
311
|
entityData.status = entityData.status || 'ACTIVE';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Body, Controller, Post } from '@nestjs/common';
|
|
2
|
-
import {
|
|
1
|
+
import { Body, Controller, Get, Post, Req, UseGuards } from '@nestjs/common';
|
|
2
|
+
import { JwtAuthGuard } from 'src/module/auth/guards/jwt.guard';
|
|
3
|
+
import { NotificationsService } from '../service/notification.service';
|
|
3
4
|
|
|
4
5
|
@Controller('notifications')
|
|
5
6
|
export class NotificationsController {
|
|
@@ -22,4 +23,11 @@ export class NotificationsController {
|
|
|
22
23
|
body.message,
|
|
23
24
|
);
|
|
24
25
|
}
|
|
26
|
+
|
|
27
|
+
@Get('all')
|
|
28
|
+
@UseGuards(JwtAuthGuard)
|
|
29
|
+
async getNotifications(@Req() req: any) {
|
|
30
|
+
const loggedInUser = req.user.userData;
|
|
31
|
+
return this.notificationsService.getAllNotifications(loggedInUser);
|
|
32
|
+
}
|
|
25
33
|
}
|
|
@@ -45,14 +45,15 @@ export class OtpController {
|
|
|
45
45
|
@HttpCode(HttpStatus.OK)
|
|
46
46
|
async verifyOtp(
|
|
47
47
|
@Body()
|
|
48
|
-
|
|
48
|
+
data: {
|
|
49
49
|
otp: string;
|
|
50
50
|
otp_id: string;
|
|
51
51
|
identifier: string;
|
|
52
52
|
subdomain: string;
|
|
53
|
+
fcm_token: string;
|
|
53
54
|
},
|
|
54
55
|
) {
|
|
55
|
-
return await this.otpService.verifyOtp(
|
|
56
|
+
return await this.otpService.verifyOtp(data);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
@Post('send-mail')
|
|
@@ -1,8 +1,22 @@
|
|
|
1
|
+
// firebase-admin.provider.ts
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
1
3
|
import * as admin from 'firebase-admin';
|
|
2
|
-
import * as serviceAccount from './firebase-admin.json';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export const FirebaseAdminProvider = {
|
|
6
|
+
provide: 'FIREBASE_ADMIN',
|
|
7
|
+
inject: [ConfigService],
|
|
8
|
+
useFactory: async (configService: ConfigService) => {
|
|
9
|
+
if (!admin.apps.length) {
|
|
10
|
+
admin.initializeApp({
|
|
11
|
+
credential: admin.credential.cert({
|
|
12
|
+
projectId: configService.get<string>('FIREBASE_PROJECT_ID'),
|
|
13
|
+
clientEmail: configService.get<string>('FIREBASE_CLIENT_EMAIL'),
|
|
14
|
+
privateKey: configService
|
|
15
|
+
.get<string>('FIREBASE_PRIVATE_KEY')
|
|
16
|
+
?.replace(/\\n/g, '\n'),
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return admin;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
2
|
import { OtpService } from './service/otp.service';
|
|
3
3
|
import { OtpRepository } from './repository/otp.repository';
|
|
4
4
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
@@ -14,7 +14,9 @@ import { UserModule } from '../user/user.module';
|
|
|
14
14
|
import { IcsMeetingModule } from '../ics/ics.module';
|
|
15
15
|
import { NotificationData } from './entity/notification.entity';
|
|
16
16
|
import { NotificationsController } from './controller/notification.controller';
|
|
17
|
-
import { NotificationsService } from './service/
|
|
17
|
+
import { NotificationsService } from './service/notification.service';
|
|
18
|
+
import { EntityModule } from '../meta/entity.module';
|
|
19
|
+
import { FirebaseAdminProvider } from './firebase-admin.config';
|
|
18
20
|
|
|
19
21
|
@Module({
|
|
20
22
|
imports: [
|
|
@@ -47,9 +49,21 @@ import { NotificationsService } from './service/firebase.service';
|
|
|
47
49
|
AuthModule,
|
|
48
50
|
UserModule,
|
|
49
51
|
IcsMeetingModule,
|
|
52
|
+
EntityModule,
|
|
53
|
+
],
|
|
54
|
+
providers: [
|
|
55
|
+
OtpService,
|
|
56
|
+
OtpRepository,
|
|
57
|
+
EmailService,
|
|
58
|
+
NotificationsService,
|
|
59
|
+
FirebaseAdminProvider,
|
|
60
|
+
],
|
|
61
|
+
exports: [
|
|
62
|
+
OtpService,
|
|
63
|
+
EmailService,
|
|
64
|
+
FirebaseAdminProvider,
|
|
65
|
+
NotificationsService,
|
|
50
66
|
],
|
|
51
|
-
providers: [OtpService, OtpRepository, EmailService, NotificationsService],
|
|
52
|
-
exports: [OtpService, EmailService],
|
|
53
67
|
controllers: [OtpController, NotificationsController],
|
|
54
68
|
})
|
|
55
69
|
export class NotificationModule {}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
2
|
+
import { DataSource } from 'typeorm';
|
|
3
|
+
import { MediaDataService } from 'src/module/meta/service/media-data.service';
|
|
4
|
+
import * as admin from 'firebase-admin';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class NotificationsService {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly dataSource: DataSource,
|
|
10
|
+
private readonly mediaDataService: MediaDataService,
|
|
11
|
+
@Inject('FIREBASE_ADMIN') private readonly firebaseAdmin: typeof admin,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
private tokens: Map<string, string> = new Map(); // store in memory for now
|
|
15
|
+
|
|
16
|
+
async saveToken(userId: string | undefined, token: string) {
|
|
17
|
+
if (userId) {
|
|
18
|
+
this.tokens.set(userId, token);
|
|
19
|
+
}
|
|
20
|
+
return { success: true, token };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async sendToDevice(token: string, title: string, body: string) {
|
|
24
|
+
const message = {
|
|
25
|
+
token,
|
|
26
|
+
notification: { title, body },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return this.firebaseAdmin.messaging().send(message);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Helper: send to a registered user by userId
|
|
33
|
+
async sendToUser(userId: string, title: string, body: string) {
|
|
34
|
+
const token = this.tokens.get(userId);
|
|
35
|
+
if (!token) return { error: 'No token found for user' };
|
|
36
|
+
|
|
37
|
+
return this.sendToDevice(token, title, body);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getAllNotifications(loggedInUser: any) {
|
|
41
|
+
const { id, level_id, level_type } = loggedInUser;
|
|
42
|
+
|
|
43
|
+
const notifications = await this.dataSource.query(
|
|
44
|
+
`
|
|
45
|
+
SELECT
|
|
46
|
+
n.*,
|
|
47
|
+
u.name AS user_name,
|
|
48
|
+
u.profile_image AS user_profile
|
|
49
|
+
FROM cr_notification n
|
|
50
|
+
LEFT JOIN eth_user_profile u ON n.user_id = u.parent_id
|
|
51
|
+
WHERE n.user_id = ? AND n.level_id = ? AND n.level_type = ?
|
|
52
|
+
ORDER BY n.created_date DESC
|
|
53
|
+
`,
|
|
54
|
+
[id, level_id, 'SCH'],
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Profile media enrichment
|
|
58
|
+
const mediaCache = new Map();
|
|
59
|
+
for (const notification of notifications) {
|
|
60
|
+
notification.is_read = true;
|
|
61
|
+
|
|
62
|
+
if (notification.user_profile) {
|
|
63
|
+
if (!mediaCache.has(notification.user_profile)) {
|
|
64
|
+
const url = await this.mediaDataService.getMediaDownloadUrl(
|
|
65
|
+
notification.user_profile,
|
|
66
|
+
loggedInUser,
|
|
67
|
+
);
|
|
68
|
+
mediaCache.set(notification.user_profile, url);
|
|
69
|
+
}
|
|
70
|
+
notification.user_profile = mediaCache.get(notification.user_profile);
|
|
71
|
+
} else {
|
|
72
|
+
notification.user_profile = null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Batch update all fetched notifications
|
|
77
|
+
if (notifications.length > 0) {
|
|
78
|
+
await this.dataSource.query(
|
|
79
|
+
`
|
|
80
|
+
UPDATE cr_notification
|
|
81
|
+
SET is_read = 1
|
|
82
|
+
WHERE user_id = ? AND level_id = ? AND level_type = ?
|
|
83
|
+
`,
|
|
84
|
+
[id, level_id, level_type],
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return notifications;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -53,13 +53,14 @@ export class OtpService {
|
|
|
53
53
|
return await this.otpRepository.save(otp);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
async verifyOtp(
|
|
56
|
+
async verifyOtp(data: {
|
|
57
57
|
otp: string;
|
|
58
58
|
otp_id: string;
|
|
59
59
|
identifier: string;
|
|
60
60
|
subdomain: string;
|
|
61
|
+
fcm_token: string;
|
|
61
62
|
}) {
|
|
62
|
-
const { otp, otp_id, identifier, subdomain } =
|
|
63
|
+
const { otp, otp_id, identifier, subdomain, fcm_token } = data;
|
|
63
64
|
const verifyOTPResponse = { isValid: false };
|
|
64
65
|
|
|
65
66
|
// Find OTP entity by ID
|
|
@@ -98,7 +99,12 @@ export class OtpService {
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
// Proceed to login
|
|
101
|
-
return this.loginService.login(
|
|
102
|
+
return this.loginService.login({
|
|
103
|
+
email: data.identifier,
|
|
104
|
+
is_otp: true,
|
|
105
|
+
subdomain: data.subdomain,
|
|
106
|
+
fcm_token: data.fcm_token,
|
|
107
|
+
});
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
async findByOtpId(otpId: string) {
|
|
@@ -28,13 +28,23 @@ export class LoginController {
|
|
|
28
28
|
|
|
29
29
|
@Post('login')
|
|
30
30
|
async login(@Body() body, @Res() res: Response) {
|
|
31
|
-
const {
|
|
32
|
-
const result = await this.loginService.login(
|
|
31
|
+
const {
|
|
33
32
|
email_id,
|
|
34
33
|
password,
|
|
35
|
-
|
|
34
|
+
appcode,
|
|
35
|
+
organization_id,
|
|
36
36
|
subdomain,
|
|
37
|
-
|
|
37
|
+
fcm_token,
|
|
38
|
+
} = body;
|
|
39
|
+
|
|
40
|
+
const result = await this.loginService.login({
|
|
41
|
+
email: email_id,
|
|
42
|
+
password,
|
|
43
|
+
subdomain,
|
|
44
|
+
fcm_token,
|
|
45
|
+
is_otp: false, // default since you had it before
|
|
46
|
+
});
|
|
47
|
+
|
|
38
48
|
return res.status(HttpStatus.OK).json(result);
|
|
39
49
|
}
|
|
40
50
|
@Post('form-login')
|
|
@@ -67,9 +77,12 @@ export class LoginController {
|
|
|
67
77
|
async googleAuthRedirect(@Req() req: any, @Res() res: Response) {
|
|
68
78
|
const {
|
|
69
79
|
email,
|
|
80
|
+
password,
|
|
70
81
|
name,
|
|
71
82
|
accessToken: googleAccessToken,
|
|
72
83
|
refreshToken: googleRefreshToken,
|
|
84
|
+
subdomain,
|
|
85
|
+
fcm_token,
|
|
73
86
|
} = req.user;
|
|
74
87
|
const { state } = req.query;
|
|
75
88
|
|
|
@@ -92,18 +105,20 @@ export class LoginController {
|
|
|
92
105
|
actualState,
|
|
93
106
|
);
|
|
94
107
|
|
|
95
|
-
return res.redirect(
|
|
96
|
-
`${this.configService.get('BASE_URL')}`,
|
|
97
|
-
);
|
|
108
|
+
return res.redirect(`${this.configService.get('BASE_URL')}`);
|
|
98
109
|
} catch (error) {
|
|
99
|
-
return res.redirect(
|
|
100
|
-
`${this.configService.get('BASE_URL')}`,
|
|
101
|
-
);
|
|
110
|
+
return res.redirect(`${this.configService.get('BASE_URL')}`);
|
|
102
111
|
}
|
|
103
112
|
}
|
|
104
113
|
|
|
105
114
|
// Original login flow
|
|
106
|
-
const data = await this.loginService.loginWithGoogle(
|
|
115
|
+
const data = await this.loginService.loginWithGoogle({
|
|
116
|
+
email,
|
|
117
|
+
password,
|
|
118
|
+
name,
|
|
119
|
+
subdomain,
|
|
120
|
+
fcm_token,
|
|
121
|
+
});
|
|
107
122
|
|
|
108
123
|
if (!('accessToken' in data) || !data.accessToken)
|
|
109
124
|
return res.redirect(
|
|
@@ -29,7 +29,12 @@ export class UserController {
|
|
|
29
29
|
|
|
30
30
|
@Post('check-email')
|
|
31
31
|
@HttpCode(HttpStatus.OK)
|
|
32
|
-
async checkEmail(@Body(
|
|
33
|
-
|
|
32
|
+
async checkEmail(@Body() body, @Res() res: Response) {
|
|
33
|
+
const { email, subdomain } = body;
|
|
34
|
+
const result = await this.userService.checkEmailExists({
|
|
35
|
+
email,
|
|
36
|
+
subdomain,
|
|
37
|
+
});
|
|
38
|
+
return res.status(HttpStatus.OK).json(result);
|
|
34
39
|
}
|
|
35
40
|
}
|
|
@@ -31,17 +31,22 @@ export class LoginService {
|
|
|
31
31
|
@Inject('ListMasterService')
|
|
32
32
|
private readonly listMasterService: ListMasterService,
|
|
33
33
|
private readonly jwtAuthService: JwtAuthService,
|
|
34
|
+
@InjectRepository(UserData)
|
|
35
|
+
private readonly userRepository: Repository<UserData>,
|
|
34
36
|
) {}
|
|
35
37
|
|
|
36
38
|
masterKey: string = this.configService.get('MASTER_KEY') || '';
|
|
37
39
|
masterIv: string = this.configService.get('MASTER_IV') || '';
|
|
38
40
|
|
|
39
|
-
async login(
|
|
40
|
-
email: string
|
|
41
|
-
password?: string
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
async login(data: {
|
|
42
|
+
email: string;
|
|
43
|
+
password?: string;
|
|
44
|
+
subdomain: string;
|
|
45
|
+
fcm_token: string;
|
|
46
|
+
is_otp?: boolean;
|
|
47
|
+
}) {
|
|
48
|
+
const { email, password, is_otp = false, subdomain, fcm_token } = data;
|
|
49
|
+
|
|
45
50
|
let organization;
|
|
46
51
|
|
|
47
52
|
// 🔹 Step 1: If subdomain is provided, resolve the organization
|
|
@@ -63,6 +68,10 @@ export class LoginService {
|
|
|
63
68
|
throw new BadRequestException('User not found in organization.');
|
|
64
69
|
}
|
|
65
70
|
|
|
71
|
+
if (fcm_token) {
|
|
72
|
+
await this.userRepository.update({ id: user.id }, { fcm_token });
|
|
73
|
+
}
|
|
74
|
+
|
|
66
75
|
// 🔹 Step 3: Verify org status
|
|
67
76
|
const userOrgData = await this.organizationRepository.findOrganizationById(
|
|
68
77
|
user.organization_id,
|
|
@@ -245,7 +254,14 @@ export class LoginService {
|
|
|
245
254
|
);
|
|
246
255
|
}
|
|
247
256
|
|
|
248
|
-
async loginWithGoogle(
|
|
257
|
+
async loginWithGoogle(data: {
|
|
258
|
+
email: string;
|
|
259
|
+
password: string;
|
|
260
|
+
name;
|
|
261
|
+
subdomain: string;
|
|
262
|
+
fcm_token: string;
|
|
263
|
+
}) {
|
|
264
|
+
const { email, password, name, subdomain, fcm_token } = data;
|
|
249
265
|
const user = await this.userService.findByEmailId(email);
|
|
250
266
|
|
|
251
267
|
if (!user) {
|
|
@@ -269,7 +285,7 @@ export class LoginService {
|
|
|
269
285
|
}
|
|
270
286
|
|
|
271
287
|
// Create session (Same as JWT login flow)
|
|
272
|
-
return await this.login(
|
|
288
|
+
return await this.login(data);
|
|
273
289
|
}
|
|
274
290
|
|
|
275
291
|
async logout(sessionKey: string) {
|
|
@@ -19,12 +19,14 @@ import {
|
|
|
19
19
|
import { CreateUserDto } from '../dto/create-user.dto';
|
|
20
20
|
import { UserRoleMappingService } from './user-role-mapping.service';
|
|
21
21
|
import { UserRoleMapping } from '../entity/user-role-mapping.entity';
|
|
22
|
-
import { EntityManager } from 'typeorm';
|
|
22
|
+
import { EntityManager, Repository } from 'typeorm';
|
|
23
23
|
import { UpdateUserDto } from '../dto/update-user.dto';
|
|
24
24
|
import { ConfigService } from '@nestjs/config';
|
|
25
25
|
// import { UserAppMappingService } from 'src/module/meta/service/user-app-mapping.service';
|
|
26
26
|
import { ServiceResult } from 'src/dtos/response.dto';
|
|
27
27
|
import { ListMasterService } from 'src/module/listmaster/service/list-master.service';
|
|
28
|
+
import { OrganizationRepository } from 'src/module/enterprise/repository/organization.repository';
|
|
29
|
+
import { InjectRepository } from '@nestjs/typeorm';
|
|
28
30
|
|
|
29
31
|
@Injectable()
|
|
30
32
|
export class UserService extends EntityServiceImpl {
|
|
@@ -33,6 +35,7 @@ export class UserService extends EntityServiceImpl {
|
|
|
33
35
|
private userRoleMappingService: UserRoleMappingService,
|
|
34
36
|
private readonly clockIDGenService: ClockIDGenService,
|
|
35
37
|
private configService: ConfigService,
|
|
38
|
+
private readonly organizationRepository: OrganizationRepository,
|
|
36
39
|
// private readonly userAppMappingService: UserAppMappingService,
|
|
37
40
|
@Inject('RoleService') private readonly roleService: RoleService,
|
|
38
41
|
@Inject('ListMasterService')
|
|
@@ -53,7 +56,7 @@ export class UserService extends EntityServiceImpl {
|
|
|
53
56
|
|
|
54
57
|
let existingUser = await this.userRepository.findByEmailId(
|
|
55
58
|
userData.email_id,
|
|
56
|
-
|
|
59
|
+
loggedInUser?.organization_id,
|
|
57
60
|
);
|
|
58
61
|
if (existingUser) {
|
|
59
62
|
return { success: false, error: 'User with this email already exists' };
|
|
@@ -61,7 +64,7 @@ export class UserService extends EntityServiceImpl {
|
|
|
61
64
|
|
|
62
65
|
existingUser = await this.userRepository.findByMobile(
|
|
63
66
|
userData.mobile,
|
|
64
|
-
|
|
67
|
+
loggedInUser?.organization_id,
|
|
65
68
|
);
|
|
66
69
|
if (existingUser) {
|
|
67
70
|
return { success: false, error: 'User with this mobile already exists' };
|
|
@@ -298,13 +301,36 @@ export class UserService extends EntityServiceImpl {
|
|
|
298
301
|
await this.userRepository.saveUser(user); // This persists the updated field
|
|
299
302
|
}
|
|
300
303
|
|
|
301
|
-
async checkEmailExists(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
+
async checkEmailExists(data: {
|
|
305
|
+
email: string;
|
|
306
|
+
subdomain: string;
|
|
307
|
+
}): Promise<any> {
|
|
308
|
+
const { email, subdomain } = data;
|
|
309
|
+
|
|
310
|
+
if (!email || !subdomain) {
|
|
311
|
+
return { success: false, message: 'Email and Subdomain is required' };
|
|
304
312
|
}
|
|
305
313
|
|
|
314
|
+
let organization;
|
|
315
|
+
|
|
316
|
+
if (subdomain) {
|
|
317
|
+
organization =
|
|
318
|
+
await this.organizationRepository.findOrganizationBySubdomain(
|
|
319
|
+
subdomain,
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
if (!organization) {
|
|
323
|
+
throw new BadRequestException('Organization not found.');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// 🔹 Step 2: Find the user by email + organization check
|
|
306
328
|
const user = await this.userRepository.findByEmailId(email);
|
|
307
329
|
|
|
330
|
+
if (!user || (organization && user.organization_id !== organization.id)) {
|
|
331
|
+
throw new BadRequestException('User not found in organization.');
|
|
332
|
+
}
|
|
333
|
+
|
|
308
334
|
if (user) {
|
|
309
335
|
return {
|
|
310
336
|
success: true,
|
|
@@ -9,6 +9,7 @@ import { ActivityLogService } from './activity-log.service';
|
|
|
9
9
|
import { ACTIVITY_CATEGORIES } from '../repository/activity-log.repository';
|
|
10
10
|
import { MediaDataService } from 'src/module/meta/service/media-data.service';
|
|
11
11
|
import { Cron, CronExpression } from '@nestjs/schedule';
|
|
12
|
+
import { NotificationsService } from 'src/module/notification/service/notification.service';
|
|
12
13
|
|
|
13
14
|
@Injectable()
|
|
14
15
|
export class TaskService extends EntityServiceImpl {
|
|
@@ -19,6 +20,7 @@ export class TaskService extends EntityServiceImpl {
|
|
|
19
20
|
@Inject('ActivityLogService')
|
|
20
21
|
private readonly activityLogService: ActivityLogService,
|
|
21
22
|
private readonly mediaDataService: MediaDataService,
|
|
23
|
+
private readonly notificationsService: NotificationsService, // 👈 inject here
|
|
22
24
|
) {
|
|
23
25
|
super();
|
|
24
26
|
}
|
|
@@ -485,6 +487,11 @@ export class TaskService extends EntityServiceImpl {
|
|
|
485
487
|
task.level_type,
|
|
486
488
|
],
|
|
487
489
|
);
|
|
490
|
+
await this.notificationsService.sendToUser(
|
|
491
|
+
String(task.task_owner), // userId as string
|
|
492
|
+
'Task Reminder',
|
|
493
|
+
message,
|
|
494
|
+
);
|
|
488
495
|
}
|
|
489
496
|
}
|
|
490
497
|
}
|
|
@@ -62,6 +62,7 @@ import { ActivityLog } from './entity/activity-log.entity';
|
|
|
62
62
|
import { ActivityLogService } from './service/activity-log.service';
|
|
63
63
|
import { ActivityLogRepository } from './repository/activity-log.repository';
|
|
64
64
|
import { ActivityLogController } from './controller/activity-log.controller';
|
|
65
|
+
import { NotificationModule } from '../notification/notification.module';
|
|
65
66
|
|
|
66
67
|
@Module({
|
|
67
68
|
imports: [
|
|
@@ -87,6 +88,7 @@ import { ActivityLogController } from './controller/activity-log.controller';
|
|
|
87
88
|
]),
|
|
88
89
|
EntityModule,
|
|
89
90
|
ListMasterModule,
|
|
91
|
+
NotificationModule,
|
|
90
92
|
],
|
|
91
93
|
providers: [
|
|
92
94
|
{ provide: 'ActionCategoryService', useClass: ActionCategoryService },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
DB_HOST:
|
|
1
|
+
DB_HOST: '13.234.25.234'
|
|
2
2
|
# DB_HOST: 'localhost'
|
|
3
3
|
DB_PORT: '3306'
|
|
4
4
|
DB_USER: 'root'
|
|
@@ -16,9 +16,13 @@ OTP_LENGTH: '6'
|
|
|
16
16
|
VERIFY_OTP: 'false'
|
|
17
17
|
DEFAULT_OTP: '123456'
|
|
18
18
|
TOKEN_EXPIRY: 1
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
AWS:
|
|
20
|
+
S3:
|
|
21
|
+
AWS_ACCESS_KEY_ID: 'AKIAYYKIBDDSQF3KILGE'
|
|
22
|
+
AWS_SECRET_KEY: 'PPDMAeO2mVUY1w2f46n/dlt5l9+7NY7E9twJb9LU'
|
|
23
|
+
AWS_REGION: 'ap-south-1'
|
|
24
|
+
BUCKET_NAME: 'testether'
|
|
25
|
+
|
|
26
|
+
FIREBASE_PROJECT_ID: 'sample-d7855'
|
|
27
|
+
FIREBASE_CLIENT_EMAIL: 'firebase-adminsdk-fbsvc@sample-d7855.iam.gserviceaccount.com'
|
|
28
|
+
FIREBASE_PRIVATE_KEY: '-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwGkpDLqFYgDEW\nnrraMja7ICmd05rJlsTachdcbB25Jm2cWMv1ROfNqWEZE3b14pUJOQgCAPI79Lgj\n+nQ0ATsUWK8Th2esKT9kaHg54UZg/qKNcnM5njVn+xIXc+i/AP/eSGBLich+uljU\nRMFuKrpcN1yNa3t0ib+kZxLHE43aFM9aJYOhET6/37DUdFMZ7GyzSLH3tuy1gB2G\negFyC7ulLnyMBFtL37XOtnP3BPwbjVWdP0qv9I6c0aacS5dQ4PNjCBklnkr6tPsc\n0MYr3VUrqNd/xNNOgk26TwoOaePjjjeaSeOGO2FcBG6WsYSLoZ3zmrlCT4vBlXL7\nPaZGQGfjAgMBAAECggEAHtsMZgcWmCYl87uuK6sesdzpzdCUz3uOVGQnObdr4dQc\n4ocgfYIsR3nFHJqvflfMG0iV4Zv+1YiEdzFcCPyqOF9tlbNk8+JqTBKN9j5FkZss\nKjKCg/b3jpeMTPWvM0BelLkDvliO+7108QR3C/GKo7vDiLfrcrjsDkdNH/qKIUq3\nkHeQE0QDLaoe3sLL4mjPp5A4SnnNBInk1gQZS2iVhTgDAAlSOz7JocyVZr3QhxmF\nUlKYzzJVx8zxIJm3ymH6z6NQNbWnBGWF1eeSZgYRkJG1q+Aqm3kRU/uT3V0HPsvZ\nrg4JGkzM/qFA2mpKuj4ysWGfvERKaEe4Ua84SvbcYQKBgQDjjvgBpQL2V71Ssr2E\nWJO/8Bv3TutWODWEvTRv3woQmuZwT81yIR3R8Ir59xLK0oBQCAONvKnrB5RM5yXQ\nmR6hvyKHFUKWTRqwGCFiD4fh0joO4zQTaFDdbqMYyeTJ4r2W66wXbRXtUvuwhDlg\nmDKamZ1E+EAoYkog6/iNYIcwswKBgQDGHO0n2r8yXYm7dM+EYONGLh76IvxVXJDn\nN8igi1zI2fV3cfUuwXaVlMYUa//aRkNXrBvPdXZEvfRRRLkm6dYLbFZ4Sq6T+NUT\noYNan13R59E6UcA/Oi5jitq9l4Wwn8pDaCbmmR1xdj7+r+H9A5N3BXHeuPLy0f48\nyEY8GF8kEQKBgQDCzhmyDrlCekoxCaMEMXAK2FqYlI8S+HuYbwD85EuRe4nai/as\nxXzpxKq04rbLuvjtim7AX8p20b47N4Y/1VVL0nyUd7bRRKCcL4wkjncc8wOQyyBB\nnQPdDGHDTtL1oY38LTTduR0UVf3xVsBn2OM5RlhEOuFxsPMUy+2z2fbh0QKBgBz3\nMb14AChvAKpFw+mI+PHT4HeWEeqxJAaKY20Fs0UyiO8z3DM/2gS4wdVOjRPu3f29\njjtg4y/dzhDryV5lJgR5jJL96FR+NzktjjT7xA3ipPav6TnVWd73+E9sDgHq+vms\nCrQAgwuJzGAUeygxE6h9RU7ZH7xc850TcyFqNs7hAoGBAMviFpBfpZz/amStyan+\nIPBGpDNV8dUrRE1POIdi6M44mlrI5hkD1ldVl3wjDJtg4VGkMosltLtvC0dDcIou\nuWZT8ENKM2G400PvQ9JJYah9dTkYQL1qMxvpX+biMoRSiAswPwRQjmBQUaz1aN1g\nmXv1VJBLLZVg8x1ckLDjeD20\n-----END PRIVATE KEY-----\n'
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"type": "service_account",
|
|
3
|
-
"project_id": "sample-d7855",
|
|
4
|
-
"private_key_id": "753237e3e7d64a87155b916deda9f3d1cb9cdd52",
|
|
5
|
-
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQChrgvD+0M3u8EU\ntm3xV27RGuYRSjIpZIRi6I3tH0BTwpOde4DnwZWUQnTEbg/wgBGvFtGS7T4UXaef\ngkhTSRqPhIqEaIVRXf34NOhYTAOxBcvDaG9skQbOzhH9gz8cEG1HyDRCWqmxgpCy\nt0jUig5Ta72t0zSaQKc/H6AhwWF8Yiz+KnwGR837FvKDM+ZN28B21sRNcOciDXHf\nEeh4H4GjBQguM+5aMGFRACclIFztwxwTBXCJ2r/AMxSjCntzOCHimgG6dOtlW/KS\neZqunZjxvbmHZpj3N1sGRJQFHFjRLQSgCdMzwOclJ82AImcOYLJ3w1kKTmts6JlW\nVYvj6jzpAgMBAAECggEAA9xhIYv1ffY41SLKG1JILiwjRFRuQDjLRIVjJj9xzM4/\nsioJ2P7xcHnpyesK7GZShcjYtlZ9/gSChTeaPIrpXHYAzMqmLFw/PVceGUWvbOHD\njOYIiyIndHbNTS1+K1BlG6q3PMJnfPquM+ZWkeS+FNXk0KrTfb9/fu1laIjyqAKy\na8w7IwNkk4iBkKxRc74204TxQsgUpooROuoP9JfoVVL90R1EDFJWnrciTcqB77SS\nAFsPbOY9kZ5WOmUp6ZzkQD434fRRCUis7WdicV4OU0VEQmLX57UxzxNTOZzw8Adn\nnn7nmFXfcF5+ODX1htkTSn84p+qP4CR+a99/4rLqgQKBgQDbbsySP4I0KBhXT+xQ\n8iHpTo8lV71R1t4gboBIQXIHkmlrI9Qy/oOe3yViATp54oH727W/vWm4OEomzpl4\nNrs27HrI65XZcYyRCU6mLEaDx2ZjYYKHLMwx0DdQ9MPn+n1JusadiRN671ZZ3smb\nbtMLqeslmoN43SPDiG2CSNOycQKBgQC8n3RViNpHZJDUQoLxHZ7rpfIa/0v3qpjd\nI3nDxDH8udu2ipsVjqXmGJTBY+NQcWhuvuhYTzH5plnSuD3tBrPnA3VoN7FFDd29\nx+5K60acjgbu0sa9yO4aSAYD7sjkfkxVAKhzIgNWlAzl2zluakq5r3+uGQ+FVvJh\nmo5FxSj9+QKBgBkaBqrgOvvObmJmkSj9WeW/h96Et/KJuuVI3sHlQq8dD5QjCB5B\nQTtGWZdpfo/82lO+YX8qotJhFhJ0Zdf7otT4nl8nm//A3oyk3OtjezmN8OeDexQN\nitpT8FABf/ukivqJNDlHOgRBJsanFrcCKYBXEsA9eba0zWeLzsMto5HxAoGBAIaH\nW5udzcDZkwownd+GdtAvPSvQJchwnjIqmS/tAJH1pSTeWpnXca9YnNAJhBjdqdRC\nyMgjQ8uAv9OwoEorW6hKKTS5c++CYkJ3FBfPEj+adItlPWYipt+Luu6XIiUFhz+h\nBoOHIMZhNYnC/4UmvkENUI1FRnKdfqXqa8qLQh9RAoGBAMxOm2fMUKzLPY8xqp0j\nWmo3ZYMkRRi/BFqVn1F+aFGx0ahW8GVT70qy30rhiNJAkl2QnPnllQ6rD/CBc3UT\n3kJLwTc5BWXP1nKxEOuu33xB5wk4mIzyItFf/eYhYFzsWMpJo2gaKE3iNNUKUP0W\nG2coAWXT2iRSS6OHh9B1bRnQ\n-----END PRIVATE KEY-----\n",
|
|
6
|
-
"client_email": "firebase-adminsdk-fbsvc@sample-d7855.iam.gserviceaccount.com",
|
|
7
|
-
"client_id": "115995668082397151669",
|
|
8
|
-
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
9
|
-
"token_uri": "https://oauth2.googleapis.com/token",
|
|
10
|
-
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
|
11
|
-
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40sample-d7855.iam.gserviceaccount.com",
|
|
12
|
-
"universe_domain": "googleapis.com"
|
|
13
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export declare class NotificationsService {
|
|
2
|
-
private tokens;
|
|
3
|
-
saveToken(userId: string | undefined, token: string): Promise<{
|
|
4
|
-
success: boolean;
|
|
5
|
-
token: string;
|
|
6
|
-
}>;
|
|
7
|
-
sendToDevice(token: string, title: string, body: string): Promise<string>;
|
|
8
|
-
sendToUser(userId: string, title: string, body: string): Promise<string | {
|
|
9
|
-
error: string;
|
|
10
|
-
}>;
|
|
11
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.NotificationsService = void 0;
|
|
10
|
-
const common_1 = require("@nestjs/common");
|
|
11
|
-
const firebase_admin_config_1 = require("../firebase-admin.config");
|
|
12
|
-
let NotificationsService = class NotificationsService {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.tokens = new Map();
|
|
15
|
-
}
|
|
16
|
-
async saveToken(userId, token) {
|
|
17
|
-
if (userId) {
|
|
18
|
-
this.tokens.set(userId, token);
|
|
19
|
-
}
|
|
20
|
-
return { success: true, token };
|
|
21
|
-
}
|
|
22
|
-
async sendToDevice(token, title, body) {
|
|
23
|
-
const message = {
|
|
24
|
-
token,
|
|
25
|
-
notification: { title, body },
|
|
26
|
-
};
|
|
27
|
-
return firebase_admin_config_1.firebaseAdmin.messaging().send(message);
|
|
28
|
-
}
|
|
29
|
-
async sendToUser(userId, title, body) {
|
|
30
|
-
const token = this.tokens.get(userId);
|
|
31
|
-
if (!token)
|
|
32
|
-
return { error: 'No token found for user' };
|
|
33
|
-
return this.sendToDevice(token, title, body);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
exports.NotificationsService = NotificationsService;
|
|
37
|
-
exports.NotificationsService = NotificationsService = __decorate([
|
|
38
|
-
(0, common_1.Injectable)()
|
|
39
|
-
], NotificationsService);
|
|
40
|
-
//# sourceMappingURL=firebase.service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"firebase.service.js","sourceRoot":"","sources":["../../../../src/module/notification/service/firebase.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAC5C,oEAAyD;AAGlD,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAA1B;QACG,WAAM,GAAwB,IAAI,GAAG,EAAE,CAAC;IAyBlD,CAAC;IAvBC,KAAK,CAAC,SAAS,CAAC,MAA0B,EAAE,KAAa;QACvD,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,KAAa,EAAE,IAAY;QAC3D,MAAM,OAAO,GAAG;YACd,KAAK;YACL,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;SAC9B,CAAC;QAEF,OAAO,qCAAa,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;IAGD,KAAK,CAAC,UAAU,CAAC,MAAc,EAAE,KAAa,EAAE,IAAY;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;QAExD,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;CACF,CAAA;AA1BY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;GACA,oBAAoB,CA0BhC"}
|