summaryrefslogtreecommitdiff
path: root/lib/VNWeb/User/Notifications.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNWeb/User/Notifications.pm')
-rw-r--r--lib/VNWeb/User/Notifications.pm145
1 files changed, 107 insertions, 38 deletions
diff --git a/lib/VNWeb/User/Notifications.pm b/lib/VNWeb/User/Notifications.pm
index 59512f05..513cec23 100644
--- a/lib/VNWeb/User/Notifications.pm
+++ b/lib/VNWeb/User/Notifications.pm
@@ -3,28 +3,46 @@ package VNWeb::User::Notifications;
use VNWeb::Prelude;
my %ntypes = (
- pm => 'Private Message',
- dbdel => 'Entry you contributed to has been deleted',
- listdel => 'VN in your (wish)list has been deleted',
- dbedit => 'Entry you contributed to has been edited',
- announce => 'Site announcement',
+ 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',
+ announce => 'Site announcement',
+ post => 'Reply to a thread you posted in',
+ comment => 'Comment on your review',
+ subpost => 'Reply to a thread you subscribed to',
+ subedit => 'Entry you subscribed to has been edited',
+ subreview => 'New review for a VN you subscribed to',
+ subapply => 'Trait you subscribed to has been (un)applied',
);
sub settings_ {
my $id = shift;
+ my $u = tuwf->dbRowi('SELECT notify_dbedit, notify_post, notify_comment, notify_announce FROM users WHERE id =', \$id);
+
h1_ 'Settings';
- form_ action => "/u$id/notify_options", method => 'POST', sub {
+ form_ action => "/$id/notify_options", method => 'POST', sub {
input_ type => 'hidden', class => 'hidden', name => 'csrf', value => auth->csrftoken;
p_ sub {
label_ sub {
- input_ type => 'checkbox', name => 'dbedit', auth->pref('notify_dbedit') ? (checked => 'checked') : ();
+ input_ type => 'checkbox', name => 'dbedit', $u->{notify_dbedit} ? (checked => 'checked') : ();
txt_ ' Notify me about edits of database entries I contributed to.';
};
br_;
label_ sub {
- input_ type => 'checkbox', name => 'announce', auth->pref('notify_announce') ? (checked => 'checked') : ();
+ input_ type => 'checkbox', name => 'post', $u->{notify_post} ? (checked => 'checked') : ();
+ txt_ ' Notify me about replies to threads I posted in.';
+ };
+ br_;
+ label_ sub {
+ input_ type => 'checkbox', name => 'comment', $u->{notify_comment} ? (checked => 'checked') : ();
+ txt_ ' Notify me about comments to my reviews.';
+ };
+ br_;
+ label_ sub {
+ input_ type => 'checkbox', name => 'announce', $u->{notify_announce} ? (checked => 'checked') : ();
txt_ ' Notify me about site announcements.';
};
br_;
@@ -37,7 +55,7 @@ sub settings_ {
sub listing_ {
my($id, $opt, $count, $list) = @_;
- my sub url { "/u$id/notifies?r=$opt->{r}&p=$_" }
+ my sub url { "/$id/notifies?r=$opt->{r}&p=$_" }
my sub tbl_ {
thead_ sub { tr_ sub {
@@ -53,32 +71,40 @@ sub listing_ {
txt_ ' ';
input_ type => 'submit', class => 'submit', name => 'markread', value => 'mark selected read';
input_ type => 'submit', class => 'submit', name => 'remove', value => 'remove selected';
- b_ class => 'grayedout', ' (Read notifications are automatically removed after one month)';
+ small_ ' (Read notifications are automatically removed after one month)';
}
}};
tr_ $_->{read} ? () : (class => 'unread'), sub {
my $l = $_;
- my $lid = $l->{ltype}.$l->{iid}.($l->{subid}?'.'.$l->{subid}:'');
- my $url = "/u$id/notify/$l->{id}/$lid";
+ my $lid = $l->{iid}.($l->{num}?'.'.$l->{num}:'');
td_ class => 'tc1', sub { input_ type => 'checkbox', name => 'notifysel', value => $l->{id}; };
- td_ class => 'tc2', $ntypes{$l->{ntype}};
+ 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} || $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 {
- txt_ $l->{ltype} ne 't' ? 'Edit of ' : $l->{subid} == 1 ? 'New thread ' : 'Reply to ';
- i_ $l->{c_title};
+ 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 ';
+ span_ tattr $l;
txt_ ' by ';
- i_ user_displayname $l;
+ span_ user_displayname $l;
};
};
} for @$list;
}
- form_ action => "/u$id/notify_update", method => 'POST', sub {
+ form_ action => "/$id/notify_update", method => 'POST', sub {
input_ type => 'hidden', class => 'hidden', name => 'url', value => do { local $_ = $opt->{p}; url };
paginate_ \&url, $opt->{p}, [$count, 25], 't';
- div_ class => 'mainbox browse notifies', sub {
+ article_ class => 'browse notifies', sub {
table_ class => 'stripe', \&tbl_;
};
paginate_ \&url, $opt->{p}, [$count, 25], 'b';
@@ -86,9 +112,13 @@ sub listing_ {
}
+# Redirect so that elm/Subscribe.elm can link to this page without knowing our uid.
+TUWF::get qr{/u/notifies}, sub { auth ? tuwf->resRedirect('/'.auth->uid.'/notifies', 'temp') : tuwf->resNotFound };
+
+
TUWF::get qr{/$RE{uid}/notifies}, sub {
my $id = tuwf->capture('id');
- return tuwf->resNotFound if !auth || $id != auth->uid;
+ return tuwf->resNotFound if !auth || $id ne auth->uid;
my $opt = tuwf->validate(get =>
p => { page => 1 },
@@ -96,24 +126,23 @@ TUWF::get qr{/$RE{uid}/notifies}, sub {
)->data;
my $where = sql_and(
- sql('uid =', \$id),
- $opt->{r} ? () : 'read IS NULL'
+ sql('n.uid =', \$id),
+ $opt->{r} ? () : 'n.read IS NULL'
);
- my $count = tuwf->dbVali('SELECT count(*) FROM notifications WHERE', $where);
+ my $count = tuwf->dbVali('SELECT count(*) FROM notifications n WHERE', $where);
my $list = tuwf->dbPagei({ results => 25, page => $opt->{p} },
- 'SELECT n.id, n.ntype, n.ltype, n.iid, n.subid, n.c_title
+ 'SELECT n.id, n.ntype::text[] AS ntype, n.iid, n.num, t.title, ', sql_user(), '
, ', sql_totime('n.date'), ' as date
, ', sql_totime('n.read'), ' as read
- , ', sql_user(),
- 'FROM notifications n
- LEFT JOIN users u ON u.id = n.c_byuser
+ FROM notifications n,', item_info('n.iid', 'n.num'), 't
+ LEFT JOIN users u ON u.id = t.uid
WHERE ', $where,
'ORDER BY n.id', $opt->{r} ? 'DESC' : 'ASC'
);
framework_ title => 'My notifications', js => 1,
sub {
- div_ class => 'mainbox', sub {
+ article_ sub {
h1_ 'My notifications';
p_ class => 'browseopts', sub {
a_ !$opt->{r} ? (class => 'optselected') : (), href => '?r=0', 'Unread notifications';
@@ -122,35 +151,41 @@ TUWF::get qr{/$RE{uid}/notifies}, sub {
p_ 'No notifications!' if !$count;
};
listing_ $id, $opt, $count, $list;
- div_ class => 'mainbox', sub { settings_ $id };
+ article_ sub { settings_ $id };
};
};
TUWF::post qr{/$RE{uid}/notify_options}, sub {
my $id = tuwf->capture('id');
- return tuwf->resNotFound if !auth || $id != auth->uid;
+ return tuwf->resNotFound if !auth || $id ne auth->uid;
my $frm = tuwf->validate(post =>
csrf => {},
dbedit => { anybool => 1 },
announce => { anybool => 1 },
+ post => { anybool => 1 },
+ comment => { anybool => 1 },
)->data;
return tuwf->resNotFound if !auth->csrfcheck($frm->{csrf});
- auth->prefSet(notify_dbedit => $frm->{dbedit});
- auth->prefSet(notify_announce => $frm->{announce});
- tuwf->resRedirect("/u$id/notifies", 'post');
+ tuwf->dbExeci('UPDATE users SET', {
+ notify_dbedit => $frm->{dbedit},
+ notify_announce => $frm->{announce},
+ notify_post => $frm->{post},
+ notify_comment => $frm->{comment},
+ }, 'WHERE id =', \$id);
+ tuwf->resRedirect("/$id/notifies", 'post');
};
TUWF::post qr{/$RE{uid}/notify_update}, sub {
my $id = tuwf->capture('id');
- return tuwf->resNotFound if !auth || $id != auth->uid;
+ return tuwf->resNotFound if !auth || $id ne auth->uid;
my $frm = tuwf->validate(post =>
- url => { regex => qr{^/u$id/notifies} },
- notifysel => { required => 0, default => [], type => 'array', scalar => 1, values => { id => 1 } },
+ url => { regex => qr{^/$id/notifies} },
+ notifysel => { default => [], type => 'array', scalar => 1, values => { id => 1 } },
markread => { anybool => 1 },
remove => { anybool => 1 },
)->data;
@@ -164,11 +199,45 @@ 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;
+ return tuwf->resNotFound if !auth || $id ne auth->uid;
tuwf->dbExeci('UPDATE notifications SET read = NOW() WHERE read IS NULL AND uid =', \$id, ' AND id =', \tuwf->capture('num'));
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>[vrpcsdgi]$RE{num})\.(?<rev>$RE{num})$};
+};
+
+
+
+
+our $SUB = form_compile any => {
+ id => { vndbid => [qw|t w v r p c s d i g|] },
+ subnum => { undefbool => 1 },
+ subreview => { anybool => 1 },
+ subapply => { anybool => 1 },
+ noti => { uint => 1, default => undef }, # used by the widget, ignored in the backend
+};
+
+js_api Subscribe => $SUB, sub {
+ my($data) = @_;
+ $data->{subreview} = 0 if $data->{id} !~ /^v/;
+ delete $data->{noti};
+
+ my %where = (iid => delete $data->{id}, uid => auth->uid);
+ if(!defined $data->{subnum} && !$data->{subreview} && !$data->{subapply}) {
+ tuwf->dbExeci('DELETE FROM notification_subs WHERE', \%where);
+ } else {
+ tuwf->dbExeci('INSERT INTO notification_subs', {%where, %$data}, 'ON CONFLICT (iid,uid) DO UPDATE SET', $data);
+ }
+ {};
+};
+
1;