Auspicious14 commited on
Commit
1687bb1
·
1 Parent(s): 683d259

feat(auth): add case-insensitive email matching and return user in auth response

Browse files

- Normalize email to lowercase for all auth operations to ensure case-insensitive matching
- Include user profile data in login/refresh token response payload
- Add error handling for missing user profiles in inactivity monitoring
- Standardize import quotes to double quotes in monitoring scheduler

src/auth/auth.service.ts CHANGED
@@ -54,7 +54,10 @@ export class AuthService {
54
 
55
  // Find user — build conditions dynamically to avoid empty {} matching all rows
56
  const conditions: any[] = [];
57
- if (email) conditions.push({ email });
 
 
 
58
  if (phone) conditions.push({ phone });
59
 
60
  const user = await this.prisma.userAuth.findFirst({
@@ -148,7 +151,11 @@ export class AuthService {
148
 
149
  // Check for existing user — build conditions dynamically
150
  const conditions: any[] = [];
151
- if (email) conditions.push({ email });
 
 
 
 
152
  if (phone) conditions.push({ phone });
153
 
154
  const existingUser = await this.prisma.userAuth.findFirst({
@@ -168,7 +175,7 @@ export class AuthService {
168
  try {
169
  const user = await this.prisma.userAuth.create({
170
  data: {
171
- email,
172
  phone,
173
  passwordHash,
174
  },
@@ -202,7 +209,10 @@ export class AuthService {
202
 
203
  // Find user — build conditions dynamically
204
  const loginConditions: any[] = [];
205
- if (email) loginConditions.push({ email });
 
 
 
206
  if (phone) loginConditions.push({ phone });
207
 
208
  const user = await this.prisma.userAuth.findFirst({
@@ -308,15 +318,22 @@ export class AuthService {
308
  });
309
 
310
  // Store refresh token in database
311
- await this.prisma.userAuth.update({
312
  where: { id: userId },
313
  data: { refreshToken },
 
 
 
 
 
 
314
  });
315
 
316
  return {
317
  accessToken,
318
  refreshToken,
319
  userId,
 
320
  };
321
  }
322
 
 
54
 
55
  // Find user — build conditions dynamically to avoid empty {} matching all rows
56
  const conditions: any[] = [];
57
+ if (email)
58
+ conditions.push({
59
+ email: { equals: email.toLowerCase(), mode: "insensitive" },
60
+ });
61
  if (phone) conditions.push({ phone });
62
 
63
  const user = await this.prisma.userAuth.findFirst({
 
151
 
152
  // Check for existing user — build conditions dynamically
153
  const conditions: any[] = [];
154
+ const normalizedEmail = email?.toLowerCase();
155
+ if (normalizedEmail)
156
+ conditions.push({
157
+ email: { equals: normalizedEmail, mode: "insensitive" },
158
+ });
159
  if (phone) conditions.push({ phone });
160
 
161
  const existingUser = await this.prisma.userAuth.findFirst({
 
175
  try {
176
  const user = await this.prisma.userAuth.create({
177
  data: {
178
+ email: normalizedEmail,
179
  phone,
180
  passwordHash,
181
  },
 
209
 
210
  // Find user — build conditions dynamically
211
  const loginConditions: any[] = [];
212
+ if (email)
213
+ loginConditions.push({
214
+ email: { equals: email.toLowerCase(), mode: "insensitive" },
215
+ });
216
  if (phone) loginConditions.push({ phone });
217
 
218
  const user = await this.prisma.userAuth.findFirst({
 
318
  });
319
 
320
  // Store refresh token in database
321
+ const user = await this.prisma.userAuth.update({
322
  where: { id: userId },
323
  data: { refreshToken },
324
+ select: {
325
+ id: true,
326
+ email: true,
327
+ phone: true,
328
+ isActive: true,
329
+ },
330
  });
331
 
332
  return {
333
  accessToken,
334
  refreshToken,
335
  userId,
336
+ user,
337
  };
338
  }
339
 
src/auth/dto/auth-response.dto.ts CHANGED
@@ -7,4 +7,5 @@ export class AuthResponseDto {
7
  accessToken!: string;
8
  refreshToken!: string;
9
  userId!: string;
 
10
  }
 
7
  accessToken!: string;
8
  refreshToken!: string;
9
  userId!: string;
10
+ user?: any;
11
  }
src/monitoring-engine/monitoring-scheduler.service.ts CHANGED
@@ -1,15 +1,15 @@
1
- import { Injectable, Logger } from '@nestjs/common';
2
- import { Cron, CronExpression } from '@nestjs/schedule';
3
- import { PrismaService } from '../database/prisma.service';
4
- import { MonitoringEngineService } from './monitoring-engine.service';
5
  import {
6
  FollowUpTaskStatus,
7
  FollowUpTaskType,
8
  MonitoringState,
9
- } from '@prisma/client';
10
- import { NotificationsService } from '../notifications/notifications.service';
11
- import { UserProfileService } from '../user-profile/user-profile.service';
12
- import { AppNotificationType } from '../common/enums/app-notification-type.enum';
13
 
14
  @Injectable()
15
  export class MonitoringSchedulerService {
@@ -24,7 +24,7 @@ export class MonitoringSchedulerService {
24
 
25
  @Cron(CronExpression.EVERY_HOUR)
26
  async handleOverdueFollowUps() {
27
- this.logger.log('Checking for overdue follow-up tasks...');
28
  const now = new Date();
29
 
30
  const overdueTasks = await this.prisma.followUpTask.findMany({
@@ -52,7 +52,7 @@ export class MonitoringSchedulerService {
52
  // Trigger notification
53
  await this.notificationsService.sendPushNotification(
54
  task.userId,
55
- 'Follow-up Missed',
56
  `Your ${task.type} follow-up task was missed. Current state: ${result.state}.`,
57
  { type: AppNotificationType.FOLLOW_UP_MISSED },
58
  );
@@ -62,9 +62,9 @@ export class MonitoringSchedulerService {
62
  );
63
  }
64
 
65
- @Cron('0 9 * * *') // Every day at 9 AM
66
  async handleInactivity() {
67
- this.logger.log('Checking for user inactivity...');
68
  const now = new Date();
69
  const fiveDaysAgo = new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000);
70
  const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
@@ -73,7 +73,7 @@ export class MonitoringSchedulerService {
73
  select: {
74
  id: true,
75
  bloodPressureReadings: {
76
- orderBy: { recordedAt: 'desc' },
77
  take: 1,
78
  },
79
  },
@@ -83,16 +83,25 @@ export class MonitoringSchedulerService {
83
  const lastBpReading = user.bloodPressureReadings[0];
84
  if (!lastBpReading) {
85
  // No BP ever logged, send initial reminder after 5 days of account creation
86
- const userProfile = await this.userProfileService.findByUserId(user.id);
87
- if (userProfile && userProfile.createdAt < fiveDaysAgo) {
88
- await this.notificationsService.sendPushNotification(
89
  user.id,
90
- 'BP Log Reminder',
91
- "You haven't logged your blood pressure yet. Please log your first reading.",
92
- { type: AppNotificationType.INACTIVITY_REMINDER },
93
  );
94
- this.logger.log(
95
- `Inactivity reminder sent to user ${user.id} (no BP ever logged).`,
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  );
97
  }
98
  continue;
@@ -102,7 +111,7 @@ export class MonitoringSchedulerService {
102
  // No BP logged in >7 days -> escalate messaging urgency
103
  await this.notificationsService.sendPushNotification(
104
  user.id,
105
- 'Urgent BP Reminder',
106
  "It's been over 7 days since your last blood pressure reading. Please log it now.",
107
  { type: AppNotificationType.URGENT_INACTIVITY_REMINDER },
108
  );
@@ -113,7 +122,7 @@ export class MonitoringSchedulerService {
113
  // No BP logged in >5 days -> send reminder
114
  await this.notificationsService.sendPushNotification(
115
  user.id,
116
- 'BP Log Reminder',
117
  "It's been over 5 days since your last blood pressure reading. Please log it soon.",
118
  { type: AppNotificationType.INACTIVITY_REMINDER },
119
  );
@@ -122,6 +131,6 @@ export class MonitoringSchedulerService {
122
  );
123
  }
124
  }
125
- this.logger.log('Finished checking for user inactivity.');
126
  }
127
  }
 
1
+ import { Injectable, Logger } from "@nestjs/common";
2
+ import { Cron, CronExpression } from "@nestjs/schedule";
3
+ import { PrismaService } from "../database/prisma.service";
4
+ import { MonitoringEngineService } from "./monitoring-engine.service";
5
  import {
6
  FollowUpTaskStatus,
7
  FollowUpTaskType,
8
  MonitoringState,
9
+ } from "@prisma/client";
10
+ import { NotificationsService } from "../notifications/notifications.service";
11
+ import { UserProfileService } from "../user-profile/user-profile.service";
12
+ import { AppNotificationType } from "../common/enums/app-notification-type.enum";
13
 
14
  @Injectable()
15
  export class MonitoringSchedulerService {
 
24
 
25
  @Cron(CronExpression.EVERY_HOUR)
26
  async handleOverdueFollowUps() {
27
+ this.logger.log("Checking for overdue follow-up tasks...");
28
  const now = new Date();
29
 
30
  const overdueTasks = await this.prisma.followUpTask.findMany({
 
52
  // Trigger notification
53
  await this.notificationsService.sendPushNotification(
54
  task.userId,
55
+ "Follow-up Missed",
56
  `Your ${task.type} follow-up task was missed. Current state: ${result.state}.`,
57
  { type: AppNotificationType.FOLLOW_UP_MISSED },
58
  );
 
62
  );
63
  }
64
 
65
+ @Cron("0 9 * * *") // Every day at 9 AM
66
  async handleInactivity() {
67
+ this.logger.log("Checking for user inactivity...");
68
  const now = new Date();
69
  const fiveDaysAgo = new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000);
70
  const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
 
73
  select: {
74
  id: true,
75
  bloodPressureReadings: {
76
+ orderBy: { recordedAt: "desc" },
77
  take: 1,
78
  },
79
  },
 
83
  const lastBpReading = user.bloodPressureReadings[0];
84
  if (!lastBpReading) {
85
  // No BP ever logged, send initial reminder after 5 days of account creation
86
+ try {
87
+ const userProfile = await this.userProfileService.findByUserId(
 
88
  user.id,
 
 
 
89
  );
90
+ if (userProfile && userProfile.createdAt < fiveDaysAgo) {
91
+ await this.notificationsService.sendPushNotification(
92
+ user.id,
93
+ "BP Log Reminder",
94
+ "You haven't logged your blood pressure yet. Please log your first reading.",
95
+ { type: AppNotificationType.INACTIVITY_REMINDER },
96
+ );
97
+ this.logger.log(
98
+ `Inactivity reminder sent to user ${user.id} (no BP ever logged).`,
99
+ );
100
+ }
101
+ } catch (error) {
102
+ // If profile not found, skip for now. Profiling is needed for notifications.
103
+ this.logger.debug(
104
+ `Skipping inactivity check for user ${user.id}: No profile found.`,
105
  );
106
  }
107
  continue;
 
111
  // No BP logged in >7 days -> escalate messaging urgency
112
  await this.notificationsService.sendPushNotification(
113
  user.id,
114
+ "Urgent BP Reminder",
115
  "It's been over 7 days since your last blood pressure reading. Please log it now.",
116
  { type: AppNotificationType.URGENT_INACTIVITY_REMINDER },
117
  );
 
122
  // No BP logged in >5 days -> send reminder
123
  await this.notificationsService.sendPushNotification(
124
  user.id,
125
+ "BP Log Reminder",
126
  "It's been over 5 days since your last blood pressure reading. Please log it soon.",
127
  { type: AppNotificationType.INACTIVITY_REMINDER },
128
  );
 
131
  );
132
  }
133
  }
134
+ this.logger.log("Finished checking for user inactivity.");
135
  }
136
  }