PerlModuleUsers: Difference between revisions
Jump to navigation
Jump to search
(Created page with "CssWork parent <h2>Source of users.pl</h2> <pre> #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2005 by Open Source ...") |
No edit summary |
||
| Line 2: | Line 2: | ||
<h2>Man page for users</h2> | |||
Don't waste your time... | |||
<pre> | |||
# man Slash::Users | |||
No manual entry for Slash::Users | |||
[root@slashcode htdocs]# man Slash::Users2 | |||
Users2(3) User Contributed Perl Documentation Users2(3) | |||
NAME | |||
Slash::Users2 | |||
SYNOPSIS | |||
use Slash::Users2; | |||
DESCRIPTION | |||
Provides homepages for users. | |||
AUTHOR | |||
Christopher Brown, cbrown@corp.sourcefore.com | |||
SEE ALSO | |||
perl(1). | |||
perl v5.10.1 2014-02-20 Users2(3) | |||
</pre> | |||
<h2>Source of users.pl</h2> | <h2>Source of users.pl</h2> | ||
Revision as of 19:15, 1 March 2014
CssWork parent
Man page for users
Don't waste your time...
# man Slash::Users
No manual entry for Slash::Users
[root@slashcode htdocs]# man Slash::Users2
Users2(3) User Contributed Perl Documentation Users2(3)
NAME
Slash::Users2
SYNOPSIS
use Slash::Users2;
DESCRIPTION
Provides homepages for users.
AUTHOR
Christopher Brown, cbrown@corp.sourcefore.com
SEE ALSO
perl(1).
perl v5.10.1 2014-02-20 Users2(3)
Source of users.pl
#!/usr/bin/perl -w
# This code is a part of Slash, and is released under the GPL.
# Copyright 1997-2005 by Open Source Technology Group. See README
# and COPYING for more information, or see http://slashcode.com/.
# $Id$
use strict;
use Digest::MD5 'md5_hex';
use Slash;
use Slash::Display;
use Slash::Utility;
use Slash::Constants qw(:messages);
#################################################################
sub main {
my $slashdb = getCurrentDB();
my $constants = getCurrentStatic();
my $user = getCurrentUser();
my $form = getCurrentForm();
my $gSkin = getCurrentSkin();
my $formname = $0;
$formname =~ s/.*\/(\w+)\.pl/$1/;
my $error_flag = 0;
my $formkey = $form->{formkey};
my $suadmin_flag = $user->{seclev} >= 10000 ? 1 : 0 ;
my $postflag = $user->{state}{post};
my $op = lc($form->{op});
# savepasswd is a special case, because once it's called, you
# have to reload the form, and you don't want to do any checks if
# you've just saved.
my $savepass_flag = $op eq 'savepasswd' ? 1 : 0 ;
my $ops = {
admin => {
function => \&adminDispatch,
seclev => 10000, # if this should be lower,
# then something else is
# broken, because it allows
# anyone with this seclev
# to change their own seclev
formname => $formname,
# just in case we need it for something else, we have it ...
checks => [ qw (generate_formkey) ],
},
# userlogin => {
# function => \&showInfo,
# seclev => 1,
# formname => $formname,
# checks => [],
# tab_selected_1 => 'me',
# },
no_user => {
function => \&noUser,
seclev => 0,
formname => $formname,
checks => [],
},
userinfo => {
function => \&showInfo,
#I made this change, not all sites are going to care. -Brian
seclev => $constants->{users_show_info_seclev},
formname => $formname,
checks => [],
tab_selected_1 => 'me',
tab_selected_2 => 'info',
},
userfirehose => {
function => \&showFireHose,
seclev => 0,
formname => $formname,
checks => [],
tab_selected_1 => 'me',
tab_selected_2 => 'firehose'
},
usersubmissions => {
function => \&showSubmissions,
#I made this change, not all sites are going to care. -Brian
seclev => $constants->{users_show_info_seclev},
checks => [],
tab_selected_1 => 'me',
},
usercomments => {
function => \&showComments,
#I made this change, not all sites are going to care. -Brian
seclev => $constants->{users_show_info_seclev},
checks => [],
tab_selected_1 => 'me',
},
display => {
function => \&showInfo,
#I made this change, not all sites are going to care. -Brian
seclev => $constants->{users_show_info_seclev},
formname => $formname,
checks => [],
tab_selected_1 => 'me',
tab_selected_2 => 'info',
},
# savepasswd => {
# function => \&savePasswd,
# seclev => 1,
# post => 1,
# formname => $formname,
# checks => [ qw (max_post_check valid_check
# formkey_check regen_formkey) ],
# tab_selected_1 => 'preferences',
# tab_selected_2 => 'password',
# },
saveuseradmin => {
function => \&saveUserAdmin,
seclev => 10000,
post => 1,
formname => $formname,
checks => [],
},
savehome => {
function => \&saveHome,
seclev => 1,
post => 1,
formname => $formname,
checks => [ qw (valid_check
formkey_check regen_formkey) ],
tab_selected_1 => 'preferences',
tab_selected_2 => 'home',
},
savecomm => {
function => \&saveComm,
seclev => 1,
post => 1,
formname => $formname,
checks => [ qw (valid_check
formkey_check regen_formkey) ],
tab_selected_1 => 'preferences',
tab_selected_2 => 'comments',
},
saveuser => {
function => \&saveUser,
seclev => 1,
post => 1,
formname => $formname,
checks => [ qw (valid_check
formkey_check regen_formkey) ],
tab_selected_1 => 'preferences',
tab_selected_2 => 'user',
},
# changepasswd => {
# function => \&changePasswd,
# seclev => 1,
# formname => $formname,
# checks => $savepass_flag ? [] :
# [ qw (generate_formkey) ],
# tab_selected_1 => 'preferences',
# tab_selected_2 => 'password',
# },
editmiscopts => {
function => \&editMiscOpts,
seclev => 1,
formname => $formname,
checks => [ ],
tab_selected_1 => 'preferences',
tab_selected_2 => 'misc',
},
savemiscopts => {
function => \&saveMiscOpts,
seclev => 1,
formname => $formname,
checks => [ ],
tab_selected_1 => 'preferences',
tab_selected_2 => 'misc',
},
edituser => {
function => \&editUser,
seclev => 1,
formname => $formname,
checks => [ qw (generate_formkey) ],
tab_selected_1 => 'preferences',
tab_selected_2 => 'user',
},
authoredit => {
function => \&editUser,
seclev => 10000,
formname => $formname,
checks => [],
},
edithome => {
function => \&editHome,
seclev => 1,
formname => $formname,
checks => [ qw (generate_formkey) ],
tab_selected_1 => 'preferences',
tab_selected_2 => 'home',
},
editcomm => {
function => \&editComm,
seclev => 1,
formname => $formname,
checks => [ qw (generate_formkey) ],
tab_selected_1 => 'preferences',
tab_selected_2 => 'comments',
},
# newuser => {
# function => \&newUser,
# seclev => 0,
# formname => "${formname}/nu",
# checks => [ qw (max_post_check valid_check
# formkey_check regen_formkey) ],
# },
newuseradmin => {
function => \&newUserForm,
seclev => 10000,
formname => "${formname}/nu",
checks => [],
},
previewbox => {
function => \&previewSlashbox,
seclev => 0,
formname => $formname,
checks => [],
},
# mailpasswd => {
# function => \&mailPasswd,
# seclev => 0,
# formname => "${formname}/mp",
# checks => [ qw (max_post_check valid_check
# interval_check formkey_check ) ],
# tab_selected_1 => 'preferences',
# tab_selected_2 => 'password',
# },
validateuser => {
function => \&validateUser,
seclev => 1,
formname => $formname,
checks => ['regen_formkey'],
},
showtags => {
function => \&showTags,
seclev => 1,
formname => $formname,
checks => [],
tab_selected => 'tags',
},
showbookmarks => {
function => \&showBookmarks,
seclev => 0,
formname => $formname,
checks => [],
tab_selected => 'bookmarks',
},
edittags => {
function => \&editTags,
seclev => 1,
formname => $formname,
checks => [],
tab_selected => 'tags',
},
savetags => {
function => \&saveTags,
seclev => 1,
formname => $formname,
checks => [],
tab_selected => 'tags',
},
# userclose => {
# function => \&displayForm,
# seclev => 0,
# formname => $formname,
# checks => [],
# },
# newuserform => {
# function => \&displayForm,
# seclev => 0,
# formname => "${formname}/nu",
# checks => [ qw (max_post_check
# generate_formkey) ],
# },
# mailpasswdform => {
# function => \&displayForm,
# seclev => 0,
# formname => "${formname}/mp",
# checks => [ qw (max_post_check
# generate_formkey) ],
# tab_selected_1 => 'preferences',
# tab_selected_2 => 'password',
# },
displayform => {
function => \&displayForm,
seclev => 0,
formname => $formname,
checks => [ qw (generate_formkey) ],
tab_selected_1 => 'me',
},
listreadonly => {
function => \&listReadOnly,
seclev => 100,
formname => $formname,
checks => [],
adminmenu => 'security',
tab_selected => 'readonly',
},
listbanned => {
function => \&listBanned,
seclev => 100,
formname => $formname,
checks => [],
adminmenu => 'security',
tab_selected => 'banned',
},
topabusers => {
function => \&topAbusers,
seclev => 100,
formname => $formname,
checks => [],
adminmenu => 'security',
tab_selected => 'abusers',
},
listabuses => {
function => \&listAbuses,
seclev => 100,
formname => $formname,
checks => [],
},
force_acct_verify => {
function => \&forceAccountVerify,
seclev => 100,
post => 1,
formname => $formname,
checks => []
}
} ;
# Note this is NOT the default op. "userlogin" or "userinfo" is
# the default op, and it's set either 5 lines down or about 100
# lines down, depending. Yes, that's dumb. Yes, we should
# change it. It would require tracing through a fair bit of logic
# though and I don't have the time right now. - Jamie
$ops->{default} = $ops->{displayform};
for (qw(newuser newuserform mailpasswd mailpasswdform changepasswd savepasswd userlogin userclose)) {
$ops->{$_} = $ops->{default};
}
my $errornote = "";
if ($form->{op} && ! defined $ops->{$op}) {
$errornote .= getError('bad_op', { op => $form->{op}}, 0, 1);
$op = $user->{is_anon} ? 'userlogin' : 'userinfo';
}
if ($op eq 'userlogin' && ! $user->{is_anon}) {
redirect(cleanRedirectUrl($form->{returnto} || ''));
return;
# this will only redirect if it is a section-based rootdir with
# its rootdir different from real_rootdir
} elsif ($op eq 'userclose' && $gSkin->{rootdir} ne $constants->{real_rootdir}) {
redirect($constants->{real_rootdir} . '/login.pl?op=userclose');
return;
} elsif ($op =~ /^(?:newuser|newuserform|mailpasswd|mailpasswdform|changepasswd|savepasswd|userlogin|userclose|displayform)$/) {
my $op = $form->{op};
$op = 'changeprefs' if $op eq 'changepasswd';
$op = 'saveprefs' if $op eq 'savepasswd';
redirect($constants->{real_rootdir} . '/login.pl?op=' . $op);
return;
# never get here now
} elsif ($op eq 'savepasswd') {
my $error_flag = 0;
if ($user->{seclev} < 100) {
for my $check (@{$ops->{savepasswd}{checks}}) {
# the only way to save the error message is to pass by ref
# $errornote and add the message to note (you can't print
# it out before header is called)
$error_flag = formkeyHandler($check, $formname, $formkey, \$errornote);
last if $error_flag;
}
}
if (! $error_flag) {
$error_flag = savePasswd({ noteref => \$errornote }) ;
}
# change op to edituser and let fall through;
# we need to have savePasswd set the cookie before
# header() is called -- pudge
if ($user->{seclev} < 100 && ! $error_flag) {
$slashdb->updateFormkey($formkey, length($ENV{QUERY_STRING}));
}
$op = $error_flag ? 'changepasswd' : 'userinfo';
$form->{userfield} = $user->{uid};
}
# Figure out what the op really is.
$op = 'userinfo' if (! $form->{op} && ($form->{uid} || $form->{nick}));
$op ||= $user->{is_anon} ? 'userlogin' : 'userinfo';
if ($user->{is_anon} && ( ($ops->{$op}{seclev} > 0) || ($op =~ /^newuserform|mailpasswdform|displayform$/) )) {
redirect($constants->{real_rootdir} . '/login.pl');
return;
} elsif ($user->{seclev} < $ops->{$op}{seclev}) {
$op = 'userinfo';
}
if ($ops->{$op}{post} && !$postflag) {
$op = $user->{is_anon} ? 'default' : 'userinfo';
}
# Print the header and very top stuff on the page. We have
# three ops that (may) end up routing into showInfo(), which
# needs to do some stuff before it calls header(), so for
# those three, don't bother.
my $header;
if ($op !~ /^(userinfo|display|saveuseradmin|admin|userfirehose$)/) {
my $data = {
adminmenu => $ops->{$op}{adminmenu} || 'admin',
tab_selected => $ops->{$op}{tab_selected},
};
header(getMessage('user_header'), '', $data) or return;
# This is a hardcoded position, bad idea and should be fixed -Brian
# Yeah, we should pull this into a template somewhere...
print getMessage('note', { note => $errornote }) if defined $errornote;
$header = 1;
}
if ($constants->{admin_formkeys} || $user->{seclev} < 100) {
my $done = 0;
$done = 1 if $op eq 'savepasswd'; # special case
$formname = $ops->{$op}{formname};
# No need for HumanConf if the constant for it is not
# switched on, or if the user's karma is high enough
# to get out of it. (But for "newuserform," the current
# user's karma doesn't get them out of having to prove
# they're a human for creating a *new* user.)
my $options = {};
if ( !$constants->{plugin}{HumanConf}
|| !$constants->{hc}
|| !$constants->{hc_sw_newuser}
&& ($formname eq 'users/nu' || $op eq 'newuserform')
|| !$constants->{hc_sw_mailpasswd}
&& ($formname eq 'users/mp' || $op eq 'mailpasswdform')
|| $user->{karma} > $constants->{hc_maxkarma}
&& !$user->{is_anon}
&& !($op eq 'newuser' || $op eq 'newuserform')
) {
$options->{no_hc} = 1;
}
DO_CHECKS: while (!$done) {
for my $check (@{$ops->{$op}{checks}}) {
$ops->{$op}{update_formkey} = 1 if $check eq 'formkey_check';
$error_flag = formkeyHandler($check, $formname, $formkey,
undef, $options);
if ($error_flag == -1) {
# Special error: HumanConf failed. Go
# back to the previous op, start over.
if ($op =~ /^(newuser|mailpasswd)$/) {
$op .= "form";
$error_flag = 0;
next DO_CHECKS;
}
} elsif ($error_flag) {
$done = 1;
last;
}
}
$done = 1;
}
if (!$error_flag && !$options->{no_hc}) {
my $hc = getObject("Slash::HumanConf");
$hc->reloadFormkeyHC($formname) if $hc;
}
}
errorLog("users.pl error_flag '$error_flag'") if $error_flag;
# call the method
my $retval;
$retval = $ops->{$op}{function}->({
op => $op,
tab_selected_1 => $ops->{$op}{tab_selected_1} || "",
note => $errornote,
}) if !$error_flag;
return if !$retval;
if ($op eq 'mailpasswd' && $retval) {
$ops->{$op}{update_formkey} = 0;
}
if ($ops->{$op}{update_formkey} && $user->{seclev} < 100 && ! $error_flag) {
# successful save action, no formkey errors, update existing formkey
# why assign to an unused variable? -- pudge
my $updated = $slashdb->updateFormkey($formkey, length($ENV{QUERY_STRING}));
}
# if there were legit error levels returned from the save methods
# I would have it clear the formkey in case of an error, but that
# needs to be sorted out later
# else { resetFormkey($formkey); }
writeLog($user->{nickname});
footer();
}
#################################################################
sub checkList {
my($string, $len) = @_;
my $constants = getCurrentStatic();
$string =~ s/[^\w,-]//g;
my @items = grep { $_ } split /,/, $string;
$string = join ",", @items;
$len ||= $constants->{checklist_length} || 255;
if (length($string) > $len) {
print getError('checklist_err');
$string = substr($string, 0, $len);
$string =~ s/,?\w*$//g;
} elsif (length($string) < 1) {
$string = '';
}
return $string;
}
#################################################################
sub previewSlashbox {
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $constants = getCurrentStatic();
my $user = getCurrentUser();
my $form = getCurrentForm();
my $block = $reader->getBlock($form->{bid}, ['title', 'block', 'url']);
my $is_editable = $user->{seclev} >= 1000;
my $title = getTitle('previewslashbox_title', { blocktitle => $block->{title} });
slashDisplay('previewSlashbox', {
width => '100%',
title => $title,
block => $block,
is_editable => $is_editable,
});
print portalbox($constants->{fancyboxwidth}, $block->{title},
$block->{block}, '', $block->{url});
}
#################################################################
sub newUserForm {
my $user = getCurrentUser();
my $suadmin_flag = $user->{seclev} >= 10000;
my $title = getTitle('newUserForm_title');
slashDisplay('newUserForm', {
title => $title,
suadmin_flag => $suadmin_flag,
});
}
#################################################################
sub newUser {
my $slashdb = getCurrentDB();
my $form = getCurrentForm();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $plugins = $slashdb->getDescriptions('plugins');
my $title;
my $suadmin_flag = $user->{seclev} >= 10000 ? 1 : 0;
# Check if User Exists
$form->{newusernick} = nickFix($form->{newusernick});
my $matchname = nick2matchname($form->{newusernick});
if (!$form->{email} || $form->{email} !~ /\@/) {
print getError('email_invalid', 0, 1);
return;
} elsif ($form->{email} ne $form->{email2}) {
print getError('email_do_not_match', 0, 1);
return;
} elsif ($slashdb->existsEmail($form->{email})) {
print getError('emailexists_err', 0, 1);
return;
} elsif ($matchname ne '' && $form->{newusernick} ne '') {
if ($constants->{newuser_portscan}) {
my $is_trusted = $slashdb->checkAL2($user->{srcids}, 'trusted');
if (!$is_trusted) {
my $is_proxy = $slashdb->checkForOpenProxy($user->{hostip});
if ($is_proxy) {
print getError('new user open proxy', {
unencoded_ip => $ENV{REMOTE_ADDR},
port => $is_proxy,
});
return;
}
}
}
my $uid;
my $rootdir = getCurrentSkin('rootdir');
$uid = $slashdb->createUser(
$matchname, $form->{email}, $form->{newusernick}
);
if ($uid) {
my $data = {};
getOtherUserParams($data);
for (qw(tzcode)) {
$data->{$_} = $form->{$_} if defined $form->{$_};
}
$data->{creation_ipid} = $user->{ipid};
$slashdb->setUser($uid, $data) if keys %$data;
$title = getTitle('newUser_title');
$form->{pubkey} = $plugins->{'Pubkey'} ?
strip_nohtml($form->{pubkey}, 1) : '';
print getMessage('newuser_msg', {
suadmin_flag => $suadmin_flag,
title => $title,
uid => $uid
});
if ($form->{newsletter} || $form->{comment_reply} || $form->{headlines}) {
my $messages = getObject('Slash::Messages');
my %params;
$params{MSG_CODE_COMMENT_REPLY()} = MSG_MODE_EMAIL()
if $form->{comment_reply};
$params{MSG_CODE_NEWSLETTER()} = MSG_MODE_EMAIL()
if $form->{newsletter};
$params{MSG_CODE_HEADLINES()} = MSG_MODE_EMAIL()
if $form->{headlines};
$messages->setPrefs($uid, \%params);
}
mailPasswd({ uid => $uid });
return;
} else {
$slashdb->resetFormkey($form->{formkey});
print getError('duplicate_user', {
nick => $form->{newusernick},
});
return;
}
} else {
print getError('duplicate_user', {
nick => $form->{newusernick},
});
return;
}
}
#################################################################
sub mailPasswd {
my($hr) = @_;
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $uid = $hr->{uid} || 0;
my $slashdb = getCurrentDB();
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $form = getCurrentForm();
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
if (! $uid) {
if ($form->{unickname} =~ /\@/) {
$uid = $slashdb->getUserEmail($form->{unickname});
} elsif ($form->{unickname} =~ /^\d+$/) {
my $tmpuser = $slashdb->getUser($form->{unickname}, ['uid']);
$uid = $tmpuser->{uid};
} else {
$uid = $slashdb->getUserUID($form->{unickname});
}
}
my $user_edit;
my $err_name = '';
my $err_opts = {};
if (!$uid || isAnon($uid)) {
$err_name = 'mailpasswd_notmailed_err';
}
if (!$err_name) {
# Check permissions of _this_ user, not the target
# user, to determine whether this IP is OK'd to
# send the mail to the target user.
# XXXSRCID This should check a separate field like
# 'openproxy' instead of piggybacking off of the
# existing nopost and spammer
my $srcids_to_check = $user->{srcids};
$err_name = 'mailpasswd_readonly_err'
if $reader->checkAL2($srcids_to_check, 'nopost');
}
if (!$err_name) {
$err_name = 'mailpasswd_toooften_err'
if $slashdb->checkMaxMailPasswords($user_edit);
}
if (!$err_name) {
if ($constants->{mailpasswd_portscan}) {
my $is_trusted = $slashdb->checkAL2($user->{srcids}, 'trusted');
if (!$is_trusted) {
my $is_proxy = $slashdb->checkForOpenProxy($user->{hostip});
if ($is_proxy) {
$err_name = 'mailpasswd open proxy';
$err_opts = { unencoded_ip => $ENV{REMOTE_ADDR}, port => $is_proxy };
}
}
}
}
if ($err_name) {
print getError($err_name, $err_opts);
$slashdb->resetFormkey($form->{formkey});
$form->{op} = 'mailpasswdform';
displayForm();
return(1);
}
my $newpasswd = $slashdb->getNewPasswd($uid);
my $tempnick = $user_edit->{nickname};
my $emailtitle = getTitle('mailPassword_email_title', {
nickname => $user_edit->{nickname}
}, 1);
# Pull out some data passed in with the request. Only the IP
# number is actually trustworthy, the others could be forged.
# Note that we strip the forgeable ones to make sure there
# aren't any "<>" chars which could fool a stupid mail client
# into parsing a plaintext email as HTML.
my $r = Apache->request;
my $remote_ip = $r->connection->remote_ip;
my $xff = $r->header_in('X-Forwarded-For') || '';
$xff =~ s/\s+/ /g;
$xff = substr(strip_notags($xff), 0, 20);
my $ua = $r->header_in('User-Agent') || '';
$ua =~ s/\s+/ /g;
$ua = substr(strip_attribute($ua), 0, 60);
my $msg = getMessage('mailpasswd_msg', {
newpasswd => $newpasswd,
tempnick => $tempnick,
remote_ip => $remote_ip,
x_forwarded_for => $xff,
user_agent => $ua,
}, 1);
doEmail($uid, $emailtitle, $msg) if $user_edit->{nickname};
print getMessage('mailpasswd_mailed_msg', { name => $user_edit->{nickname} });
$slashdb->setUserMailPasswd($user_edit);
}
#################################################################
sub showSubmissions {
my($hr) = @_;
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $form = getCurrentForm();
my $constants = getCurrentStatic();
my $user = getCurrentUser();
my($uid, $nickname);
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
if ($form->{uid} or $form->{nick}) {
$uid = $form->{uid} || $reader->getUserUID($form->{nick});
$nickname = $reader->getUser($uid, 'nickname');
} else {
$nickname = $user->{nickname};
$uid = $user->{uid};
}
my $storycount = $reader->countStoriesBySubmitter($uid);
my $stories = $reader->getStoriesBySubmitter(
$uid,
$constants->{user_submitter_display_default}
) unless !$storycount;
slashDisplay('userSub', {
nick => $nickname,
uid => $uid,
nickmatch_flag => ($user->{uid} == $uid ? 1 : 0),
stories => $stories,
storycount => $storycount,
});
}
#################################################################
sub showComments {
my($hr) = @_;
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $form = getCurrentForm();
my $constants = getCurrentStatic();
my $user = getCurrentUser();
my $commentstruct = [];
my($uid, $nickname);
my $user_edit;
if ($form->{uid} || $form->{nick}) {
$uid = $form->{uid} || $reader->getUserUID($form->{nick});
$user_edit = $reader->getUser($uid);
} else {
$uid = $user->{uid};
$user_edit = $user;
}
$nickname = $user_edit->{nickname};
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $user_edit->{uid} == $user->{uid} ? 'me' : 'otheruser',
});
my $min_comment = $form->{min_comment} || 0;
$min_comment = 0 unless $user->{seclev} > $constants->{comments_more_seclev}
|| $constants->{comments_more_seclev} == 2 && $user->{is_subscriber};
my $comments_wanted = $user->{show_comments_num}
|| $constants->{user_comment_display_default};
my $commentcount = $reader->countCommentsByUID($uid);
my $comments = $reader->getCommentsByUID(
$uid, $comments_wanted, $min_comment
) if $commentcount;
if (ref($comments) eq 'ARRAY') {
my $kinds = $reader->getDescriptions('discussion_kinds');
for my $comment (@$comments) {
# This works since $sid is numeric.
$comment->{replies} = $reader->countCommentsBySidPid($comment->{sid}, $comment->{cid});
# This is ok, since with all luck we will not be hitting the DB
# ...however, the "sid" parameter here must be the string
# based SID from either the "stories" table or from
# pollquestions.
my $discussion = $reader->getDiscussion($comment->{sid});
if ($kinds->{ $discussion->{dkid} } =~ /^journal(?:-story)?$/) {
$comment->{type} = 'journal';
} elsif ($kinds->{ $discussion->{dkid} } eq 'poll') {
$comment->{type} = 'poll';
} else {
$comment->{type} = 'story';
}
$comment->{disc_title} = $discussion->{title};
$comment->{url} = $discussion->{url};
}
}
my $mod_reader = getObject("Slash::$constants->{m1_pluginname}", { db_type => 'reader' });
slashDisplay('userCom', {
nick => $nickname,
useredit => $user_edit,
nickmatch_flag => ($user->{uid} == $uid ? 1 : 0),
commentstruct => $comments,
commentcount => $commentcount,
min_comment => $min_comment,
reasons => $mod_reader->getReasons(),
karma_flag => 0,
admin_flag => $user->{is_admin},
});
}
sub noUser {
print getData("no_user");
}
sub showFireHose {
my($hr) = @_;
my $user = getCurrentUser();
my $form = getCurrentForm();
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $uid = $form->{uid} || $user->{uid};
my $user_edit = $reader->getUser($uid);
$user->{state}{firehose_page} = "user";
$user->{state}{firehose_user_uid} = $uid;
my $firehose = getObject("Slash::FireHose");
header(getMessage('userfirehose_header', { useredit => $user_edit })) or return;
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $user_edit->{uid} == $user->{uid} ? 'me' : 'otheruser',
});
$form->{mode} = "full";
$form->{color} = "black";
$form->{orderby} = "createtime";
$form->{orderdir} = "DESC";
$form->{skipmenu} = 1;
$form->{duration} = -1;
$form->{fhfilter} = "\"user:$user_edit->{nickname}\"";
$form->{pause} = 1;
$form->{listonly} = 1;
$form->{legacy} = 1;
my $fhbox = $firehose->listView({ fh_page => 'users.pl', tab => 'userfirehose', user_view => $user_edit });
slashDisplay("userFireHose", { firehosebox => $fhbox, uid => $uid, useredit => $user_edit });
}
#################################################################
# arhgghgh. I love torture. I love pain. This subroutine satisfies
# these needs of mine
sub showInfo {
my($hr) = @_;
my $id = $hr->{uid} || 0;
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $slashdb = getCurrentDB();
my $form = getCurrentForm();
my $constants = getCurrentStatic();
my $user = getCurrentUser();
my $admin_flag = ($user->{is_admin}) ? 1 : 0;
my $suadmin_flag = $user->{seclev} >= 10000 ? 1 : 0;
my($title, $admin_block, $fieldkey) = ('', '', '');
my $comments = undef;
my $commentcount = 0;
my $commentcount_time = 0;
my $commentstruct = [];
my $requested_user = {};
my $time_period = $constants->{admin_comment_display_days} || 30;
my $cid_for_time_period = $reader->getVar("min_cid_last_$time_period\_days",'value', 1) || 0;
my $admin_time_period_limit = $constants->{admin_daysback_commentlimit} || 100;
my $admin_non_time_limit = $constants->{admin_comment_subsequent_pagesize} || 24;
my($points, $nickmatch_flag, $uid, $nick);
my($mod_flag, $karma_flag, $n) = (0, 0, 0);
if ($admin_flag
&& (defined($form->{show_m2s}) || defined($form->{show_m1s}) || defined($form->{m2_listing})))
{
my $update_hr = {};
$update_hr->{mod_with_comm} = $form->{show_m1s}
if defined $form->{show_m1s};
$update_hr->{m2_with_mod} = ($constants->{m2} ? $form->{show_m2s} : undef)
if defined $form->{show_m2s};
$update_hr->{show_m2_listing} = ($constants->{m2} ? $form->{m2_listing} : undef)
if defined $form->{m2_listing};
$slashdb->setUser($user->{uid}, $update_hr);
}
if (!$id && !$form->{userfield}) {
if ($form->{uid} && ! $id) {
$fieldkey = 'uid';
($uid, $id) = ($form->{uid}, $form->{uid});
$requested_user = isAnon($uid) ? $user : $reader->getUser($id);
$nick = $requested_user->{nickname};
$form->{userfield} = $nick if $admin_flag;
} elsif ($form->{nick} && ! $id) {
$fieldkey = 'nickname';
($nick, $id) = ($form->{nick}, $form->{nick});
$uid = $reader->getUserUID($id);
if (isAnon($uid)) {
$requested_user = $user;
($nick, $uid, $id) = @{$user}{qw(nickname uid nickname)};
} else {
$requested_user = $reader->getUser($uid);
}
$form->{userfield} = $uid if $admin_flag;
} else {
$fieldkey = 'uid';
($id, $uid) = ($user->{uid}, $user->{uid});
$requested_user = $reader->getUser($uid);
$form->{userfield} = $uid if $admin_flag;
}
} elsif ($user->{is_admin}) {
$id ||= $form->{userfield} || $user->{uid};
if ($id =~ /^[0-9a-f]{16}$/) {
$requested_user->{nonuid} = 1;
$fieldkey = "srcid";
$requested_user->{$fieldkey} = $id;
} elsif ($id =~ /^\d+$/) {
# If it's longer than a uid could possibly be, it
# must be a srcid. The uid column right now is a
# MEDIUMINT (max 16M) but at most might someday
# be an INT (max 4G).
if (length($id) > 11) {
$requested_user->{nonuid} = 1;
$fieldkey = "srcid";
$requested_user->{$fieldkey} = $id;
} else {
$fieldkey = 'uid';
$requested_user = $reader->getUser($id);
$uid = $requested_user->{uid};
$nick = $requested_user->{nickname};
if ((my $conflict_id = $reader->getUserUID($id)) && $form->{userinfo}) {
slashDisplay('showInfoConflict', {
op => 'userinfo',
id => $uid,
nick => $nick,
conflict_id => $conflict_id
});
return 1;
}
}
} elsif (length($id) == 32) {
$requested_user->{nonuid} = 1;
if ($form->{fieldname}
&& $form->{fieldname} =~ /^(ipid|subnetid)$/) {
$fieldkey = $form->{fieldname};
} else {
$fieldkey = 'md5id';
}
$requested_user->{$fieldkey} = $id;
} elsif ($id =~ /^(\d{1,3}\.\d{1,3}.\d{1,3}\.0)$/
|| $id =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3})\.?$/) {
$fieldkey = 'subnetid';
$requested_user->{subnetid} = $1;
$requested_user->{subnetid} .= '.0' if $requested_user->{subnetid} =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}$/;
$requested_user->{nonuid} = 1;
$requested_user->{subnetid} = md5_hex($requested_user->{subnetid});
} elsif ($id =~ /^([\d+\.]+)$/) {
$fieldkey = 'ipid';
$requested_user->{nonuid} = 1;
$id ||= $1;
$requested_user->{ipid} = md5_hex($1);
} elsif ($id =~ /^(.*@.*\..*?)$/) {
# check for email addy, but make it by uid
$fieldkey = 'uid';
$id = $uid = $reader->getUserEmail($id);
$requested_user = $reader->getUser($uid);
$nick = $requested_user->{nickname};
} else { # go by nickname, but make it by uid
$fieldkey = 'uid';
$id = $uid = $reader->getUserUID($id);
$requested_user = $reader->getUser($uid);
$nick = $requested_user->{nickname};
}
} else {
$fieldkey = 'uid';
($id, $uid) = ($user->{uid}, $user->{uid});
$requested_user = $reader->getUser($uid);
}
# Can't get user data for the anonymous user.
if ($fieldkey eq 'uid' && isAnon($uid)) {
header(getMessage('user_header')) or return;
return displayForm();
}
my $user_change = { };
if ($fieldkey eq 'uid' && !$user->{is_anon}
&& $uid != $user->{uid} && !isAnon($uid)) {
# Store the fact that this user last looked at that user.
# For maximal convenience in stalking.
$user_change->{lastlookuid} = $uid;
$user_change->{lastlooktime} = time;
$user->{lastlookuid} = $uid;
$user->{lastlooktime} = time;
$hr->{tab_selected_1} = 'otheruser';
}
# showInfo's header information is delayed until here, because
# the target user's info is not available until here.
vislenify($requested_user);
header(getMessage('user_header', { useredit => $requested_user, fieldkey => $fieldkey })) or return;
# This is a hardcoded position, bad idea and should be fixed -Brian
# Yeah, we should pull this into a template somewhere...
print getMessage('note', { note => $hr->{note} }) if defined $hr->{note};
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
my $comments_wanted = $user->{show_comments_num}
|| $constants->{user_comment_display_default};
my $min_comment = $form->{min_comment} || 0;
$min_comment = 0 unless $user->{seclev} > $constants->{comments_more_seclev}
|| $constants->{comments_more_seclev} == 2 && $user->{is_subscriber};
my($netid, $netid_vis) = ('', '');
my $comment_time;
my $non_admin_limit = $comments_wanted;
if ($requested_user->{nonuid}) {
$requested_user->{fg} = $user->{fg};
$requested_user->{bg} = $user->{bg};
if ($requested_user->{ipid}) {
$netid = $requested_user->{ipid} ;
} elsif ($requested_user->{md5id}) {
$netid = $requested_user->{md5id} ;
} elsif ($requested_user->{srcid}) {
$netid = $requested_user->{srcid} ;
} else {
$netid = $requested_user->{subnetid} ;
}
my $data = {
id => $id,
md5id => $netid,
};
vislenify($data); # add $data->{md5id_vis}
$netid_vis = $data->{md5id_vis};
$title = getTitle('user_netID_user_title', $data);
$admin_block = getUserAdmin($netid, $fieldkey, 0) if $admin_flag;
if ($form->{fieldname}) {
if ($form->{fieldname} eq 'ipid') {
$commentcount = $reader->countCommentsByIPID($netid);
$commentcount_time = $reader->countCommentsByIPID($netid, { cid_at_or_after => $cid_for_time_period });
$comments = getCommentListing("ipid", $netid,
$min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period,
$non_admin_limit, $admin_time_period_limit, $admin_non_time_limit)
if $commentcount;
} elsif ($form->{fieldname} eq 'subnetid') {
$commentcount = $reader->countCommentsBySubnetID($netid);
$commentcount_time = $reader->countCommentsBySubnetID($netid, { cid_at_or_after => $cid_for_time_period });
$comments = getCommentListing("subnetid", $netid,
$min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period,
$non_admin_limit, $admin_time_period_limit, $admin_non_time_limit)
if $commentcount;
} else {
delete $form->{fieldname};
}
}
if (!defined($comments)) {
# Last resort; here for backwards compatibility mostly.
my $type;
($commentcount,$type) = $reader->countCommentsByIPIDOrSubnetID($netid);
$commentcount_time = $reader->countCommentsByIPIDOrSubnetID($netid, { cid_at_or_after => $cid_for_time_period });
if ($type eq "ipid") {
$comments = getCommentListing("ipid", $netid,
$min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period,
$non_admin_limit, $admin_time_period_limit, $admin_non_time_limit)
if $commentcount;
} elsif ($type eq "subnetid") {
$comments = getCommentListing("subnetid", $netid,
$min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period,
$non_admin_limit, $admin_time_period_limit, $admin_non_time_limit)
if $commentcount;
}
}
} else {
$admin_block = getUserAdmin($id, $fieldkey, 1) if $admin_flag;
$commentcount = $reader->countCommentsByUID($requested_user->{uid});
$commentcount_time = $reader->countCommentsByUID($requested_user->{uid}, { cid_at_or_after => $cid_for_time_period });
$comments = getCommentListing("uid", $requested_user->{uid},
$min_comment, $time_period, $commentcount, $commentcount_time, $cid_for_time_period,
$non_admin_limit, $admin_time_period_limit, $admin_non_time_limit,
{ use_uid_cid_cutoff => 1 })
if $commentcount;
$netid = $requested_user->{uid};
}
# Grab the nicks of the uids we have, we're going to be adding them
# into the struct.
my @users_extra_cols_wanted = qw( nickname );
my @discussions_extra_cols_wanted = qw( type );
my $uid_hr = { };
my $sid_hr = { };
if ($comments && @$comments) {
my %uids = ();
my %sids = ();
for my $c (@$comments) {
$uids{$c->{uid}}++;
$sids{$c->{sid}}++;
}
my $uids = join(", ", sort { $a <=> $b } keys %uids);
my $sids = join(", ", sort { $a <=> $b } keys %sids);
$uid_hr = $reader->sqlSelectAllHashref(
"uid",
"uid, " . join(", ", @users_extra_cols_wanted),
"users",
"uid IN ($uids)"
);
$sid_hr = $reader->sqlSelectAllHashref(
"id",
"id, " . join(", ", @discussions_extra_cols_wanted),
"discussions",
"id IN ($sids)"
);
}
my $cids_seen = {};
my $kinds = $slashdb->getDescriptions('discussion_kinds');
for my $comment (@$comments) {
$cids_seen->{$comment->{cid}}++;
my $type;
# This works since $sid is numeric.
my $replies = $reader->countCommentsBySidPid($comment->{sid}, $comment->{cid});
# This is cached.
my $discussion = $reader->getDiscussion($comment->{sid});
#use Data::Dumper; if ($discussion && !$discussion->{dkid}) { print STDERR scalar(gmtime) . " users.pl discussion but no dkid: " . Dumper($discussion) }
if (!$discussion || !$discussion->{dkid}) {
# A comment with no accompanying discussion;
# basically we pretend it doesn't exist.
next;
} elsif ($kinds->{ $discussion->{dkid} } =~ /^journal(?:-story)?$/) {
$type = 'journal';
} elsif ($kinds->{ $discussion->{dkid} } eq 'poll') {
$type = 'poll';
} else {
$type = 'story';
}
$comment->{points} += $user->{karma_bonus}
if $user->{karma_bonus} && $comment->{karma_bonus} eq 'yes';
$comment->{points} += $user->{subscriber_bonus}
if $user->{subscriber_bonus} && $comment->{subscriber_bonus} eq 'yes';
# fix points in case they are out of bounds
$comment->{points} = $constants->{comment_minscore} if $comment->{points} < $constants->{comment_minscore};
$comment->{points} = $constants->{comment_maxscore} if $comment->{points} > $constants->{comment_maxscore};
vislenify($comment);
my $data = {
pid => $comment->{pid},
url => $discussion->{url},
disc_type => $type,
disc_title => $discussion->{title},
disc_time => $discussion->{ts},
sid => $comment->{sid},
cid => $comment->{cid},
subj => $comment->{subject},
cdate => $comment->{date},
pts => $comment->{points},
reason => $comment->{reason},
uid => $comment->{uid},
replies => $replies,
ipid => $comment->{ipid},
ipid_vis => $comment->{ipid_vis},
karma => $comment->{karma},
tweak => $comment->{tweak},
tweak_orig => $comment->{tweak_orig},
};
#Karma bonus time
for my $col (@users_extra_cols_wanted) {
$data->{$col} = $uid_hr->{$comment->{uid}}{$col} if defined $uid_hr->{$comment->{uid}}{$col};
}
for my $col(@discussions_extra_cols_wanted) {
$data->{$col} = $sid_hr->{$comment->{sid}}{$col} if defined $sid_hr->{$comment->{sid}}{$col};
}
push @$commentstruct, $data;
}
# if (grep { !defined($_->{disc_time}) || !defined($_->{sid}) } @$commentstruct) { use Data::Dumper; print STDERR "showInfo undef in commentstruct for id=$id: " . Dumper($commentstruct) }
# Sort so the chosen group of comments is sorted by discussion
@$commentstruct = sort {
$b->{disc_time} cmp $a->{disc_time} || $b->{sid} <=> $a->{sid}
} @$commentstruct
unless $user->{user_comment_sort_type} && $user->{user_comment_sort_type} == 1;
my $cid_list = [ keys %$cids_seen ];
my $cids_to_mods = {};
my $mod_reader = getObject("Slash::$constants->{m1_pluginname}", { db_type => 'reader' });
if ($constants->{m1} && $admin_flag && $constants->{show_mods_with_comments}) {
my $comment_mods = $mod_reader->getModeratorCommentLog("DESC",
$constants->{mod_limit_with_comments}, "cidin", $cid_list);
# Loop through mods and group them by the sid they're attached to
while (my $mod = shift @$comment_mods) {
push @{$cids_to_mods->{$mod->{cid}}}, $mod;
}
}
my $sub_limit = ((($admin_flag || $user->{uid} == $requested_user->{uid}) ? $constants->{submissions_all_page_size} : $constants->{submissions_accepted_only_page_size}) || "");
my $sub_options = { limit_days => 365 };
$sub_options->{accepted_only} = 1 if !$admin_flag && $user->{uid} != $requested_user->{uid};
my $sub_field = $form->{fieldname};
my ($subcount, $ret_field) = $reader->countSubmissionsByNetID($netid, $sub_field)
if $requested_user->{nonuid};
my $submissions = $reader->getSubmissionsByNetID($netid, $ret_field, $sub_limit, $sub_options)
if $requested_user->{nonuid};
my $ipid_hoursback = $constants->{istroll_ipid_hours} || 72;
my $uid_hoursback = $constants->{istroll_uid_hours} || 72;
if ($requested_user->{nonuid}) {
slashDisplay('netIDInfo', {
title => $title,
id => $id,
useredit => $requested_user,
commentstruct => $commentstruct || [],
commentcount => $commentcount,
min_comment => $min_comment,
admin_flag => $admin_flag,
admin_block => $admin_block,
netid => $netid,
netid_vis => $netid_vis,
reasons => $mod_reader->getReasons(),
subcount => $subcount,
submissions => $submissions,
hr_hours_back => $ipid_hoursback,
cids_to_mods => $cids_to_mods,
comment_time => $comment_time
});
} else {
if (! $requested_user->{uid}) {
print getError('userinfo_idnf_err', { id => $id, fieldkey => $fieldkey});
return 1;
}
$karma_flag = 1 if $admin_flag;
$requested_user->{nick_plain} = $nick ||= $requested_user->{nickname};
$nick = strip_literal($nick);
if ($requested_user->{uid} == $user->{uid}) {
$karma_flag = 1;
$nickmatch_flag = 1;
$points = $requested_user->{points};
$mod_flag = 1 if $points > 0;
$title = getTitle('userInfo_main_title', { nick => $nick, uid => $uid });
} else {
$title = getTitle('userInfo_user_title', { nick => $nick, uid => $uid });
}
my $lastjournal = _get_lastjournal($uid);
my $subcount = $reader->countSubmissionsByUID($uid);
my $submissions = $reader->getSubmissionsByUID($uid, $sub_limit, $sub_options);
my $metamods;
if ($constants->{m2} && $admin_flag) {
my $metamod_reader = getObject('Slash::Metamod', { db_type => 'reader' });
$metamods = $metamod_reader->getMetamodlogForUser($uid, 30);
}
my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' });
my $tagshist = [];
if ($tags_reader && $user->{is_admin}) {
$tagshist = $tags_reader->getAllTagsFromUser($requested_user->{uid}, { orderby => 'created_at', orderdir => 'DESC', limit => 30, include_private => 1 });
}
slashDisplay('userInfo', {
title => $title,
uid => $uid,
useredit => $requested_user,
points => $points,
commentstruct => $commentstruct || [],
commentcount => $commentcount,
min_comment => $min_comment,
nickmatch_flag => $nickmatch_flag,
mod_flag => $mod_flag,
karma_flag => $karma_flag,
admin_block => $admin_block,
admin_flag => $admin_flag,
suadmin_flag => $suadmin_flag,
reasons => $mod_reader->getReasons(),
lastjournal => $lastjournal,
hr_hours_back => $ipid_hoursback,
cids_to_mods => $cids_to_mods,
comment_time => $comment_time,
submissions => $submissions,
subcount => $subcount,
metamods => $metamods,
tagshist => $tagshist
});
}
if ($user_change && %$user_change) {
$slashdb->setUser($user->{uid}, $user_change);
}
return 1;
}
sub _get_lastjournal {
my($uid) = @_;
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $lastjournal = undef;
if (my $journal = getObject('Slash::Journal', { db_type => 'reader' })) {
my $j = $journal->getsByUid($uid, 0, 1);
if ($j && @$j) {
# Yep, there are 1 or more journals... get the first.
$j = $j->[0];
}
if ($j && @$j) {
# Yep, that first journal exists and has entries...
# convert from stupid numeric array to a hashref.
my @field = qw( date article description id
posttype tid discussion );
$lastjournal = { };
for my $i (0..$#field) {
$lastjournal->{$field[$i]} = $j->[$i];
}
}
}
if ($lastjournal) {
# Strip the article field for display.
$lastjournal->{article} = strip_mode($lastjournal->{article},
$lastjournal->{posttype});
# For display, include a reduced-size version, where the
# size is based on the user's maxcomment size (which
# defaults to 4K) and can't have too many line-breaking
# tags.
my $art_shrunk = $lastjournal->{article};
my $maxsize = int($constants->{default_maxcommentsize} / 25);
$maxsize = 80 if $maxsize < 80;
$maxsize = 600 if $maxsize > 600;
$art_shrunk = chopEntity($art_shrunk, $maxsize);
my $approvedtags_break = $constants->{approvedtags_break} || [];
my $break_tag = join '|', @$approvedtags_break;
if (scalar(() = $art_shrunk =~ /<(?:$break_tag)>/gi) > 2) {
$art_shrunk =~ s/\A
(
(?: <(?:$break_tag)> )?
.*? <(?:$break_tag)>
.*?
) <(?:$break_tag)>.*
/$1/six;
if (length($art_shrunk) < 15) {
# This journal entry has too much whitespace
# in its first few chars; scrap it.
undef $art_shrunk;
}
$art_shrunk = chopEntity($art_shrunk) if defined($art_shrunk);
}
if (defined $art_shrunk) {
if (length($art_shrunk) < length($lastjournal->{article})) {
$art_shrunk .= " ...";
}
$art_shrunk = strip_html($art_shrunk);
$art_shrunk = balanceTags($art_shrunk);
}
$lastjournal->{article_shrunk} = $art_shrunk;
if ($lastjournal->{discussion}) {
$lastjournal->{commentcount} = $reader->getDiscussion(
$lastjournal->{discussion}, 'commentcount');
}
}
return $lastjournal;
}
#####################################################################
sub validateUser {
my($hr) = @_;
my $user = getCurrentUser();
my $form = getCurrentForm();
my $slashdb = getCurrentDB();
my $constants = getCurrentStatic();
# If we aren't expiring accounts in some way, we don't belong here.
if (! allowExpiry()) {
displayForm();
return;
}
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
# Since we are here, if the minimum values for the comment trigger and
# the day trigger are -1, then they should be reset to 1.
$constants->{min_expiry_comm} = $constants->{min_expiry_days} = 1
if $constants->{min_expiry_comm} <= 0 ||
$constants->{min_expiry_days} <= 0;
if ($user->{is_anon} || $user->{registered}) {
if ($user->{is_anon}) {
print getError('anon_validation_attempt');
displayForm();
return;
} else {
print getMessage('no_registration_needed')
if !$user->{reg_id};
showInfo({ uid => $user->{uid} });
return;
}
# Maybe this should be taken care of in a more centralized location?
} elsif ($user->{reg_id} eq $form->{id}) {
# We have a user and the registration IDs match. We are happy!
my($maxComm, $maxDays) = ($constants->{max_expiry_comm},
$constants->{max_expiry_days});
my($userComm, $userDays) =
($user->{user_expiry_comm}, $user->{user_expiry_days});
# Ensure both $userComm and $userDays aren't -1 (expiry has
# just been turned on).
$userComm = $constants->{min_expiry_comm}
if $userComm < $constants->{min_expiry_comm};
$userDays = $constants->{min_expiry_days}
if $userDays < $constants->{min_expiry_days};
my $exp = $constants->{expiry_exponent};
# Increment only the trigger that was used.
my $new_comment_expiry = ($maxComm > 0 && $userComm > $maxComm)
? $maxComm
: $userComm * (($user->{expiry_comm} < 0)
? $exp
: 1
);
my $new_days_expiry = ($maxDays > 0 && $userDays > $maxDays)
? $maxDays
: $userDays * (($user->{expiry_days} < 0)
? $exp
: 1
);
# Reset re-registration triggers for user.
$slashdb->setUser($user->{uid}, {
'expiry_comm' => $new_comment_expiry,
'expiry_days' => $new_days_expiry,
'user_expiry_comm' => $new_comment_expiry,
'user_expiry_days' => $new_days_expiry,
});
# Handles rest of re-registration process.
setUserExpired($user->{uid}, 0);
}
slashDisplay('regResult');
}
#####################################################################
sub editTags {
my($hr) = @_;
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $note = $hr->{note} || "";
return if $user->{is_anon}; # shouldn't be, but can't hurt to check
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
my $user_edit = $slashdb->getUser($user->{uid});
my $title = getTitle('editTags_title');
slashDisplay('editTags', {
user_edit => $user_edit,
title => $title,
note => $note,
});
}
sub saveTags {
my($hr) = @_;
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
my $form = getCurrentForm();
my $constants = getCurrentStatic();
return if $user->{is_anon}; # shouldn't be, but can't hurt to check
$slashdb->setUser($user->{uid}, {
tags_turnedoff => $form->{showtags} ? '' : 1 });
editTags({ note => getMessage('savetags_msg') });
}
#####################################################################
sub showTags {
my($hr) = @_;
my $user = getCurrentUser();
my $form = getCurrentForm();
my $slashdb = getCurrentDB();
my $constants = getCurrentStatic();
my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' });
# XXX if $user_edit->{acl}{spammer}, either abort or put ref=nofollow in all links
my $tagname = $form->{tagname} || '';
$tagname = '' if !$tags_reader->tagnameSyntaxOK($tagname);
my($uid, $user_edit);
if ($form->{uid} || $form->{nick}) {
$uid = $form->{uid} || $tags_reader->getUserUID($form->{nick});
$user_edit = $tags_reader->getUser($uid);
}
if (!$user_edit || $user_edit->{is_anon}) {
$uid = $user->{uid};
$user_edit = $user;
}
my $nickname = $user_edit->{nickname};
if (!$constants->{plugin}{Tags}) {
print getError('bad_op', { op => $form->{op}});
return;
}
my $tagnameid = $tags_reader->getTagnameidFromNameIfExists($tagname);
if ($tagnameid) {
# Show all user's tags for one particular tagname.
my $tags_hr = $tags_reader->getGroupedTagsFromUser($user_edit->{uid},
{ tagnameid => $tagnameid });
my $tags_ar = $tags_hr->{$tagname} || [ ];
slashDisplay('usertagsforname', {
useredit => $user_edit,
tagname => $tagname,
tags => $tags_ar,
});
} else {
my $tags_hr = $tags_reader->getGroupedTagsFromUser($user_edit->{uid});
my $num_tags = 0;
for my $tn (keys %$tags_hr) {
$num_tags += scalar @{ $tags_hr->{$tn} };
}
my $cutoff = $constants->{tags_usershow_cutoff} || 200;
if ($num_tags <= $cutoff) {
# Show all user's tags, grouped by tagname.
slashDisplay('usertags', {
useredit => $user_edit,
tags_grouped => $tags_hr,
});
} else {
# Show all user's tagnames, with links to show all
# tags for each particular tagname.
my $tagname_ar = [ sort keys %$tags_hr ];
slashDisplay('usertagnames', {
useredit => $user_edit,
tagnames => $tagname_ar,
});
}
}
}
#################################################################
sub showBookmarks {
my($hr) = @_;
my $user = getCurrentUser();
my $form = getCurrentForm();
my $slashdb = getCurrentDB();
my $constants = getCurrentStatic();
my $tags_reader = getObject('Slash::Tags', { db_type => 'reader' });
my($uid, $user_edit);
if ($form->{uid} || $form->{nick}) {
$uid = $form->{uid} || $tags_reader->getUserUID($form->{nick});
$user_edit = $tags_reader->getUser($uid);
}
if (!$user_edit || $user_edit->{is_anon}) {
$uid = $user->{uid};
$user_edit = $user;
}
my $nickname = $user_edit->{nickname};
if (!$constants->{plugin}{Tags}) {
print getError('bad_op', { op => $form->{op}});
return;
}
my $tags_ar = $tags_reader->getGroupedTagsFromUser($user_edit->{uid}, { type => "urls", only_bookmarked => 1 });
slashDisplay('userbookmarks', {
useredit => $user_edit,
tags_grouped => $tags_ar,
});
}
#################################################################
sub editKey {
my($uid) = @_;
my $slashdb = getCurrentDB();
my $pubkey = $slashdb->getUser($uid, 'pubkey');
my $editkey = slashDisplay('editKey', { pubkey => $pubkey }, 1);
return $editkey;
}
#################################################################
# We arrive here without header() having been called. Some of the
# functions we dispatch to call it, some do not.
sub adminDispatch {
my($hr) = @_;
my $form = getCurrentForm();
my $op = $hr->{op} || $form->{op};
if ($op eq 'authoredit') {
# editUser() does not call header(), so we DO need to.
header(getMessage('user_header'), '', {}) or return;
editUser($hr);
} elsif ($form->{saveuseradmin}) {
# saveUserAdmin() tail-calls showInfo(), which calls
# header(), so we need to NOT.
saveUserAdmin($hr);
} elsif ($form->{userinfo}) {
# showInfo() calls header(), so we need to NOT.
showInfo($hr);
} elsif ($form->{userfield}) {
# none of these calls header(), so we DO need to.
header(getMessage('user_header'), '', {}) or return;
if ($form->{edituser}) {
editUser($hr);
} elsif ($form->{edithome}) {
editHome($hr);
} elsif ($form->{editcomm}) {
editComm($hr);
} elsif ($form->{changepasswd}) {
changePasswd($hr);
}
} else {
# showInfo() calls header(), so we need to NOT.
showInfo($hr);
}
}
#################################################################
sub tildeEd {
my($user_edit) = @_;
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $constants = getCurrentStatic();
my %story023_default = (
author => { },
nexus => { },
topic => { },
);
my %prefs = ( );
for my $field (qw(
story_never_topic story_never_author story_never_nexus
story_always_topic story_always_author story_always_nexus story_brief_always_nexus
story_full_brief_nexus story_full_best_nexus story_brief_best_nexus
)) {
for my $id (
grep /^\d+$/,
split /,/,
($user_edit->{$field} || "")
) {
$prefs{$field}{$id} = 1;
}
}
#print STDERR scalar(localtime) . " prefs: " . Dumper(\%prefs);
# Set up $author_hr, @aid_order, and $story023_default{author}.
my $author_hr = $reader->getDescriptions('authors');
my @aid_order = sort { lc $author_hr->{$a} cmp lc $author_hr->{$b} } keys %$author_hr;
for my $aid (@aid_order) {
if ($prefs{story_never_author}{$aid}) {
$story023_default{author}{$aid} = 0;
} elsif ($prefs{story_always_author}{$aid}) {
$story023_default{author}{$aid} = 3;
} else {
$story023_default{author}{$aid} = 2;
}
}
# Set up $topic_hr, @topictid_order, and $story023_default{topic}.
my $topic_hr = $reader->getDescriptions('non_nexus_topics-storypickable');
my @topictid_order = sort { lc $topic_hr->{$a} cmp lc $topic_hr->{$b} } keys %$topic_hr;
for my $tid (@topictid_order) {
if ($prefs{story_never_topic}{$tid}) {
$story023_default{topic}{$tid} = 0;
} elsif ($prefs{story_always_topic}{$tid}) {
$story023_default{topic}{$tid} = 3;
} else {
$story023_default{topic}{$tid} = 2;
}
}
# Set up $nexus_hr, @nexustid_order, and $story023_default{nexus}.
my $topic_tree = $reader->getTopicTree();
my $nexus_tids_ar = $reader->getStorypickableNexusChildren($constants->{mainpage_nexus_tid}, 1);
my $nexus_hr = { };
for my $tid (@$nexus_tids_ar) {
$nexus_hr->{$tid} = $topic_tree->{$tid}{textname};
}
my @nexustid_order = sort {($b == $constants->{mainpage_nexus_tid}) <=> ($a == $constants->{mainpage_nexus_tid}) ||
lc $nexus_hr->{$a} cmp lc $nexus_hr->{$b} } keys %$nexus_hr;
my $mp_disp_nexuses = $reader->getMainpageDisplayableNexuses();
my %mp_disp_nexus = ( map { ($_, 1) } @$mp_disp_nexuses );
for my $tid (@nexustid_order) {
if ($prefs{story_never_nexus}{$tid}) {
$story023_default{nexus}{$tid} = 0;
} elsif ($prefs{story_always_nexus}{$tid}) {
$story023_default{nexus}{$tid} = 5;
} elsif ($prefs{story_full_brief_nexus}{$tid}) {
$story023_default{nexus}{$tid} = 4;
} elsif ($prefs{story_brief_always_nexus}{$tid}) {
$story023_default{nexus}{$tid} = 3;
} elsif ($prefs{story_full_best_nexus}{$tid}) {
$story023_default{nexus}{$tid} = 2;
} elsif ($prefs{story_brief_best_nexus}{$tid}) {
$story023_default{nexus}{$tid} = 1;
} else {
# If brief_sectional_mainpage is set, then all
# nexuses in getMainpageDisplayableNexuses are,
# by default, shown as brief on the mainpage.
if ($constants->{brief_sectional_mainpage}
&& $mp_disp_nexus{$tid}
) {
$story023_default{nexus}{$tid} = 4;
} else {
$story023_default{nexus}{$tid} = 2;
}
}
}
# Set up $section_descref and $box_order, used to decide which
# slashboxes appear. Really this doesn't seem to have anything
# to do with sections, so I'm not sure why it's called
# "section"_descref.
my $section_descref = { };
my $box_order;
my $sections_description = $reader->getSectionBlocks();
# the names of all the boxes in @{$skinBoxes->{$constants->{mainpage_skid}}}
# should be unioned into sections_description. whether the
# values are 0 or 1 is calculated correctly, but we're
# missing some 0's that should appear, I think, under
# some circumstances. ah heck, the whole concept of
# sectional slashboxes should be redone (why the heck
# do we have skinname_more instead of just a block
# called olderstories?)
my $slashboxes_hr = { };
my $slashboxes_textlist = $user_edit->{slashboxes};
if (!$slashboxes_textlist) {
# Use the default.
my($boxes, $skinBoxes) = $reader->getPortalsCommon();
$slashboxes_textlist = join ",", @{$skinBoxes->{$constants->{mainpage_skid}}};
}
for my $bid (
map { /^'?([^']+)'?$/; $1 }
split /,/,
$slashboxes_textlist
) {
$slashboxes_hr->{$bid} = 1;
}
for my $ary (sort { lc $a->[1] cmp lc $b->[1]} @$sections_description) {
my($bid, $title, $boldflag) = @$ary;
push @$box_order, $bid;
$section_descref->{$bid}{checked} =
$slashboxes_hr->{$bid}
? $constants->{markup_checked_attribute}
: '';
$title =~ s/<(.*?)>//g;
$section_descref->{$bid}{title} = $title;
}
my $dynamic_blocks = getObject("Slash::DynamicBlocks");
my $extra_blocks = [];
if ($dynamic_blocks) {
my $userblocks = $dynamic_blocks->getUserBlocks("name", $user_edit->{uid}) || {};
my $friendblocks = $dynamic_blocks->getFriendBlocks("name", $user_edit->{uid}) || {};
push(@$extra_blocks, grep { $slashboxes_textlist =~ $_; } (keys(%$userblocks), keys(%$friendblocks)));
}
# Userspace.
my $userspace = $user_edit->{mylinks} || "";
# Titles of stuff.
my $tildeEd_title = getTitle('tildeEd_title');
my $criteria_msg = getMessage('tilded_criteria_msg');
my $customize_title = getTitle('tildeEd_customize_title');
my $tilded_customize_msg = getMessage('tilded_customize_msg',
{ userspace => $userspace });
my $tilded_box_msg = getMessage('tilded_box_msg');
my $tilde_ed = slashDisplay('tildeEd', {
user_edit => $user_edit,
title => $tildeEd_title,
criteria_msg => $criteria_msg,
customize_title => $customize_title,
tilded_customize_msg => $tilded_customize_msg,
tilded_box_msg => $tilded_box_msg,
story023_default => \%story023_default,
authorref => $author_hr,
aid_order => \@aid_order,
topicref => $topic_hr,
topictid_order => \@topictid_order,
nexusref => $nexus_hr,
nexustid_order => \@nexustid_order,
section_descref => $section_descref,
box_order => $box_order,
userspace => $userspace,
extra_blocks => $extra_blocks,
}, 1);
return $tilde_ed;
}
#################################################################
sub changePasswd {
my($hr) = @_;
my $form = getCurrentForm();
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
my $user_edit = {};
my $title;
my $suadmin_flag = ($user->{seclev} >= 10000) ? 1 : 0;
my $admin_flag = ($user->{is_admin}) ? 1 : 0;
my $admin_block = '';
my $id = '';
if ($admin_flag) {
if ($form->{userfield}) {
$id ||= $form->{userfield};
if ($id =~ /^\d+$/) {
$user_edit = $slashdb->getUser($id);
} else {
$user_edit = $slashdb->getUser($slashdb->getUserUID($id));
}
} else {
$user_edit = $id eq '' ? $user : $slashdb->getUser($id);
$id = $user_edit->{uid};
}
} else {
$id = $user->{uid};
$user_edit = $user;
}
$admin_block = getUserAdmin($id, 'uid', 1) if $admin_flag;
# print getMessage('note', { note => $form->{note}}) if $form->{note};
$title = getTitle('changePasswd_title', { user_edit => $user_edit });
my $session = $slashdb->getDescriptions('session_login');
my $session_select = createSelect('session_login', $session, $user_edit->{session_login}, 1);
my $clocation = $slashdb->getDescriptions('cookie_location');
my @clocation_order = grep { exists $clocation->{$_} } qw(none classbid subnetid ipid);
my $clocation_select = createSelect('cookie_location', $clocation,
$user_edit->{cookie_location}, 1, 0, \@clocation_order
);
my $got_oldpass = 0;
if ($form->{oldpass}) {
my $return_uid = $slashdb->getUserAuthenticate($id, $form->{oldpass}, 1);
$got_oldpass = 1 if $return_uid && $id == $return_uid;
}
slashDisplay('changePasswd', {
useredit => $user_edit,
admin_flag => $suadmin_flag,
title => $title,
session => $session_select,
clocation => $clocation_select,
admin_block => $admin_block,
got_oldpass => $got_oldpass
});
}
#################################################################
sub editUser {
my($hr) = @_;
my $id = $hr->{uid} || '';
my $note = $hr->{note} || '';
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
my $form = getCurrentForm();
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $plugins = $slashdb->getDescriptions('plugins');
my $user_edit = {};
my($admin_block, $title);
my $admin_flag = ($user->{is_admin}) ? 1 : 0;
my $fieldkey;
if ($admin_flag && $form->{userfield}) {
$id ||= $form->{userfield};
if ($form->{userfield} =~ /^\d+$/) {
$user_edit = $slashdb->getUser($id);
$fieldkey = 'uid';
} else {
$user_edit = $slashdb->getUser($slashdb->getUserUID($id));
$fieldkey = 'nickname';
}
} else {
$user_edit = $id eq '' ? $user : $slashdb->getUser($id);
$fieldkey = 'uid';
$id = $user_edit->{uid};
}
return if isAnon($user_edit->{uid}) && ! $admin_flag;
$admin_block = getUserAdmin($id, $fieldkey, 1) if $admin_flag;
$user_edit->{homepage} ||= "http://";
# Remove domain tags, they'll be added back in, in saveUser.
for my $dat (@{$user_edit}{qw(sig bio)}) {
$dat = parseDomainTags($dat, 0, 1);
}
$title = getTitle('editUser_title', { user_edit => $user_edit});
my $editkey = "";
$editkey = editKey($user_edit->{uid}) if $fieldkey eq 'uid' && $plugins->{PubKey};
slashDisplay('editUser', {
useredit => $user_edit,
admin_flag => $admin_flag,
title => $title,
editkey => $editkey,
admin_block => $admin_block,
note => $note,
});
}
#################################################################
sub editHome {
my($hr) = @_;
my $id = $hr->{uid} || '';
my $note = $hr->{note} || '';
my $slashdb = getCurrentDB();
my $form = getCurrentForm();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
my($formats, $title, $tzformat_select);
my $user_edit = {};
my $fieldkey;
my $admin_flag = ($user->{is_admin}) ? 1 : 0;
my $admin_block = '';
if ($admin_flag && $form->{userfield}) {
$id ||= $form->{userfield};
if ($form->{userfield} =~ /^\d+$/) {
$user_edit = $slashdb->getUser($id);
$fieldkey = 'uid';
} else {
$user_edit = $slashdb->getUser($slashdb->getUserUID($id));
$fieldkey = 'nickname';
}
} else {
$user_edit = $id eq '' ? $user : $slashdb->getUser($id);
$fieldkey = 'uid';
}
#use Data::Dumper; $Data::Dumper::Sortkeys = 1; print STDERR scalar(localtime) . " user_edit: " . Dumper($user_edit);
return if isAnon($user_edit->{uid}) && ! $admin_flag;
$admin_block = getUserAdmin($id, $fieldkey, 1) if $admin_flag;
$title = getTitle('editHome_title');
return if $user->{seclev} < 100 && isAnon($user_edit->{uid});
$formats = $slashdb->getDescriptions('dateformats');
$tzformat_select = createSelect('tzformat', $formats, $user_edit->{dfid}, 1);
my $lb_check = $user_edit->{lowbandwidth} ? $constants->{markup_checked_attribute} : '';
my $sd_check = $user_edit->{simpledesign} ? $constants->{markup_checked_attribute} : '';
my $i_check = $user_edit->{noicons} ? $constants->{markup_checked_attribute} : '';
my $w_check = $user_edit->{willing} ? $constants->{markup_checked_attribute} : '';
my $classic_check = $user_edit->{index_classic} ? $constants->{markup_checked_attribute} : '';
my $tilde_ed = tildeEd($user_edit);
slashDisplay('editHome', {
title => $title,
admin_block => $admin_block,
user_edit => $user_edit,
tzformat_select => $tzformat_select,
i_check => $i_check,
w_check => $w_check,
lb_check => $lb_check,
sd_check => $sd_check,
classic_check => $classic_check,
tilde_ed => $tilde_ed,
note => $note,
});
}
#################################################################
sub editComm {
my($hr) = @_;
my $id = $hr->{uid} || '';
my $note = $hr->{note} || '';
my $slashdb = getCurrentDB();
my $form = getCurrentForm();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $user_edit = {};
my($formats, $commentmodes_select, $commentsort_select, $title,
$uthreshold_select, $highlightthresh_select, $posttype_select,
$bytelimit_select);
my $admin_block = '';
my $fieldkey;
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
my $admin_flag = $user->{is_admin} ? 1 : 0;
if ($admin_flag && $form->{userfield}) {
$id ||= $form->{userfield};
if ($form->{userfield} =~ /^\d+$/) {
$user_edit = $slashdb->getUser($id);
$fieldkey = 'uid';
} else {
$user_edit = $slashdb->getUser($slashdb->getUserUID($id));
$fieldkey = 'nickname';
}
} else {
$user_edit = $id eq '' ? $user : $slashdb->getUser($id);
$fieldkey = 'uid';
}
my $hi = $constants->{comment_maxscore} - $constants->{comment_minscore};
my $lo = -$hi;
my @range = map { $_ > 0 ? "+$_" : $_ } ($lo .. $hi);
my @reasons = ( );
my %reason_select = ( );
if ($constants->{m1}) {
my $mod_reader = getObject("Slash::$constants->{m1_pluginname}", { db_type => 'reader' });
my $reasons = $mod_reader->getReasons();
for my $id (sort { $a <=> $b } keys %$reasons) {
push @reasons, $reasons->{$id}{name};
}
# Reason modifiers
for my $reason_name (@reasons) {
my $key = "reason_alter_$reason_name";
$reason_select{$reason_name} = createSelect(
$key, \@range,
$user_edit->{$key} || 0, 1, 1
);
}
}
# Zoo relation modifiers
my %people_select;
my @people = qw(friend foe anonymous fof eof freak fan);
for (@people) {
my $key = "people_bonus_$_";
$people_select{$_} = createSelect($key, \@range,
$user_edit->{$key} || 0, 1, 1
);
}
# New-user modifier
my $new_user_bonus_select = createSelect('new_user_bonus', \@range,
$user_edit->{new_user_bonus} || 0, 1, 1);
my $new_user_percent_select = createSelect('new_user_percent',
[( 1..15, 20, 25, 30, 35, 40, 45, 50, 55,
60, 65, 70, 75, 80, 85, 90, 95 )],
$user_edit->{new_user_percent} || 100, 1, 1);
# Karma modifier
my $karma_bonus = createSelect('karma_bonus', \@range,
$user_edit->{karma_bonus} || 0, 1, 1);
# Subscriber modifier
my $subscriber_bonus = createSelect('subscriber_bonus', \@range,
$user_edit->{subscriber_bonus} || 0, 1, 1);
# Length modifier
my $small_length_bonus_select = createSelect('clsmall_bonus', \@range,
$user_edit->{clsmall_bonus} || 0, 1, 1);
my $long_length_bonus_select = createSelect('clbig_bonus', \@range,
$user_edit->{clbig_bonus} || 0, 1, 1);
return if isAnon($user_edit->{uid}) && ! $admin_flag;
$admin_block = getUserAdmin($id, $fieldkey, 1) if $admin_flag;
$title = getTitle('editComm_title');
$formats = $slashdb->getDescriptions('commentmodes');
$commentmodes_select=createSelect('umode', $formats, $user_edit->{mode}, 1);
$formats = $slashdb->getDescriptions('sortcodes');
$commentsort_select = createSelect(
'commentsort', $formats, $user_edit->{commentsort}, 1
);
$formats = $slashdb->getDescriptions('threshcodes');
$uthreshold_select = createSelect(
'uthreshold', $formats, $user_edit->{threshold}, 1
);
$formats = $slashdb->getDescriptions('threshcodes');
$highlightthresh_select = createSelect(
'highlightthresh', $formats, $user_edit->{highlightthresh}, 1
);
$user_edit->{bytelimit} = $constants->{defaultbytelimit}
if $user_edit->{bytelimit} < 0 || $user_edit->{bytelimit} > 7;
my $bytelimit_desc = $user_edit->{is_subscriber} ? 'bytelimit' : 'bytelimit_sub';
$formats = $slashdb->getDescriptions($bytelimit_desc);
$bytelimit_select = createSelect(
'bytelimit', $formats, $user_edit->{bytelimit}, 1
);
my $h_check = $user_edit->{hardthresh} ? $constants->{markup_checked_attribute} : '';
my $r_check = $user_edit->{reparent} ? $constants->{markup_checked_attribute} : '';
my $n_check = $user_edit->{noscores} ? $constants->{markup_checked_attribute} : '';
my $s_check = $user_edit->{nosigs} ? $constants->{markup_checked_attribute} : '';
my $b_check = $user_edit->{nobonus} ? $constants->{markup_checked_attribute} : '';
my $sb_check = $user_edit->{nosubscriberbonus} ? $constants->{markup_checked_attribute} : '';
my $p_check = $user_edit->{postanon} ? $constants->{markup_checked_attribute} : '';
my $nospell_check = $user_edit->{no_spell} ? $constants->{markup_checked_attribute} : '';
my $s_mod_check = $user_edit->{mod_with_comm} ? $constants->{markup_checked_attribute} : '';
my $s_m2_check = $user_edit->{m2_with_mod} ? $constants->{markup_checked_attribute} : '';
my $s_m2c_check = $user_edit->{m2_with_comm_mod} ? $constants->{markup_checked_attribute} : '';
$formats = $slashdb->getDescriptions('postmodes');
$posttype_select = createSelect(
'posttype', $formats, $user_edit->{posttype}, 1
);
slashDisplay('editComm', {
title => $title,
admin_block => $admin_block,
user_edit => $user_edit,
h_check => $h_check,
r_check => $r_check,
n_check => $n_check,
s_check => $s_check,
b_check => $b_check,
sb_check => $sb_check,
p_check => $p_check,
s_mod_check => $s_mod_check,
s_m2_check => $s_m2_check,
s_m2c_check => $s_m2c_check,
nospell_check => $nospell_check,
commentmodes_select => $commentmodes_select,
commentsort_select => $commentsort_select,
highlightthresh_select => $highlightthresh_select,
uthreshold_select => $uthreshold_select,
posttype_select => $posttype_select,
reasons => \@reasons,
reason_select => \%reason_select,
people => \@people,
people_select => \%people_select,
new_user_percent_select => $new_user_percent_select,
new_user_bonus_select => $new_user_bonus_select,
note => $note,
karma_bonus => $karma_bonus,
subscriber_bonus => $subscriber_bonus,
small_length_bonus_select => $small_length_bonus_select,
long_length_bonus_select => $long_length_bonus_select,
bytelimit_select => $bytelimit_select,
});
}
#################################################################
sub saveUserAdmin {
my($hr) = @_;
my $slashdb = getCurrentDB();
my $form = getCurrentForm();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my($user_edits_table, $user_edit) = ({}, {});
my $author_flag;
my $note = '';
my $srcid;
my $id;
my $user_editfield_flag;
my $banned = 0;
my $banref;
if ($form->{uid}) {
$user_editfield_flag = 'uid';
$id = $form->{uid};
$user_edit = $slashdb->getUser($id);
$srcid = $id;
} elsif ($form->{subnetid}) {
$user_editfield_flag = 'subnetid';
($id, $user_edit->{subnetid}) = ($form->{subnetid}, $form->{subnetid});
$user_edit->{nonuid} = 1;
$srcid = convert_srcid(subnetid => $id);
} elsif ($form->{ipid}) {
$user_editfield_flag = 'ipid';
($id, $user_edit->{ipid}) = ($form->{ipid}, $form->{ipid});
$user_edit->{nonuid} = 1;
$srcid = convert_srcid(ipid => $id);
} elsif ($form->{md5id}) {
$user_editfield_flag = 'md5id';
my $fieldname = $form->{fieldname} || 'md5id';
($id, $user_edit->{$fieldname})
= ($form->{md5id}, $form->{md5id});
warn "form field md5id specified, no srcid saving possible";
} elsif ($form->{srcid}) {
$user_editfield_flag = 'srcid';
my $fieldname = $form->{fieldname} || 'srcid';
($id, $user_edit->{$fieldname})
= ($form->{srcid}, $form->{srcid});
$srcid = $id;
} else {
# If we were not fed valid data, don't do anything.
return ;
}
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $all_al2types = $reader->getAL2Types;
my $al2_change = { };
# First, get a hash of what aclams (AL2's and ACLs) this user
# had when the previous admin page was loaded.
# XXXSRCID Right now acl_old is just calculated for debugging
# printing purposes, not actually used.
my @al2_old = ( );
@al2_old =
@{ $form->{al2_old_multiple} } if $form->{al2_old_multiple};
my %al2_old = ( map { ($_, 1) } @al2_old );
my @acl_old = ( );
@acl_old =
@{ $form->{acl_old_multiple} } if $form->{acl_old_multiple};
my %acl_old = ( map { ($_, 1) } @acl_old );
# Next, get the list of the new data submitted. Separate
# it out into AL2's which are legitimate. Anything left
# over is an ACL.
my @al2_new_formfields = ( );
@al2_new_formfields = @{ $form->{aclams_new_multiple} } if $form->{aclams_new_multiple};
my @al2_new_submitted = map { s/^aclam_//; $_ } @al2_new_formfields;
my @al2_new = grep { exists $all_al2types->{$_} } @al2_new_submitted;
my %al2_new = ( map { ($_, 1) } @al2_new );
my @acl_new = grep { !$al2_new{$_} } @al2_new_submitted;
my %acl_new = ( map { ($_, 1) } @acl_new );
# Find out what changed for AL2's.
for my $al2 (@al2_old, @al2_new) {
next if defined($al2_old{$al2}) && defined($al2_new{$al2})
&& $al2_old{$al2} == $al2_new{$al2};
$al2_change->{$al2} = $al2_new{$al2} ? 1 : 0;
}
#print STDERR "al2_change for '$srcid': " . Dumper($al2_change);
# If there's a comment, throw that in.
if ($form->{al2_new_comment}) {
$al2_change->{comment} = $form->{al2_new_comment};
}
$al2_change = undef if !keys %$al2_change;
# Find out what changed for ACL's.
my $acl_change = { };
for my $acl (@acl_old, @acl_new) {
next if $acl_old{$acl} == $acl_new{$acl};
$acl_change->{$acl} = $acl_new{$acl} ? 1 : 0;
}
$acl_change = undef if !keys %$acl_change;
if ($user->{is_admin} && $srcid) {
$slashdb->setAL2($srcid, $al2_change);
}
if ($user->{is_admin} && ($user_editfield_flag eq 'uid' ||
$user_editfield_flag eq 'nickname')) {
# This admin user cannot assign a seclev higher than he/she
# already has.
my $seclev = $form->{seclev};
$seclev = $user->{seclev} if $seclev > $user->{seclev};
$user_edits_table->{seclev} = $seclev;
$user_edits_table->{section} = $form->{section};
$user_edits_table->{author} = $form->{author} ? 1 : 0 ;
$user_edits_table->{defaultpoints} = $form->{defaultpoints};
$user_edits_table->{tokens} = $form->{tokens};
$user_edits_table->{tag_clout} = $form->{tag_clout};
$user_edits_table->{m2info} = $form->{m2info};
$user_edits_table->{acl} = $acl_change if $acl_change;
$user_edits_table->{shill_static_marquee} = $form->{shill_static_marquee} ? 1 : undef;
$user_edits_table->{u2_friends_bios} = $form->{u2_friends_bios} ? 1 : undef;
$user_edits_table->{shill_rss_url} = $form->{shill_rss_url} ? $form->{shill_rss_url} : undef;
my $author = $slashdb->getAuthor($id);
my $was_author = ($author && $author->{author}) ? 1 : 0;
$slashdb->setUser($id, $user_edits_table);
$note .= getMessage('saveuseradmin_saveduser', { field => $user_editfield_flag, id => $id });
if ($was_author xor $user_edits_table->{author}) {
# A frequently-asked question for new Slash admins is
# why their authors aren't showing up immediately.
# Give them some help here with an informative message.
$note .= getMessage('saveuseradmin_authorchg', {
basedir => $slashdb->getDescriptions("site_info")
->{base_install_directory},
virtuser => $slashdb->{virtual_user},
});
}
}
if (!$user_edit->{nonuid}) {
if ($form->{expired} && $form->{expired} eq 'on') {
# $slashdb->setExpired($user_edit->{uid});
} else {
# $slashdb->setUnexpired($user_edit->{uid});
}
}
my $data = { uid => $id };
$data->{note} = $note if defined $note;
showInfo($data);
}
#################################################################
sub savePasswd {
my($hr) = @_;
my $note = $hr->{noteref} || undef;
my $slashdb = getCurrentDB();
my $form = getCurrentForm();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $error_flag = 0;
my $user_edit = {};
my $uid;
my $user_edits_table = {};
if ($user->{is_admin}) {
$uid = $form->{uid} || $user->{uid};
} else {
$uid = ($user->{uid} == $form->{uid}) ? $form->{uid} : $user->{uid};
}
$user_edit = $slashdb->getUser($uid);
if (!$user_edit->{nickname}) {
$$note .= getError('cookie_err', { titlebar => 0 }, 0, 1)
if $note;
$error_flag++;
}
if ($form->{pass1} ne $form->{pass2}) {
$$note .= getError('saveuser_passnomatch_err', { titlebar => 0 }, 0, 1)
if $note;
$error_flag++;
}
if (!$form->{pass1} || length $form->{pass1} < 6) {
$$note .= getError('saveuser_passtooshort_err', { titlebar => 0 }, 0, 1)
if $note;
$error_flag++;
}
if (!$user->{is_admin}){
# not an admin -- check old password before changing passwd
my $return_uid = $slashdb->getUserAuthenticate($uid, $form->{oldpass}, 1);
if (!$return_uid || $return_uid != $uid) {
$$note .= getError('saveuser_badoldpass_err', { titlebar => 0 }, 0, 1)
if $note;
$error_flag++;
}
}
if (! $error_flag) {
$user_edits_table->{passwd} = $form->{pass1} if $form->{pass1};
$user_edits_table->{session_login} = $form->{session_login};
$user_edits_table->{cookie_location} = $form->{cookie_location};
# changed pass, so delete all logtokens
$slashdb->deleteLogToken($form->{uid}, 1);
if ($user->{admin_clearpass}
&& !$user->{state}{admin_clearpass_thisclick}) {
# User is an admin who sent their password in the clear
# some time ago; now that it's been changed, we'll forget
# about that incident, unless this click was sent in the
# clear as well.
$user_edits_table->{admin_clearpass} = '';
}
getOtherUserParams($user_edits_table);
$slashdb->setUser($uid, $user_edits_table) ;
$$note .= getMessage('saveuser_passchanged_msg',
{ nick => $user_edit->{nickname}, uid => $user_edit->{uid} },
0, 1) if $note;
# only set cookie if user is current user
if ($form->{uid} eq $user->{uid}) {
$user->{logtoken} = bakeUserCookie($uid, $slashdb->getLogToken($form->{uid}, 1));
setCookie('user', $user->{logtoken}, $user_edits_table->{session_login});
}
}
return $error_flag;
}
#################################################################
sub saveUser {
my($hr) = @_;
my $slashdb = getCurrentDB();
my $form = getCurrentForm();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $gSkin = getCurrentSkin();
my $plugins = $slashdb->getDescriptions('plugins');
my $uid;
my $user_editfield_flag;
$uid = $user->{is_admin} && $form->{uid} ? $form->{uid} : $user->{uid};
my $user_edit = $slashdb->getUser($uid);
my($note, $formname);
$note .= getMessage('savenickname_msg', {
nickname => $user_edit->{nickname},
}, 1);
if (!$user_edit->{nickname}) {
$note .= getError('cookie_err', 0, 1);
}
# Check to ensure that if a user is changing his email address, that
# it doesn't already exist in the userbase.
if ($user_edit->{realemail} ne $form->{realemail}) {
if ($slashdb->existsEmail($form->{realemail})) {
$note .= getError('emailexists_err', 0, 1);
$form->{realemail} = $user_edit->{realemail}; # can't change!
}
}
my(%extr, $err_message, %limit);
$limit{sig} = 120; # schema is 200, give an extra buffer for domain tags
$limit{bio} = $constants->{users_bio_length} || 1024; # can be up to 2^16
for my $key (keys %limit) {
my $dat = chopEntity($form->{$key}, $limit{$key});
$dat = strip_html($dat);
$dat = balanceTags($dat, { deep_nesting => 2, length => $limit{$key} });
$dat = addDomainTags($dat) if $dat;
# If the sig becomes too long to fit (domain tagging causes
# string expansion and tag balancing can too), warn the user to
# use shorter domain names and don't save their change.
if ($key eq 'sig' && defined($dat) && length($dat) > 200) {
print getError('sig_too_long_err');
$extr{sig} = undef;
}
# really, comment filters should ignore short length IMO ... oh well.
if (length($dat) > 1 && ! filterOk('comments', 'postersubj', $dat, \$err_message)) {
print getError('filter message', {
err_message => $err_message,
item => $key,
});
$extr{$key} = undef;
} elsif (! compressOk('comments', 'postersubj', $dat)) {
print getError('compress filter', {
ratio => 'postersubj',
item => $key,
});
$extr{$key} = undef;
} else {
$extr{$key} = $dat;
}
}
# We should do some conformance checking on a user's pubkey,
# make sure it looks like one of the known types of public
# key. Until then, just make sure it doesn't have HTML.
$form->{pubkey} = $plugins->{'PubKey'} ? strip_nohtml($form->{pubkey}, 1) : '';
my $homepage = $form->{homepage};
$homepage = '' if $homepage eq 'http://';
$homepage = fudgeurl($homepage);
$homepage = URI->new_abs($homepage, $gSkin->{absolutedir})
->canonical
->as_string if $homepage ne '';
$homepage = substr($homepage, 0, 100) if $homepage ne '';
my $calendar_url = $form->{calendar_url};
if (length $calendar_url) {
# fudgeurl() doesn't like webcal; will remove later anyway
$calendar_url =~ s/^webcal/http/i;
$calendar_url = fudgeurl($calendar_url);
$calendar_url = URI->new_abs($calendar_url, $gSkin->{absolutedir})
->canonical
->as_string if $calendar_url ne '';
$calendar_url =~ s|^http://||i;
$calendar_url = substr($calendar_url, 0, 200) if $calendar_url ne '';
}
# for the users table
my $user_edits_table = {
homepage => $homepage,
realname => $form->{realname},
pubkey => $form->{pubkey},
copy => $form->{copy},
quote => $form->{quote},
calendar_url => $calendar_url,
yahoo => $form->{yahoo},
jabber => $form->{jabber},
aim => $form->{aim},
aimdisplay => $form->{aimdisplay},
icq => $form->{icq},
playing => $form->{playing},
mobile_text_address => $form->{mobile_text_address},
};
if ($constants->{wow}) {
my $wowdb = getObject("Slash::WoW");
if ($wowdb) {
$user_edits_table->{wow_main_name} = "\L\u$form->{wow_main_name}";
$user_edits_table->{wow_main_realm} = $form->{wow_main_realm};
my $charid = $wowdb->getCharidCreate($user_edits_table->{wow_main_realm},
$user_edits_table->{wow_main_name});
$wowdb->setChar($charid, { uid => $uid }, { if_unclaimed => 1 }) if $charid;
}
}
for (keys %extr) {
$user_edits_table->{$_} = $extr{$_} if defined $extr{$_};
}
# don't want undef, want to be empty string so they
# will overwrite the existing record
for (keys %$user_edits_table) {
$user_edits_table->{$_} = '' unless defined $user_edits_table->{$_};
}
if ($user_edit->{realemail} ne $form->{realemail}) {
$user_edits_table->{realemail} =
chopEntity($form->{realemail}, 50);
my $new_fakeemail = ''; # at emaildisplay 0, don't show any email address
if ($user->{emaildisplay}) {
$new_fakeemail = getArmoredEmail($uid, $user_edits_table->{realemail})
if $user->{emaildisplay} == 1;
$new_fakeemail = $user_edits_table->{realemail}
if $user->{emaildisplay} == 2;
}
$user_edits_table->{fakeemail} = $new_fakeemail;
$note .= getMessage('changeemail_msg', {
realemail => $user_edit->{realemail}
}, 1);
my $saveuser_emailtitle = getTitle('saveUser_email_title', {
nickname => $user_edit->{nickname},
realemail => $form->{realemail}
}, 1);
my $saveuser_email_msg = getMessage('saveuser_email_msg', {
nickname => $user_edit->{nickname},
realemail => $form->{realemail}
}, 1);
sendEmail($form->{realemail}, $saveuser_emailtitle, $saveuser_email_msg);
doEmail($uid, $saveuser_emailtitle, $saveuser_email_msg);
}
getOtherUserParams($user_edits_table);
$slashdb->setUser($uid, $user_edits_table);
editUser({ uid => $uid, note => $note });
}
#################################################################
sub saveComm {
my($hr) = @_;
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
my $form = getCurrentForm();
my $constants = getCurrentStatic();
my($uid, $user_fakeemail);
if ($user->{is_admin}) {
$uid = $form->{uid} || $user->{uid};
} else {
$uid = ($user->{uid} == $form->{uid}) ?
$form->{uid} : $user->{uid};
}
# Do the right thing with respect to the chosen email display mode
# and the options that can be displayed.
my $user_edit = $slashdb->getUser($uid);
my $new_fakeemail = ''; # at emaildisplay 0, don't show any email address
if ($form->{emaildisplay}) {
$new_fakeemail = getArmoredEmail($uid) if $form->{emaildisplay} == 1;
$new_fakeemail = $user_edit->{realemail} if $form->{emaildisplay} == 2;
}
my $name = $user->{seclev} && $form->{name} ?
$form->{name} : $user->{nickname};
my $note = getMessage('savenickname_msg',
{ nickname => $name });
print getError('cookie_err') if isAnon($uid) || !$name;
# Take care of the lists
# Enforce Ranges for variables that need it
$form->{commentlimit} = 0 if $form->{commentlimit} < 1;
my $cl_max = $constants->{comment_commentlimit} || 0;
$form->{commentlimit} = $cl_max if $cl_max > 0 && $form->{commentlimit} > $cl_max;
$form->{commentspill} = 0 if $form->{commentspill} < 1;
# For some of these values, namely the ones that we happen to
# know get stored in users_param, we change them to 'undef'
# if they are the default value. This deletes them from the
# users_param table, which has the same effect as storing the
# default except it's faster all around. If we ever change
# the schema to promote these fields from params into a
# proper users_* table, then this will no longer be correct.
# See prepareUser().
my $max = $constants->{comment_maxscore} - $constants->{comment_minscore};
my $min = -$max;
my $karma_bonus = ($form->{karma_bonus} !~ /^[\-+]?\d+$/) ? "+1" : $form->{karma_bonus};
my $subscriber_bonus = ($form->{subscriber_bonus} !~ /^[\-+]?\d+$/) ? "+1" : $form->{subscriber_bonus};
my $new_user_bonus = ($form->{new_user_bonus} !~ /^[\-+]?\d+$/) ? 0 : $form->{new_user_bonus};
my $new_user_percent = (($form->{new_user_percent} <= 100 && $form->{new_user_percent} >= 0)
? $form->{new_user_percent}
: 100);
my $clsmall_bonus = ($form->{clsmall_bonus} !~ /^[\-+]?\d+$/) ? 0 : $form->{clsmall_bonus};
my $clbig_bonus = ($form->{clbig_bonus} !~ /^[\-+]?\d+$/) ? 0 : $form->{clbig_bonus};
# plum
$form->{d2_comment_q} = (isSubscriber($user_edit) || $user_edit->{seclev} >= 100)
? $form->{d2_comment_q}
: ($form->{d2_comment_q} eq '0')
? 1
: $form->{d2_comment_q};
my $user_edits_table = {
# MC: More D2 neutring
#discussion2 => $form->{discussion2} || undef,
#d2_comment_q => $form->{d2_comment_q} || undef,
#d2_comment_order => $form->{d2_comment_order} || undef,
clsmall => $form->{clsmall},
clsmall_bonus => ($clsmall_bonus || undef),
clbig => $form->{clbig},
clbig_bonus => ($clbig_bonus || undef),
commentlimit => $form->{commentlimit},
bytelimit => $form->{bytelimit},
commentsort => $form->{commentsort},
commentspill => $form->{commentspill},
domaintags => ($form->{domaintags} != 2 ? $form->{domaintags} : undef),
emaildisplay => $form->{emaildisplay} || undef,
fakeemail => $new_fakeemail,
highlightthresh => $form->{highlightthresh},
mode => $form->{umode},
posttype => $form->{posttype},
threshold => $form->{uthreshold},
nosigs => ($form->{nosigs} ? 1 : 0),
reparent => ($form->{reparent} ? 1 : 0),
noscores => ($form->{noscores} ? 1 : 0),
hardthresh => ($form->{hardthresh} ? 1 : 0),
no_spell => ($form->{no_spell} ? 1 : undef),
nobonus => ($form->{nobonus} ? 1 : undef),
nosubscriberbonus => ($form->{nosubscriberbonus} ? 1 : undef),
postanon => ($form->{postanon} ? 1 : undef),
new_user_percent => ($new_user_percent && $new_user_percent != 100
? $new_user_percent : undef),
new_user_bonus => ($new_user_bonus || undef),
karma_bonus => ($karma_bonus ne '+1' ? $karma_bonus : undef),
subscriber_bonus => ($subscriber_bonus || undef),
textarea_rows => ($form->{textarea_rows} != $constants->{textarea_rows}
? $form->{textarea_rows} : undef),
textarea_cols => ($form->{textarea_cols} != $constants->{textarea_cols}
? $form->{textarea_cols} : undef),
user_comment_sort_type => ($form->{user_comment_sort_type} != 2
? $form->{user_comment_sort_type} : undef ),
mod_with_comm => ($form->{mod_with_comm} ? 1 : undef),
m2_with_mod => ($form->{m2_with_mod} ? 1 : undef),
m2_with_comm_mod => ($form->{m2_with_mod_on_comm} ? 1 : undef),
};
# set our default values for the items where an empty-string won't do
my $defaults = {
posttype => 2,
highlightthresh => 4,
reparent => 1,
commentlimit => 100,
commentspill => 50,
mode => 'thread'
};
my $mod_reader = getObject("Slash::$constants->{m1_pluginname}", { db_type => 'reader' });
my @reasons = ( );
my $reasons = $mod_reader->getReasons();
for my $id (sort { $a <=> $b } keys %$reasons) {
push @reasons, $reasons->{$id}{name};
}
for my $reason_name (@reasons) {
my $key = "reason_alter_$reason_name";
my $answer = $form->{$key} || 0;
$answer = 0 if !$answer || $answer !~ /^[\-+]?\d+$/;
$user_edits_table->{$key} = ($answer == 0) ? '' : $answer;
}
for (qw| friend foe anonymous fof eof freak fan |) {
my $answer = $form->{"people_bonus_$_"};
$answer = 0 if $answer !~ /^[\-+]?\d+$/;
$user_edits_table->{"people_bonus_$_"} = ($answer == 0) ? '' : $answer;
}
getOtherUserParams($user_edits_table);
setToDefaults($user_edits_table, {}, $defaults) if $form->{restore_defaults};
$slashdb->setUser($uid, $user_edits_table);
editComm({ uid => $uid, note => $note });
}
#################################################################
sub saveHome {
my($hr) = @_;
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
my $form = getCurrentForm();
my $constants = getCurrentStatic();
my($uid, $error);
if ($user->{is_admin}) {
$uid = $form->{uid} || $user->{uid} ;
} else {
$uid = ($user->{uid} == $form->{uid}) ?
$form->{uid} : $user->{uid};
}
my $edit_user = $slashdb->getUser($uid);
my $name = $user->{seclev} && $form->{name} ?
$form->{name} : $user->{nickname};
$name = substr($name, 0, 20);
my $note = getMessage('savenickname_msg',
{ nickname => $name });
if (isAnon($uid) || !$name) {
my $cookiemsg = getError('cookie_err');
print $cookiemsg;
}
# Using the existing list of slashboxes and the set of
# what's checked and not, build up the new list.
# (New arrivals go at the end.)
my $slashboxes = $edit_user->{slashboxes};
# Only go through all this if the user clicked save,
# not "Restore Slashbox Defaults"!
my($boxes, $skinBoxes) = $slashdb->getPortalsCommon();
my $default_slashboxes_textlist = join ",",
@{$skinBoxes->{$constants->{mainpage_skid}}};
if (!$form->{restore_slashbox_defaults}) {
$slashboxes = $default_slashboxes_textlist if !$slashboxes;
my @slashboxes = split /,/, $slashboxes;
my %slashboxes = ( );
for my $i (0..$#slashboxes) {
$slashboxes{$slashboxes[$i]} = $i;
}
# Add new boxes in.
for my $key (sort grep /^showbox_/, keys %$form) {
my($bid) = $key =~ /^showbox_(\w+)$/;
next if length($bid) < 1 || length($bid) > 30 || $bid !~ /^\w+$/;
if (! exists $slashboxes{$bid}) {
$slashboxes{$bid} = 999; # put it at the end
}
}
# Remove any boxes that weren't checked.
for my $bid (@slashboxes) {
delete $slashboxes{$bid} unless $form->{"showbox_$bid"};
}
for my $key (sort grep /^dynamic_/, keys %$form) {
my($bid) = $key =~ /^dynamic_(.+)$/;
next if length($bid) < 1;
if (! exists $slashboxes{$bid}) {
$slashboxes{$bid} = 999;
}
}
@slashboxes = sort {
$slashboxes{$a} <=> $slashboxes{$b}
||
$a cmp $b
} keys %slashboxes;
# This probably should be a var (and appear in tilded_customize_msg)
$#slashboxes = 19 if $#slashboxes > 19;
$slashboxes = join ",", @slashboxes;
}
# If we're right back to the default, that means the
# empty string.
if ($slashboxes eq $default_slashboxes_textlist) {
$slashboxes = "";
}
# Set the story_never and story_always fields.
my $author_hr = $slashdb->getDescriptions('authors');
my $tree = $slashdb->getTopicTree();
my(@story_never_topic, @story_never_author, @story_never_nexus);
my(@story_always_topic, @story_always_author);
my(@story_always_nexus, @story_full_brief_nexus, @story_brief_always_nexus, @story_full_best_nexus, @story_brief_best_nexus);
my($story_topic_all, $story_author_all, $story_nexus_all) = (0, 0, 0);
# Topics are either present (value=2) or absent (value=0). If absent,
# push them onto the never list. Otherwise, do nothing. (There's no
# way to have an "always" topic, at the moment.) If the hidden
# field topictids_present is false, then there are no topic tids,
# skip this.
if ($form->{topictids_present}) {
for my $tid (
sort { $a <=> $b }
grep { !$tree->{$_}{nexus} }
keys %$tree
) {
my $key = "topictid$tid";
$story_topic_all++;
if (!$form->{$key}) { push @story_never_topic, $tid }
}
}
# Authors are either present (value=2) or absent (value=0). If
# absent, push them onto the never list. Otherwise, do nothing.
# (There's no way to have an "always" author, at the moment.)
for my $aid (sort { $a <=> $b } keys %$author_hr) {
my $key = "aid$aid";
$story_author_all++;
if (!$form->{$key}) { push @story_never_author, $aid }
}
# Nexuses can have value 0, 1, 2, 3, 4, 5.
# 0 means the never list,
# 1 means brief view of mainpage articles only
# 2 means full view of mainpage articles only
# 3 means brief view of all content
# 4 means full view of mainpage content, brief view of sectional
# 5 means full view of all content
for my $tid (
sort { $a <=> $b }
map { /^nexustid(\d+)$/; $1 }
grep { /^nexustid\d+$/ }
keys %$form
) {
my $key = "nexustid$tid";
next unless $tid && $tree->{$tid} && $tree->{$tid}{nexus};
$story_nexus_all++;
if (!$form->{$key}) { push @story_never_nexus, $tid }
elsif ($form->{$key} == 5 ) { push @story_always_nexus, $tid }
elsif ($form->{$key} == 4 ) { push @story_full_brief_nexus, $tid }
elsif ($form->{$key} == 3 ) { push @story_brief_always_nexus, $tid }
elsif ($form->{$key} == 2 ) { push @story_full_best_nexus, $tid }
elsif ($form->{$key} == 1 ) { push @story_brief_best_nexus, $tid }
}
#use Data::Dumper; $Data::Dumper::Sortkeys = 1; print STDERR scalar(localtime) . " s_n_t '@story_never_topic' s_n_a '@story_never_author' s_n_n '@story_never_nexus' s_a_n '@story_always_nexus' form: " . Dumper($form);
# Sanity check.
$#story_never_topic = 299 if $#story_never_topic > 299;
$#story_never_author = 299 if $#story_never_author > 299;
$#story_never_nexus = 299 if $#story_never_nexus > 299;
$#story_always_topic = 299 if $#story_always_topic > 299;
$#story_always_author = 299 if $#story_always_author > 299;
$#story_always_nexus = 299 if $#story_always_nexus > 299;
$#story_full_brief_nexus = 299 if $#story_full_brief_nexus > 299;
$#story_brief_always_nexus = 299 if $#story_brief_always_nexus > 299;
$#story_brief_best_nexus = 299 if $#story_brief_best_nexus > 299;
$#story_full_best_nexus = 299 if $#story_full_best_nexus > 299;
my $story_never_topic = join ",", @story_never_topic;
$story_never_topic = ($constants->{subscribe} && $user->{is_subscriber})
? checkList($story_never_topic, 1024)
: checkList($story_never_topic);
my $story_never_author = checkList(join ",", @story_never_author);
my $story_never_nexus = checkList(join ",", @story_never_nexus);
my $story_always_topic = checkList(join ",", @story_always_topic);
$story_always_topic = ($constants->{subscribe} && $user->{is_subscriber})
? checkList($story_always_topic, 1024)
: checkList($story_always_topic);
my $story_always_author = checkList(join ",", @story_always_author);
my $story_always_nexus = checkList(join ",", @story_always_nexus);
my $story_full_brief_nexus = checkList(join ",", @story_full_brief_nexus);
my $story_brief_always_nexus = checkList(join ",", @story_brief_always_nexus);
my $story_brief_best_nexus = checkList(join ",", @story_brief_best_nexus);
my $story_full_best_nexus = checkList(join ",", @story_full_best_nexus);
my $user_edits_table = {
story_never_topic => $story_never_topic,
story_never_author => $story_never_author,
story_never_nexus => $story_never_nexus,
story_always_topic => $story_always_topic,
story_always_author => $story_always_author,
story_always_nexus => $story_always_nexus,
story_brief_always_nexus => $story_brief_always_nexus,
story_full_brief_nexus => $story_full_brief_nexus,
story_full_best_nexus => $story_full_best_nexus,
story_brief_best_nexus => $story_brief_best_nexus,
slashboxes => checkList($slashboxes, 1024),
maxstories => 30, # XXXSKIN fix this later
noboxes => ($form->{useslashboxes} ? 0 : 1),
lowbandwidth => ($form->{lowbandwidth} ? 1 : 0),
simpledesign => ($form->{simpledesign} ? 1 : 0),
noicons => ($form->{noicons} ? 1 : 0),
willing => ($form->{willing} ? 1 : 0),
index_classic => ($form->{index_classic} ? 1 : undef),
};
if (defined $form->{tzcode} && defined $form->{tzformat}) {
$user_edits_table->{tzcode} = $form->{tzcode};
$user_edits_table->{dfid} = $form->{tzformat};
$user_edits_table->{dst} = $form->{dst};
}
# Force the User Space area to contain only known-good HTML tags.
# Unfortunately the cookie login model makes it just too risky
# to allow scripts in here; CSS's steal passwords. There are
# no known vulnerabilities at this time, but a combination of the
# social engineering taking place (inviting users to put Javascript
# from websites in here, and making available script URLs for that
# purpose), plus the fact that this could be used to amplify the
# seriousness of any future vulnerabilities, means it's way past
# time to shut this feature down. - Jamie 2002/03/06
# it's a VARCHAR ...
my $mylinks_limit = 255;
$user_edits_table->{mylinks} = balanceTags(strip_html(
chopEntity($form->{mylinks} || '', $mylinks_limit)
), { deep_nesting => 2, length => $mylinks_limit });
$user_edits_table->{mylinks} = '' unless defined $user_edits_table->{mylinks};
$error = 1;
# must select at least 1/4 of nexuses, topics, authors
if ( scalar(@story_never_author) > ($story_author_all * 3/4) ) {
$note = getError('editHome_too_many_disabled');
} elsif ( scalar(@story_never_nexus) > ($story_nexus_all * 3/4) ) {
$note = getError('editHome_too_many_disabled');
} elsif ( scalar(@story_never_topic) > ($story_topic_all * 3/4) ) {
$note = getError('editHome_too_many_disabled');
} else {
$error = 0;
}
unless ($error) {
# If a user is unwilling to moderate, we should cancel all points, lest
# they be preserved when they shouldn't be.
if (!isAnon($uid) && !$form->{willing}) {
$slashdb->setUser($uid, { points => 0 });
}
getOtherUserParams($user_edits_table);
if ($form->{restore_defaults}) {
setToDefaults($user_edits_table, {}, {
maxstories => 30,
tzcode => "EST",
# XXX shouldn't this reset ALL the defaults,
# not just these two?
});
}
if ($form->{restore_slashbox_defaults}) {
setToDefaults($user_edits_table, {
'story_never_topic' => 1,
'story_never_author' => 1,
'story_never_nexus' => 1,
'story_always_topic' => 1,
'story_always_author' => 1,
'story_always_nexus' => 1,
'story_full_brief_nexus' => 1,
'story_brief_always_nexus' => 1,
'story_full_best_nexus' => 1,
'story_brief_best_nexus' => 1,
'maxstories' => 1,
'noboxes' => 1,
'light' => 1,
'noicons' => 1,
'willing' => 1
}, { slashboxes => "" });
}
#print scalar(localtime) . " uet: " . Dumper($user_edits_table);
$slashdb->setUser($uid, $user_edits_table);
}
editHome({ uid => $uid, note => $note });
}
#################################################################
# A generic way for a site to allow users to edit data about themselves.
# Most useful when your plugin or theme wants to let the user change
# minor settings but you don't want to write a whole new version
# of users.pl to provide a user interface. The user can save any
# param of the format "opt_foo", as long as "foo" shows up in
# getMiscUserOpts which lists all the misc opts that this user can edit.
# This is *not* protected by formkeys (yet), so assume attackers can make
# users click and accidentally edit their own settings: no really important
# data should be stored in this way.
sub editMiscOpts {
my($hr) = @_;
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
my $constants = getCurrentStatic();
my $note = $hr->{note} || "";
return if $user->{is_anon}; # shouldn't be, but can't hurt to check
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
my $edit_user = $slashdb->getUser($user->{uid});
my $title = getTitle('editMiscOpts_title');
my $opts = $slashdb->getMiscUserOpts();
for my $opt (@$opts) {
my $opt_name = "opt_" . $opt->{name};
$opt->{checked} = $edit_user->{$opt_name} ? 1 : 0;
}
slashDisplay('editMiscOpts', {
# useredit => $user_edit,
title => $title,
opts => $opts,
note => $note,
});
}
#################################################################
#
sub saveMiscOpts {
my($hr) = @_;
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
my $form = getCurrentForm();
my $constants = getCurrentStatic();
return if $user->{is_anon}; # shouldn't be, but can't hurt to check
my $edit_user = $slashdb->getUser($user->{uid});
my %opts_ok_hash = ( );
my $opts = $slashdb->getMiscUserOpts();
for my $opt (@$opts) {
$opts_ok_hash{"opt_$opt->{name}"} = 1;
}
my $update = { };
for my $opt (grep /^opt_/, keys %$form) {
next unless $opts_ok_hash{$opt};
$update->{$opt} = $form->{$opt} ? 1 : 0;
}
# Make the changes.
$slashdb->setUser($edit_user->{uid}, $update);
# Inform the user the change was made. Since we don't
# require formkeys, we always want to print a message to
# make sure the user sees what s/he did. This is done
# by passing in a note which ends up passed to the
# editMiscOpts template, which displays it.
editMiscOpts({ note => getMessage('savemiscopts_msg') });
}
#################################################################
sub listReadOnly {
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $readonlylist = $reader->getAL2List('nopost');
slashDisplay('listReadOnly', {
readonlylist => $readonlylist,
});
}
#################################################################
sub listBanned {
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $bannedlist = $reader->getAL2List('ban');
slashDisplay('listBanned', {
bannedlist => $bannedlist,
});
}
#################################################################
sub topAbusers {
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $topabusers = $reader->getTopAbusers();
slashDisplay('topAbusers', {
topabusers => $topabusers,
});
}
#################################################################
sub listAbuses {
my $user = getCurrentUser();
my $form = getCurrentForm();
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $constants = getCurrentStatic();
my $abuses = $reader->getAbuses($form->{key}, $form->{abuseid});
slashDisplay('listAbuses', {
abuseid => $form->{abuseid},
abuses => $abuses,
});
}
#################################################################
sub forceAccountVerify {
my $user = getCurrentUser();
my $form = getCurrentForm();
my $slashdb = getCurrentDB();
my $constants = getCurrentStatic();
my $uid = $form->{uid};
my $useredit = $slashdb->getUser($uid);
if ($useredit->{uid}) {
my $newpasswd = $slashdb->resetUserAccount($uid);
$slashdb->deleteLogToken($uid, 1);
my $emailtitle = getTitle('reset_acct_email_title', {
nickname => $useredit->{nickname}
}, 1);
my $msg = getMessage('reset_acct_msg', {
newpasswd => $newpasswd,
tempnick => $useredit->{nickname},
}, 1);
$slashdb->setUser($useredit->{uid}, {
waiting_for_account_verify => 1,
account_verify_request_time => $slashdb->getTime()
});
doEmail($useredit->{uid}, $emailtitle, $msg) if $useredit->{uid};
}
print getMessage("reset_acct_complete", { useredit => $useredit }, 1);
}
#################################################################
sub displayForm {
my($hr) = @_;
my $user = getCurrentUser();
my $form = getCurrentForm();
my $slashdb = getCurrentDB();
my $constants = getCurrentStatic();
my $suadmin_flag = $user->{seclev} >= 10000 ? 1 : 0;
print createMenu("users", {
style => 'tabbed',
justify => 'right',
color => 'colored',
tab_selected => $hr->{tab_selected_1} || "",
});
my $op = $hr->{op} || $form->{op} || 'displayform';
my $ops = {
displayform => 'loginForm',
edithome => 'loginForm',
editcomm => 'loginForm',
edituser => 'loginForm',
# mailpasswdform => 'sendPasswdForm',
# newuserform => 'newUserForm',
userclose => 'loginForm',
userlogin => 'loginForm',
editmiscopts => 'loginForm',
savemiscopts => 'loginForm',
default => 'loginForm'
};
$op = 'default' if !defined($ops->{$op});
my($title, $title2, $msg1, $msg2) = ('', '', '', '');
if ($op eq 'userclose') {
$title = getMessage('userclose');
} elsif ($op eq 'displayForm') {
$title = $form->{unickname}
? getTitle('displayForm_err_title')
: getTitle('displayForm_title');
} elsif ($op eq 'mailpasswdform') {
$title = getTitle('mailPasswdForm_title');
} elsif ($op eq 'newuserform') {
$title = getTitle('newUserForm_title');
} else {
$title = getTitle('displayForm_title');
}
$form->{unickname} ||= $form->{newusernick};
if ($form->{newusernick}) {
$title2 = getTitle('displayForm_dup_title');
} else {
$title2 = getTitle('displayForm_new_title');
}
$msg1 = getMessage('dispform_new_msg_1');
if (! $form->{newusernick} && $op eq 'newuserform') {
$msg2 = getMessage('dispform_new_msg_2');
} elsif ($op eq 'displayform' || $op eq 'userlogin') {
$msg2 = getMessage('newuserform_msg');
}
slashDisplay($ops->{$op}, {
newnick => nickFix($form->{newusernick}),
suadmin_flag => $suadmin_flag,
title => $title,
title2 => $title2,
logged_in => $user->{is_anon} ? 0 : 1,
msg1 => $msg1,
msg2 => $msg2
});
}
#################################################################
# this groups all the messages together in
# one template, called "messages;users;default"
sub getMessage {
my($value, $hashref, $nocomm) = @_;
$hashref ||= {};
$hashref->{value} = $value;
return slashDisplay('messages', $hashref,
{ Return => 1, Nocomm => $nocomm });
}
#################################################################
# this groups all the errors together in
# one template, called "errors;users;default"
sub getError {
my($value, $hashref, $nocomm) = @_;
$hashref ||= {};
$hashref->{value} = $value;
return slashDisplay('errors', $hashref,
{ Return => 1, Nocomm => $nocomm });
}
#################################################################
# this groups all the titles together in
# one template, called "users-titles"
sub getTitle {
my($value, $hashref, $nocomm) = @_;
$hashref ||= {};
$hashref->{value} = $value;
return slashDisplay('titles', $hashref,
{ Return => 1, Nocomm => $nocomm });
}
#################################################################
# getUserAdmin - returns a block of HTML text that provides
# information and editing capabilities for admin users.
# Most of this data is already in the getUserAdmin template,
# but really, we should try to get more of this logic into
# that template.
sub getUserAdmin {
my($id, $field, $seclev_field) = @_;
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $logdb = getObject('Slash::DB', { db_type => 'log_slave' });
my $user = getCurrentUser();
my $form = getCurrentForm();
my $constants = getCurrentStatic();
my $slashdb = getCurrentDB();
$id ||= $user->{uid};
my($expired, $uidstruct, $readonly);
my($user_edit, $user_editfield, $ipstruct, $ipstruct_order, $authors, $author_flag, $topabusers, $thresh_select,$section_select);
my $srcid;
my $proxy_check = {};
my @accesshits;
my $user_editinfo_flag = (!$form->{op} || $form->{op} eq 'userinfo'
|| $form->{userinfo} || $form->{saveuseradmin}
) ? 1 : 0;
my $authoredit_flag = ($user->{seclev} >= 10000) ? 1 : 0;
my $sectionref = $reader->getDescriptions('skins');
$sectionref->{''} = getData('all_sections');
$field ||= 'uid';
if ($field eq 'uid') {
$user_edit = $slashdb->getUser($id);
$user_editfield = $user_edit->{uid};
$srcid = convert_srcid( uid => $id );
#$expired = $slashdb->checkExpired($user_edit->{uid}) ? $constants->{markup_checked_attribute} : '';
$ipstruct = $slashdb->getNetIDStruct($user_edit->{uid});
@accesshits = $logdb->countAccessLogHitsInLastX($field, $user_edit->{uid}) if defined($logdb);
$section_select = createSelect('section', $sectionref, $user_edit->{section}, 1);
} elsif ($field eq 'nickname') {
$user_edit = $slashdb->getUser($slashdb->getUserUID($id));
$user_editfield = $user_edit->{nickname};
#$expired = $slashdb->checkExpired($user_edit->{uid}) ? $constants->{markup_checked_attribute} : '';
$ipstruct = $slashdb->getNetIDStruct($user_edit->{uid});
@accesshits = $logdb->countAccessLogHitsInLastX('uid', $user_edit->{uid}) if defined($logdb);
$section_select = createSelect('section', $sectionref, $user_edit->{section}, 1);
} elsif ($field eq 'md5id') {
$user_edit->{nonuid} = 1;
$user_edit->{md5id} = $id;
if ($form->{fieldname} && $form->{fieldname} =~ /^(ipid|subnetid)$/) {
$uidstruct = $slashdb->getUIDStruct($form->{fieldname}, $user_edit->{md5id});
@accesshits = $logdb->countAccessLogHitsInLastX($form->{fieldname}, $user_edit->{md5id}) if defined($logdb);
} else {
$uidstruct = $slashdb->getUIDStruct('md5id', $user_edit->{md5id});
@accesshits = $logdb->countAccessLogHitsInLastX($field, $user_edit->{md5id}) if defined($logdb);
}
} elsif ($field eq 'ipid') {
$user_edit->{nonuid} = 1;
$user_edit->{ipid} = $id;
$srcid = convert_srcid( ipid => $id );
$user_editfield = $id;
$uidstruct = $slashdb->getUIDStruct('ipid', $user_edit->{ipid});
@accesshits = $logdb->countAccessLogHitsInLastX('host_addr', $user_edit->{ipid}) if defined($logdb);
if ($form->{userfield} =~/^\d+\.\d+\.\d+\.(\d+)$/) {
if ($1 ne "0"){
$proxy_check->{available} = 1;
$proxy_check->{results} = $slashdb->checkForOpenProxy($form->{userfield}) if $form->{check_proxy};
}
}
} elsif ($field eq 'subnetid') {
$user_edit->{nonuid} = 1;
$srcid = convert_srcid( ipid => $id );
if ($id =~ /^(\d+\.\d+\.\d+)(?:\.\d)?/) {
$id = $1 . ".0";
$user_edit->{subnetid} = $id;
} else {
$user_edit->{subnetid} = $id;
}
$user_editfield = $id;
$uidstruct = $slashdb->getUIDStruct('subnetid', $user_edit->{subnetid});
@accesshits = $logdb->countAccessLogHitsInLastX($field, $user_edit->{subnetid}) if defined($logdb);
} elsif ($field eq "srcid") {
$user_edit->{nonuid} = 1;
$user_edit->{srcid} = $id;
$srcid = $id;
} else {
$user_edit = $id ? $slashdb->getUser($id) : $user;
$user_editfield = $user_edit->{uid};
$ipstruct = $slashdb->getNetIDStruct($user_edit->{uid});
@accesshits = $logdb->countAccessLogHitsInLastX('uid', $user_edit->{uid}) if defined($logdb);
}
##########
# Put together the array and hashref that the template will need
# to construct the list for display to the admin.
# Note that currently a srcid which is not a uid (i.e. which
# represents an IP address or masked IP network) cannot have
# any ACLs assigned to it. This may change in the future.
# The term "aclam" is used because it has a field set for both
# every ACL and every access modifier (i.e. AL2 bit) that is set
# for this user or srcid.
# For now, ACLs will be listed for IPs as well.
# First get the list of ACLs that can be used.
my $all_acls_ar = $reader->getAllACLNames();
my $all_acls_hr = { map { ( $_, 1 ) } @$all_acls_ar };
# Add in any ACLs selected for this user (just in case
# getAllACLNames is cached and stale).
for my $acl (keys %{$user_edit->{acl}}) {
$all_acls_hr->{$acl} = 1;
}
# Start creating the $all_aclam_hr data, in which the keys are
# the HTML selection names that all begin with aclam_ and the
# the values are their names/descriptions shown to the admin.
# First put all the ACLs into the hash, if we're editing a user.
my $all_aclam_hr = { };
if (!$user_edit->{nonuid}) {
$all_aclam_hr = { map { ( "aclam_$_", "ACL: $_" ) } keys %$all_acls_hr };
}
# Next put in all the al2 types.
my $all_al2types = $reader->getAL2Types;
for my $key (keys %$all_al2types) {
next if $key eq 'comment'; # skip the 'comment' type
$all_aclam_hr->{"aclam_$key"} = $all_al2types->{$key}{title};
}
# Finally, sort the keys of the hash into the order that we
# want them displayed to the admin (ACLs first).
my $all_acls_longkeys_hr = { map { ( "aclam_$_", 1 ) } keys %$all_acls_hr };
my $all_aclam_ar = [
sort {
(exists($all_acls_longkeys_hr->{$a}) ? -1 : 1) <=> (exists($all_acls_longkeys_hr->{$b}) ? -1 : 1)
||
$all_aclam_hr->{$a} cmp $all_aclam_hr->{$b}
} keys %$all_aclam_hr
];
# Now put together the hashref that identifies which of those
# items are selected for this user.
my $user_aclam_hr = { };
for my $acl (keys %{ $user_edit->{acl} }) {
$user_aclam_hr->{"aclam_$acl"} = 1;
}
my $al2_tid_comment = $all_al2types->{comment}{al2tid} || 0;
my $al2_log_ar = [ ];
my $al2_hr = { };
# XXXSRCID Once we get rid of the silly 'md5id' field and all the
# other bizarre backward-compatibility code paths early in this
# function, this won't be necessary, but until then we need this
# sanity check...
if ($srcid) {
# getAL2 works with either a srcids hashref or a single srcid
$al2_hr = $slashdb->getAL2($srcid);
for my $al2 (keys %{ $al2_hr }) {
$user_aclam_hr->{"aclam_$al2"} = 1;
}
$al2_log_ar = $slashdb->getAL2Log($srcid);
}
# Generate al2_nick_hr, which will be populated with keys of all
# the (presumably) admin uids who have logged rows for this al2,
# and values of their nicks.
my $al2_nick_hr = { };
for my $al2_log (@$al2_log_ar) {
my $uid = $al2_log->{adminuid};
next if !$uid; # odd error, might want to flag this
$al2_nick_hr->{$uid} ||= $slashdb->getUser($uid, 'nickname');
}
##########
$user_edit->{author} = ($user_edit->{author} && $user_edit->{author} == 1)
? $constants->{markup_checked_attribute} : '';
if (! $user->{nonuid}) {
my $threshcodes = $reader->getDescriptions('threshcode_values','',1);
$thresh_select = createSelect('defaultpoints', $threshcodes, $user_edit->{defaultpoints}, 1);
}
if (!ref $ipstruct) {
undef $ipstruct;
} else {
@$ipstruct_order = sort { $ipstruct->{$b}{dmin} cmp $ipstruct->{$a}{dmin} } keys %$ipstruct;
}
my $m2total = ($user_edit->{m2fair} || 0) + ($user_edit->{m2unfair} || 0);
if ($m2total) {
$user_edit->{m2unfairpercent} = sprintf("%.2f",
$user_edit->{m2unfair}*100/$m2total);
}
my $mod_total = ($user_edit->{totalmods} || 0) + ($user_edit->{stirred} || 0);
if ($mod_total) {
$user_edit->{stirredpercent} = sprintf("%.2f",
$user_edit->{stirred}*100/$mod_total);
}
if ($constants->{subscribe} and my $subscribe = getObject('Slash::Subscribe')) {
$user_edit->{subscribe_payments} =
$subscribe->getSubscriptionsForUser($user_edit->{uid});
$user_edit->{subscribe_purchases} =
$subscribe->getSubscriptionsPurchasedByUser($user_edit->{uid},{ only_types => [ "grant", "gift" ] });
}
my $ipid = $user_edit->{ipid};
my $subnetid = $user_edit->{subnetid};
my $post_restrictions = {};
my ($subnet_karma, $ipid_karma);
if ($ipid && !$subnetid) {
$ipid = md5_hex($ipid) if length($ipid) != 32;
$proxy_check->{ipid} = $ipid;
$proxy_check->{currently} = $slashdb->getKnownOpenProxy($ipid, "ipid");
# This next call is very slow.
$subnetid = $reader->getSubnetFromIPIDBasedOnComments($ipid);
}
if ($subnetid) {
$subnetid = md5_hex($subnetid) if length($subnetid) != 32;
# These next three calls can be very slow. In fact, getNetIDKarma
# is actually called twice on the same subnetid; if we can cache
# that data somehow that wouldn't be a bad idea.
$post_restrictions = $reader->getNetIDPostingRestrictions("subnetid", $subnetid);
$subnet_karma = $reader->getNetIDKarma("subnetid", $subnetid);
$ipid_karma = $reader->getNetIDKarma("ipid", $ipid) if $ipid;
}
my $clout_types_ar = [ sort grep /\D/, keys %{$slashdb->getCloutTypes} ];
return slashDisplay('getUserAdmin', {
field => $field,
useredit => $user_edit,
srcid => $srcid,
all_aclam_ar => $all_aclam_ar,
all_aclam_hr => $all_aclam_hr,
user_aclam_hr => $user_aclam_hr,
al2_old => $al2_hr,
al2_log => $al2_log_ar,
al2_tid_comment => $al2_tid_comment,
al2_nick => $al2_nick_hr,
userinfo_flag => $user_editinfo_flag,
userfield => $user_editfield,
ipstruct => $ipstruct,
ipstruct_order => $ipstruct_order,
uidstruct => $uidstruct,
accesshits => \@accesshits,
seclev_field => $seclev_field,
expired => $expired,
topabusers => $topabusers,
readonly => $readonly,
thresh_select => $thresh_select,
authoredit_flag => $authoredit_flag,
section_select => $section_select,
all_acls => $all_acls_hr,
proxy_check => $proxy_check,
subnet_karma => $subnet_karma,
ipid_karma => $ipid_karma,
post_restrictions => $post_restrictions,
clout_types_ar => $clout_types_ar,
}, 1);
}
#################################################################
# this is to allow alternate parameters to be specified. pass in
# your hash reference to be passed to setUser(), and this will
# add in those extra parameters. add the parameters to string_param,
# type = otherusersparam, code = name of the param. they will
# be checked for the main user prefs editing screens, and on
# user creation -- pudge
sub getOtherUserParams {
my($data) = @_;
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $user = getCurrentUser();
my $form = getCurrentForm();
my $params = $reader->getDescriptions('otherusersparam');
for my $param (keys %$params) {
if (exists $form->{$param}) {
# set user too for output in this request
$data->{$param} = $user->{$param} = $form->{$param} || undef;
}
}
}
###############################################################
# This modifies a hashref to default values -- if nothing
# else we assume the empty string which clears items in the
# user_param table
#
# takes 3 hashrefs currently
# $data - hashref to change to defaults
# $skip - hashref of keys to skip modifying
# $defaults - hashref of defaults to set to something other
# than the empty string
sub setToDefaults {
my($data, $skip, $defaults) = @_;
foreach my $key (keys %$data) {
next if $skip->{$key};
$data->{$key} = exists $defaults->{$key} ? $defaults->{$key} : "";
}
}
#################################################################
sub getCommentListing {
my ($type, $value,
$min_comment, $time_period, $cc_all, $cc_time_period, $cid_for_time_period,
$non_admin_limit, $admin_time_limit, $admin_non_time_limit,
$options) = @_;
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $slashdb = getCurrentDB();
my $constants = getCurrentStatic();
my $user = getCurrentUser();
my $store_cutoff = $options->{use_uid_cid_cutoff} ? $constants->{store_com_page1_min_cid_for_user_com_cnt} : 0;
my $s_opt = {};
my $num_wanted = 0;
if ($min_comment) {
if ($user->{is_admin}) {
$num_wanted = $admin_non_time_limit;
} else {
$num_wanted = $non_admin_limit;
}
} else {
if ($user->{is_admin}) {
if ($cc_time_period >= $admin_non_time_limit) {
$s_opt->{cid_at_or_after} = $cid_for_time_period;
$num_wanted = $admin_time_limit;
} else {
$num_wanted = $admin_non_time_limit;
if($store_cutoff){
my $min_cid = $reader->getUser($value,
"com_num_".$num_wanted."_at_or_after_cid");
$s_opt->{cid_at_or_after} = $min_cid
if $min_cid && $min_cid =~ /^\d+$/;
}
}
} else {
if ($cc_time_period >= $non_admin_limit ) {
$s_opt->{cid_at_or_after} = $cid_for_time_period;
$num_wanted = $non_admin_limit;
} else {
$num_wanted = $non_admin_limit;
if($store_cutoff){
my $min_cid = $reader->getUser($value,
"com_num_".$num_wanted."_at_or_after_cid");
$s_opt->{cid_at_or_after} = $min_cid
if $min_cid && $min_cid =~ /^\d+$/;
}
}
}
}
if ($type eq "uid") {
my $comments = $reader->getCommentsByUID($value, $num_wanted, $min_comment, $s_opt) if $cc_all;
if ($store_cutoff
&& $comments && $cc_all >= $store_cutoff && $min_comment == 0
&& scalar(@$comments) == $num_wanted) {
my $min_cid = 0;
for my $comment (@$comments) {
$min_cid = $comment->{cid}
if !$min_cid || ($comment->{cid} < $min_cid);
}
if ($min_cid && $min_cid =~/^\d+$/) {
$slashdb->setUser($value, {
"com_num_".$num_wanted."_at_or_after_cid" => $min_cid
});
}
}
return $comments;
} elsif ($type eq "ipid"){
return $reader->getCommentsByIPID($value, $num_wanted, $min_comment, $s_opt) if $cc_all;
} elsif ($type eq "subnetid"){
return $reader->getCommentsBySubnetID($value, $num_wanted, $min_comment, $s_opt) if $cc_all;
} else {
return $reader->getCommentsByIPIDOrSubnetID($value, $num_wanted, $min_comment, $s_opt) if $cc_all;
}
}
createEnvironment();
main();
1;