diff options
-rw-r--r-- | lib/VNWeb/Auth.pm | 11 | ||||
-rw-r--r-- | lib/VNWeb/Discussions/Edit.pm | 3 | ||||
-rw-r--r-- | lib/VNWeb/Discussions/PostEdit.pm | 3 | ||||
-rw-r--r-- | lib/VNWeb/Discussions/Thread.pm | 5 | ||||
-rw-r--r-- | lib/VNWeb/Reviews/Edit.pm | 1 | ||||
-rw-r--r-- | lib/VNWeb/Reviews/Page.pm | 6 | ||||
-rw-r--r-- | lib/VNWeb/User/Notifications.pm | 18 | ||||
-rw-r--r-- | sql/tableattrs.sql | 2 | ||||
-rw-r--r-- | util/updates/wip-notifications.sql | 13 |
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'; |