diff --git a/server/package.json b/server/package.json index 195fac104..d7c2d149c 100644 --- a/server/package.json +++ b/server/package.json @@ -85,7 +85,7 @@ "rimraf": "3.0.2", "safe-json-stringify": "1.2.0", "seq-logging": "1.1.1", - "tachi-common": "0.10.2", + "tachi-common": "0.11.1", "ts-node": "10.4.0", "tsconfig-paths": "3.12.0", "typescript": "4.5.5", diff --git a/server/pnpm-lock.yaml b/server/pnpm-lock.yaml index 69996cbde..7e60d7acd 100644 --- a/server/pnpm-lock.yaml +++ b/server/pnpm-lock.yaml @@ -65,7 +65,7 @@ specifiers: safe-json-stringify: 1.2.0 seq-logging: 1.1.1 supertest: 6.2.2 - tachi-common: 0.10.2 + tachi-common: 0.11.1 tap: 15.1.6 ts-node: 10.4.0 tsconfig-paths: 3.12.0 @@ -112,7 +112,7 @@ dependencies: rimraf: 3.0.2 safe-json-stringify: 1.2.0 seq-logging: 1.1.1 - tachi-common: 0.10.2 + tachi-common: 0.11.1 ts-node: 10.4.0_2615db9039ce432b4abf2fc39ef336ec tsconfig-paths: 3.12.0 typescript: 4.5.5 @@ -5364,8 +5364,8 @@ packages: engines: {node: '>= 0.4'} dev: true - /tachi-common/0.10.2: - resolution: {integrity: sha512-hU3qQUacbL9rbiFibePzKeP+WuDXyKgcOlGNEXgZZIWZ3cpeEwFm6tk8PtVAoQPa5nPfXobmEmWYN4eGOQoKjA==} + /tachi-common/0.11.1: + resolution: {integrity: sha512-gLhFJG84YfzrHdoHXlVqxnBOjiKsI2xaivscmHVdZr9lqKaPUzBYmkMKZ5IsWdFxYXo8Ry+JrkZ83WPuSuVWEg==} dependencies: '@types/express-serve-static-core': 4.17.28 '@types/mongodb': 3.6.18 diff --git a/server/src/external/mongo/db.ts b/server/src/external/mongo/db.ts index ccb60cf6f..c7bfe3eba 100644 --- a/server/src/external/mongo/db.ts +++ b/server/src/external/mongo/db.ts @@ -38,6 +38,7 @@ import { GoalSubscriptionDocument, MilestoneSubscriptionDocument, UserSettings, + NotificationDocument, } from "tachi-common"; import { GetMillisecondsSince } from "utils/misc"; import { MigrationDocument, PrivateUserInfoDocument } from "utils/types"; @@ -193,6 +194,7 @@ const db = { "recent-folder-views": monkDB.get("recent-folder-views"), "milestone-sets": monkDB.get("milestone-sets"), migrations: monkDB.get("migrations"), + notifications: monkDB.get("notifications"), }; export type StaticDatabases = Exclude; diff --git a/server/src/lib/notifications/notifications.ts b/server/src/lib/notifications/notifications.ts new file mode 100644 index 000000000..eb645dd20 --- /dev/null +++ b/server/src/lib/notifications/notifications.ts @@ -0,0 +1,40 @@ +import db from "external/mongo/db"; +import { integer, NotificationBody, NotificationDocument } from "tachi-common"; +import { Random20Hex } from "utils/misc"; + +/** + * Send a notification to a user. + * + * @param title - A human friendly title for this notification. + * @param toUserID - The user to send the notification to. + * @param body - The body of the notification. + */ +export async function SendNotification(title: string, toUserID: integer, body: NotificationBody) { + const notification: NotificationDocument = { + title, + sentTo: toUserID, + read: false, + sentAt: Date.now(), + notifID: `N${Random20Hex()}`, + body, + }; + + await db.notifications.insert(notification); +} + +/** + * Mark a notification as read. This is notably different to deleting a notification, + * and is typically done when the user acknowledges the existence of the notification. + */ +export function ReadNotification(notifID: string) { + return db.notifications.update( + { notifID }, + { + $set: { read: true }, + } + ); +} + +export function DeleteNotification(notifID: string) { + return db.notifications.remove({ notifID }); +}