Implemented notifications, simplified alerts overview.
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user