update auth
This commit is contained in:
@@ -27,7 +27,6 @@ export class TokensService {
|
||||
slug: string,
|
||||
em?: EntityManager,
|
||||
) {
|
||||
const entityManager = em || this.em;
|
||||
const refreshExpire = this.configService.getOrThrow<number>('REFRESH_TOKEN_EXPIRE');
|
||||
const accessExpire = this.configService.getOrThrow<number>('JWT_EXPIRATION_TIME');
|
||||
|
||||
@@ -39,7 +38,8 @@ export class TokensService {
|
||||
const refreshToken = this.generateRefreshToken();
|
||||
const type = isAdmin ? RefreshTokenType.ADMIN : RefreshTokenType.USER;
|
||||
|
||||
await this.storeRefreshToken(ownerId, restaurantId, refreshToken, type, entityManager);
|
||||
// Only pass em if it's a transaction manager (not this.em), otherwise pass undefined to trigger flush
|
||||
await this.storeRefreshToken(ownerId, restaurantId, refreshToken, type, em);
|
||||
|
||||
return {
|
||||
accessToken: { token: accessToken, expire: dayjs().add(accessExpire, 'seconds').valueOf() },
|
||||
@@ -79,8 +79,8 @@ export class TokensService {
|
||||
// Within transaction, just persist (flush will be called by transaction)
|
||||
entityManager.persist(token);
|
||||
} else {
|
||||
// Outside transaction, persist and flush
|
||||
return entityManager.persistAndFlush(token);
|
||||
// Outside transaction, persist and flush immediately
|
||||
await entityManager.persistAndFlush(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
} from '@nestjs/websockets';
|
||||
import { Server, Socket } from 'socket.io';
|
||||
import { Logger, UseGuards, Inject, forwardRef } from '@nestjs/common';
|
||||
// import { WsRestId } from './decorators/ws-rest-id.decorator';
|
||||
import { NotificationService } from './services/notification.service';
|
||||
import { NotificationService } from './services/notification.service';
|
||||
import { WsAdminAuthGuard, type AuthenticatedSocket } from './guards/ws-admin-auth.guard';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import { ExecutionContext } from '@nestjs/common';
|
||||
@@ -46,6 +45,7 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
|
||||
this.logger.error(
|
||||
`Connection authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
);
|
||||
void client.emit('error', { message: 'Authentication failed' });
|
||||
client.disconnect();
|
||||
}
|
||||
}
|
||||
@@ -273,7 +273,7 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
|
||||
|
||||
const canActivate = await guard.canActivate(context);
|
||||
if (!canActivate) {
|
||||
throw new Error('Authentication failed');
|
||||
throw new Error('Authentication failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,6 +249,17 @@
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -370,9 +381,34 @@
|
||||
addEvent('ERROR', `Connection error: ${error.message}`);
|
||||
});
|
||||
|
||||
socket.on('joined', data => {
|
||||
addEvent('SUCCESS', `Joined room: ${data.room || 'unknown'}`, data);
|
||||
});
|
||||
|
||||
// Handle notifications event - can be either:
|
||||
// 1. List response: { notifications: [...] }
|
||||
// 2. Real-time notification: { subject: string, body: string }
|
||||
socket.on('notifications', data => {
|
||||
addEvent('SUCCESS', `Received ${data.notifications?.length || 0} notifications`, data);
|
||||
displayNotifications(data.notifications || []);
|
||||
if (Array.isArray(data.notifications)) {
|
||||
// List of notifications response
|
||||
addEvent('SUCCESS', `Received ${data.notifications.length} notifications`, data);
|
||||
displayNotifications(data.notifications);
|
||||
} else if (data.subject || data.body) {
|
||||
// Real-time single notification
|
||||
addEvent('NOTIFICATION', 'New notification received', data);
|
||||
addRealTimeNotification(data);
|
||||
} else if (Array.isArray(data)) {
|
||||
// Direct array response
|
||||
addEvent('SUCCESS', `Received ${data.length} notifications`, data);
|
||||
displayNotifications(data);
|
||||
} else {
|
||||
// Unknown format, try to extract notifications from various possible structures
|
||||
addEvent('INFO', 'Received notifications data', data);
|
||||
const notifications = data.notifications || data.data || (Array.isArray(data) ? data : [data]);
|
||||
if (Array.isArray(notifications) && notifications.length > 0) {
|
||||
displayNotifications(notifications);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('error', data => {
|
||||
@@ -423,14 +459,28 @@
|
||||
|
||||
let html = '';
|
||||
notifications.forEach(notification => {
|
||||
const date = notification.createdAt ? new Date(notification.createdAt).toLocaleString() : 'N/A';
|
||||
// Handle both full notification objects and simple payloads
|
||||
const title = notification.title || notification.subject || 'N/A';
|
||||
const content = notification.content || notification.body || 'No content';
|
||||
const id = notification.id || 'N/A';
|
||||
const date = notification.createdAt
|
||||
? new Date(notification.createdAt).toLocaleString()
|
||||
: notification.created_at
|
||||
? new Date(notification.created_at).toLocaleString()
|
||||
: 'N/A';
|
||||
|
||||
const userName = notification.user
|
||||
? `${notification.user.firstName || ''} ${notification.user.lastName || ''}`.trim()
|
||||
: notification.userName || '';
|
||||
|
||||
html += `
|
||||
<div class="notification-item">
|
||||
<div class="notification-title">${notification.title || 'N/A'}</div>
|
||||
<div class="notification-content">${notification.content || 'No content'}</div>
|
||||
<div class="notification-title">${escapeHtml(title)}</div>
|
||||
<div class="notification-content">${escapeHtml(content)}</div>
|
||||
<div class="notification-meta">
|
||||
ID: ${notification.id} | Created: ${date}
|
||||
${notification.user ? ` | User: ${notification.user.firstName || ''} ${notification.user.lastName || ''}` : ''}
|
||||
ID: ${id} | Created: ${date}
|
||||
${userName ? ` | User: ${escapeHtml(userName)}` : ''}
|
||||
${notification.admin ? ` | Admin: ${notification.admin.firstName || ''} ${notification.admin.lastName || ''}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -439,6 +489,37 @@
|
||||
listDiv.innerHTML = html;
|
||||
}
|
||||
|
||||
function addRealTimeNotification(notification) {
|
||||
const listDiv = document.getElementById('notificationsList');
|
||||
const title = notification.subject || notification.title || 'New Notification';
|
||||
const content = notification.body || notification.content || 'No content';
|
||||
const currentTime = new Date().toLocaleString();
|
||||
|
||||
const notificationHtml = `
|
||||
<div class="notification-item" style="animation: slideIn 0.3s ease-out;">
|
||||
<div class="notification-title">${escapeHtml(title)}</div>
|
||||
<div class="notification-content">${escapeHtml(content)}</div>
|
||||
<div class="notification-meta">
|
||||
Received: ${currentTime}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add to the top of the list
|
||||
if (listDiv.children.length === 1 && listDiv.children[0].textContent.includes('No notifications')) {
|
||||
listDiv.innerHTML = notificationHtml;
|
||||
} else {
|
||||
listDiv.insertAdjacentHTML('afterbegin', notificationHtml);
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
if (!text) return '';
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function updateStatus(status, message) {
|
||||
const statusEl = document.getElementById('connectionStatus');
|
||||
statusEl.className = `status ${status}`;
|
||||
@@ -457,6 +538,7 @@
|
||||
WARNING: '#dcdcaa',
|
||||
ERROR: '#f48771',
|
||||
NOTIFICATIONS_LIST: '#4fc1ff',
|
||||
NOTIFICATION: '#9cdcfe',
|
||||
};
|
||||
|
||||
eventItem.innerHTML = `
|
||||
|
||||
Reference in New Issue
Block a user