Files
speckle-server/packages/server/modules/notifications/services/notificationPreferences.ts
T
Daniel Gak Anagrov 3ca4a11ca3 feat(notifications): basic listener structure, notification record, delayed mechanism (#5432)
* feat: basic notification listener sturcuture

* feat: clean up generated gql

* chore: edited structure

* feat: added basic repo

* feat: ported comment email to job queue

* feat: ported stream access request accepted

* feat: added notification insertion

* fix: minor typings

* feat: delayed notifications

* updated types

* feat: fixed gql

* notifications are listed

* index on notifications

* feat: while loop skiping for update locked

* delayed notification for access request

* take into account user prefrences

* on comment view, notification is marked as read

* feat: added gql notifications

* feat: avoid raising errors

* fix: error added scopes

* fix: mr comments

* fix: cursor and service method

* feat: added stronger types to notifications and versioning logic

* minor: rows updated
2025-10-06 12:19:12 +01:00

80 lines
3.4 KiB
TypeScript

import type { NotificationPreferences } from '@/modules/notifications/helpers/types'
import { NotificationChannel } from '@/modules/notifications/helpers/types'
import { InvalidArgumentError } from '@/modules/shared/errors'
import type {
GetSavedUserNotificationPreferences,
GetUserNotificationPreferences,
GetUserPreferenceForNotificationType,
SaveUserNotificationPreferences
} from '@/modules/notifications/domain/operations'
import { NotificationType } from '@speckle/shared/notifications'
export const getUserNotificationPreferencesFactory =
(deps: {
getSavedUserNotificationPreferences: GetSavedUserNotificationPreferences
}): GetUserNotificationPreferences =>
async (userId: string): Promise<NotificationPreferences> => {
const savedPreferences = await deps.getSavedUserNotificationPreferences(userId)
return addDefaultPreferenceValues(savedPreferences)
}
function addDefaultPreferenceValues(
preferences: NotificationPreferences
): NotificationPreferences {
const savedPreferences = { ...preferences }
Object.values(NotificationType).forEach((nt) => {
const notificationTypeSettings = savedPreferences[nt] ?? {}
Object.values(NotificationChannel).forEach((nc) => {
notificationTypeSettings[nc] = notificationTypeSettings[nc] ?? true
})
savedPreferences[nt] = notificationTypeSettings
})
return savedPreferences
}
export const getUserPreferenceForNotificationTypeFactory =
(deps: {
getSavedUserNotificationPreferences: GetSavedUserNotificationPreferences
}): GetUserPreferenceForNotificationType =>
async (userId, notificationType, notificationChannel) => {
const preferences = await deps.getSavedUserNotificationPreferences(userId)
if (!preferences) return true
const notificationTypeSettings = preferences[notificationType]
return notificationTypeSettings?.[notificationChannel] ?? false
}
export const updateNotificationPreferencesFactory =
(deps: { saveUserNotificationPreferences: SaveUserNotificationPreferences }) =>
async (userId: string, rawPreferences: Record<string, unknown>): Promise<void> => {
const parsedPreferences: NotificationPreferences = {}
// lets do some nested attribute copying, to sanitize the input
for (const key in rawPreferences) {
if (!Object.values(NotificationType).includes(key as NotificationType))
throw new InvalidArgumentError(
`Notification preferences input contains an unknown setting: ${key}`
)
const nt = key as NotificationType
const notificationTypePreferences: Partial<Record<NotificationChannel, boolean>> =
{}
const notificationTypeSettings = rawPreferences[nt] as Record<string, unknown>
for (const ncKey in notificationTypeSettings) {
if (!Object.values(NotificationChannel).includes(ncKey as NotificationChannel))
throw new InvalidArgumentError(
`Notification preferences input contains an unknown setting: ${ncKey}`
)
const nc = ncKey as NotificationChannel
const preferenceValue = notificationTypeSettings[nc]
if (typeof preferenceValue !== 'boolean')
throw new InvalidArgumentError(
`Notification preferences input contains and invalid value: ${preferenceValue}`
)
notificationTypePreferences[nc] = preferenceValue
}
parsedPreferences[nt] = notificationTypePreferences
}
return await deps.saveUserNotificationPreferences(userId, parsedPreferences)
}