feat: auto-subscribe push on login, better push logging
- Auto-subscribe to push on login, register, and session restore - Guard against nil db in SendChannelNotification - Log push send count per channel message - Bump SW cache to v5
This commit is contained in:
@@ -185,7 +185,7 @@ func (h *Handler) SendPush(ctx context.Context, userID string, payload map[strin
|
|||||||
// SendChannelNotification sends a push notification to all server members (except the author)
|
// SendChannelNotification sends a push notification to all server members (except the author)
|
||||||
// when a new message is posted in a channel.
|
// when a new message is posted in a channel.
|
||||||
func (h *Handler) SendChannelNotification(ctx context.Context, channelID, authorID, channelName, content string) {
|
func (h *Handler) SendChannelNotification(ctx context.Context, channelID, authorID, channelName, content string) {
|
||||||
if h.vapidPub == "" || h.vapidPriv == "" {
|
if h.vapidPub == "" || h.vapidPriv == "" || h.db == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,6 +196,8 @@ func (h *Handler) SendChannelNotification(ctx context.Context, channelID, author
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.logger.Info("sending push notifications", "channel", channelName, "author", authorID)
|
||||||
|
|
||||||
body := content
|
body := content
|
||||||
if len(body) > 200 {
|
if len(body) > 200 {
|
||||||
body = body[:200] + "..."
|
body = body[:200] + "..."
|
||||||
@@ -221,6 +223,7 @@ func (h *Handler) SendChannelNotification(ctx context.Context, channelID, author
|
|||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
|
sent := 0
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var userID, endpoint, p256dh, auth string
|
var userID, endpoint, p256dh, auth string
|
||||||
if err := rows.Scan(&userID, &endpoint, &p256dh, &auth); err != nil {
|
if err := rows.Scan(&userID, &endpoint, &p256dh, &auth); err != nil {
|
||||||
@@ -250,8 +253,12 @@ func (h *Handler) SendChannelNotification(ctx context.Context, channelID, author
|
|||||||
}
|
}
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
|
if resp.StatusCode < 300 {
|
||||||
|
sent++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
h.logger.Info("push notifications sent", "count", sent, "channel", channelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateVAPIDKeys is in cmd/keygen. Use github.com/SherClockHolmes/webpush-go directly.
|
// GenerateVAPIDKeys is in cmd/keygen. Use github.com/SherClockHolmes/webpush-go directly.
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
// Dumpster PWA Service Worker
|
// Dumpster PWA Service Worker
|
||||||
// Bump CACHE_VERSION on each deploy to force re-cache of hashed assets.
|
// Bump CACHE_VERSION on each deploy to force re-cache of hashed assets.
|
||||||
const CACHE_VERSION = 'dumpster-v4';
|
const CACHE_VERSION = 'dumpster-v5';
|
||||||
const OFFLINE_URL = '/offline.html';
|
const OFFLINE_URL = '/offline.html';
|
||||||
|
|
||||||
// Assets to pre-cache on install (shell files)
|
// Assets to pre-cache on install (shell files)
|
||||||
|
|||||||
@@ -71,6 +71,16 @@ interface AuthState {
|
|||||||
clearError: () => void;
|
clearError: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ponytail: auto-subscribe to push notifications on auth
|
||||||
|
function autoSubscribePush() {
|
||||||
|
import("../stores/push.ts").then(({ usePushStore }) => {
|
||||||
|
const ps = usePushStore.getState();
|
||||||
|
if (ps.isSupported && Notification.permission !== 'denied' && !ps.isSubscribed) {
|
||||||
|
ps.subscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const useAuthStore = create<AuthState>((set) => ({
|
export const useAuthStore = create<AuthState>((set) => ({
|
||||||
user: null,
|
user: null,
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
@@ -86,6 +96,7 @@ export const useAuthStore = create<AuthState>((set) => ({
|
|||||||
});
|
});
|
||||||
const user = await api.get<User>("/auth/me");
|
const user = await api.get<User>("/auth/me");
|
||||||
set({ user, isAuthenticated: true, isLoading: false });
|
set({ user, isAuthenticated: true, isLoading: false });
|
||||||
|
autoSubscribePush();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
set({
|
set({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@@ -106,6 +117,7 @@ export const useAuthStore = create<AuthState>((set) => ({
|
|||||||
});
|
});
|
||||||
const user = await api.get<User>("/auth/me");
|
const user = await api.get<User>("/auth/me");
|
||||||
set({ user, isAuthenticated: true, isLoading: false });
|
set({ user, isAuthenticated: true, isLoading: false });
|
||||||
|
autoSubscribePush();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
set({
|
set({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@@ -135,6 +147,7 @@ export const useAuthStore = create<AuthState>((set) => ({
|
|||||||
try {
|
try {
|
||||||
const user = await api.get<User>(`/auth/me?t=${Date.now()}`);
|
const user = await api.get<User>(`/auth/me?t=${Date.now()}`);
|
||||||
set({ user, isAuthenticated: true, isLoading: false });
|
set({ user, isAuthenticated: true, isLoading: false });
|
||||||
|
autoSubscribePush();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
set({
|
set({
|
||||||
user: null,
|
user: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user