package VNDB::Handler::Users;
use strict;
use warnings;
use TUWF ':html', 'xml_escape';
use VNDB::Func;
use POSIX 'floor';
TUWF::register(
qr{u([1-9]\d*)} => \&userpage,
qr{u/login} => \&login,
qr{u([1-9]\d*)/logout} => \&logout,
qr{u/newpass} => \&newpass,
qr{u/newpass/sent} => \&newpass_sent,
qr{u([1-9]\d*)/setpass} => \&setpass,
qr{u/register} => \®ister,
qr{u/register/done} => \®ister_done,
qr{u([1-9]\d*)/edit} => \&edit,
qr{u([1-9]\d*)/posts} => \&posts,
qr{u([1-9]\d*)/del(/[od])?} => \&delete,
qr{u/(all|[0a-z])} => \&list,
qr{u([1-9]\d*)/notifies} => \¬ifies,
qr{u([1-9]\d*)/notify/([1-9]\d*)} => \&readnotify,
);
sub userpage {
my($self, $uid) = @_;
my $u = $self->dbUserGet(uid => $uid, what => 'stats hide_list')->[0];
return $self->resNotFound if !$u->{id};
my $votes = $u->{c_votes} && $self->dbVoteStats(uid => $uid);
my $title = mt '_userpage_title', $u->{username};
$self->htmlHeader(title => $title, noindex => 1);
$self->htmlMainTabs('u', $u);
div class => 'mainbox userpage';
h1 $title;
table class => 'stripe';
Tr;
td class => 'key', mt '_userpage_username';
td;
txt ucfirst($u->{username}).' (';
a href => "/u$uid", "u$uid";
txt ')';
end;
end;
Tr;
td mt '_userpage_registered';
td $self->{l10n}->date($u->{registered});
end;
Tr;
td mt '_userpage_edits';
td;
if($u->{c_changes}) {
a href => "/u$uid/hist", $u->{c_changes};
} else {
txt '-';
}
end;
end;
Tr;
td mt '_userpage_votes';
td;
if($u->{hide_list}) {
txt mt '_userpage_hidden';
} elsif($votes) {
my($total, $count) = (0, 0);
for (1..@$votes) {
$count += $votes->[$_-1][0];
$total += $votes->[$_-1][1];
}
lit mt '_userpage_votes_item', "/u$uid/votes", $count, sprintf '%.2f', $total/$count/10;
} else {
txt '-';
}
end;
end;
Tr;
td mt '_userpage_tags';
td;
if(!$u->{c_tags}) {
txt '-';
} else {
txt mt '_userpage_tags_item', $u->{c_tags}, $u->{tagcount}, $u->{tagvncount};
txt ' ';
a href => "/g/links?u=$uid"; lit mt('_userpage_tags_browse').' »'; end;
}
end;
end;
Tr;
td mt '_userpage_list';
td $u->{hide_list} ? mt('_userpage_hidden') :
mt('_userpage_list_item', $u->{releasecount}, $u->{vncount});
end;
Tr;
td mt '_userpage_forum';
td;
lit mt '_userpage_forum_item',$u->{postcount}, $u->{threadcount};
if($u->{postcount}) {
txt ' ';
a href => "/u$uid/posts"; lit mt('_userpage_forum_browse').' »'; end;
}
end;
end;
end 'table';
end 'div';
if(!$u->{hide_list} && $votes) {
div class => 'mainbox';
h1 mt '_userpage_votestats';
$self->htmlVoteStats(u => $u, $votes);
end;
}
if($u->{c_changes}) {
my $list = $self->dbRevisionGet(what => 'item user', uid => $uid, results => 5);
h1 class => 'boxtitle';
a href => "/u$uid/hist", mt '_userpage_changes';
end;
$self->htmlBrowseHist($list, { p => 1 }, 0, "/u$uid/hist");
}
$self->htmlFooter;
}
sub login {
my $self = shift;
return $self->resRedirect('/') if $self->authInfo->{id};
my $tm = $self->dbThrottleGet(norm_ip($self->reqIP));
if($tm-time() > $self->{login_throttle}[1]) {
$self->htmlHeader(title => mt '_login_title');
div class => 'mainbox';
h1 mt '_login_title';
div class => 'warning';
h2 mt '_login_throttle_title';
p; lit mt '_login_throttle_msg'; end;
end;
end 'div';
$self->htmlFooter;
return;
}
my $ref = $self->formValidate({ param => 'ref', required => 0, default => '/'})->{ref};
my $frm;
if($self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
$frm = $self->formValidate(
{ post => 'usrname', required => 1, minlength => 2, maxlength => 15 },
{ post => 'usrpass', required => 1, minlength => 4, maxlength => 64, template => 'asciiprint' },
);
if(!$frm->{_err}) {
return if $self->authLogin($frm->{usrname}, $frm->{usrpass}, $ref);
$frm->{_err} = [ 'login_failed' ];
$self->dbThrottleSet(norm_ip($self->reqIP), $tm+$self->{login_throttle}[0]);
}
}
$self->htmlHeader(noindex => 1, title => mt '_login_title');
$self->htmlForm({ frm => $frm, action => '/u/login' }, login => [ mt('_login_title'),
[ hidden => short => 'ref', value => $ref ],
[ input => short => 'usrname', name => mt '_login_username' ],
[ static => content => ''.mt('_login_register').'' ],
[ passwd => short => 'usrpass', name => mt '_login_password' ],
[ static => content => ''.mt('_login_forgotpass').'' ],
]);
$self->htmlFooter;
}
sub logout {
my $self = shift;
my $uid = shift;
return $self->resNotFound if !$self->authInfo->{id} || $self->authInfo->{id} != $uid;
$self->authLogout;
}
sub newpass {
my $self = shift;
return $self->resRedirect('/') if $self->authInfo->{id};
my($frm, $u);
if($self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
$frm = $self->formValidate(
{ post => 'mail', required => 1, template => 'mail' },
);
if(!$frm->{_err}) {
$u = $self->dbUserGet(mail => $frm->{mail})->[0];
$frm->{_err} = [ 'nomail' ] if !$u || !$u->{id};
}
if(!$frm->{_err}) {
my %o;
my $token;
($token, $o{passwd}) = $self->authPrepareReset();
$self->dbUserEdit($u->{id}, %o);
$self->mail(mt('_newpass_mail_body', $u->{username}, $self->reqBaseURI()."/u$u->{id}/setpass?t=$token"),
To => $frm->{mail},
From => 'VNDB ',
Subject => mt('_newpass_mail_subject', $u->{username}),
);
return $self->resRedirect('/u/newpass/sent', 'post');
}
}
$self->htmlHeader(title => mt('_newpass_title'), noindex => 1);
div class => 'mainbox';
h1 mt '_newpass_title';
p mt '_newpass_msg';
end;
$self->htmlForm({ frm => $frm, action => '/u/newpass' }, newpass => [ mt('_newpass_reset_title'),
[ input => short => 'mail', name => mt '_newpass_mail' ],
]);
$self->htmlFooter;
}
sub newpass_sent {
my $self = shift;
return $self->resRedirect('/') if $self->authInfo->{id};
$self->htmlHeader(title => mt('_newpass_sent_title'), noindex => 1);
div class => 'mainbox';
h1 mt '_newpass_sent_title';
div class => 'notice';
p mt '_newpass_sent_msg';
end;
end;
$self->htmlFooter;
}
sub setpass {
my($self, $uid) = @_;
return $self->resRedirect('/') if $self->authInfo->{id};
my $t = $self->formValidate({get => 't', regex => qr/^[a-f0-9]{40}$/i });
return $self->resNotFound if $t->{_err};
$t = $t->{t};
my $u = $self->dbUserGet(uid => $uid, what => 'extended')->[0];
return $self->resNotFound if !$u || !$self->authValidateReset($u->{passwd}, $t);
my $frm;
if($self->reqMethod eq 'POST') {
return if !$self->authCheckCode("/u$u->{id}/setpass?t=$t");
$frm = $self->formValidate(
{ post => 'usrpass', minlength => 4, maxlength => 64, template => 'asciiprint' },
{ post => 'usrpass2', minlength => 4, maxlength => 64, template => 'asciiprint' },
);
push @{$frm->{_err}}, 'passmatch' if $frm->{usrpass} ne $frm->{usrpass2};
if(!$frm->{_err}) {
my %o = (email_confirmed => 1);
$o{passwd} = $self->authPreparePass($frm->{usrpass});
$self->dbUserEdit($uid, %o);
return $self->authLogin($u->{username}, $frm->{usrpass}, "/u$uid");
}
}
$self->htmlHeader(title => mt('_setpass_title', $u->{username}), noindex => 1);
$self->htmlForm({ frm => $frm, action => "/u$u->{id}/setpass?t=$t" }, setpass => [ mt('_setpass_title', $u->{username}),
[ static => nolabel => 1, content => mt '_setpass_msg' ],
[ passwd => short => 'usrpass', name => mt('_setpass_password') ],
[ passwd => short => 'usrpass2', name => mt('_setpass_confirm') ],
]);
$self->htmlFooter;
}
sub register {
my $self = shift;
return $self->resRedirect('/') if $self->authInfo->{id};
my $frm;
if($self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
$frm = $self->formValidate(
{ post => 'usrname', template => 'pname', minlength => 2, maxlength => 15 },
{ post => 'mail', template => 'mail' },
{ post => 'type', regex => [ qr/^[1-3]$/ ] },
{ post => 'answer', template => 'int' },
);
my $num = $self->{stats}{[qw|vn releases producers|]->[ $frm->{type} - 1 ]};
push @{$frm->{_err}}, 'notanswer' if !$frm->{_err} && ($frm->{answer} > $num || $frm->{answer} < $num*0.995);
push @{$frm->{_err}}, 'usrexists' if $frm->{usrname} eq 'anonymous' || !$frm->{_err} && $self->dbUserGet(username => $frm->{usrname})->[0]{id};
push @{$frm->{_err}}, 'mailexists' if !$frm->{_err} && $self->dbUserGet(mail => $frm->{mail})->[0]{id};
# Use /32 match for IPv4 and /48 for IPv6. The /48 is fairly broad, so some
# users may have to wait a bit before they can register...
my $ip = $self->reqIP;
push @{$frm->{_err}}, 'oneaday' if !$frm->{_err} && $self->dbUserGet(ip => $ip =~ /:/ ? "$ip/48" : $ip, registered => time-24*3600)->[0]{id};
if(!$frm->{_err}) {
my($token, $pass) = $self->authPrepareReset();
my $uid = $self->dbUserAdd($frm->{usrname}, $pass, $frm->{mail});
$self->mail(mt('_register_mail_body', $frm->{usrname}, $self->reqBaseURI()."/u$uid/setpass?t=$token"),
To => $frm->{mail},
From => 'VNDB ',
Subject => mt('_register_mail_subject', $frm->{usrname}),
);
return $self->resRedirect('/u/register/done', 'post');
}
}
$self->htmlHeader(title => mt('_register_title'), noindex => 1);
my $type = $frm->{type} || floor(rand 3)+1;
$self->htmlForm({ frm => $frm, action => '/u/register' }, register => [ mt('_register_title'),
[ hidden => short => 'type', value => $type ],
[ input => short => 'usrname', name => mt '_register_username' ],
[ static => content => mt '_register_username_msg' ],
[ input => short => 'mail', name => mt '_register_mail' ],
[ static => content => mt('_register_mail_msg').'
' ],
[ static => content => '
'.mt('_register_question', $type-1) ],
[ input => short => 'answer', name => mt '_register_answer' ],
]);
$self->htmlFooter;
}
sub register_done {
my $self = shift;
return $self->resRedirect('/') if $self->authInfo->{id};
$self->htmlHeader(title => mt('_register_done_title'), noindex => 1);
div class => 'mainbox';
h1 mt '_register_done_title';
div class => 'notice';
p mt '_register_done_msg';
end;
end;
$self->htmlFooter;
}
sub edit {
my($self, $uid) = @_;
# are we allowed to edit this user?
return $self->htmlDenied if !$self->authInfo->{id} || $self->authInfo->{id} != $uid && !$self->authCan('usermod');
# fetch user info (cached if uid == loggedin uid)
my $u = $self->authInfo->{id} == $uid ? $self->authInfo : $self->dbUserGet(uid => $uid, what => 'extended prefs')->[0];
return $self->resNotFound if !$u->{id};
# check POST data
my $frm;
if($self->reqMethod eq 'POST') {
return if !$self->authCheckCode;
$frm = $self->formValidate(
$self->authCan('usermod') ? (
{ post => 'usrname', template => 'pname', minlength => 2, maxlength => 15 },
{ post => 'perms', required => 0, multi => 1, enum => [ keys %{$self->{permissions}} ] },
{ post => 'ign_votes', required => 0, default => 0 },
) : (),
{ post => 'mail', template => 'mail' },
{ post => 'usrpass', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
{ post => 'usrpass2', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
{ post => 'hide_list', required => 0, default => 0, enum => [0,1] },
{ post => 'show_nsfw', required => 0, default => 0, enum => [0,1] },
{ post => 'tags_all', required => 0, default => 0, enum => [0,1] },
{ post => 'skin', required => 0, default => $self->{skin_default}, enum => [ keys %{$self->{skins}} ] },
{ post => 'customcss', required => 0, maxlength => 2000, default => '' },
);
push @{$frm->{_err}}, 'passmatch'
if ($frm->{usrpass} || $frm->{usrpass2}) && (!$frm->{usrpass} || !$frm->{usrpass2} || $frm->{usrpass} ne $frm->{usrpass2});
if(!$frm->{_err}) {
$frm->{skin} = '' if $frm->{skin} eq $self->{skin_default};
$self->dbUserPrefSet($uid, $_ => $frm->{$_}) for (qw|skin customcss show_nsfw tags_all hide_list |);
my %o;
if($self->authCan('usermod')) {
$o{username} = $frm->{usrname} if $frm->{usrname};
$o{perm} = 0;
$o{perm} |= $self->{permissions}{$_} for(@{ delete $frm->{perms} });
}
$o{mail} = $frm->{mail};
$o{passwd} = $self->authPreparePass($frm->{usrpass}) if $frm->{usrpass};
$o{ign_votes} = $frm->{ign_votes} ? 1 : 0 if $self->authCan('usermod');
$self->dbUserEdit($uid, %o);
return $self->resRedirect("/u$uid/edit?d=1", 'post');
}
}
# fill out default values
$frm->{usrname} ||= $u->{username};
$frm->{mail} ||= $u->{mail};
$frm->{perms} ||= [ grep $u->{perm} & $self->{permissions}{$_}, keys %{$self->{permissions}} ];
$frm->{$_} //= $u->{prefs}{$_} for(qw|skin customcss show_nsfw tags_all hide_list|);
$frm->{ign_votes} = $u->{ign_votes} if !defined $frm->{ign_votes};
$frm->{skin} ||= $self->{skin_default};
# create the page
$self->htmlHeader(title => mt('_usere_title'), noindex => 1);
$self->htmlMainTabs('u', $u, 'edit');
if($self->reqGet('d')) {
div class => 'mainbox';
h1 mt '_usere_saved_title';
div class => 'notice';
p mt '_usere_saved_msg';
end;
end
}
$self->htmlForm({ frm => $frm, action => "/u$uid/edit" }, useredit => [ mt('_usere_title'),
[ part => title => mt '_usere_geninfo' ],
$self->authCan('usermod') ? (
[ input => short => 'usrname', name => mt('_usere_username') ],
[ select => short => 'perms', name => mt('_usere_perm'), multi => 1, size => (scalar keys %{$self->{permissions}}), options => [
map [ $_, $_ ], sort keys %{$self->{permissions}} ] ],
[ check => short => 'ign_votes', name => mt '_usere_ignvotes' ],
) : (
[ static => label => mt('_usere_username'), content => $frm->{usrname} ],
),
[ input => short => 'mail', name => mt '_usere_mail' ],
[ part => title => mt '_usere_changepass' ],
[ static => content => mt '_usere_changepass_msg' ],
[ passwd => short => 'usrpass', name => mt '_usere_password' ],
[ passwd => short => 'usrpass2', name => mt '_usere_confirm' ],
[ part => title => mt '_usere_options' ],
[ check => short => 'hide_list', name => mt '_usere_flist', "/u$uid/list", "/u$uid/votes", "/u$uid/wish" ],
[ check => short => 'show_nsfw', name => mt '_usere_fnsfw' ],
[ check => short => 'tags_all', name => mt '_usere_ftags' ],
[ select => short => 'skin', name => mt('_usere_skin'), width => 300, options => [
map [ $_, $self->{skins}{$_}[0].($self->debug?" [$_]":'') ], sort { $self->{skins}{$a}[0] cmp $self->{skins}{$b}[0] } keys %{$self->{skins}} ] ],
[ textarea => short => 'customcss', name => mt '_usere_css' ],
]);
$self->htmlFooter;
}
sub posts {
my($self, $uid) = @_;
# fetch user info (cached if uid == loggedin uid)
my $u = $self->authInfo->{id} && $self->authInfo->{id} == $uid ? $self->authInfo : $self->dbUserGet(uid => $uid, what => 'hide_list')->[0];
return $self->resNotFound if !$u->{id};
my $f = $self->formValidate(
{ get => 'p', required => 0, default => 1, template => 'int' }
);
return $self->resNotFound if $f->{_err};
my($posts, $np) = $self->dbPostGet(uid => $uid, hide => 1, what => 'thread', page => $f->{p}, sort => 'date', reverse => 1);
my $title = mt '_uposts_title', $u->{username};
$self->htmlHeader(title => $title, noindex => 1);
$self->htmlMainTabs(u => $u, 'posts');
div class => 'mainbox';
h1 $title;
if(!@$posts) {
p mt '_uposts_noresults', $u->{username};
}
end;
$self->htmlBrowse(
items => $posts,
class => 'uposts',
options => $f,
nextpage => $np,
pageurl => "/u$uid/posts",
header => [
[ '' ],
[ '' ],
[ mt '_uposts_col_date' ],
[ mt '_uposts_col_title' ],
],
row => sub {
my($s, $n, $l) = @_;
Tr;
td class => 'tc1'; a href => "/t$l->{tid}.$l->{num}", 't'.$l->{tid}; end;
td class => 'tc2'; a href => "/t$l->{tid}.$l->{num}", '.'.$l->{num}; end;
td class => 'tc3', $self->{l10n}->date($l->{date});
td class => 'tc4';
a href => "/t$l->{tid}.$l->{num}", $l->{title};
b class => 'grayedout'; lit bb2html $l->{msg}, 150; end;
end;
end;
},
) if @$posts;
$self->htmlFooter;
}
sub delete {
my($self, $uid, $act) = @_;
return $self->htmlDenied if !$self->authCan('usermod');
# rarely used admin function, won't really need translating
# confirm
if(!$act) {
my $code = $self->authGetCode("/u$uid/del/o");
my $u = $self->dbUserGet(uid => $uid, what => 'hide_list')->[0];
return $self->resNotFound if !$u->{id};
$self->htmlHeader(title => 'Delete user', noindex => 1);
$self->htmlMainTabs('u', $u, 'del');
div class => 'mainbox';
div class => 'warning';
h2 'Delete user';
p;
lit qq|Are you sure you want to remove $u->{username}'s account?
|
.qq|Yes, I'm not kidding!|;
end;
end;
end;
$self->htmlFooter;
}
# delete
elsif($act eq '/o') {
return if !$self->authCheckCode;
$self->dbUserDel($uid);
$self->resRedirect("/u$uid/del/d", 'post');
}
# done
elsif($act eq '/d') {
$self->htmlHeader(title => 'Delete user', noindex => 1);
div class => 'mainbox';
div class => 'notice';
p 'User deleted.';
end;
end;
$self->htmlFooter;
}
}
sub list {
my($self, $char) = @_;
my $f = $self->formValidate(
{ get => 's', required => 0, default => 'username', enum => [ qw|username registered votes changes tags| ] },
{ get => 'o', required => 0, default => 'a', enum => [ 'a','d' ] },
{ get => 'p', required => 0, default => 1, template => 'int' },
{ get => 'q', required => 0, default => '', maxlength => 50 },
);
return $self->resNotFound if $f->{_err};
$self->htmlHeader(noindex => 1, title => mt '_ulist_title');
div class => 'mainbox';
h1 mt '_ulist_title';
form action => '/u/all', 'accept-charset' => 'UTF-8', method => 'get';
$self->htmlSearchBox('u', $f->{q});
end;
p class => 'browseopts';
for ('all', 'a'..'z', 0) {
a href => "/u/$_", $_ eq $char ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#';
}
end;
end;
my($list, $np) = $self->dbUserGet(
sort => $f->{s}, reverse => $f->{o} eq 'd',
what => 'hide_list',
$char ne 'all' ? (
firstchar => $char ) : (),
results => 50,
page => $f->{p},
search => $f->{q},
);
$self->htmlBrowse(
items => $list,
options => $f,
nextpage => $np,
pageurl => "/u/$char?o=$f->{o};s=$f->{s};q=$f->{q}",
sorturl => "/u/$char?q=$f->{q}",
header => [
[ mt('_ulist_col_username'), 'username' ],
[ mt('_ulist_col_registered'), 'registered' ],
[ mt('_ulist_col_votes'), 'votes' ],
[ mt('_ulist_col_edits'), 'changes' ],
[ mt('_ulist_col_tags'), 'tags' ],
],
row => sub {
my($s, $n, $l) = @_;
Tr;
td class => 'tc1';
a href => '/u'.$l->{id}, $l->{username};
end;
td class => 'tc2', $self->{l10n}->date($l->{registered});
td class => 'tc3'.($l->{hide_list} && $self->authCan('usermod') ? ' linethrough' : '');
lit $l->{hide_list} && !$self->authCan('usermod') ? '-' : !$l->{c_votes} ? 0 :
qq|$l->{c_votes}|;
end;
td class => 'tc4';
lit !$l->{c_changes} ? 0 : qq|$l->{c_changes}|;
end;
td class => 'tc5';
lit !$l->{c_tags} ? 0 : qq|$l->{c_tags}|;
end;
end 'tr';
},
);
$self->htmlFooter;
}
sub notifies {
my($self, $uid) = @_;
my $u = $self->authInfo;
return $self->htmlDenied if !$u->{id} || $uid != $u->{id};
my $f = $self->formValidate(
{ get => 'p', required => 0, default => 1, template => 'int' },
{ get => 'r', required => 0, default => 0, enum => [0,1] },
);
return $self->resNotFound if $f->{_err};
# changing the notification settings
my $saved;
if($self->reqMethod() eq 'POST' && $self->reqPost('set')) {
return if !$self->authCheckCode;
my $frm = $self->formValidate(
{ post => 'notify_nodbedit', required => 0, default => 1, enum => [0,1] },
{ post => 'notify_announce', required => 0, default => 0, enum => [0,1] }
);
return $self->resNotFound if $frm->{_err};
$self->authPref($_, $frm->{$_}) for ('notify_nodbedit', 'notify_announce');
$saved = 1;
# updating notifications
} elsif($self->reqMethod() eq 'POST') {
return if !$self->authCheckCode;
my $frm = $self->formValidate(
{ post => 'notifysel', multi => 1, required => 0, template => 'int' },
{ post => 'markread', required => 0 },
{ post => 'remove', required => 0 }
);
return $self->resNotFound if $frm->{_err};
my @ids = grep $_, @{$frm->{notifysel}};
$self->dbNotifyMarkRead(@ids) if @ids && $frm->{markread};
$self->dbNotifyRemove(@ids) if @ids && $frm->{remove};
$self->authInfo->{notifycount} = $self->dbUserGet(uid => $uid, what => 'notifycount')->[0]{notifycount};
}
my($list, $np) = $self->dbNotifyGet(
uid => $uid,
page => $f->{p},
results => 25,
what => 'titles',
read => $f->{r} == 1 ? undef : 0,
reverse => $f->{r} == 1,
);
$self->htmlHeader(title => mt('_usern_title'), noindex => 1);
$self->htmlMainTabs(u => $u);
div class => 'mainbox';
h1 mt '_usern_title';
p class => 'browseopts';
a !$f->{r} ? (class => 'optselected') : (), href => "/u$uid/notifies?r=0", mt '_usern_o_unread';
a $f->{r} ? (class => 'optselected') : (), href => "/u$uid/notifies?r=1", mt '_usern_o_alsoread';
end;
p mt '_usern_nonotifies' if !@$list;
end;
my $code = $self->authGetCode("/u$uid/notifies");
if(@$list) {
form action => "/u$uid/notifies?r=$f->{r};formcode=$code", method => 'post', id => 'notifies';
$self->htmlBrowse(
items => $list,
options => $f,
nextpage => $np,
class => 'notifies',
pageurl => "/u$uid/notifies?r=$f->{r}",
header => [
[ '' ],
[ mt '_usern_col_type' ],
[ mt '_usern_col_age' ],
[ mt '_usern_col_id' ],
[ mt '_usern_col_act' ],
],
row => sub {
my($s, $n, $l) = @_;
Tr $l->{read} ? () : (class => 'unread');
td class => 'tc1';
input type => 'checkbox', name => 'notifysel', value => "$l->{id}";
end;
td class => 'tc2', mt "_usern_type_$l->{ntype}";
td class => 'tc3', $self->{l10n}->age($l->{date});
td class => 'tc4';
a href => "/u$uid/notify/$l->{id}", "$l->{ltype}$l->{iid}".($l->{subid}?".$l->{subid}":'');
end;
td class => 'tc5 clickable', id => "notify_$l->{id}";
lit mt '_usern_n_'.(
$l->{ltype} eq 't' ? ($l->{subid} == 1 ? 't_new' : 't_reply')
: 'item_edit'),
sprintf('%s', xml_escape $l->{c_title}), sprintf('%s', xml_escape $l->{username});
end;
end 'tr';
},
footer => sub {
Tr;
td colspan => 5;
input type => 'checkbox', class => 'checkall', name => 'notifysel', value => 0;
txt ' ';
input type => 'submit', name => 'markread', value => mt '_usern_but_markread';
input type => 'submit', name => 'remove', value => mt '_usern_but_remove';
b class => 'grayedout', ' '.mt '_usern_autodel';
end;
end;
}
);
end;
}
form method => 'post', action => "/u$uid/notifies?formcode=$code";
div class => 'mainbox';
h1 mt '_usern_set_title';
div class => 'notice', mt '_usern_set_saved' if $saved;
p;
for('nodbedit', 'announce') {
my $def = $_ eq 'nodbedit'? 0 : 1;
input type => 'checkbox', name => "notify_$_", id => "notify_$_", value => $def,
($self->authPref("notify_$_")||0) == $def ? (checked => 'checked') : ();
label for => "notify_$_", ' '.mt("_usern_set_$_");
br;
}
input type => 'submit', name => 'set', value => mt '_usern_set_submit';
end;
end;
end 'form';
$self->htmlFooter;
}
sub readnotify {
my($self, $uid, $nid) = @_;
return $self->htmlDenied if !$self->authInfo->{id} || $uid != $self->authInfo->{id};
my $n = $self->dbNotifyGet(uid => $uid, id => $nid)->[0];
return $self->resNotFound if !$n->{iid};
$self->dbNotifyMarkRead($n->{id}) if !$n->{read};
# NOTE: for t+.+ IDs, this will create a double redirect, which is rather awkward...
$self->resRedirect("/$n->{ltype}$n->{iid}".($n->{subid}?".$n->{subid}":''), 'perm');
}
1;