diff --git a/components/alerts/create.vue b/components/alerts/create.vue
index 377f34e..3a288f1 100644
--- a/components/alerts/create.vue
+++ b/components/alerts/create.vue
@@ -418,6 +418,13 @@ const email = ref(false);
const stashes = ref([]);
async function createAlert() {
+ const alertLabel = [
+ ...actors.value.map((actor) => actor.name),
+ ...tags.value.map((tag) => tag.name),
+ ...entities.value.map((entity) => entity.name),
+ ...matches.value.map((match) => match.expression),
+ ].filter(Boolean).join(', ');
+
await post('/alerts', {
all: fieldsAnd.value,
allActors: actorAnd.value,
@@ -430,7 +437,11 @@ async function createAlert() {
notify: notify.value,
email: email.value,
stashes: stashes.value.map((stash) => stash.id),
- }, { appendErrorMessage: true });
+ }, {
+ successFeedback: `Alert for '${alertLabel}' set`,
+ errorFeedback: `Failed to set alert for '${alertLabel}'`,
+ appendErrorMessage: true,
+ });
emit('close', true);
}
diff --git a/components/stashes/heart.vue b/components/stashes/heart.vue
index 9b8b356..4c31f14 100644
--- a/components/stashes/heart.vue
+++ b/components/stashes/heart.vue
@@ -3,6 +3,34 @@
v-if="user"
class="bookmarks"
>
+
+
+
+
+
+
+
+
0);
const hasSecondaryStash = computed(() => itemStashes.value.some((itemStash) => !itemStash.isPrimary));
+if (props.domain === 'actors') {
+ console.log(itemAlerts.value);
+}
+
const done = ref(true);
const showStashes = ref(false);
const showStashDialog = ref(false);
@@ -154,9 +190,9 @@ async function stashItem(stash) {
emit('stashed', stash);
} catch (error) {
itemStashes.value = stashState;
+ } finally {
+ done.value = true;
}
-
- done.value = true;
}
async function unstashItem(stash) {
@@ -178,9 +214,68 @@ async function unstashItem(stash) {
emit('unstashed', stash);
} catch (error) {
itemStashes.value = stashState;
+ } finally {
+ done.value = true;
+ }
+}
+
+async function alertItem() {
+ if (!done.value) {
+ return;
}
- done.value = true;
+ const alertLabel = props.item.title || props.item.name;
+
+ done.value = false;
+ itemAlerted.value = true;
+
+ try {
+ const newAlert = await post('/alerts', {
+ ...(props.domain === 'actors' && { actors: [props.item.id] }),
+ ...(props.domain === 'tags' && { tags: [props.item.id] }),
+ ...(props.domain === 'entities' && { entities: [props.item.id] }),
+ notify: true,
+ email: false,
+ preset: true,
+ }, {
+ successFeedback: `Alert set for '${alertLabel}'`,
+ errorFeedback: `Failed to set alert for '${alertLabel}'`,
+ appendErrorMessage: true,
+ });
+
+ itemAlerts.value.only = itemAlerts.value.only.concat(newAlert.id);
+ } catch (error) {
+ itemAlerted.value = false;
+ } finally {
+ done.value = true;
+ }
+}
+
+async function removeAlert() {
+ if (done.value === false) {
+ return;
+ }
+
+ const alertLabel = props.item.title || props.item.name;
+ const alertIds = itemAlerts.value.only;
+
+ done.value = false;
+
+ itemAlerted.value = false;
+ itemAlerts.value.only = itemAlerts.value.only.filter((alertId) => !alertIds.includes(alertId));
+
+ try {
+ await del(`/alerts/${alertIds.join(',')}`, {
+ undoFeedback: `Removed alert for '${alertLabel}'`,
+ errorFeedback: `Failed to remove alert for '${alertLabel}'`,
+ appendErrorMessage: true,
+ });
+ } catch (error) {
+ itemAlerted.value = true;
+ itemAlerts.value.only = itemAlerts.value.only.concat(alertIds);
+ } finally {
+ done.value = true;
+ }
}
function toggleShowStashes(state) {
@@ -229,10 +324,22 @@ async function reloadStashes(newStash) {
}
}
+ .icon.alert {
+ width: 1.3rem;
+ padding: .7rem .5rem;
+ }
+
.icon.heart:hover,
- .icon.heart.favorited {
+ .icon.alert:hover,
+ .icon.heart.favorited,
+ .icon.alert.active {
cursor: pointer;
fill: var(--primary);
}
+
+ .icon.alert.partial {
+ cursor: pointer;
+ fill: var(--text-light);
+ }
}
diff --git a/pages/actors/@actorId/edit/+Page.vue b/pages/actors/@actorId/edit/+Page.vue
index 07075f7..c21a47c 100644
--- a/pages/actors/@actorId/edit/+Page.vue
+++ b/pages/actors/@actorId/edit/+Page.vue
@@ -357,8 +357,6 @@ const pageContext = inject('pageContext');
const user = pageContext.user;
const actor = ref(pageContext.pageProps.actor);
-// console.log(actor.value);
-
const fields = computed(() => [
...(actor.value.photos.length > 0 ? [{
key: 'avatar',
diff --git a/src/actors.js b/src/actors.js
index 9b29e55..437b82c 100644
--- a/src/actors.js
+++ b/src/actors.js
@@ -166,6 +166,10 @@ export function curateActor(actor, context = {}) {
scenes: actor.scenes,
likes: actor.stashed,
stashes: context.stashes?.map((stash) => curateStash(stash)) || [],
+ alerts: {
+ only: context.alerts?.filter((alert) => alert.is_only).flatMap((alert) => alert.alert_ids) || [],
+ multi: context.alerts?.filter((alert) => !alert.is_only).flatMap((alert) => alert.alert_ids) || [],
+ },
...context.append?.[actor.id],
};
}
@@ -198,7 +202,7 @@ export function sortActorsByGender(actors, context = {}) {
}
export async function fetchActorsById(actorIds, options = {}, reqUser) {
- const [actors, profiles, photos, socials, stashes] = await Promise.all([
+ const [actors, profiles, photos, socials, stashes, alerts] = await Promise.all([
knex('actors')
.select(
'actors.*',
@@ -253,11 +257,17 @@ export async function fetchActorsById(actorIds, options = {}, reqUser) {
.where('stashes.user_id', reqUser.id)
.whereIn('stashes_actors.actor_id', actorIds)
: [],
+ reqUser
+ ? knex('alerts_users_actors')
+ .where('user_id', reqUser.id)
+ .whereIn('actor_id', actorIds)
+ : [],
]);
if (options.order) {
return actors.map((actorEntry) => curateActor(actorEntry, {
stashes: stashes.filter((stash) => stash.actor_id === actorEntry.id),
+ alerts: alerts.filter((alert) => alert.actor_id === actorEntry.id),
append: options.append,
}));
}
@@ -272,6 +282,7 @@ export async function fetchActorsById(actorIds, options = {}, reqUser) {
return curateActor(actor, {
stashes: stashes.filter((stash) => stash.actor_id === actor.id),
+ alerts: alerts.filter((alert) => alert.actor_id === actor.id),
profiles: profiles.filter((profile) => profile.actor_id === actor.id),
photos: photos.filter((photo) => photo.actor_id === actor.id),
socials: socials.filter((social) => social.actor_id === actor.id),
diff --git a/src/alerts.js b/src/alerts.js
index 1aeb49b..75f1f5a 100755
--- a/src/alerts.js
+++ b/src/alerts.js
@@ -120,6 +120,7 @@ export async function createAlert(alert, reqUser) {
all_entities: alert.allEntities,
all_tags: alert.allTags,
all_matches: alert.allMatches,
+ from_preset: alert.preset,
})
.returning('id');
@@ -149,14 +150,43 @@ export async function createAlert(alert, reqUser) {
})).slice(0, alert.allEntities ? 1 : Infinity)), // one scene can never match multiple entities in AND mode
]);
+ await Promise.all([
+ alert.actors?.length > 0 && knex.schema.refreshMaterializedView('alerts_users_actors'),
+ alert.tags?.length > 0 && knex.schema.refreshMaterializedView('alerts_users_tags'),
+ alert.entities?.length > 0 && knex.schema.refreshMaterializedView('alerts_users_entities'),
+ ]);
+
return alertId;
}
export async function removeAlert(alertId, reqUser) {
+ const alert = await knex('alerts')
+ .where('alerts.id', alertId)
+ .select(
+ 'alerts.id',
+ knex.raw('coalesce(array_agg(distinct alerts_actors.actor_id) filter (where alerts_actors.actor_id is not null), \'{}\') as actor_ids'),
+ knex.raw('coalesce(array_agg(distinct alerts_entities.entity_id) filter (where alerts_entities.entity_id is not null), \'{}\') as entity_ids'),
+ knex.raw('coalesce(array_agg(distinct alerts_tags.tag_id) filter (where alerts_tags.tag_id is not null), \'{}\') as tag_ids'),
+ )
+ .leftJoin('alerts_actors', 'alerts_actors.alert_id', 'alerts.id')
+ .leftJoin('alerts_entities', 'alerts_entities.alert_id', 'alerts.id')
+ .leftJoin('alerts_tags', 'alerts_tags.alert_id', 'alerts.id')
+ .leftJoin('alerts_matches', 'alerts_matches.alert_id', 'alerts.id')
+ .groupBy('alerts.id')
+ .first();
+
+ console.log(alertId, alert);
+
await knex('alerts')
.where('id', alertId)
.where('user_id', reqUser.id)
.delete();
+
+ await Promise.all([
+ alert.actor_ids.length > 0 && knex.schema.refreshMaterializedView('alerts_users_actors'),
+ alert.tag_ids.length > 0 && knex.schema.refreshMaterializedView('alerts_users_tags'),
+ alert.entity_ids?.length > 0 && knex.schema.refreshMaterializedView('alerts_users_entities'),
+ ]);
}
export async function fetchUnseenNotificationsCount(reqUser) {
diff --git a/src/web/alerts.js b/src/web/alerts.js
index 9b8773f..d113693 100755
--- a/src/web/alerts.js
+++ b/src/web/alerts.js
@@ -20,7 +20,7 @@ export async function createAlertApi(req, res) {
}
export async function removeAlertApi(req, res) {
- await removeAlert(req.params.alertId, req.user);
+ await Promise.all(req.params.alertId.split(',').map(async (alertId) => removeAlert(alertId, req.user)));
res.status(204).send();
}