notifications big
This commit is contained in:
parent
af1635b7da
commit
95fc180d3c
@ -315,11 +315,205 @@ export class RocketChatAdapter implements NotificationAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getNotifications(userId: string, page = 1, limit = 20): Promise<Notification[]> {
|
async getNotifications(userId: string, page = 1, limit = 20): Promise<Notification[]> {
|
||||||
// For now, return empty array - we can implement this later if needed
|
logger.debug('[ROCKETCHAT_ADAPTER] getNotifications called', { userId, page, limit });
|
||||||
// The notification count is what matters for the badge
|
|
||||||
|
try {
|
||||||
|
const email = await this.getUserEmail();
|
||||||
|
if (!email) {
|
||||||
|
logger.error('[ROCKETCHAT_ADAPTER] Could not get user email');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rocketChatUserId = await this.getRocketChatUserId(email);
|
||||||
|
if (!rocketChatUserId) {
|
||||||
|
logger.debug('[ROCKETCHAT_ADAPTER] User not found in RocketChat');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const userToken = await this.getUserToken(rocketChatUserId);
|
||||||
|
if (!userToken) {
|
||||||
|
logger.error('[ROCKETCHAT_ADAPTER] Could not get user token');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const userHeaders = {
|
||||||
|
'X-Auth-Token': userToken.authToken,
|
||||||
|
'X-User-Id': userToken.userId,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get user's subscriptions with unread messages
|
||||||
|
const subscriptionsResponse = await fetch(`${this.baseUrl}/api/v1/subscriptions.get`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: userHeaders
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!subscriptionsResponse.ok) {
|
||||||
|
logger.error('[ROCKETCHAT_ADAPTER] Failed to get subscriptions', {
|
||||||
|
status: subscriptionsResponse.status,
|
||||||
|
});
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscriptionsData = await subscriptionsResponse.json();
|
||||||
|
if (!subscriptionsData.success || !Array.isArray(subscriptionsData.update)) {
|
||||||
|
logger.error('[ROCKETCHAT_ADAPTER] Invalid subscriptions response');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter subscriptions with unread messages
|
||||||
|
const userSubscriptions = subscriptionsData.update.filter((sub: any) => {
|
||||||
|
return (sub.unread > 0 || sub.alert) && ['d', 'c', 'p'].includes(sub.t);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get user info for comparison
|
||||||
|
const usersResponse = await fetch(`${this.baseUrl}/api/v1/users.list`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'X-Auth-Token': process.env.ROCKET_CHAT_TOKEN!,
|
||||||
|
'X-User-Id': process.env.ROCKET_CHAT_USER_ID!,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let currentUser: any = null;
|
||||||
|
if (usersResponse.ok) {
|
||||||
|
const usersData = await usersResponse.json();
|
||||||
|
if (usersData.success && Array.isArray(usersData.users)) {
|
||||||
|
const username = email.split('@')[0];
|
||||||
|
currentUser = usersData.users.find((u: any) =>
|
||||||
|
u.username === username || u.emails?.some((e: any) => e.address === email)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const notifications: Notification[] = [];
|
||||||
|
|
||||||
|
// Fetch messages for each subscription with unread messages
|
||||||
|
for (const subscription of userSubscriptions) {
|
||||||
|
try {
|
||||||
|
// Determine the correct endpoint based on room type
|
||||||
|
let endpoint;
|
||||||
|
switch (subscription.t) {
|
||||||
|
case 'c':
|
||||||
|
endpoint = 'channels.messages';
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
endpoint = 'groups.messages';
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
endpoint = 'im.messages';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParams = new URLSearchParams({
|
||||||
|
roomId: subscription.rid,
|
||||||
|
count: String(Math.max(subscription.unread, 1)) // Fetch at least 1 message
|
||||||
|
});
|
||||||
|
|
||||||
|
const messagesResponse = await fetch(
|
||||||
|
`${this.baseUrl}/api/v1/${endpoint}?${queryParams}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: userHeaders
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!messagesResponse.ok) {
|
||||||
|
logger.error('[ROCKETCHAT_ADAPTER] Failed to get messages for room', {
|
||||||
|
roomName: subscription.name,
|
||||||
|
status: messagesResponse.status,
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageData = await messagesResponse.json();
|
||||||
|
|
||||||
|
if (messageData.success && messageData.messages?.length > 0) {
|
||||||
|
// Get the latest unread message (skip own messages)
|
||||||
|
const unreadMessages = messageData.messages.filter((msg: any) => {
|
||||||
|
// Skip messages sent by current user
|
||||||
|
if (currentUser && msg.u?._id === currentUser._id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Skip system messages
|
||||||
|
if (msg.t || !msg.msg) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (unreadMessages.length > 0) {
|
||||||
|
const latestMessage = unreadMessages[0];
|
||||||
|
const messageUser = latestMessage.u || {};
|
||||||
|
const roomName = subscription.fname || subscription.name || subscription.name;
|
||||||
|
|
||||||
|
// Determine room type for link
|
||||||
|
let roomTypePath = 'channel';
|
||||||
|
if (subscription.t === 'd') roomTypePath = 'direct';
|
||||||
|
else if (subscription.t === 'p') roomTypePath = 'group';
|
||||||
|
|
||||||
|
const notification: Notification = {
|
||||||
|
id: `rocketchat-${latestMessage._id}`,
|
||||||
|
source: 'rocketchat',
|
||||||
|
sourceId: latestMessage._id,
|
||||||
|
type: 'message',
|
||||||
|
title: subscription.t === 'd'
|
||||||
|
? `Message de ${messageUser.name || messageUser.username || 'Utilisateur'}`
|
||||||
|
: `${messageUser.name || messageUser.username || 'Utilisateur'} dans ${roomName}`,
|
||||||
|
message: latestMessage.msg || '',
|
||||||
|
link: `${this.baseUrl}/${roomTypePath}/${subscription.name}`,
|
||||||
|
isRead: false, // All messages here are unread
|
||||||
|
timestamp: new Date(latestMessage.ts),
|
||||||
|
priority: subscription.alert ? 'high' : 'normal',
|
||||||
|
user: {
|
||||||
|
id: messageUser._id || '',
|
||||||
|
name: messageUser.name || messageUser.username || 'Utilisateur',
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
roomId: subscription.rid,
|
||||||
|
roomName: roomName,
|
||||||
|
roomType: subscription.t,
|
||||||
|
unreadCount: subscription.unread,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
notifications.push(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('[ROCKETCHAT_ADAPTER] Error fetching messages for room', {
|
||||||
|
roomName: subscription.name,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by timestamp (newest first) and apply pagination
|
||||||
|
notifications.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
||||||
|
|
||||||
|
const startIndex = (page - 1) * limit;
|
||||||
|
const endIndex = startIndex + limit;
|
||||||
|
const paginatedNotifications = notifications.slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
logger.debug('[ROCKETCHAT_ADAPTER] getNotifications result', {
|
||||||
|
total: notifications.length,
|
||||||
|
returned: paginatedNotifications.length,
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
return paginatedNotifications;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('[ROCKETCHAT_ADAPTER] Error getting notifications', {
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async markAsRead(userId: string, notificationId: string): Promise<boolean> {
|
async markAsRead(userId: string, notificationId: string): Promise<boolean> {
|
||||||
// Not implemented yet - RocketChat handles read status automatically
|
// Not implemented yet - RocketChat handles read status automatically
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
export interface Notification {
|
export interface Notification {
|
||||||
id: string;
|
id: string;
|
||||||
source: 'leantime' | 'nextcloud' | 'gitea' | 'dolibarr' | 'moodle';
|
source: 'leantime' | 'rocketchat' | 'email' | 'nextcloud' | 'gitea' | 'dolibarr' | 'moodle';
|
||||||
sourceId: string; // Original ID from the source system
|
sourceId: string; // Original ID from the source system
|
||||||
type: string; // Type of notification (e.g., 'task', 'mention', 'comment')
|
type: string; // Type of notification (e.g., 'task', 'mention', 'comment', 'message')
|
||||||
title: string;
|
title: string;
|
||||||
message: string;
|
message: string;
|
||||||
link?: string; // Link to view the item in the source system
|
link?: string; // Link to view the item in the source system
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user