notifications
This commit is contained in:
parent
c23fcb5783
commit
38b0f162f8
@ -1,5 +1,20 @@
|
||||
import { Notification, NotificationCount } from '@/lib/types/notification';
|
||||
import { NotificationAdapter } from './notification-adapter.interface';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
|
||||
|
||||
// Leantime notification type from their API
|
||||
interface LeantimeNotification {
|
||||
id: number;
|
||||
userId: number;
|
||||
username: string;
|
||||
message: string;
|
||||
type: string;
|
||||
moduleId: number;
|
||||
url: string;
|
||||
read: number; // 0 for unread, 1 for read
|
||||
date: string; // ISO format date
|
||||
}
|
||||
|
||||
export class LeantimeAdapter implements NotificationAdapter {
|
||||
readonly sourceName = 'leantime';
|
||||
@ -9,34 +24,348 @@ export class LeantimeAdapter implements NotificationAdapter {
|
||||
constructor() {
|
||||
this.apiUrl = process.env.LEANTIME_API_URL || '';
|
||||
this.apiToken = process.env.LEANTIME_TOKEN || '';
|
||||
|
||||
console.log('[LEANTIME_ADAPTER] Initialized with API URL and token');
|
||||
}
|
||||
|
||||
async getNotifications(userId: string, page = 1, limit = 20): Promise<Notification[]> {
|
||||
return [];
|
||||
console.log(`[LEANTIME_ADAPTER] getNotifications called for userId: ${userId}, page: ${page}, limit: ${limit}`);
|
||||
|
||||
try {
|
||||
// Get the user's email directly from the session
|
||||
const email = await this.getUserEmail();
|
||||
console.log(`[LEANTIME_ADAPTER] Retrieved email from session:`, email || 'null');
|
||||
|
||||
if (!email) {
|
||||
console.error('[LEANTIME_ADAPTER] Could not get user email from session');
|
||||
return [];
|
||||
}
|
||||
|
||||
const leantimeUserId = await this.getLeantimeUserId(email);
|
||||
console.log(`[LEANTIME_ADAPTER] Retrieved Leantime userId for email ${email}:`, leantimeUserId || 'null');
|
||||
|
||||
if (!leantimeUserId) {
|
||||
console.error('[LEANTIME_ADAPTER] User not found in Leantime:', email);
|
||||
return [];
|
||||
}
|
||||
|
||||
// Calculate pagination limits
|
||||
const limitStart = (page - 1) * limit;
|
||||
const limitEnd = limit;
|
||||
|
||||
// Make request to Leantime API using the correct jsonrpc method
|
||||
console.log('[LEANTIME_ADAPTER] Sending request to get all notifications');
|
||||
const jsonRpcBody = {
|
||||
jsonrpc: '2.0',
|
||||
method: 'leantime.rpc.Notifications.Notifications.getAllNotifications',
|
||||
params: {
|
||||
userId: leantimeUserId,
|
||||
showNewOnly: 0, // Get all notifications, not just unread
|
||||
limitStart: limitStart,
|
||||
limitEnd: limitEnd,
|
||||
filterOptions: [] // No additional filters
|
||||
},
|
||||
id: 1
|
||||
};
|
||||
console.log('[LEANTIME_ADAPTER] Request body:', JSON.stringify(jsonRpcBody));
|
||||
|
||||
const response = await fetch(`${this.apiUrl}/api/jsonrpc`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-API-Key': this.apiToken
|
||||
},
|
||||
body: JSON.stringify(jsonRpcBody)
|
||||
});
|
||||
|
||||
console.log('[LEANTIME_ADAPTER] Response status:', response.status);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error('[LEANTIME_ADAPTER] Failed to fetch Leantime notifications:', {
|
||||
status: response.status,
|
||||
body: errorText.substring(0, 200) + (errorText.length > 200 ? '...' : '')
|
||||
});
|
||||
return [];
|
||||
}
|
||||
|
||||
const responseText = await response.text();
|
||||
console.log('[LEANTIME_ADAPTER] Raw response (truncated):', responseText.substring(0, 200) + (responseText.length > 200 ? '...' : ''));
|
||||
|
||||
const data = JSON.parse(responseText);
|
||||
console.log('[LEANTIME_ADAPTER] Parsed response data:', {
|
||||
hasResult: !!data.result,
|
||||
resultIsArray: Array.isArray(data.result),
|
||||
resultLength: Array.isArray(data.result) ? data.result.length : 'n/a',
|
||||
error: data.error
|
||||
});
|
||||
|
||||
if (!data.result || !Array.isArray(data.result)) {
|
||||
if (data.error) {
|
||||
console.error(`[LEANTIME_ADAPTER] API error: ${data.error.message || JSON.stringify(data.error)}`);
|
||||
} else {
|
||||
console.error('[LEANTIME_ADAPTER] Invalid response format from Leantime notifications API');
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
const notifications = this.transformNotifications(data.result, userId);
|
||||
console.log('[LEANTIME_ADAPTER] Transformed notifications count:', notifications.length);
|
||||
return notifications;
|
||||
} catch (error) {
|
||||
console.error('[LEANTIME_ADAPTER] Error fetching Leantime notifications:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getNotificationCount(userId: string): Promise<NotificationCount> {
|
||||
return {
|
||||
total: 0,
|
||||
unread: 0,
|
||||
sources: {
|
||||
leantime: {
|
||||
total: 0,
|
||||
unread: 0
|
||||
console.log(`[LEANTIME_ADAPTER] getNotificationCount called for userId: ${userId}`);
|
||||
|
||||
try {
|
||||
// Get all notifications and count them
|
||||
const notifications = await this.getNotifications(userId, 1, 100); // Get up to 100 for counting
|
||||
|
||||
// Count total and unread
|
||||
const totalCount = notifications.length;
|
||||
const unreadCount = notifications.filter(n => !n.isRead).length;
|
||||
|
||||
console.log('[LEANTIME_ADAPTER] Notification counts:', {
|
||||
total: totalCount,
|
||||
unread: unreadCount
|
||||
});
|
||||
|
||||
return {
|
||||
total: totalCount,
|
||||
unread: unreadCount,
|
||||
sources: {
|
||||
leantime: {
|
||||
total: totalCount,
|
||||
unread: unreadCount
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[LEANTIME_ADAPTER] Error fetching notification count:', error);
|
||||
return {
|
||||
total: 0,
|
||||
unread: 0,
|
||||
sources: {
|
||||
leantime: {
|
||||
total: 0,
|
||||
unread: 0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async markAsRead(userId: string, notificationId: string): Promise<boolean> {
|
||||
return true;
|
||||
console.log(`[LEANTIME_ADAPTER] markAsRead called for ${notificationId}`);
|
||||
|
||||
try {
|
||||
// Extract the source ID from our compound ID
|
||||
const sourceId = notificationId.replace(`${this.sourceName}-`, '');
|
||||
|
||||
// Get user email and ID
|
||||
const email = await this.getUserEmail();
|
||||
if (!email) {
|
||||
console.error('[LEANTIME_ADAPTER] Could not get user email from session');
|
||||
return false;
|
||||
}
|
||||
|
||||
const leantimeUserId = await this.getLeantimeUserId(email);
|
||||
if (!leantimeUserId) {
|
||||
console.error('[LEANTIME_ADAPTER] User not found in Leantime:', email);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make request to Leantime API to mark notification as read
|
||||
const jsonRpcBody = {
|
||||
jsonrpc: '2.0',
|
||||
method: 'leantime.rpc.Notifications.Notifications.markNotificationAsRead',
|
||||
params: {
|
||||
userId: leantimeUserId,
|
||||
notificationId: parseInt(sourceId)
|
||||
},
|
||||
id: 1
|
||||
};
|
||||
|
||||
const response = await fetch(`${this.apiUrl}/api/jsonrpc`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-API-Key': this.apiToken
|
||||
},
|
||||
body: JSON.stringify(jsonRpcBody)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`[LEANTIME_ADAPTER] Failed to mark notification as read: ${response.status}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.result === true || data.result === "true" || !!data.result;
|
||||
} catch (error) {
|
||||
console.error('[LEANTIME_ADAPTER] Error marking notification as read:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async markAllAsRead(userId: string): Promise<boolean> {
|
||||
return true;
|
||||
console.log(`[LEANTIME_ADAPTER] markAllAsRead called for ${userId}`);
|
||||
|
||||
try {
|
||||
// Get user email and ID
|
||||
const email = await this.getUserEmail();
|
||||
if (!email) {
|
||||
console.error('[LEANTIME_ADAPTER] Could not get user email from session');
|
||||
return false;
|
||||
}
|
||||
|
||||
const leantimeUserId = await this.getLeantimeUserId(email);
|
||||
if (!leantimeUserId) {
|
||||
console.error('[LEANTIME_ADAPTER] User not found in Leantime:', email);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make request to Leantime API to mark all notifications as read
|
||||
const jsonRpcBody = {
|
||||
jsonrpc: '2.0',
|
||||
method: 'leantime.rpc.Notifications.Notifications.markAllNotificationsAsRead',
|
||||
params: {
|
||||
userId: leantimeUserId
|
||||
},
|
||||
id: 1
|
||||
};
|
||||
|
||||
const response = await fetch(`${this.apiUrl}/api/jsonrpc`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-API-Key': this.apiToken
|
||||
},
|
||||
body: JSON.stringify(jsonRpcBody)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`[LEANTIME_ADAPTER] Failed to mark all notifications as read: ${response.status}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.result === true || data.result === "true" || !!data.result;
|
||||
} catch (error) {
|
||||
console.error('[LEANTIME_ADAPTER] Error marking all notifications as read:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async isConfigured(): Promise<boolean> {
|
||||
return !!(this.apiUrl && this.apiToken);
|
||||
}
|
||||
|
||||
private transformNotifications(data: any[], userId: string): Notification[] {
|
||||
if (!Array.isArray(data)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return data.map(notification => {
|
||||
// Determine properties from notification object
|
||||
// Adjust these based on actual structure of Leantime notifications
|
||||
const id = notification.id || notification._id || notification.notificationId;
|
||||
const message = notification.message || notification.text || notification.content || '';
|
||||
const type = notification.type || 'notification';
|
||||
const read = notification.read || notification.isRead || 0;
|
||||
const date = notification.date || notification.datetime || notification.createdDate || new Date().toISOString();
|
||||
const url = notification.url || notification.link || '';
|
||||
|
||||
return {
|
||||
id: `${this.sourceName}-${id}`,
|
||||
source: this.sourceName as 'leantime',
|
||||
sourceId: id.toString(),
|
||||
type: type,
|
||||
title: type, // Use type as title if no specific title field
|
||||
message: message,
|
||||
link: url.startsWith('http') ? url : `${this.apiUrl}${url.startsWith('/') ? '' : '/'}${url}`,
|
||||
isRead: read === 1 || read === true,
|
||||
timestamp: new Date(date),
|
||||
priority: 'normal',
|
||||
user: {
|
||||
id: userId,
|
||||
name: notification.username || notification.userName || ''
|
||||
},
|
||||
metadata: {
|
||||
// Include any other useful fields from notification
|
||||
moduleId: notification.moduleId || notification.module || '',
|
||||
projectId: notification.projectId || '',
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to get user's email directly from the session
|
||||
private async getUserEmail(): Promise<string | null> {
|
||||
try {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || !session.user?.email) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return session.user.email;
|
||||
} catch (error) {
|
||||
console.error('[LEANTIME_ADAPTER] Error getting user email from session:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to get Leantime user ID by email
|
||||
private async getLeantimeUserId(email: string): Promise<number | null> {
|
||||
try {
|
||||
if (!this.apiToken) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const response = await fetch(`${this.apiUrl}/api/jsonrpc`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-API-Key': this.apiToken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
method: 'leantime.rpc.users.getAll',
|
||||
id: 1
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.result || !Array.isArray(data.result)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const users = data.result;
|
||||
|
||||
// Find user with matching email (check in both username and email fields)
|
||||
const user = users.find((u: any) =>
|
||||
u.username === email ||
|
||||
u.email === email ||
|
||||
(typeof u.username === 'string' && u.username.toLowerCase() === email.toLowerCase())
|
||||
);
|
||||
|
||||
if (user) {
|
||||
return user.id;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('[LEANTIME_ADAPTER] Error getting Leantime user ID:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user