fix notification issue
This commit is contained in:
parent
536bdc4cb9
commit
10d48ca47d
@ -35,9 +35,9 @@ from pathlib import Path
|
|||||||
# }
|
# }
|
||||||
# )
|
# )
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings")
|
||||||
django.setup()
|
# django.setup()
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
# BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
app = get_asgi_application()
|
app = get_asgi_application()
|
||||||
|
|
||||||
# app = WhiteNoise(app, root=str(BASE_DIR / 'staticfiles'))
|
# app = WhiteNoise(app, root=str(BASE_DIR / 'staticfiles'))
|
||||||
@ -50,7 +50,7 @@ application = ProtocolTypeRouter(
|
|||||||
path("sse/notifications/", NotificationSSEApp()),
|
path("sse/notifications/", NotificationSSEApp()),
|
||||||
re_path(
|
re_path(
|
||||||
r"", app
|
r"", app
|
||||||
), # All other routes go to Django
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@ -58,5 +58,5 @@ application = ProtocolTypeRouter(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if django.conf.settings.DEBUG:
|
# if django.conf.settings.DEBUG:
|
||||||
application = ASGIStaticFilesHandler(app)
|
# application = ASGIStaticFilesHandler(app)
|
||||||
@ -5,7 +5,7 @@ from django.urls import path, include
|
|||||||
from schema_graph.views import Schema
|
from schema_graph.views import Schema
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.conf.urls.i18n import i18n_patterns
|
from django.conf.urls.i18n import i18n_patterns
|
||||||
from inventory.notifications.sse import NotificationSSEApp
|
# from inventory.notifications.sse import NotificationSSEApp
|
||||||
|
|
||||||
# import debug_toolbar
|
# import debug_toolbar
|
||||||
# from two_factor.urls import urlpatterns as tf_urls
|
# from two_factor.urls import urlpatterns as tf_urls
|
||||||
|
|||||||
@ -1,82 +1,3 @@
|
|||||||
# import json
|
|
||||||
# from django.contrib.auth.models import AnonymousUser
|
|
||||||
# from django.contrib.auth import get_user_model
|
|
||||||
# from django.db import close_old_connections
|
|
||||||
# from urllib.parse import parse_qs
|
|
||||||
# from channels.db import database_sync_to_async
|
|
||||||
# from inventory.models import Notification
|
|
||||||
# import asyncio
|
|
||||||
|
|
||||||
# @database_sync_to_async
|
|
||||||
# def get_notifications(user, last_id):
|
|
||||||
# return Notification.objects.filter(
|
|
||||||
# user=user, id__gt=last_id, is_read=False
|
|
||||||
# ).order_by("created")
|
|
||||||
|
|
||||||
# class NotificationSSEApp:
|
|
||||||
# async def __call__(self, scope, receive, send):
|
|
||||||
# if scope["type"] != "http":
|
|
||||||
# return
|
|
||||||
|
|
||||||
# query_string = parse_qs(scope["query_string"].decode())
|
|
||||||
# last_id = int(query_string.get("last_id", [0])[0])
|
|
||||||
|
|
||||||
# # Get user from scope if using AuthMiddlewareStack
|
|
||||||
# user = scope.get("user", AnonymousUser())
|
|
||||||
# if not user.is_authenticated:
|
|
||||||
# await send({
|
|
||||||
# "type": "http.response.start",
|
|
||||||
# "status": 403,
|
|
||||||
# "headers": [(b"content-type", b"text/plain")],
|
|
||||||
# })
|
|
||||||
# await send({
|
|
||||||
# "type": "http.response.body",
|
|
||||||
# "body": b"Unauthorized",
|
|
||||||
# })
|
|
||||||
# return
|
|
||||||
|
|
||||||
# await send({
|
|
||||||
# "type": "http.response.start",
|
|
||||||
# "status": 200,
|
|
||||||
# "headers": [
|
|
||||||
# (b"content-type", b"text/event-stream"),
|
|
||||||
# (b"cache-control", b"no-cache"),
|
|
||||||
# (b"x-accel-buffering", b"no"),
|
|
||||||
# ]
|
|
||||||
# })
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# while True:
|
|
||||||
# close_old_connections()
|
|
||||||
|
|
||||||
# notifications = await get_notifications(user, last_id)
|
|
||||||
# for notification in notifications:
|
|
||||||
# data = {
|
|
||||||
# "id": notification.id,
|
|
||||||
# "message": notification.message,
|
|
||||||
# "created": notification.created.isoformat(),
|
|
||||||
# "is_read": notification.is_read,
|
|
||||||
# }
|
|
||||||
|
|
||||||
# event_str = (
|
|
||||||
# f"id: {notification.id}\n"
|
|
||||||
# f"event: notification\n"
|
|
||||||
# f"data: {json.dumps(data)}\n\n"
|
|
||||||
# )
|
|
||||||
|
|
||||||
# await send({
|
|
||||||
# "type": "http.response.body",
|
|
||||||
# "body": event_str.encode("utf-8"),
|
|
||||||
# "more_body": True
|
|
||||||
# })
|
|
||||||
|
|
||||||
# last_id = notification.id
|
|
||||||
|
|
||||||
# await asyncio.sleep(2)
|
|
||||||
|
|
||||||
# except asyncio.CancelledError:
|
|
||||||
# pass
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
|||||||
@ -10238,7 +10238,8 @@ def payment_callback(request, dealer_slug):
|
|||||||
# return render(request, "payment_failed.html", {"message": message})
|
# return render(request, "payment_failed.html", {"message": message})
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
async def sse_stream(request): # 👈 Mark as async!
|
async def sse_stream(request):
|
||||||
|
import asyncio
|
||||||
def event_generator():
|
def event_generator():
|
||||||
last_id = int(request.GET.get("last_id", 0))
|
last_id = int(request.GET.get("last_id", 0))
|
||||||
|
|
||||||
|
|||||||
@ -87,9 +87,13 @@
|
|||||||
didOpen: (toast) => {
|
didOpen: (toast) => {
|
||||||
toast.onmouseenter = Swal.stopTimer;
|
toast.onmouseenter = Swal.stopTimer;
|
||||||
toast.onmouseleave = Swal.resumeTimer;
|
toast.onmouseleave = Swal.resumeTimer;
|
||||||
} });
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
{% with last_notif=notifications_|last %}
|
||||||
|
let lastNotificationId = {{ last_notif.id|default:0 }};
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
let lastNotificationId = {{ notifications_.last.id|default:0 }};
|
|
||||||
let seenNotificationIds = new Set();
|
let seenNotificationIds = new Set();
|
||||||
let counter = document.getElementById('notification-counter');
|
let counter = document.getElementById('notification-counter');
|
||||||
let notificationsContainer = document.getElementById('notifications-container');
|
let notificationsContainer = document.getElementById('notifications-container');
|
||||||
@ -100,7 +104,6 @@
|
|||||||
let initialUnreadCount = {{ notifications_.count|default:0 }};
|
let initialUnreadCount = {{ notifications_.count|default:0 }};
|
||||||
updateCounter(initialUnreadCount);
|
updateCounter(initialUnreadCount);
|
||||||
|
|
||||||
|
|
||||||
fetchInitialNotifications();
|
fetchInitialNotifications();
|
||||||
|
|
||||||
function fetchInitialNotifications() {
|
function fetchInitialNotifications() {
|
||||||
@ -108,29 +111,22 @@
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.notifications && data.notifications.length > 0) {
|
if (data.notifications && data.notifications.length > 0) {
|
||||||
|
|
||||||
lastNotificationId = data.notifications[0].id;
|
lastNotificationId = data.notifications[0].id;
|
||||||
|
|
||||||
seenNotificationIds = new Set();
|
seenNotificationIds = new Set();
|
||||||
|
|
||||||
let unreadCount = 0;
|
let unreadCount = 0;
|
||||||
|
|
||||||
data.notifications.forEach(notification => {
|
data.notifications.forEach(notification => {
|
||||||
seenNotificationIds.add(notification.id);
|
seenNotificationIds.add(notification.id);
|
||||||
if (!notification.is_read) {
|
if (!notification.is_read) unreadCount++;
|
||||||
unreadCount++;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
renderNotifications(data.notifications);
|
renderNotifications(data.notifications);
|
||||||
|
|
||||||
updateCounter(unreadCount);
|
updateCounter(unreadCount);
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
connectSSE();
|
|
||||||
}, 5000);
|
|
||||||
}
|
}
|
||||||
|
// Always connect SSE after initial load
|
||||||
|
setTimeout(() => {
|
||||||
|
connectSSE();
|
||||||
|
}, 1000);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error fetching initial notifications:', error);
|
console.error('Error fetching initial notifications:', error);
|
||||||
@ -143,12 +139,12 @@
|
|||||||
eventSource.close();
|
eventSource.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ FIXED URL HERE
|
||||||
eventSource = new EventSource("/sse/notifications/?last_id=" + lastNotificationId);
|
eventSource = new EventSource("/sse/notifications/?last_id=" + lastNotificationId);
|
||||||
|
|
||||||
eventSource.addEventListener('notification', function(e) {
|
eventSource.addEventListener('notification', function(e) {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(e.data);
|
const data = JSON.parse(e.data);
|
||||||
|
|
||||||
if (seenNotificationIds.has(data.id)) return;
|
if (seenNotificationIds.has(data.id)) return;
|
||||||
seenNotificationIds.add(data.id);
|
seenNotificationIds.add(data.id);
|
||||||
|
|
||||||
@ -158,6 +154,11 @@
|
|||||||
|
|
||||||
updateCounter('increment');
|
updateCounter('increment');
|
||||||
|
|
||||||
|
if (!notificationsContainer) {
|
||||||
|
console.warn("Notification container missing, can't render SSE event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const notificationElement = createNotificationElement(data);
|
const notificationElement = createNotificationElement(data);
|
||||||
notificationsContainer.insertAdjacentHTML('afterbegin', notificationElement);
|
notificationsContainer.insertAdjacentHTML('afterbegin', notificationElement);
|
||||||
|
|
||||||
@ -168,7 +169,7 @@
|
|||||||
|
|
||||||
Toast.fire({
|
Toast.fire({
|
||||||
icon: 'info',
|
icon: 'info',
|
||||||
html:`${data.message}`
|
html: `${data.message}`
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -220,7 +221,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCounter(action) {
|
function updateCounter(action) {
|
||||||
@ -231,12 +232,14 @@
|
|||||||
if (notificationCountDiv) {
|
if (notificationCountDiv) {
|
||||||
notificationCountDiv.innerHTML = `
|
notificationCountDiv.innerHTML = `
|
||||||
<span class="badge bg-danger rounded-pill" id="notification-counter" style="position: absolute; top: 8px; right: 3px; font-size: 0.50rem;">0</span>
|
<span class="badge bg-danger rounded-pill" id="notification-counter" style="position: absolute; top: 8px; right: 3px; font-size: 0.50rem;">0</span>
|
||||||
`;
|
`;
|
||||||
counter = document.getElementById('notification-counter');
|
counter = document.getElementById('notification-counter');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!counter) return;
|
||||||
|
|
||||||
let currentCount = parseInt(counter.textContent) || 0;
|
let currentCount = parseInt(counter.textContent) || 0;
|
||||||
|
|
||||||
if (action === 'increment') {
|
if (action === 'increment') {
|
||||||
@ -294,7 +297,7 @@
|
|||||||
notificationCard.closest('.notification-card').classList.add('fade-out');
|
notificationCard.closest('.notification-card').classList.add('fade-out');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
notificationCard.closest('.notification-card').remove();
|
notificationCard.closest('.notification-card').remove();
|
||||||
}, 200);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user