#!/usr/bin/perl #------------------------------------------------------------------------------ # mwForum - Web-based discussion forum # Copyright (c) 1999-2015 Markus Wichitill # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. #------------------------------------------------------------------------------ use strict; use warnings; no warnings qw(uninitialized redefine); # Imports use TyfMain; use List::Util qw(first); #------------------------------------------------------------------------------ # Init my ( $m, $cfg, $lng, $user, $userId ) = TyfMain->new( $_[0] ); # Check if user is admin $user->{admin} or $m->error('errNoAccess'); # Print header $m->printHeader(); # Get CGI parameters my $page = $m->paramInt('pg') || 1; my $search = $m->paramStr('search') || ""; my $field = $m->paramStrId('field') || $m->getVar( 'usrAdmFld', $userId ) || 'realName'; my $sort = $m->paramStrId('sort') || $m->getVar( 'usrAdmSrt', $userId ) || 'userName'; my $order = $m->paramStrId('order') || $m->getVar( 'usrAdmOrd', $userId ) || 'desc'; my $hideEmpty = $m->paramDefined('search') ? $m->paramBool('hide') : $m->getVar( 'usrAdmHid', $userId ) || 0; # Enforce valid parameters $sort = 'userName' if $sort !~ /^(?:userName|id|lastOnTime|field)\z/; $order = 'desc' if $order !~ /^(?:asc|desc)\z/; # What to search through when searching for "identity" my @identity = qw(userName realName oldNames email homepage icq lastIp comment); push @identity, grep( $cfg->{$_}, qw(extra1 extra2 extra3) ); # Shared formatting functions my $defTime = sub { $m->formatTime( $_[0]{$field}, $m->{user}{timezone} ) }; my $defUrl = sub { my $v = $_[0]{$field}; $v =~ /^https?:\/\/[^\s\\\[\]{}<>)|^`'"]+\z/ ? "$v" : $v; }; # Install case-i LIKE function for SQLite $m->{dbh}->func( 'LIKE', 2, sub { my $a = shift(); my $b = shift(); utf8::decode($a); utf8::decode($b); index( lc($a), lc($b) ) > -1; }, 'create_function' ) if $m->{sqlite} && $cfg->{sqliteLike} && length($search); # Parse badges my %badges = (); if ( $field eq '_badges' ) { for my $line ( @{ $cfg->{badges} } ) { my ( $id, $smallIcon, $bigIcon ) = $line =~ /(\w+)\s+\w+\s+(\S+)\s+(\S+)/; $badges{$id} = $smallIcon ne '-' ? $smallIcon : $bigIcon; } } # Define views my $like = $m->{pgsql} ? 'ILIKE' : 'LIKE'; my $percent = $m->{sqlite} && $cfg->{sqliteLike} ? "" : "%"; my $defFields = join( ", ", 'users.id', 'users.userName', $sort eq 'lastOnTime' ? 'users.lastOnTime' : () ); my $defFrom = "FROM users AS users WHERE users.id IN (:pageUserIds)"; my $defJoin = $hideEmpty ? 'INNER' : 'LEFT'; my $defGroup = $defFields; my $defSort = $sort ne 'field' ? "users.$sort" : 'users.userName'; my $searchEsc = $m->escHtml($search); my $searchLike = $m->dbEscLike($searchEsc); my $views = [ { name => " Identity", field => '_identity', notes => "no view-specific sorting; searching by username, real name, old usernames, email, " . "website, messenger, last IP, comments, and custom profile fields 1-3 when used; " . "no empty entry hiding", searchParam => $percent . $searchLike . $percent, searchUsers => sub { my $where = !length($search) ? "" : "WHERE " . join( " $like :search OR ", @identity ) . " $like :search"; $m->fetchAllArray( " SELECT id FROM users AS users $where ORDER BY $defSort $order", $_[0] ); }, fetchUsers => sub { $m->fetchAllHash( " SELECT $defFields, realName, email $defFrom ORDER BY $defSort $order", $_[0] ); }, columns => [ { name => "Email", value => sub {"$_[0]{email}"} }, { name => "Real Name", value => sub { $_[0]{realName} } }, { name => "Old Names", value => sub { $_[0]{oldNames} } }, ], }, { name => "Bans", field => '_bans', notes => "view-specific sorting by ban time; searching by both reasons; only banned users are shown", searchParam => $percent . $searchLike . $percent, searchUsers => sub { my $where = length($search) ? "WHERE reason $like :search OR intReason $like :search" : ""; my $fldSort = $sort eq 'field' ? 'bans.banTime' : "users.$sort"; $m->fetchAllArray( " SELECT users.id FROM users AS users INNER JOIN userBans AS bans ON bans.userId = users.id $where ORDER BY $fldSort $order, users.userName", $_[0] ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'bans.banTime' : "users.$sort"; $m->fetchAllHash( " SELECT $defFields, bans.banTime, bans.duration, bans.reason, bans.intReason FROM users AS users INNER JOIN userBans AS bans ON bans.userId = users.id WHERE users.id IN (:pageUserIds) ORDER BY $fldSort $order, users.userName", $_[0] ); }, columns => [ { name => "Ban Time", value => sub { my $v = $_[0]{banTime}; $v ? $m->formatTime( $v, $m->{user}{timezone} ) : ""; } }, { name => "Dur.", value => sub { my $v = $_[0]{duration}; return "" if !defined($v); return "∞" if $v == 0; $v; } }, { name => "Reason", value => sub { $_[0]{reason} } }, { name => "Internal", value => sub { $_[0]{intReason} } }, ], }, { name => "Badges", field => '_badges', notes => "no view-specific sorting; searching by identifier prefix", searchParam => $searchLike . $percent, searchUsers => sub { my $where = length($search) ? "WHERE userBadges.badge LIKE :search" : ""; $m->fetchAllArray( " SELECT users.id, GROUP_CONCAT(userBadges.badge) AS badges FROM users AS users $defJoin JOIN userBadges AS userBadges ON userBadges.userId = users.id $where GROUP BY $defGroup ORDER BY $defSort $order", $_[0] ); }, fetchUsers => sub { $m->fetchAllHash( " SELECT users.id, users.userName, GROUP_CONCAT(userBadges.badge) AS badges FROM users AS users $defJoin JOIN userBadges AS userBadges ON userBadges.userId = users.id WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $defSort $order", $_[0] ); }, columns => [ { name => "Badges", value => sub { join( " ", map("{dataPath}/$badges{$_}\" alt=\"$_\">", sort( split( ',', $_[0]{badges} ) ) ) ); } }, ], }, { name => "Notifications", field => '_notes', notes => "no view-specific sorting; no searching", searchUsers => sub { $m->fetchAllArray( " SELECT users.id FROM users AS users $defJoin JOIN notes AS notes ON notes.userId = users.id GROUP BY $defGroup ORDER BY $defSort $order" ); }, fetchUsers => sub { $m->dbDo("SET group_concat_max_len = 32768") if $m->{mysql}; $m->fetchAllHash( " SELECT users.id, users.userName, GROUP_CONCAT('
' || notes.body || '
') AS notes FROM users AS users $defJoin JOIN notes AS notes ON notes.userId = users.id WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $defSort $order", $_[0] ); }, columns => [ { name => "Notifications", value => sub { my $v = $_[0]{notes}; $v =~ s!,
!
\n
!g; $v; } }, ], }, { name => "Style Snippets", field => '_snippets', notes => "no view-specific sorting; searching by identifier prefix", searchParam => $searchLike . $percent, searchUsers => sub { my $where = length($search) ? "WHERE vars.name LIKE :search" : ""; $m->fetchAllArray( " SELECT users.id FROM users AS users $defJoin JOIN userVariables AS vars ON vars.userId = users.id AND vars.name LIKE 'sty%' $where GROUP BY $defGroup ORDER BY $defSort $order", $_[0] ); }, fetchUsers => sub { $m->fetchAllHash( " SELECT users.id, users.userName, GROUP_CONCAT(vars.name) AS snippets FROM users AS users $defJoin JOIN userVariables AS vars ON vars.userId = users.id AND vars.name LIKE 'sty%' WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $defSort $order", $_[0] ); }, columns => [ { name => "Style Snippets", value => sub { $_[0]{snippets} } } ], }, { name => "Groups", field => '_groups', notes => "no view-specific sorting; searching by group title", searchParam => $searchLike, searchUsers => sub { my $where = length($search) ? "WHERE groups.title = :search" : ""; $m->fetchAllArray( " SELECT users.id FROM users AS users $defJoin JOIN groupMembers AS groupMembers ON groupMembers.userId = users.id $defJoin JOIN groups AS groups ON groups.id = groupMembers.groupId $where GROUP BY $defGroup ORDER BY $defSort $order", $_[0] ); }, fetchUsers => sub { $m->dbDo("SET group_concat_max_len = 32768") if $m->{mysql}; $m->fetchAllHash( " SELECT users.id, users.userName, GROUP_CONCAT('#' || groups.title || '#') AS groups FROM users AS users $defJoin JOIN groupMembers AS groupMembers ON groupMembers.userId = users.id $defJoin JOIN groups AS groups ON groups.id = groupMembers.groupId WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $defSort $order", $_[0] ); }, columns => [ { name => "Groups", value => sub { my $v = $_[0]{groups}; $v =~ s!#,#!, !g; $v =~ s!#!!g; $v; } }, ], }, { name => "Ignored By", field => '_ignored', notes => "view-specific sorting by number of ignoring users; no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'ignoreNum' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(ignores.userId) AS ignoreNum FROM users AS users $defJoin JOIN userIgnores AS ignores ON ignores.ignoredId = users.id GROUP BY $defGroup ORDER BY $fldSort $order, users.userName" ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'ignoreNum' : "users.$sort"; $m->fetchAllHash( " SELECT users.id, users.userName, COUNT(ignores.userId) AS ignoreNum, GROUP_CONCAT(ignorers.userName) AS ignorerNames FROM users AS users $defJoin JOIN userIgnores AS ignores ON ignores.ignoredId = users.id $defJoin JOIN users AS ignorers ON ignorers.id = ignores.userId WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order, users.userName", $_[0] ); }, columns => [ { name => "#", value => sub { $_[0]{ignoreNum} } }, { name => "Ignored By", value => sub { my $v = $_[0]{ignorerNames}; $v =~ s!,!, !g; $v } } ], }, { name => "Ignored Users", field => '_ignoring', notes => "view-specific sorting by number of ignored users; no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'ignoreNum' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(ignores.userId) AS ignoreNum FROM users AS users $defJoin JOIN userIgnores AS ignores ON ignores.userId = users.id GROUP BY $defGroup ORDER BY $fldSort $order, users.userName" ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'ignoreNum' : "users.$sort"; $m->fetchAllHash( " SELECT users.id, users.userName, COUNT(ignores.userId) AS ignoreNum, GROUP_CONCAT(ignoreds.userName) AS ignoredNames FROM users AS users $defJoin JOIN userIgnores AS ignores ON ignores.userId = users.id $defJoin JOIN users AS ignoreds ON ignoreds.id = ignores.ignoredId WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order, users.userName", $_[0] ); }, columns => [ { name => "#", value => sub { $_[0]{ignoreNum} } }, { name => "Ignored Users", value => sub { my $v = $_[0]{ignoredNames}; $v =~ s!,!, !g; $v } } ], }, { name => "Watched By", field => '_watched', notes => "view-specific sorting by number of watching users; no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'watchNum' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(watches.userId) AS watchNum FROM users AS users $defJoin JOIN watchUsers AS watches ON watches.watchedId = users.id GROUP BY $defGroup ORDER BY $fldSort $order, users.userName" ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'watchNum' : "users.$sort"; $m->fetchAllHash( " SELECT users.id, users.userName, COUNT(watches.userId) AS watchNum, GROUP_CONCAT(watchers.userName) AS watcherNames FROM users AS users $defJoin JOIN watchUsers AS watches ON watches.watchedId = users.id $defJoin JOIN users AS watchers ON watchers.id = watches.userId WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order, users.userName", $_[0] ); }, columns => [ { name => "#", value => sub { $_[0]{watchNum} } }, { name => "Watched By", value => sub { my $v = $_[0]{watcherNames}; $v =~ s!,!, !g; $v } } ], }, { name => "Watched Users", field => '_watching', notes => "view-specific sorting by number of watched users; no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'watchNum' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(watches.userId) AS watchNum FROM users AS users $defJoin JOIN watchUsers AS watches ON watches.userId = users.id GROUP BY $defGroup ORDER BY $fldSort $order, users.userName" ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'watchNum' : "users.$sort"; $m->fetchAllHash( " SELECT users.id, users.userName, COUNT(watches.userId) AS watchNum, GROUP_CONCAT(watched.userName) AS watchedNames FROM users AS users $defJoin JOIN watchUsers AS watches ON watches.userId = users.id $defJoin JOIN users AS watched ON watched.id = watches.watchedId WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order, users.userName", $_[0] ); }, columns => [ { name => "#", value => sub { $_[0]{watchNum} } }, { name => "Watched Users", value => sub { my $v = $_[0]{watchedNames}; $v =~ s!,!, !g; $v } } ], }, { name => "Watched Words", field => '_words', notes => "view-specific sorting by number of watched words; no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'watchNum' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(watches.word) AS watchNum FROM users AS users $defJoin JOIN watchWords AS watches ON watches.userId = users.id GROUP BY $defGroup ORDER BY $fldSort $order, users.userName" ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'watchNum' : "users.$sort"; $m->fetchAllHash( " SELECT users.id, users.userName, COUNT(watches.word) AS watchNum, GROUP_CONCAT(watches.word) AS words FROM users AS users $defJoin JOIN watchWords AS watches ON watches.userId = users.id WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order, users.userName", $_[0] ); }, columns => [ { name => "#", value => sub { $_[0]{watchNum} } }, { name => "Words", value => sub { my $v = $_[0]{words}; $v =~ s!,!, !g; $v } } ], }, { name => "Board Subscriptions", field => '_boardsubs', notes => "view-specific sorting by number of subscribed boards; no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'subsNum' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(subs.userId) AS subsNum FROM users AS users $defJoin JOIN boardSubscriptions AS subs ON subs.userId = users.id GROUP BY $defGroup ORDER BY $fldSort $order, users.userName" ); }, fetchUsers => sub { $m->dbDo("SET group_concat_max_len = 32768") if $m->{mysql}; my $fldSort = $sort eq 'field' ? 'subsNum' : "users.$sort"; $m->fetchAllHash( " SELECT users.id, users.userName, COUNT(subs.userId) AS subsNum, GROUP_CONCAT(REPLACE(boards.title, ',', '')) AS title FROM users AS users $defJoin JOIN boardSubscriptions AS subs ON subs.userId = users.id $defJoin JOIN boards AS boards ON boards.id = subs.boardId WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order, users.userName", $_[0] ); }, columns => [ { name => "#", value => sub { $_[0]{subsNum} } }, { name => "Board Subscriptions", value => sub { my $v = $_[0]{title}; $v =~ s!,!, !g; $v } } ], }, { name => "Topic Subscriptions", field => '_topicsubs', notes => "view-specific sorting by number of subscribed topics; no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'subsNum' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(subs.userId) AS subsNum FROM users AS users $defJoin JOIN topicSubscriptions AS subs ON subs.userId = users.id GROUP BY $defGroup ORDER BY $fldSort $order, users.userName" ); }, fetchUsers => sub { $m->dbDo("SET group_concat_max_len = 32768") if $m->{mysql}; my $fldSort = $sort eq 'field' ? 'subsNum' : "users.$sort"; $m->fetchAllHash( " SELECT users.id, users.userName, COUNT(subs.userId) AS subsNum, GROUP_CONCAT(REPLACE(topics.subject, ',', '')) AS subject FROM users AS users $defJoin JOIN topicSubscriptions AS subs ON subs.userId = users.id $defJoin JOIN topics AS topics ON topics.id = subs.topicId WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order, users.userName", $_[0] ); }, columns => [ { name => "#", value => sub { $_[0]{subsNum} } }, { name => "Topic Subscriptions", value => sub { my $v = $_[0]{subject}; $v =~ s!,!, !g; $v } } ], }, { name => "Birthdate", field => '_birthdate', notes => "no searching", searchUsers => sub { my $where = $hideEmpty ? "WHERE birthday <> ''" : ""; $m->fetchAllArray( " SELECT id FROM users AS users $where ORDER BY birthyear $order, birthday $order", $_[0] ); }, fetchUsers => sub { $m->fetchAllHash( " SELECT $defFields, birthyear, birthday $defFrom ORDER BY birthyear $order, birthday $order", $_[0] ); }, columns => [ { name => "Birthdate", value => sub { ( $_[0]->{birthyear} ? $_[0]->{birthyear} : "0000" ) . "-$_[0]->{birthday}"; } }, ], }, { name => "Active Time", field => '_active', notes => "no searching", searchUsers => sub { my $where = $hideEmpty ? "WHERE lastOnTime - regTime > 0" : ""; my $fldSort = $sort eq 'field' ? 'activeSeconds' : "users.$sort"; $m->fetchAllArray( " SELECT id, lastOnTime - regTime AS activeSeconds FROM users AS users $where ORDER BY $fldSort $order", $_[0] ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'activeSeconds' : "users.$sort"; $m->fetchAllHash( " SELECT $defFields, lastOnTime - regTime AS activeSeconds, ROUND((lastOnTime - regTime) / 86400) AS activeDays $defFrom ORDER BY $fldSort $order", $_[0] ); }, columns => [ { name => "Active Time (days)", value => sub { $_[0]->{activeDays} } }, { name => "Active Time (seconds)", value => sub { $_[0]->{activeSeconds} } }, ], }, { name => "Posts Existing", field => '_postexist', notes => "no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'postsExist' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(posts.id) AS postsExist FROM users AS users $defJoin JOIN posts ON posts.userId = users.id GROUP BY $defGroup ORDER BY $fldSort $order", $_[0] ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'postsExist' : "users.$sort"; $m->fetchAllHash( " SELECT $defFields, COUNT(posts.id) AS postsExist FROM users AS users $defJoin JOIN posts AS posts ON posts.userId = users.id WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order", $_[0] ); }, columns => [ { name => "Posts Existing", value => sub { $_[0]->{postsExist} } }, ], }, { name => "Post Upvotes", field => '_upvotes', notes => "no searching", searchUsers => sub { my $fldSort = $sort eq 'field' ? 'postLikes' : "users.$sort"; $m->fetchAllArray( " SELECT users.id, COUNT(postLikes.postId) AS postLikes FROM users AS users $defJoin JOIN posts ON posts.userId = users.id $defJoin JOIN postLikes ON postLikes.postId = posts.id GROUP BY $defGroup ORDER BY $fldSort $order", $_[0] ); }, fetchUsers => sub { my $fldSort = $sort eq 'field' ? 'postLikes' : "users.$sort"; $m->fetchAllHash( " SELECT $defFields, COUNT(postLikes.postId) AS postLikes FROM users AS users $defJoin JOIN posts ON posts.userId = users.id $defJoin JOIN postLikes ON postLikes.postId = posts.id WHERE users.id IN (:pageUserIds) GROUP BY $defGroup ORDER BY $fldSort $order", $_[0] ); }, columns => [ { name => "Post Upvotes", value => sub { $_[0]->{postLikes} } }, ], }, { name => "Avatar", field => 'avatar', columns => [ { name => "Avatar", value => sub { my $v = $_[0]{avatar}; return if !$v; index( $v, "gravatar:" ) == 0 ? "md5( substr( $v, 9 ) ) . "?s=$m->{cfg}{avatarWidth}\" alt=\"\">" : "{cfg}{attachUrlPath}/avatars/$v\" alt=\"\">"; }, }, { name => "Type", value => sub { my $v = $_[0]{avatar}; return "Gravatar" if index( $v, "gravatar:" ) == 0; return "Gallery" if index( $v, "gallery/" ) == 0; return "Upload" if $v; }, }, ], }, { name => "Email", field => 'email', columns => [ { name => "Email", value => sub {"$_[0]{email}"} }, ], }, { name => "Registration Time", field => 'regTime', type => 'int', columns => [ { name => "Registration Time", value => $defTime } ], }, { name => "Last Online Time", field => 'lastOnTime', type => 'int', columns => [ { name => "Last Online Time", value => $defTime } ], }, { name => "Prev. Online Time", field => 'prevOnTime', type => 'int', columns => [ { name => "Prev. Online Time", value => $defTime } ], }, { name => "Website", field => 'homepage', columns => [ { name => "Website", value => $defUrl } ], }, { name => "OpenID", field => 'openId', columns => [ { name => "OpenID", value => $defUrl } ], }, { name => "Username", field => 'userName', columns => [] }, { name => "Administrator", field => 'admin', type => 'int' }, { name => "Birthyear", field => 'birthyear', type => 'int' }, { name => "Disable Email", field => 'dontEmail', type => 'int' }, { name => "Email Notifications", field => 'msgNotify', type => 'int' }, { name => "Reply Notifications", field => 'notify', type => 'int' }, { name => "Privacy", field => 'privacy', type => 'int' }, { name => "Temporary Login", field => 'tempLogin', type => 'int' }, { name => "Show Board Desc.", field => 'boardDescs', type => 'int' }, { name => "Show Decoration", field => 'showDeco', type => 'int' }, { name => "Show Avatars", field => 'showAvatars', type => 'int' }, { name => "Show Embed. Images", field => 'showImages', type => 'int' }, { name => "Show Signatures", field => 'showSigs', type => 'int' }, { name => "Collapse Branches", field => 'collapse', type => 'int' }, { name => "Font Size", field => 'fontSize', type => 'int' }, { name => "Threading Indent", field => 'indent', type => 'int' }, { name => "Posts Per Page", field => 'postsPP', type => 'int' }, { name => "Topics Per Page", field => 'topicsPP', type => 'int' }, { name => "Posts Posted", field => 'postNum', type => 'int' }, { name => "Bounce Counter", field => 'bounceNum', type => 'int' }, { name => "Policy Version", field => 'policyAccept', type => 'int' }, { name => "Renames Left", field => 'renamesLeft', type => 'int' }, { name => "Old Usernames", field => 'oldNames' }, { name => "Real Name", field => 'realName' }, { name => "Title", field => 'title' }, { name => "Occupation", field => 'occupation' }, { name => "Hobbies", field => 'hobbies' }, { name => "Location", field => 'location' }, { name => "Messenger", field => 'icq' }, { name => "Signature", field => 'signature' }, { name => "Miscellaneous", field => 'blurb' }, { name => "Custom 1", field => 'extra1' }, { name => "Custom 2", field => 'extra2' }, { name => "Custom 3", field => 'extra3' }, { name => "Birthday", field => 'birthday' }, { name => "Timezone", field => 'timezone' }, { name => "Language", field => 'language' }, { name => "Style", field => 'style' }, { name => "Font Face", field => 'fontFace' }, { name => "User Agent", field => 'userAgent' }, { name => "IP Address", field => 'lastIp' }, { name => "PGP Key ID", field => 'gpgKeyId' }, { name => "Comments", field => 'comment' }, ]; my $view = ( first { $_->{field} eq $field } @$views ) || $views->[1]; $field = $view->{field}; # Save options $m->setVar( 'usrAdmFld', $field, $userId ); $m->setVar( 'usrAdmSrt', $sort, $userId ); $m->setVar( 'usrAdmOrd', $order, $userId ); $m->setVar( 'usrAdmHid', $hideEmpty, $userId ); # Searching my $searchParam = ""; my $searchStr = ""; if ( length($search) ) { if ( $view->{searchUsers} ) { $searchParam = $view->{searchParam}; } elsif ( $view->{type} eq 'int' ) { $searchParam = int( $search || 0 ); $searchStr = "AND $field = :search"; } else { $searchParam = $percent . $searchLike . $percent; $searchStr = "AND $field $like :search"; } } # Hiding empty fields my $hideEmptyStr = ""; if ( $hideEmpty && !$view->{searchUsers} ) { if ( $view->{type} eq 'int' ) { $hideEmptyStr = "AND $field > 0" } else { $hideEmptyStr = "AND $field <> ''" } } # Ordering my $orderStr = ""; if ( $sort eq 'id' ) { $orderStr = "users.id $order" } elsif ( $sort eq 'userName' ) { $orderStr = "users.userName $order" } elsif ( $sort eq 'lastOnTime' ) { $orderStr = "users.lastOnTime $order" } elsif ( $sort eq 'field' ) { $orderStr = "users.$field $order, users.userName"; } # Get ids of users my $users = $view->{searchUsers} ? $view->{searchUsers}( { search => $searchParam } ) : $m->fetchAllArray( " SELECT id FROM users AS users WHERE 1 = 1 $searchStr $hideEmptyStr ORDER BY $orderStr", { search => $searchParam } ); # Print page bar my $usersPP = $cfg->{usersPP} || 100; my $pageNum = int( @$users / $usersPP ) + ( @$users % $usersPP != 0 ); my @pageLinks = $pageNum < 2 ? () : $m->pageLinks( 'user_admin', [], $page, $pageNum ); my @navLinks = ( { url => $m->url('forum_show'), txt => 'comUp', ico => 'up' } ); my @adminLinks = ( { url => $m->url('user_set'), txt => "Set", ico => 'edit' } ); $m->printPageBar( mainTitle => "User Administration", navLinks => \@navLinks, pageLinks => \@pageLinks, adminLinks => \@adminLinks ); # Get users on page my @pageUsers = @$users[ ( $page - 1 ) * $usersPP .. $m->min( $page * $usersPP, scalar @$users ) - 1 ]; my @pageUserIds = map( $_->[0], @pageUsers ); $users = $view->{fetchUsers} ? $view->{fetchUsers}( { pageUserIds => \@pageUserIds } ) : $m->fetchAllHash( " SELECT $defFields, $field FROM users AS users WHERE id IN (:pageUserIds) ORDER BY $orderStr", { pageUserIds => \@pageUserIds } ); # Determine checkbox, radiobutton and listbox states my $hideEmptyChk = $hideEmpty ? 'checked' : "", my %state = ( $sort => 'selected', $order => 'selected', "field$field" => 'selected' ); # Print user list form print "
{ext}\" method=\"GET\">\n", "
\n", "
List Users
\n", "
\n", "
\n", "\n", "\n", "\n", "\n", "\n", $m->submitButton( "List", 'search' ), "
\n", $view->{notes} ? "
View notes: $view->{notes}
" : "", "
\n", "
\n", "
\n\n"; # Print user list header my $defColumns = [ { name => $view->{name}, value => sub { $_[0]{$field} } } ]; my $columns = $view->{columns} ? $view->{columns} : $defColumns; print "\n", "\n", "\n", map( "\n", @$columns ), "\n"; # Print user list for my $listUser (@$users) { my $infUrl = $m->url( 'user_info', uid => $listUser->{id} ); print "\n", "\n", map( "\n", @$columns ), "\n"; } print "
Username$_->{name}
$listUser->{userName}" . $_->{value}($listUser) . "
\n\n"; # Log action and finish $m->logAction( 3, 'user', 'admin', $userId ); $m->printFooter(); $m->finish();