From de8239167a5070c92ba155a6a72d06767ea7ad43 Mon Sep 17 00:00:00 2001 From: DebaucheryLibrarian Date: Thu, 16 Jul 2026 01:11:17 +0200 Subject: [PATCH] Removed alerts and notify, now fully handeld by web. --- src/alerts.js | 291 ------------------------------------------ src/store-releases.js | 4 - 2 files changed, 295 deletions(-) delete mode 100755 src/alerts.js diff --git a/src/alerts.js b/src/alerts.js deleted file mode 100755 index 81a5d7ef..00000000 --- a/src/alerts.js +++ /dev/null @@ -1,291 +0,0 @@ -'use strict'; - -const escapeRegexp = require('escape-string-regexp'); - -const argv = require('./argv'); -const logger = require('./logger')(__filename); -const knex = require('./knex'); -const { indexApi } = require('./manticore'); -const bulkInsert = require('./utils/bulk-insert'); -const { HttpError } = require('./errors'); - -async function addAlert(alert, sessionUser) { - if (!sessionUser) { - throw new HttpError('You are not authenthicated', 401); - } - - if ((!alert.actors || alert.actors.length === 0) && (!alert.tags || alert.tags.length === 0) && (!alert.entities || alert.entities.length === 0) && (!alert.matches || alert.matches.length === 0)) { - throw new HttpError('Alert must contain at least one actor, tag or entity', 400); - } - - if (alert.matches?.some((match) => !match.property || !match.expression)) { - throw new HttpError('Match must define a property and an expression', 400); - } - - const [{ id: alertId }] = await knex('alerts') - .insert({ - user_id: sessionUser.id, - notify: alert.notify, - email: alert.email, - all: alert.all, - }) - .returning('id'); - - await Promise.all([ - alert.actors?.length > 0 && bulkInsert('alerts_actors', alert.actors.map((actorId) => ({ - alert_id: alertId, - actor_id: actorId, - })), false), - alert.tags?.length > 0 && bulkInsert('alerts_tags', alert.tags.map((tagId) => ({ - alert_id: alertId, - tag_id: tagId, - })), false), - alert.matches?.length > 0 && bulkInsert('alerts_matches', alert.matches.map((match) => ({ - alert_id: alertId, - property: match.property, - expression: /\/.*\//.test(match.expression) - ? match.expression.slice(1, -1) - : escapeRegexp(match.expression), - })), false), - alert.stashes?.length > 0 && bulkInsert('alerts_stashes', alert.stashes.map((stashId) => ({ - alert_id: alertId, - stash_id: stashId, - })), false), - alert.entities && bulkInsert('alerts_entities', alert.entities.map((entityId) => ({ - alert_id: alertId, - entity_id: entityId, - })).slice(0, alert.all ? 1 : Infinity), false), // one scene can never match multiple entities in AND mode - ]); - - return alertId; -} - -async function removeAlert(alertId) { - await knex('alerts').where('id', alertId).delete(); -} - -async function notify(scenes) { - if (argv.showcased === false) { - logger.info(`Skipping notify for ${scenes.length} scenes because showcase flag is disabled.`); - return []; - } - - const sceneIds = scenes.map((scene) => scene.id); - - const [ - releasesActors, - releasesTags, - rawAlerts, - alertsActors, - alertsTags, - alertsEntities, - alertsMatches, - alertsStashes, - ] = await Promise.all([ - knex('releases_actors').whereIn('release_id', sceneIds), - knex('releases_tags').whereIn('release_id', sceneIds), - knex('alerts'), - knex('alerts_actors'), - knex('alerts_tags'), - knex('alerts_entities'), - knex('alerts_matches'), - knex('alerts_stashes'), - ]); - - const actorIdsByReleaseId = releasesActors.reduce((acc, releaseActor) => { - if (!acc[releaseActor.release_id]) { - acc[releaseActor.release_id] = []; - } - - acc[releaseActor.release_id].push(releaseActor.actor_id); - - return acc; - }, {}); - - const tagIdsByReleaseId = releasesTags.reduce((acc, releaseTag) => { - if (!acc[releaseTag.release_id]) { - acc[releaseTag.release_id] = []; - } - - acc[releaseTag.release_id].push(releaseTag.tag_id); - - return acc; - }, {}); - - const alertsActorsByAlertId = alertsActors.reduce((acc, alertActor) => { if (!acc[alertActor.alert_id]) { acc[alertActor.alert_id] = []; } acc[alertActor.alert_id].push(alertActor.actor_id); return acc; }, {}); - const alertsTagsByAlertId = alertsTags.reduce((acc, alertTag) => { if (!acc[alertTag.alert_id]) { acc[alertTag.alert_id] = []; } acc[alertTag.alert_id].push(alertTag.tag_id); return acc; }, {}); - const alertsEntitiesByAlertId = alertsEntities.reduce((acc, alertEntity) => { if (!acc[alertEntity.alert_id]) { acc[alertEntity.alert_id] = []; } acc[alertEntity.alert_id].push(alertEntity.entity_id); return acc; }, {}); - const alertsStashesByAlertId = alertsStashes.reduce((acc, alertStash) => { if (!acc[alertStash.alert_id]) { acc[alertStash.alert_id] = []; } acc[alertStash.alert_id].push(alertStash.stash_id); return acc; }, {}); - - const alertsMatchesByAlertId = alertsMatches.reduce((acc, alertMatch) => { - if (!acc[alertMatch.alert_id]) { - acc[alertMatch.alert_id] = []; - } - - acc[alertMatch.alert_id].push({ - property: alertMatch.property, - expression: new RegExp(alertMatch.expression, 'ui'), - }); - - return acc; - }, {}); - - const alerts = rawAlerts.map((alert) => ({ - id: alert.id, - userId: alert.user_id, - notify: alert.notify, - email: alert.email, - all: alert.all, - allActors: alert.all_actors, - allEntities: alert.all_entities, - allTags: alert.all_tags, - allMatches: alert.all_matches, - actors: alertsActorsByAlertId[alert.id] || [], - tags: alertsTagsByAlertId[alert.id] || [], - entities: alertsEntitiesByAlertId[alert.id] || [], - matches: alertsMatchesByAlertId[alert.id] || [], - stashes: alertsStashesByAlertId[alert.id] || [], - })); - - const curatedScenes = scenes.map((scene) => ({ - id: scene.id, - title: scene.title, - description: scene.description, - actorIds: actorIdsByReleaseId[scene.id] || [], - tagIds: tagIdsByReleaseId[scene.id] || [], - entityId: scene.entity.id, - parentEntityId: scene.entity.parent?.id, - })); - - const triggers = alerts.flatMap((alert) => { - const alertScenes = curatedScenes.filter((scene) => { - if (alert.all) { - if (alert.actors.length === 0 - && alert.tags.length === 0 - && alert.entities.length === 0 - && alert.matches.length === 0) { - // we must match on *something*, this is likely a release date alert handled separately - return false; - } - - if (alert.actors.length > 0 && !alert.actors[alert.allActors ? 'every' : 'some']((actorId) => scene.actorIds.includes(actorId))) { - return false; - } - - if (alert.tags.length > 0 && !alert.tags[alert.allTags ? 'every' : 'some']((tagId) => scene.tagIds.includes(tagId))) { - return false; - } - - // multiple entities can only be matched in OR mode - if (alert.entities.length > 0 && !alert.entities.some((alertEntityId) => alertEntityId === scene.entityId || alertEntityId === scene.parentEntityId)) { - return false; - } - - if (alert.matches.length > 0 && !alert.matches[alert.allMatches ? 'every' : 'some']((match) => match.expression.test(scene[match.property]))) { - return false; - } - - return true; - } - - if (alert.matches.length > 0 && alert.actors[alert.allActors ? 'every' : 'some']((actorId) => scene.actorIds.includes(actorId))) { - return true; - } - - if (alert.tags.length > 0 && alert.tags[alert.allTags ? 'every' : 'some']((tagId) => scene.tagIds.includes(tagId))) { - return true; - } - - // multiple entities can only be matched in OR mode - if (alert.entities.length > 0 && alert.entities.some((alertEntityId) => alertEntityId === scene.entityId || alertEntityId === scene.parentEntityId)) { - return true; - } - - if (alert.matches.length > 0 && alert.matches[alert.allMatches ? 'every' : 'some']((match) => match.expression.test(scene[match.property]))) { - return true; - } - - return false; - }); - - return alertScenes.map((scene) => ({ - sceneId: scene.id, - alert, - })); - }); - - const notifications = Object.values(Object.fromEntries(triggers // prevent multiple notifications for the same scene - .filter((trigger) => trigger.alert.notify) - .map((trigger) => [`${trigger.alert.userId}:${trigger.sceneId}`, trigger]))) - .map((trigger) => ({ - user_id: trigger.alert.userId, - alert_id: trigger.alert.id, - scene_id: trigger.sceneId, - })); - - const uniqueStashes = Object.values(Object.fromEntries(triggers.flatMap((trigger) => trigger.alert.stashes.map((stashId) => ({ - stashId, - sceneId: trigger.sceneId, - userId: trigger.alert.userId, - }))).map((stash) => [`${stash.stashId}:${stash.sceneId}`, stash]))); - - const stashEntries = uniqueStashes.map((stash) => ({ - scene_id: stash.sceneId, - stash_id: stash.stashId, - })); - - const [stashed] = await Promise.all([ - bulkInsert('stashes_scenes', stashEntries, false), - bulkInsert('notifications', notifications, false), - ]); - - // we need created_at from the databased, but user_id is not returned. it's easier to query it than to try and merge it with the input data - const stashedEntries = await knex('stashes_scenes') - .select('stashes_scenes.*', 'stashes.user_id') - .leftJoin('stashes', 'stashes.id', 'stashes_scenes.stash_id') - .whereIn('stashes_scenes.id', stashed.map((stash) => stash.id)); - - const docs = stashedEntries.map((stash) => ({ - replace: { - index: 'scenes_stashed', - id: stash.id, - doc: { - scene_id: stash.scene_id, - user_id: stash.user_id, - stash_id: stash.stash_id, - created_at: Math.round(stash.created_at.getTime() / 1000), - }, - }, - })); - - if (docs.length > 0) { - await indexApi.bulk(docs.map((doc) => JSON.stringify(doc)).join('\n')); - } - - return triggers; -} - -async function updateNotification(notificationId, notification, sessionUser) { - await knex('notifications') - .where('user_id', sessionUser.id) - .where('id', notificationId) - .update({ - seen: notification.seen, - }); -} - -async function updateNotifications(notification, sessionUser) { - await knex('notifications') - .where('user_id', sessionUser.id) - .update({ - seen: notification.seen, - }); -} - -module.exports = { - addAlert, - removeAlert, - notify, - updateNotification, - updateNotifications, -}; diff --git a/src/store-releases.js b/src/store-releases.js index ad48098b..2df5082b 100755 --- a/src/store-releases.js +++ b/src/store-releases.js @@ -18,7 +18,6 @@ const { associateReleaseTags } = require('./tags'); const { curateEntity } = require('./entities'); const { associateReleaseMedia } = require('./media'); const { updateSceneSearch, updateMovieSearch } = require('./update-search'); -const { notify } = require('./alerts'); const geoCommon = import('../common/geo.mjs'); // eslint-disable-line import/extensions, import/no-relative-packages @@ -503,9 +502,6 @@ async function storeScenes(releases, useBatchId) { logger.info(`Stored ${storedReleaseEntries.length}, updated ${updated} releases`); - // TODO: disable, handled by web sync now - await notify(releasesWithId); - return releasesWithId; }