Implemented notifications, simplified alerts overview.

This commit is contained in:
2024-05-27 03:06:54 +02:00
parent 342ba6191e
commit 9e18fb4455
8 changed files with 417 additions and 84 deletions

View File

@@ -1,4 +1,7 @@
import escapeRegexp from 'escape-string-regexp';
import { knexOwner as knex } from './knex.js';
import { fetchScenesById } from './scenes.js';
import promiseProps from '../utils/promise-props.js';
import { HttpError } from './errors.js';
@@ -29,7 +32,7 @@ function curateAlert(alert, context = {}) {
id: entity.entity_id,
name: entity.entity_name,
slug: entity.entity_slug,
type: entity.type,
type: entity.entity_type,
})) || [],
matches: context.matches?.map((match) => ({
id: match.id,
@@ -118,7 +121,9 @@ export async function createAlert(alert, reqUser) {
alert.matches?.length > 0 && knex('alerts_matches').insert(alert.matches.map((match) => ({
alert_id: alertId,
property: match.property,
expression: match.expression,
expression: /\/.*\//.test(match.expression)
? match.expression.slice(1, -1)
: escapeRegexp(match.expression),
}))),
alert.stashes?.length > 0 && knex('alerts_stashes').insert(alert.stashes.map((stashId) => ({
alert_id: alertId,
@@ -141,25 +146,60 @@ export async function removeAlert(alertId, reqUser) {
}
export async function fetchNotifications(reqUser, options = {}) {
if (!reqUser) {
return [];
}
const notifications = await knex('notifications')
.select('notifications.*', 'alerts.id as alert_id', 'scenes.title as scene_title')
.leftJoin('releases as scenes', 'scenes.id', 'notifications.scene_id')
.select(
'notifications.*',
'alerts.id as alert_id',
knex.raw('coalesce(array_agg(alerts_actors.actor_id) filter (where alerts_actors.id is not null), \'{}\') as alert_actors'),
knex.raw('coalesce(array_agg(alerts_tags.tag_id) filter (where alerts_tags.id is not null), \'{}\') as alert_tags'),
knex.raw('coalesce(array_agg(alerts_entities.entity_id) filter (where alerts_entities.id is not null), \'{}\') as alert_entities'),
knex.raw('coalesce(json_agg(alerts_matches) filter (where alerts_matches.id is not null), \'[]\') as alert_matches'),
)
.leftJoin('alerts', 'alerts.id', 'notifications.alert_id')
.leftJoin('alerts_actors', 'alerts_actors.alert_id', 'alerts.id')
.leftJoin('alerts_tags', 'alerts_tags.alert_id', 'alerts.id')
.leftJoin('alerts_entities', 'alerts_entities.alert_id', 'alerts.id')
.leftJoin('alerts_matches', 'alerts_matches.alert_id', 'alerts.id')
.where('notifications.user_id', reqUser.id)
.limit(options.limit || 10)
.groupBy('notifications.id', 'alerts.id')
.orderBy('created_at', 'desc');
return notifications.map((notification) => ({
id: notification.id,
sceneId: notification.scene_id,
scene: {
id: notification.scene_id,
title: notification.scene_title,
},
alertId: notification.alert_id,
isSeen: notification.seen,
createdAt: notification.created_at,
}));
const scenes = await fetchScenesById(notifications.map((notification) => notification.scene_id));
const unseen = notifications.filter((notification) => !notification.seen).length;
const curatedNotifications = notifications
.slice(0, options.limit || 10)
.map((notification) => {
const scene = scenes.find((sceneX) => sceneX.id === notification.scene_id);
return {
id: notification.id,
sceneId: notification.scene_id,
scene,
alertId: notification.alert_id,
matchedActors: scene.actors.filter((actor) => notification.alert_actors.includes(actor.id)),
matchedTags: scene.tags.filter((tag) => notification.alert_tags.includes(tag.id)),
matchedEntity: [scene.channel, scene.network].find((entity) => notification.alert_entities.includes(entity?.id)) || null,
matchedExpressions: notification.alert_matches
.filter((match) => new RegExp(match.expression, 'ui').test(scene[match.property]))
.map((match) => ({
id: match.id,
property: match.property,
expression: match.expression,
})),
isSeen: notification.seen,
createdAt: notification.created_at,
};
});
return {
notifications: curatedNotifications,
unseen,
};
}
export async function updateNotification(notificationId, updatedNotification, reqUser) {

View File

@@ -47,6 +47,7 @@ import {
fetchAlertsApi,
createAlertApi,
removeAlertApi,
fetchNotificationsApi,
updateNotificationApi,
updateNotificationsApi,
} from './alerts.js';
@@ -129,6 +130,7 @@ export default async function initServer() {
router.get('/api/users/:userId', fetchUserApi);
router.post('/api/users', signupApi);
router.get('/api/users/:userId/notifications', fetchNotificationsApi);
router.patch('/api/users/:userId/notifications', updateNotificationsApi);
router.patch('/api/users/:userId/notifications/:notificationId', updateNotificationApi);