'use strict'; const knex = require('./knex'); 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?.length > 0 && !alert.tags?.length > 0 && !alert.entity) { throw new HttpError('Alert must contain at least one actor, tag or entity', 400); } const [alertId] = await knex('alerts') .insert({ user_id: sessionUser.id, notify: alert.notify, email: alert.email, }) .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.stashes?.length > 0 && bulkInsert('alerts_stashes', alert.stashes.map((stashId) => ({ alert_id: alertId, stash_id: stashId, })), false), alert.entity && bulkInsert('alerts_entities', [{ alert_id: alertId, entity_id: alert.entity, }], false), ]); return alertId; } async function removeAlert(alertId) { await knex('alerts').where('id', alertId).delete(); } async function notify(scenes) { const releases = await knex.raw(` SELECT alerts.id as alert_id, alerts.notify, alerts.email, releases.id as scene_id, users.id as user_id, COALESCE(json_agg(alerts_stashes.stash_id) FILTER (WHERE alerts_stashes.stash_id IS NOT NULL), '[]') as stashes FROM releases CROSS JOIN alerts LEFT JOIN users ON users.id = alerts.user_id LEFT JOIN alerts_stashes ON alerts_stashes.alert_id = alerts.id /* match updated IDs from input */ WHERE (releases.id = ANY(:sceneIds)) /* match tags */ AND (NOT EXISTS (SELECT alerts_tags.alert_id FROM alerts_tags WHERE alerts_tags.alert_id = alerts.id) OR (SELECT array_agg(releases_tags.tag_id) FROM releases_tags WHERE releases_tags.release_id = releases.id GROUP BY releases_tags.release_id) @> (SELECT array_agg(alerts_tags.tag_id) FROM alerts_tags WHERE alerts_tags.alert_id = alerts.id GROUP BY alerts_tags.alert_id)) /* match actors */ AND (NOT EXISTS (SELECT alerts_actors.alert_id FROM alerts_actors WHERE alerts_actors.alert_id = alerts.id) OR (SELECT array_agg(releases_actors.actor_id) FROM releases_actors WHERE releases_actors.release_id = releases.id GROUP BY releases_actors.release_id) @> (SELECT array_agg(alerts_actors.actor_id) FROM alerts_actors WHERE alerts_actors.alert_id = alerts.id GROUP BY alerts_actors.alert_id)) /* match entity */ AND ((NOT EXISTS (SELECT alerts_entities.entity_id FROM alerts_entities WHERE alerts_entities.alert_id = alerts.id)) OR (releases.entity_id = ANY(array( /* include children of entities */ WITH RECURSIVE included AS ( SELECT entities.* FROM alerts_entities LEFT JOIN entities ON entities.id = alerts_entities.entity_id WHERE alerts_entities.alert_id = alerts.id UNION ALL SELECT entities.* FROM entities INNER JOIN included ON included.id = entities.parent_id ) SELECT included.id FROM included GROUP BY included.id )))) GROUP BY releases.id, users.id, alerts.id; `, { sceneIds: scenes.map((scene) => scene.id), }); const notifications = releases.rows .filter((alert) => alert.notify) .map((notification) => ({ user_id: notification.user_id, alert_id: notification.alert_id, scene_id: notification.scene_id, })); const stashes = releases.rows .filter((release) => release.stashes.length > 0) .flatMap((release) => release.stashes.map((stash) => ({ scene_id: release.scene_id, stash_id: stash, }))); await Promise.all([ bulkInsert('notifications', notifications, false), bulkInsert('stashes_scenes', stashes, false), ]); return releases.rows; } 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, };