summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2020-10-07 17:13:45 +0200
committerYorhel <git@yorhel.nl>2020-10-07 17:14:25 +0200
commit7eb7a3e073107bb5ad6ec20ae18f296bde33b4da (patch)
treef9ee217a77f3908abc786c14cb4ed5c4a2a24191
parentb43423e9ab6543c30660368e128d88a78b1aed39 (diff)
notifications: Mark as read when opening page + delete when deleting posts/reviews
The mark as read functionality was already present in some form for threads, but is now made consistent among all notification types. This removes the need for the redirect from the notification listing. The deletion of notifications is intended to avoid pointless notifications, especially in case of spam.
-rw-r--r--lib/VNWeb/Auth.pm11
-rw-r--r--lib/VNWeb/Discussions/Edit.pm3
-rw-r--r--lib/VNWeb/Discussions/PostEdit.pm3
-rw-r--r--lib/VNWeb/Discussions/Thread.pm5
-rw-r--r--lib/VNWeb/Reviews/Edit.pm1
-rw-r--r--lib/VNWeb/Reviews/Page.pm6
-rw-r--r--lib/VNWeb/User/Notifications.pm18
-rw-r--r--sql/tableattrs.sql2
-rw-r--r--util/updates/wip-notifications.sql13
9 files changed, 46 insertions, 16 deletions
diff --git a/lib/VNWeb/Auth.pm b/lib/VNWeb/Auth.pm
index 907fb2f4..9707108f 100644
--- a/lib/VNWeb/Auth.pm
+++ b/lib/VNWeb/Auth.pm
@@ -287,6 +287,17 @@ sub prefSet {
}
+# Mark any notifications for a particular item for the current user as read.
+# Arguments: $vndbid, $num||[@nums]||<missing>
+sub notiRead {
+ my($self, $id, $num) = @_;
+ tuwf->dbExeci('
+ UPDATE notifications SET read = NOW() WHERE read IS NULL AND uid =', \$self->uid, 'AND iid =', \$id,
+ @_ == 2 ? () : !defined $num ? 'AND num IS NULL' : !ref $num ? sql 'AND num =', \$num : sql 'AND num IN', $num
+ ) if $self->uid;
+}
+
+
# Add an entry to the audit log.
sub audit {
my($self, $affected_uid, $action, $detail) = @_;
diff --git a/lib/VNWeb/Discussions/Edit.pm b/lib/VNWeb/Discussions/Edit.pm
index dddc1ac8..b85514ec 100644
--- a/lib/VNWeb/Discussions/Edit.pm
+++ b/lib/VNWeb/Discussions/Edit.pm
@@ -47,10 +47,11 @@ elm_api DiscussionsEdit => $FORM_OUT, $FORM_IN, sub {
return tuwf->resNotFound if $tid && !$t->{id};
return elm_Unauth if !can_edit t => $t;
+ tuwf->dbExeci(q{DELETE FROM notifications WHERE iid =}, \$tid) if $tid && auth->permBoardmod && ($data->{delete} || $data->{hidden});
+
if($tid && $data->{delete} && auth->permBoardmod) {
auth->audit($t->{user_id}, 'post delete', "deleted $tid.1");
tuwf->dbExeci('DELETE FROM threads WHERE id =', \$tid);
- tuwf->dbExeci(q{DELETE FROM notifications WHERE iid =}, \$tid);
return elm_Redirect '/t';
}
auth->audit($t->{user_id}, 'post edit', "edited $tid.1") if $tid && $t->{user_id} != auth->uid;
diff --git a/lib/VNWeb/Discussions/PostEdit.pm b/lib/VNWeb/Discussions/PostEdit.pm
index a645fb6f..520a215f 100644
--- a/lib/VNWeb/Discussions/PostEdit.pm
+++ b/lib/VNWeb/Discussions/PostEdit.pm
@@ -44,11 +44,12 @@ elm_api DiscussionsPostEdit => $FORM_OUT, $FORM_IN, sub {
return tuwf->resNotFound if !$t->{id};
return elm_Unauth if !can_edit t => $t;
+ tuwf->dbExeci(q{DELETE FROM notifications WHERE iid =}, \$id, 'AND num =', \$num) if auth->permBoardmod && ($data->{delete} || $data->{hidden});
+
if($data->{delete} && auth->permBoardmod) {
auth->audit($t->{user_id}, 'post delete', "deleted $id.$num");
tuwf->dbExeci('DELETE FROM threads_posts WHERE tid =', \$id, 'AND num =', \$num);
tuwf->dbExeci('DELETE FROM reviews_posts WHERE id =', \$id, 'AND num =', \$num);
- tuwf->dbExeci(q{DELETE FROM notifications WHERE iid =}, \$id, 'AND num =', \$num);
return elm_Redirect "/$id";
}
auth->audit($t->{user_id}, 'post edit', "edited $id.$num") if $t->{user_id} != auth->uid;
diff --git a/lib/VNWeb/Discussions/Thread.pm b/lib/VNWeb/Discussions/Thread.pm
index 3fd67dbe..39de4b96 100644
--- a/lib/VNWeb/Discussions/Thread.pm
+++ b/lib/VNWeb/Discussions/Thread.pm
@@ -192,10 +192,7 @@ TUWF::get qr{/$RE{tid}(?:(?<sep>[\./])$RE{num})?}, sub {
GROUP BY tpo.id, tpo.option, tpm.optid'
);
- # Mark a notification for this thread as read, if there is one.
- tuwf->dbExeci(
- 'UPDATE notifications SET read = NOW() WHERE uid =', \auth->uid, 'AND iid =', \$id, 'AND read IS NULL'
- ) if auth && $t->{count} <= $page*25;
+ auth->notiRead($id, [ map $_->{num}, $posts->@* ]) if @$posts;
framework_ title => $t->{title}, $num ? (js => 1, pagevars => {sethash=>$num}) : (), sub {
metabox_ $t;
diff --git a/lib/VNWeb/Reviews/Edit.pm b/lib/VNWeb/Reviews/Edit.pm
index a3323d62..c7b829bc 100644
--- a/lib/VNWeb/Reviews/Edit.pm
+++ b/lib/VNWeb/Reviews/Edit.pm
@@ -101,6 +101,7 @@ elm_api ReviewsDelete => undef, { id => { vndbid => 'w' } }, sub {
my $review = tuwf->dbRowi('SELECT id, uid AS user_id FROM reviews WHERE id =', \$data->{id});
return elm_Unauth if !can_edit w => $review;
auth->audit($review->{user_id}, 'review delete', "deleted $review->{id}");
+ tuwf->dbExeci('DELETE FROM notifications WHERE iid =', \$data->{id});
tuwf->dbExeci('DELETE FROM reviews WHERE id =', \$data->{id});
elm_Success
};
diff --git a/lib/VNWeb/Reviews/Page.pm b/lib/VNWeb/Reviews/Page.pm
index 927a39f4..8aa35d4c 100644
--- a/lib/VNWeb/Reviews/Page.pm
+++ b/lib/VNWeb/Reviews/Page.pm
@@ -119,10 +119,8 @@ TUWF::get qr{/$RE{wid}(?:(?<sep>[\./])$RE{num})?}, sub {
);
return tuwf->resNotFound if $num && !grep $_->{num} == $num, @$posts;
- # Mark a notification for this thread as read, if there is one.
- tuwf->dbExeci(
- 'UPDATE notifications SET read = NOW() WHERE uid =', \auth->uid, 'AND iid =', \$id, 'AND read IS NULL'
- ) if auth && $w->{count} <= $page*25;
+ auth->notiRead($id, undef);
+ auth->notiRead($id, [ map $_->{num}, $posts->@* ]) if @$posts;
my $title = "Review of $w->{title}";
framework_ title => $title, index => 1, type => 'w', dbobj => $w,
diff --git a/lib/VNWeb/User/Notifications.pm b/lib/VNWeb/User/Notifications.pm
index e4bc0b06..3831402b 100644
--- a/lib/VNWeb/User/Notifications.pm
+++ b/lib/VNWeb/User/Notifications.pm
@@ -3,7 +3,7 @@ package VNWeb::User::Notifications;
use VNWeb::Prelude;
my %ntypes = (
- pm => 'Private Message',
+ pm => 'Message on your board',
dbdel => 'Entry you contributed to has been deleted',
listdel => 'VN in your list has been deleted',
dbedit => 'Entry you contributed to has been edited',
@@ -74,20 +74,20 @@ sub listing_ {
tr_ $_->{read} ? () : (class => 'unread'), sub {
my $l = $_;
my $lid = $l->{iid}.($l->{num}?'.'.$l->{num}:'');
- my $url = "/u$id/notify/$l->{id}/$lid";
td_ class => 'tc1', sub { input_ type => 'checkbox', name => 'notifysel', value => $l->{id}; };
td_ class => 'tc2', sub {
# Hide some not very interesting overlapping notification types
my %t = map +($_,1), $l->{ntype}->@*;
- delete $t{subpost} if $t{post} || $t{comment};
+ delete $t{subpost} if $t{post} || $t{comment} || $t{pm};
+ delete $t{post} if $t{pm};
delete $t{subedit} if $t{dbedit};
delete $t{dbedit} if $t{dbdel};
join_ \&br_, sub { txt_ $ntypes{$_} }, sort keys %t;
};
td_ class => 'tc3', fmtage $l->{date};
- td_ class => 'tc4', sub { a_ href => $url, $lid };
+ td_ class => 'tc4', sub { a_ href => "/$lid", $lid };
td_ class => 'tc5', sub {
- a_ href => $url, sub {
+ a_ href => "/$lid", sub {
txt_ $l->{iid} =~ /^w/ ? ($l->{num} ? 'Comment on ' : 'Review of ') :
$l->{iid} =~ /^t/ ? ($l->{num} == 1 ? 'New thread ' : 'Reply to ') : 'Edit of ';
i_ $l->{title};
@@ -190,6 +190,8 @@ TUWF::post qr{/$RE{uid}/notify_update}, sub {
};
+# XXX: Not currently used anymore, just visiting the destination pages will mark the relevant notifications as read
+# (but that's subject to change in the future, so let's keep this around)
TUWF::get qr{/$RE{uid}/notify/$RE{num}/(?<lid>[a-z0-9\.]+)}, sub {
my $id = tuwf->capture('id');
return tuwf->resNotFound if !auth || $id != auth->uid;
@@ -197,4 +199,10 @@ TUWF::get qr{/$RE{uid}/notify/$RE{num}/(?<lid>[a-z0-9\.]+)}, sub {
tuwf->resRedirect('/'.tuwf->capture('lid'), 'temp');
};
+
+# It's a bit annoying to add auth->notiRead() to each revision page, so do that in bulk with a simple hook.
+TUWF::hook before => sub {
+ auth->notiRead($+{vndbid}, $+{rev}) if auth && tuwf->reqPath() =~ qr{^/(?<vndbid>[vrpcsd]$RE{num})\.(?<rev>$RE{num})$};
+};
+
1;
diff --git a/sql/tableattrs.sql b/sql/tableattrs.sql
index 23dd362a..8e408b92 100644
--- a/sql/tableattrs.sql
+++ b/sql/tableattrs.sql
@@ -119,7 +119,7 @@ CREATE INDEX chars_vns_vid ON chars_vns (vid);
CREATE INDEX chars_image ON chars (image);
CREATE UNIQUE INDEX image_votes_pkey ON image_votes (uid, id);
CREATE INDEX image_votes_id ON image_votes (id);
-CREATE INDEX notifications_uid ON notifications (uid);
+CREATE INDEX notifications_uid_iid ON notifications (uid,iid);
CREATE INDEX releases_producers_pid ON releases_producers (pid);
CREATE INDEX releases_vn_vid ON releases_vn (vid);
CREATE INDEX reports_new ON reports (date) WHERE status = 'new';
diff --git a/util/updates/wip-notifications.sql b/util/updates/wip-notifications.sql
index 1a817b33..ef0f574b 100644
--- a/util/updates/wip-notifications.sql
+++ b/util/updates/wip-notifications.sql
@@ -13,6 +13,19 @@ ALTER TABLE notifications ALTER COLUMN ntype TYPE notification_ntype[] USING ARR
ALTER TABLE notifications DROP COLUMN c_title;
ALTER TABLE notifications DROP COLUMN c_byuser;
+DROP INDEX notifications_uid;
+CREATE INDEX notifications_uid_iid ON notifications (uid,iid);
+
+-- Merge duplicate notifications (dbdel & listdel could cause duplicates)
+UPDATE notifications n SET ntype = ntype || ARRAY['dbdel'::notification_ntype]
+ WHERE ntype = ARRAY['listdel'::notification_ntype]
+ AND EXISTS(SELECT 1 FROM notifications m WHERE m.id <> n.id AND m.uid = n.uid AND m.iid = n.iid AND m.num IS NOT DISTINCT FROM n.num AND m.ntype = ARRAY['dbdel'::notification_ntype]);
+DELETE FROM notifications n
+ WHERE ntype = ARRAY['dbdel'::notification_ntype]
+ AND EXISTS(SELECT 1 FROM notifications m WHERE m.id <> n.id AND m.uid = n.uid AND m.iid = n.iid AND m.num IS NOT DISTINCT FROM n.num AND m.ntype = ARRAY['listdel'::notification_ntype,'dbdel']);
+-- For some reason a few notifications from 2014 were duplicated, let's just get rid of those.
+DELETE FROM notifications n WHERE EXISTS(SELECT 1 FROM notifications m WHERE m.id <> n.id AND m.uid = n.uid AND m.iid = n.iid AND m.num IS NOT DISTINCT FROM n.num AND m.id > n.id);
+
-- Subscriptions
ALTER TYPE notification_ntype ADD VALUE 'subpost' AFTER 'comment';
ALTER TYPE notification_ntype ADD VALUE 'subedit' AFTER 'subpost';