feat: implement privacy-aware profile visibility and activity status filtering using optional authentication guard

This commit is contained in:
pradeepkumar
2026-03-28 18:46:49 +05:30
parent ba931c350b
commit a71145f6a6
8 changed files with 235 additions and 38 deletions

View File

@@ -16,6 +16,17 @@ export class MessagesService {
private readonly eventEmitter: EventEmitter2,
) {}
/**
* Check if a user's activity status allows showing online status.
* Connected users always see online status for 'connections' setting.
*/
private shouldShowOnlineStatus(privacyPreferences: any, isConnected = true): boolean {
const activityStatus = (privacyPreferences as any)?.privacySettings?.activity_status || 'public';
if (activityStatus === 'public') return true;
if (activityStatus === 'connections' && isConnected) return true;
return false;
}
/**
* Validate if a user can message an agent (must have ACCEPTED connection)
*/
@@ -87,6 +98,7 @@ export class MessagesService {
select: {
isOnline: true,
lastSeenAt: true,
privacyPreferences: true,
},
},
},
@@ -96,6 +108,7 @@ export class MessagesService {
id: true,
isOnline: true,
lastSeenAt: true,
privacyPreferences: true,
userProfile: {
select: {
firstName: true,
@@ -130,8 +143,10 @@ export class MessagesService {
}
// Transform to include otherParty based on caller role
// Conversations only exist between connected users, so isConnected=true
if (callerRole === UserRole.AGENT) {
// Agent is viewing — other party is the user
const showStatus = this.shouldShowOnlineStatus(conversation.user.privacyPreferences);
return {
...conversation,
unreadCount: conversation.agentUnreadCount,
@@ -139,12 +154,13 @@ export class MessagesService {
id: conversation.user.id,
name: `${conversation.user.userProfile?.firstName || ''} ${conversation.user.userProfile?.lastName || ''}`.trim() || 'User',
avatar: conversation.user.userProfile?.avatar,
isOnline: conversation.user.isOnline,
lastSeenAt: conversation.user.lastSeenAt,
isOnline: showStatus ? conversation.user.isOnline : false,
lastSeenAt: showStatus ? conversation.user.lastSeenAt : null,
},
};
} else {
// User is viewing — other party is the agent
const showStatus = this.shouldShowOnlineStatus(conversation.agentProfile.user?.privacyPreferences);
return {
...conversation,
unreadCount: conversation.userUnreadCount,
@@ -154,8 +170,8 @@ export class MessagesService {
name: `${conversation.agentProfile.firstName || ''} ${conversation.agentProfile.lastName || ''}`.trim() || 'Agent',
avatar: conversation.agentProfile.avatar,
headline: conversation.agentProfile.headline,
isOnline: conversation.agentProfile.user?.isOnline || false,
lastSeenAt: conversation.agentProfile.user?.lastSeenAt || null,
isOnline: showStatus ? (conversation.agentProfile.user?.isOnline || false) : false,
lastSeenAt: showStatus ? (conversation.agentProfile.user?.lastSeenAt || null) : null,
},
};
}
@@ -306,6 +322,7 @@ export class MessagesService {
id: true,
isOnline: true,
lastSeenAt: true,
privacyPreferences: true,
userProfile: {
select: {
firstName: true,
@@ -324,17 +341,20 @@ export class MessagesService {
});
// Map to include unread count from agent perspective
return conversations.map((conv) => ({
...conv,
unreadCount: conv.agentUnreadCount,
otherParty: {
id: conv.user.id,
name: `${conv.user.userProfile?.firstName || ''} ${conv.user.userProfile?.lastName || ''}`.trim() || 'User',
avatar: conv.user.userProfile?.avatar,
isOnline: conv.user.isOnline,
lastSeenAt: conv.user.lastSeenAt,
},
}));
return conversations.map((conv) => {
const showStatus = this.shouldShowOnlineStatus(conv.user.privacyPreferences);
return {
...conv,
unreadCount: conv.agentUnreadCount,
otherParty: {
id: conv.user.id,
name: `${conv.user.userProfile?.firstName || ''} ${conv.user.userProfile?.lastName || ''}`.trim() || 'User',
avatar: conv.user.userProfile?.avatar,
isOnline: showStatus ? conv.user.isOnline : false,
lastSeenAt: showStatus ? conv.user.lastSeenAt : null,
},
};
});
} else {
// Regular user
conversations = await this.prisma.conversation.findMany({
@@ -352,6 +372,7 @@ export class MessagesService {
select: {
isOnline: true,
lastSeenAt: true,
privacyPreferences: true,
},
},
},
@@ -365,19 +386,22 @@ export class MessagesService {
});
// Map to include unread count from user perspective
return conversations.map((conv) => ({
...conv,
unreadCount: conv.userUnreadCount,
otherParty: {
id: conv.agentProfile.id,
userId: conv.agentProfile.userId,
name: `${conv.agentProfile.firstName || ''} ${conv.agentProfile.lastName || ''}`.trim() || 'Agent',
avatar: conv.agentProfile.avatar,
headline: conv.agentProfile.headline,
isOnline: conv.agentProfile.user.isOnline,
lastSeenAt: conv.agentProfile.user.lastSeenAt,
},
}));
return conversations.map((conv) => {
const showStatus = this.shouldShowOnlineStatus(conv.agentProfile.user.privacyPreferences);
return {
...conv,
unreadCount: conv.userUnreadCount,
otherParty: {
id: conv.agentProfile.id,
userId: conv.agentProfile.userId,
name: `${conv.agentProfile.firstName || ''} ${conv.agentProfile.lastName || ''}`.trim() || 'Agent',
avatar: conv.agentProfile.avatar,
headline: conv.agentProfile.headline,
isOnline: showStatus ? conv.agentProfile.user.isOnline : false,
lastSeenAt: showStatus ? conv.agentProfile.user.lastSeenAt : null,
},
};
});
}
}