Files
kycnotme/web/src/actions/notifications.ts
2025-06-02 03:53:03 +00:00

193 lines
6.5 KiB
TypeScript

import { z } from 'astro:content'
import { defineProtectedAction } from '../lib/defineProtectedAction'
import { prisma } from '../lib/prisma'
export const notificationActions = {
updateReadStatus: defineProtectedAction({
accept: 'form',
permissions: 'user',
input: z.object({
notificationId: z.literal('all').or(z.coerce.number().int().positive()),
read: z.coerce.boolean(),
}),
handler: async (input, context) => {
await prisma.notification.updateMany({
where:
input.notificationId === 'all'
? { userId: context.locals.user.id, read: !input.read }
: { userId: context.locals.user.id, id: input.notificationId },
data: {
read: input.read,
},
})
},
}),
webPush: {
subscribe: defineProtectedAction({
accept: 'json',
permissions: 'user',
input: z.object({
endpoint: z.string(),
p256dhKey: z.string(),
authKey: z.string(),
userAgent: z.string().optional(),
}),
handler: async (input, context) => {
await prisma.pushSubscription.upsert({
where: {
userId: context.locals.user.id,
endpoint: input.endpoint,
},
update: {
p256dh: input.p256dhKey,
auth: input.authKey,
userAgent: input.userAgent,
},
create: {
userId: context.locals.user.id,
endpoint: input.endpoint,
p256dh: input.p256dhKey,
auth: input.authKey,
userAgent: input.userAgent,
},
})
},
}),
unsubscribe: defineProtectedAction({
accept: 'json',
permissions: 'user',
input: z.object({
endpoint: z.string().optional(),
}),
handler: async (input, context) => {
if (input.endpoint) {
await prisma.pushSubscription.deleteMany({
where: {
userId: context.locals.user.id,
endpoint: input.endpoint,
},
})
} else {
await prisma.pushSubscription.deleteMany({
where: {
userId: context.locals.user.id,
},
})
}
},
}),
},
preferences: {
update: defineProtectedAction({
accept: 'form',
permissions: 'user',
input: z.object({
enableOnMyCommentStatusChange: z.coerce.boolean().optional(),
enableAutowatchMyComments: z.coerce.boolean().optional(),
enableNotifyPendingRepliesOnWatch: z.coerce.boolean().optional(),
karmaNotificationThreshold: z.coerce.number().int().min(1).max(1_000_000).optional(),
}),
handler: async (input, context) => {
await prisma.notificationPreferences.upsert({
where: { userId: context.locals.user.id },
update: {
enableOnMyCommentStatusChange: input.enableOnMyCommentStatusChange,
enableAutowatchMyComments: input.enableAutowatchMyComments,
enableNotifyPendingRepliesOnWatch: input.enableNotifyPendingRepliesOnWatch,
karmaNotificationThreshold: input.karmaNotificationThreshold,
},
create: {
userId: context.locals.user.id,
enableOnMyCommentStatusChange: input.enableOnMyCommentStatusChange,
enableAutowatchMyComments: input.enableAutowatchMyComments,
enableNotifyPendingRepliesOnWatch: input.enableNotifyPendingRepliesOnWatch,
karmaNotificationThreshold: input.karmaNotificationThreshold,
},
})
},
}),
watchComment: defineProtectedAction({
accept: 'form',
permissions: 'user',
input: z.object({
commentId: z.coerce.number().int().positive(),
watch: z.coerce.boolean(),
}),
handler: async (input, context) => {
await prisma.notificationPreferences.upsert({
where: { userId: context.locals.user.id },
update: {
watchedComments: input.watch
? { connect: { id: input.commentId } }
: { disconnect: { id: input.commentId } },
},
create: {
userId: context.locals.user.id,
watchedComments: input.watch ? { connect: { id: input.commentId } } : undefined,
},
})
},
}),
watchService: defineProtectedAction({
accept: 'form',
permissions: 'user',
input: z.object({
serviceId: z.coerce.number().int().positive(),
watchType: z.enum(['all', 'comments', 'events', 'verification']),
value: z.coerce.boolean(),
}),
handler: async (input, context) => {
await prisma.notificationPreferences.upsert({
where: { userId: context.locals.user.id },
update: {
onEventCreatedForServices:
input.watchType === 'events' || input.watchType === 'all'
? input.value
? { connect: { id: input.serviceId } }
: { disconnect: { id: input.serviceId } }
: undefined,
onRootCommentCreatedForServices:
input.watchType === 'comments' || input.watchType === 'all'
? input.value
? { connect: { id: input.serviceId } }
: { disconnect: { id: input.serviceId } }
: undefined,
onVerificationChangeForServices:
input.watchType === 'verification' || input.watchType === 'all'
? input.value
? { connect: { id: input.serviceId } }
: { disconnect: { id: input.serviceId } }
: undefined,
},
create: {
userId: context.locals.user.id,
onEventCreatedForServices:
input.watchType === 'events' || input.watchType === 'all'
? input.value
? { connect: { id: input.serviceId } }
: undefined
: undefined,
onRootCommentCreatedForServices:
input.watchType === 'comments' || input.watchType === 'all'
? input.value
? { connect: { id: input.serviceId } }
: undefined
: undefined,
onVerificationChangeForServices:
input.watchType === 'verification' || input.watchType === 'all'
? input.value
? { connect: { id: input.serviceId } }
: undefined
: undefined,
},
})
},
}),
},
}