d1d5984e30
* refactor(server emails): email transports module refactor to TypeScript * refactor(docker-compose deps): move local email server to common dev compose file * chore(server launch.json): add ts-node script running example * chore(server deps): add nodemailer types package * refactor(server activitystream): add strongly typed activity definitions * feat(server activitystream): add activity repository * feat(server info): add canonical url on the service level * feat(server): add static file serving route to server core * feat(server): add dependencies for periodical email digests * feat(server activity stream): call the initialization step from the activity stream module * feat(server activity digest): add WIP weekly email digest implementation * feat(server digest email): smul upgrades and fixes to the email template and its contents * just for Fabs to test * chore(root package.json): remove deleted docker-compose references * feat(frontend profile): add notification preferences panel * feat(server digest emails): set prod ready cron tab and timespan * refactor(server email digest): move templates into the email module * refactor(server activity digests): refactor to use notifications infrastructure * test(server activities): add tests and some refactor to activities and notification preferences * refactor(notification preferences): fix minor issues * test(server notification preferences test): fix describe nesting * fix(server activities): add missing action types * fix(server activities): fix errors after merging main * test(server activity notifications): add test coverage for activity notifications service * refactor(server activities): fixing tests and some cleanup * feat(server cli): add summary notification command to cli * chore(dev env db versions): upgrade local dev env versions * chore(server deps): upgrade local dev db to pg 14 * fix(docker-compose): bind maildev to localhost * process-scoped notifications test queues * test(activity tests): add sleep to fix flaky CI * feat(activity digests): add demo date for digest trigger * feat(activity digest): add UK timezone trigger date Co-authored-by: Iain Sproat <68657+iainsproat@users.noreply.github.com> Co-authored-by: Fabians <fabis94@live.com>
64 lines
2.4 KiB
TypeScript
64 lines
2.4 KiB
TypeScript
import * as repo from '@/modules/notifications/repositories'
|
|
import {
|
|
NotificationChannel,
|
|
NotificationType,
|
|
NotificationPreferences
|
|
} from '@/modules/notifications/helpers/types'
|
|
import { InvalidArgumentError } from '@/modules/shared/errors'
|
|
|
|
export async function getUserNotificationPreferences(
|
|
userId: string
|
|
): Promise<NotificationPreferences> {
|
|
const savedPreferences = await repo.getUserNotificationPreferences(userId)
|
|
return addDefaultPreferenceValues(savedPreferences)
|
|
}
|
|
|
|
export 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 async function updateNotificationPreferences(
|
|
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 repo.saveUserNotificationPreferences(userId, parsedPreferences)
|
|
}
|