mirror of
https://github.com/OPSnet/Gazelle.git
synced 2026-10-07 01:13:28 -04:00
511 lines
20 KiB
PHP
511 lines
20 KiB
PHP
<?php
|
|
|
|
$userMan = new Gazelle\Manager\User;
|
|
|
|
if (isset($_GET['search'])) {
|
|
$_GET['search'] = trim($_GET['search']);
|
|
}
|
|
|
|
if (!empty($_GET['search'])) {
|
|
if (preg_match(IP_REGEXP, $_GET['search'])) {
|
|
$_GET['ip'] = $_GET['search'];
|
|
} elseif (preg_match(EMAIL_REGEXP, $_GET['search'])) {
|
|
$_GET['email'] = $_GET['search'];
|
|
} elseif (preg_match(USERNAME_REGEXP, $_GET['search'], $match)) {
|
|
$username = $match['username'];
|
|
$found = $userMan->findByUsername($username);
|
|
if ($found) {
|
|
header('Location: ' . $found->location());
|
|
exit;
|
|
}
|
|
$_GET['username'] = $username;
|
|
} else {
|
|
$_GET['comment'] = $_GET['search'];
|
|
}
|
|
}
|
|
|
|
foreach (['ip', 'email', 'username', 'comment'] as $field) {
|
|
if (isset($_GET[$field])) {
|
|
$_GET[$field] = trim($_GET[$field]);
|
|
}
|
|
}
|
|
|
|
class SQLMatcher {
|
|
public function __construct(
|
|
protected string $key,
|
|
) {}
|
|
|
|
public function matchField($field) {
|
|
return match ($this->key) {
|
|
'regexp' => "$field REGEXP ?",
|
|
'strict' => "$field = ?",
|
|
default => "$field LIKE concat('%', ?, '%')",
|
|
};
|
|
}
|
|
|
|
public function left_match($field) {
|
|
return match ($this->key) {
|
|
'regexp' => "$field REGEXP ?",
|
|
'strict' => "$field = ?",
|
|
default => "$field LIKE concat(?, '%')",
|
|
};
|
|
}
|
|
|
|
public function op($field, $compare) {
|
|
return match ($compare) {
|
|
'above' => "$field > ?",
|
|
'below' => "$field < ?",
|
|
'between' => "$field BETWEEN ? AND ?",
|
|
'isnotnull' => "$field IS NOT NULL",
|
|
'isnull' => "$field IS NULL",
|
|
'no', 'not_equal' => "$field != ?",
|
|
default => "$field = ?",
|
|
};
|
|
}
|
|
|
|
public function date($field, $compare) {
|
|
return match ($compare) {
|
|
'after' => "$field > ? + INTERVAL 1 DAY",
|
|
'before' => "$field < ?",
|
|
'between' => "$field BETWEEN ? AND ? + INTERVAL 1 DAY",
|
|
default => "$field >= ? AND $field < ? + INTERVAL 1 DAY",
|
|
};
|
|
}
|
|
}
|
|
|
|
function option($field, $value, $label) {
|
|
return sprintf('<option value="%s"%s>%s</option>',
|
|
$value,
|
|
($_GET[$field] ?? '') === $value ? ' selected="selected"' : '',
|
|
$label);
|
|
}
|
|
|
|
$OrderTable = [
|
|
'Bounty' => 'Bounty',
|
|
'Downloaded' => 'uls1.Downloaded',
|
|
'Downloads' => 'Downloads',
|
|
'Email' => 'um1.Email',
|
|
'Invites' => 'um1.Invites',
|
|
'Joined' => 'ui1.JoinDate',
|
|
'Last Seen' => 'ula.last_access',
|
|
'Ratio' => '(uls1.Uploaded / uls1.Downloaded)',
|
|
'Seeding' => 'Seeding',
|
|
'Snatches' => 'Snatches',
|
|
'Uploaded' => 'uls1.Uploaded',
|
|
'Username' => 'um1.Username',
|
|
];
|
|
$WayTable = ['Ascending'=>'ASC', 'Descending'=>'DESC'];
|
|
|
|
// Arrays, regexps, and all that fun stuff we can use for validation, form generation, etc
|
|
$OrderVals = ['inarray'=>array_keys($OrderTable)];
|
|
$WayVals = ['inarray'=>array_keys($WayTable)];
|
|
|
|
$DateChoices = ['inarray'=>['on', 'before', 'after', 'between']];
|
|
$SingleDateChoices = ['inarray'=>['on', 'before', 'after']];
|
|
$NumberChoices = ['inarray'=>['equal', 'above', 'below', 'between', 'buffer']];
|
|
$OffNumberChoices = ['inarray'=>['equal', 'above', 'below', 'between', 'buffer', 'off']];
|
|
$YesNo = ['inarray'=>['any', 'yes', 'no']];
|
|
$Nullable = ['inarray'=>['any', 'isnull', 'isnotnull']];
|
|
|
|
$emailHistoryChecked = false;
|
|
$ipHistoryChecked = false;
|
|
$disabledIpChecked = false;
|
|
$trackerLiveSource = true;
|
|
|
|
$paginator = new Gazelle\Util\Paginator(USERS_PER_PAGE, (int)($_GET['page'] ?? 1));
|
|
$Stylesheets = (new \Gazelle\Manager\Stylesheet)->list();
|
|
|
|
$matchMode = ($_GET['matchtype'] ?? 'fuzzy');
|
|
$searchDisabledInvites = (isset($_GET['disabled_invites']) && $_GET['disabled_invites'] != '');
|
|
$searchDisabledUploads = (isset($_GET['disabled_uploads']) && $_GET['disabled_uploads'] != '');
|
|
$searchLockedAccount = (($_GET['lockedaccount'] ?? '') == 'locked');
|
|
$showInvited = (($_GET['invited'] ?? 'off') !== 'off');
|
|
|
|
if (!empty($_GET)) {
|
|
$emailHistoryChecked = !empty($_GET['email_history']);
|
|
$disabledIpChecked = !empty($_GET['disabled_ip']);
|
|
$ipHistoryChecked = !empty($_GET['ip_history']);
|
|
$trackerLiveSource = ($_GET['tracker-src'] ?? 'live') == 'live';
|
|
$DateRegexp = ['regexp' => '/\d{4}-\d{2}-\d{2}/'];
|
|
$ClassIDs = [];
|
|
$SecClassIDs = [];
|
|
$Classes = $userMan->classList();
|
|
foreach ($Classes as $id => $value) {
|
|
if ($value['Secondary']) {
|
|
$SecClassIDs[] = $id;
|
|
} else {
|
|
$ClassIDs[] = $id;
|
|
}
|
|
}
|
|
|
|
$validator = new Gazelle\Util\Validator;
|
|
$validator->setFields([
|
|
['avatar', '0', 'string', 'Avatar URL too long', ['maxlength' => 512]],
|
|
['bounty', '0', 'inarray', "Invalid bounty field", $OffNumberChoices],
|
|
['cc', '0', 'inarray', 'Invalid Country Code', ['maxlength' => 2]],
|
|
['comment', '0', 'string', 'Comment is too long.', ['maxlength' => 512]],
|
|
['disabled_invites', '0', 'inarray', 'Invalid disabled_invites field', $YesNo],
|
|
['disabled_uploads', '0', 'inarray', 'Invalid disabled_uploads field', $YesNo],
|
|
['donor', '0', 'inarray', 'Invalid donor field', $YesNo],
|
|
['downloaded', '0', 'inarray', 'Invalid downloaded field', $NumberChoices],
|
|
['enabled', '0', 'inarray', 'Invalid enabled field', ['inarray' => ['', 0, 1, 2]]],
|
|
['join1', '0', 'regexp', 'Invalid join1 field', $DateRegexp],
|
|
['join2', '0', 'regexp', 'Invalid join2 field', $DateRegexp],
|
|
['joined', '0', 'inarray', 'Invalid joined field', $DateChoices],
|
|
['lastactive', '0', 'inarray', 'Invalid lastactive field', $DateChoices],
|
|
['lastactive1', '0', 'regexp', 'Invalid lastactive1 field', $DateRegexp],
|
|
['lastactive2', '0', 'regexp', 'Invalid lastactive2 field', $DateRegexp],
|
|
['lockedaccount', '0', 'inarray', 'Invalid locked account field', ['inarray' => ['any', 'locked', 'unlocked']]],
|
|
['matchtype', '0', 'inarray', 'Invalid matchtype field', ['inarray' => ['strict', 'fuzzy', 'regexp']]],
|
|
['order', '0', 'inarray', 'Invalid ordering', $OrderVals],
|
|
['passkey', '0', 'string', 'Invalid passkey', ['maxlength' => 32]],
|
|
['ratio', '0', 'inarray', 'Invalid ratio field', $NumberChoices],
|
|
['secclass', '0', 'inarray', 'Invalid class', ['inarray' => $SecClassIDs]],
|
|
['seeding', '0', 'inarray', "Invalid seeding field", $OffNumberChoices],
|
|
['snatched', '0', 'inarray', "Invalid snatched field", $OffNumberChoices],
|
|
['stylesheet', '0', 'inarray', 'Invalid stylesheet', ['inarray' => array_keys($Stylesheets)]],
|
|
['uploaded', '0', 'inarray', 'Invalid uploaded field', $NumberChoices],
|
|
['warned', '0', 'inarray', 'Invalid warned field', $Nullable],
|
|
['way', '0', 'inarray', 'Invalid way', $WayVals],
|
|
]);
|
|
if (!$validator->validate($_GET)) {
|
|
error($validator->errorMessage());
|
|
}
|
|
|
|
$m = new SQLMatcher($matchMode);
|
|
$Where = [];
|
|
$Args = [];
|
|
$Having = [];
|
|
$HavingArgs = [];
|
|
$Join = [];
|
|
$Distinct = false;
|
|
$Order = '';
|
|
|
|
$invitedValue = $showInvited
|
|
? '(SELECT count(*) FROM users_info AS ui2 WHERE ui2.Inviter = um1.ID)'
|
|
: "'X'";
|
|
$seedingValue = ($_GET['seeding'] ?? 'off') == 'off'
|
|
? "'X'"
|
|
: '(SELECT count(DISTINCT fid)
|
|
FROM xbt_files_users xfu
|
|
WHERE xfu.active = 1 AND xfu.remaining = 0 AND xfu.mtime > unix_timestamp(now() - INTERVAL 1 HOUR)
|
|
AND xfu.uid = um1.ID)';
|
|
$snatchesValue = ($_GET['snatched'] ?? 'off') == 'off'
|
|
? "'X'"
|
|
: '(SELECT count(DISTINCT fid) FROM xbt_snatched AS xs WHERE xs.uid = um1.ID)';
|
|
|
|
$columns = "
|
|
um1.ID AS user_id,
|
|
$seedingValue AS seeding,
|
|
$snatchesValue AS snatches,
|
|
$invitedValue AS invited
|
|
";
|
|
|
|
$from = "FROM users_main AS um1
|
|
INNER JOIN permissions p ON (p.ID = um1.PermissionID)
|
|
INNER JOIN users_leech_stats AS uls1 ON (uls1.UserID = um1.ID)
|
|
INNER JOIN users_info AS ui1 ON (ui1.UserID = um1.ID)
|
|
LEFT JOIN user_last_access AS ula ON (ula.user_id = um1.ID)
|
|
";
|
|
|
|
if (!empty($_GET['username'])) {
|
|
$Where[] = $m->matchField('um1.Username');
|
|
$Args[] = $_GET['username'];
|
|
}
|
|
|
|
if (!empty($_GET['email'])) {
|
|
if (isset($_GET['email_history'])) {
|
|
$Distinct = true;
|
|
$Join['he'] = 'INNER JOIN users_history_emails AS he ON (he.UserID = um1.ID)';
|
|
$Where[] = $m->matchField('he.Email');
|
|
} else {
|
|
$Where[] = $m->matchField('um1.Email');
|
|
}
|
|
$Args[] = $_GET['email'];
|
|
}
|
|
|
|
if (isset($_GET['email_opt']) && isset($_GET['email_cnt']) && strlen($_GET['email_cnt'])) {
|
|
$Where[] = sprintf('um1.ID IN (%s)',
|
|
$m->op("
|
|
SELECT UserID FROM users_history_emails GROUP BY UserID HAVING count(DISTINCT Email)
|
|
", $_GET['emails_opt']
|
|
)
|
|
);
|
|
$Args[] = (int)$_GET['email_cnt'];
|
|
}
|
|
|
|
if (!empty($_GET['ip'])) {
|
|
if ($ipHistoryChecked) {
|
|
$Distinct = true;
|
|
$Join['hi'] = 'INNER JOIN users_history_ips AS hi ON (hi.UserID = um1.ID)';
|
|
$Where[] = $m->left_match('hi.IP');
|
|
} else {
|
|
$Where[] = $m->left_match('um1.IP');
|
|
}
|
|
$Args[] = trim($_GET['ip']);
|
|
}
|
|
|
|
if ($searchLockedAccount) {
|
|
$Join['la'] .= 'INNER JOIN locked_accounts AS la ON (la.UserID = um1.ID)';
|
|
}
|
|
elseif (isset($_GET['lockedaccount']) && $_GET['lockedaccount'] == 'unlocked') {
|
|
$Join['la'] = 'LEFT JOIN locked_accounts AS la ON (la.UserID = um1.ID)';
|
|
$Where[] = 'la.UserID IS NULL';
|
|
}
|
|
|
|
if (!empty($_GET['cc'])) {
|
|
$Where[] = $m->op('um1.ipcc', $_GET['cc_op']);
|
|
$Args[] = trim($_GET['cc']);
|
|
}
|
|
|
|
if (!empty($_GET['tracker_ip'])) {
|
|
$Distinct = true;
|
|
$Join['xfu'] = $trackerLiveSource
|
|
? 'INNER JOIN xbt_files_users AS xfu ON (um1.ID = xfu.uid)'
|
|
: 'INNER JOIN xbt_snatched AS xfu ON (um1.ID = xfu.uid)';
|
|
$Where[] = $m->left_match('xfu.ip');
|
|
$Args[] = trim($_GET['tracker_ip']);
|
|
}
|
|
|
|
if (!empty($_GET['comment'])) {
|
|
$Where[] = $m->matchField('ui1.AdminComment');
|
|
$Args[] = $_GET['comment'];
|
|
}
|
|
|
|
if (!empty($_GET['lastfm'])) {
|
|
$Distinct = true;
|
|
$Join['lfm'] = 'INNER JOIN lastfm_users AS lfm ON (lfm.ID = um1.ID)';
|
|
$Where[] = $m->matchField('lfm.Username');
|
|
$Args[] = $_GET['lastfm'];
|
|
}
|
|
|
|
if (isset($_GET['invites']) && !empty($_GET['invites']) && isset($_GET['invites1']) && strlen($_GET['invites1'])) {
|
|
$op = $_GET['invites'];
|
|
$Where[] = $m->op('um1.Invites', $op);
|
|
$Args = array_merge($Args, [$_GET['invites1']], ($op === 'between' ? [$_GET['invites2']] : []));
|
|
}
|
|
|
|
if ($showInvited && isset($_GET['invited1']) && strlen($_GET['invited1'])) {
|
|
$op = $_GET['invited'];
|
|
$Where[] = "um1.ID IN ("
|
|
. $m->op("SELECT umi.ID FROM users_info uii INNER JOIN users_main umi ON (umi.ID = uii.Inviter) GROUP BY umi.ID HAVING count(*)", $op)
|
|
. ")";
|
|
$Args = array_merge($Args, [$_GET['invited1']], ($op === 'between' ? [$_GET['invited2']] : []));
|
|
}
|
|
|
|
if ($searchDisabledInvites) {
|
|
$Where[] = 'ui1.DisableInvites = ?';
|
|
$Args[] = $_GET['disabled_invites'] == 'yes' ? '1' : '0';
|
|
}
|
|
|
|
if ($searchDisabledUploads) {
|
|
$Where[] = 'ui1.DisableUpload = ?';
|
|
$Args[] = $_GET['disabled_uploads'] === 'yes' ? '1' : '0';
|
|
}
|
|
|
|
if (isset($_GET['joined']) && !empty($_GET['joined']) && isset($_GET['join1']) && !empty($_GET['join1'])) {
|
|
$op = $_GET['joined'];
|
|
$Where[] = $m->date('ui1.JoinDate', $op);
|
|
$Args[] = $_GET['join1'];
|
|
if ($op === 'on') {
|
|
$Args[] = $_GET['join1'];
|
|
}
|
|
elseif ($op === 'between') {
|
|
$Args[] = $_GET['join2'];
|
|
}
|
|
}
|
|
|
|
if (isset($_GET['lastactive']) && !empty($_GET['lastactive']) && isset($_GET['lastactive1']) && !empty($_GET['lastactive1'])) {
|
|
$op = $_GET['lastactive'];
|
|
$Where[] = $m->date('ula.last_access', $op);
|
|
$Args[] = $_GET['lastactive1'];
|
|
if ($op === 'on') {
|
|
$Args[] = $_GET['lastactive1'];
|
|
}
|
|
elseif ($op === 'between') {
|
|
$Args[] = $_GET['lastactive2'];
|
|
}
|
|
}
|
|
|
|
if (isset($_GET['ratio']) && !empty($_GET['ratio']) && isset($_GET['ratio1']) && strlen($_GET['ratio1'])) {
|
|
$Decimals = strlen(array_pop(explode('.', $_GET['ratio1'])));
|
|
if (!$Decimals) {
|
|
$Decimals = 0;
|
|
}
|
|
$op = $_GET['ratio'];
|
|
$Where[] = $m->op('CASE WHEN uls1.Downloaded = 0 then 0 ELSE round(uls1.Uploaded/uls1.Downloaded, ?) END', $op);
|
|
$Args = array_merge($Args, [$Decimals, $_GET['ratio1']], ($op === 'between' ? [$_GET['ratio2']] : []));
|
|
}
|
|
|
|
if (isset($_GET['bounty']) && !empty($_GET['bounty']) && $_GET['bounty'] !== 'off' && isset($_GET['bounty1']) && strlen($_GET['bounty1'])) {
|
|
$op = $_GET['bounty'];
|
|
$Where[] = $m->op('(SELECT sum(Bounty) FROM requests_votes rv WHERE rv.UserID = um1.ID)', $op);
|
|
$Args = array_merge($Args, [$_GET['bounty1'] * 1024 ** 3], ($op === 'between' ? [$_GET['bounty2'] * 1024 ** 3] : []));
|
|
}
|
|
|
|
if (isset($_GET['downloads']) && !empty($_GET['downloads']) && $_GET['downloads'] !== 'off' && isset($_GET['downloads1']) && strlen($_GET['downloads1'])) {
|
|
$op = $_GET['downloads'];
|
|
$Where[] = $m->op('(SELECT count(DISTINCT TorrentID) FROM users_downloads ud WHERE ud.UserID = um1.ID)', $op);
|
|
$Args = array_merge($Args, [$_GET['downloads1']], ($op === 'between' ? [$_GET['downloads2']] : []));
|
|
}
|
|
|
|
if (isset($_GET['seeding']) && $_GET['seeding'] !== 'off' && isset($_GET['seeding1'])) {
|
|
$op = $_GET['seeding'];
|
|
$Where[] = $m->op('(SELECT count(DISTINCT fid)
|
|
FROM xbt_files_users xfu
|
|
WHERE xfu.active = 1 AND xfu.remaining = 0 AND xfu.mtime > unix_timestamp(now() - INTERVAL 1 HOUR)
|
|
AND xfu.uid = um1.ID)', $op);
|
|
$Args = array_merge($Args, [$_GET['seeding1']], ($op === 'between' ? [$_GET['seeding2']] : []));
|
|
}
|
|
|
|
if (isset($_GET['snatched']) && $_GET['snatched'] !== 'off' && isset($_GET['snatched1'])) {
|
|
$op = $_GET['snatched'];
|
|
$Where[] = $m->op('(SELECT count(DISTINCT fid) FROM xbt_snatched AS xs WHERE xs.uid = um1.ID)', $op);
|
|
$Args = array_merge($Args, [$_GET['snatched1']], ($op === 'between' ? [$_GET['snatched2']] : []));
|
|
}
|
|
|
|
if (isset($_GET['uploaded']) && !empty($_GET['uploaded']) && isset($_GET['uploaded1']) && strlen($_GET['uploaded1'])) {
|
|
$op = $_GET['uploaded'];
|
|
if ($op === 'buffer') {
|
|
$Where[] = 'uls1.Uploaded - uls1.Downloaded BETWEEN ? AND ?';
|
|
$Args = array_merge($Args, [0.9 * $_GET['uploaded1'] * 1024 ** 3, 1.1 * $_GET['uploaded1'] * 1024 ** 3]);
|
|
} else {
|
|
$Where[] = $m->op('uls1.Uploaded', $op);
|
|
$Args[] = $_GET['uploaded1'] * 1024 ** 3;
|
|
if ($op === 'on') {
|
|
$Args[] = $_GET['uploaded1'] * 1024 ** 3;
|
|
}
|
|
elseif ($op === 'between') {
|
|
$Args[] = $_GET['uploaded2'] * 1024 ** 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isset($_GET['downloaded']) && !empty($_GET['downloaded']) && isset($_GET['downloaded1']) && strlen($_GET['downloaded1'])) {
|
|
$op = $_GET['downloaded'];
|
|
$Where[] = $m->op('uls1.Downloaded', $op);
|
|
$Args[] = $_GET['downloaded1'] * 1024 ** 3;
|
|
if ($op === 'on') {
|
|
$Args[] = $_GET['downloaded1'] * 1024 ** 3;
|
|
}
|
|
elseif ($op === 'between') {
|
|
$Args[] = $_GET['downloaded2'] * 1024 ** 3;
|
|
}
|
|
}
|
|
|
|
if (isset($_GET['enabled']) && $_GET['enabled'] != '') {
|
|
$Where[] = 'um1.Enabled = ?';
|
|
$Args[] = $_GET['enabled'];
|
|
}
|
|
|
|
if (isset($_GET['class']) && is_array($_GET['class'])) {
|
|
$Where[] = 'um1.PermissionID IN (' . placeholders($_GET['class']) . ')';
|
|
$Args = array_merge($Args, $_GET['class']);
|
|
}
|
|
|
|
if (isset($_GET['secclass']) && $_GET['secclass'] != '') {
|
|
$Join['ul'] = 'INNER JOIN users_levels AS ul ON (um1.ID = ul.UserID)';
|
|
$Where[] = 'ul.PermissionID = ?';
|
|
$Args[] = $_GET['secclass'];
|
|
}
|
|
|
|
if (isset($_GET['donor']) && !empty($_GET['donor'])) {
|
|
$Where[] = 'ui1.Donor = ?';
|
|
$Args[] = $_GET['donor'] === 'yes' ? '1' : '0';
|
|
}
|
|
|
|
if (isset($_GET['warned']) && !empty($_GET['warned'])) {
|
|
$Where[] = $m->op('ui1.Warned', $_GET['warned']);
|
|
}
|
|
|
|
if ($disabledIpChecked) {
|
|
$Distinct = true;
|
|
if ($ipHistoryChecked) {
|
|
if (!isset($Join['hi'])) {
|
|
$Join['hi'] = 'LEFT JOIN users_history_ips AS hi ON (hi.UserID = um1.ID)';
|
|
}
|
|
$Join['um2'] = 'LEFT JOIN users_main AS um2 ON (um2.ID != um1.ID AND um2.Enabled = \'2\' AND um2.ID = hi.UserID)';
|
|
} else {
|
|
$Join['um2'] = 'LEFT JOIN users_main AS um2 ON (um2.ID != um1.ID AND um2.Enabled = \'2\' AND um2.IP = um1.IP)';
|
|
}
|
|
}
|
|
|
|
if (isset($_GET['passkey']) && !empty($_GET['passkey'])) {
|
|
$Where[] = $m->matchField('um1.torrent_pass');
|
|
$Args[] = $_GET['passkey'];
|
|
}
|
|
|
|
if (isset($_GET['avatar']) && !empty($_GET['avatar'])) {
|
|
$Where[] = $m->matchField('ui1.Avatar');
|
|
$Args[] = $_GET['avatar'];
|
|
}
|
|
|
|
if (isset($_GET['stylesheet']) && !empty($_GET['stylesheet'])) {
|
|
$Where[] = $m->matchField('ui1.StyleID');
|
|
$Args[] = $_GET['stylesheet'];
|
|
}
|
|
|
|
$Order = 'ORDER BY ' . $OrderTable[$_GET['order'] ?? 'Joined'] . ' ' . $WayTable[$_GET['way'] ?? 'Descending'];
|
|
|
|
//---------- Build the query
|
|
$SQL = "SELECT count(*) $from " . implode("\n", $Join);
|
|
if (count($Where)) {
|
|
$SQL .= "WHERE " . implode("\nAND ", $Where);
|
|
}
|
|
if ($Distinct) {
|
|
$SQL .= "\nGROUP BY um1.ID";
|
|
}
|
|
if (count($Having)) {
|
|
$SQL .= "\nHAVING " . implode(' AND ', $Having);
|
|
}
|
|
$paginator->setTotal($DB->scalar($SQL, ...array_merge($Args, $HavingArgs)) ?? 0);
|
|
|
|
$SQL = "SELECT $columns $from " . implode("\n", $Join);
|
|
if (count($Where)) {
|
|
$SQL .= "WHERE " . implode("\nAND ", $Where);
|
|
}
|
|
if ($Distinct) {
|
|
$SQL .= "\nGROUP BY um1.ID";
|
|
}
|
|
if (count($Having)) {
|
|
$SQL .= "\nHAVING " . implode(' AND ', $Having);
|
|
}
|
|
$SQL .= "\n$Order LIMIT ? OFFSET ?";
|
|
|
|
$DB->prepared_query($SQL, ...array_merge($Args, $HavingArgs, [$paginator->limit(), $paginator->offset()]));
|
|
$Results = $DB->to_array(false, MYSQLI_ASSOC, false);
|
|
foreach ($Results as &$r) {
|
|
$r['user'] = $userMan->findById($r['user_id']);
|
|
}
|
|
unset($r);
|
|
}
|
|
|
|
// Neither level nor ID is particularly useful when searching secondary classes, so sort them alphabetically.
|
|
$ClassLevels = $userMan->classLevelList();
|
|
$Secondaries = array_filter($ClassLevels, fn ($c) => $c['Secondary'] == '1');
|
|
usort($Secondaries, fn($c1, $c2) => $c1['Name'] <=> $c2['Name']);
|
|
|
|
echo $Twig->render('admin/advanced-user-search.twig', [
|
|
'page' => $Results,
|
|
'paginator' => $paginator,
|
|
'show_invited' => $showInvited,
|
|
'url_stem' => (new Gazelle\User\Stylesheet($Viewer))->imagePath(),
|
|
'viewer' => $Viewer,
|
|
'input' => $_GET,
|
|
|
|
'tracker_live_source' => $trackerLiveSource,
|
|
'check_disabled_ip' => $disabledIpChecked,
|
|
'check_ip_history' => $ipHistoryChecked,
|
|
'check_email_history' => $emailHistoryChecked,
|
|
|
|
// third column
|
|
'primary_class' => array_filter($ClassLevels, fn ($c) => $c['Secondary'] == '0'),
|
|
'secondary_class' => $Secondaries,
|
|
'stylesheet' => $Stylesheets,
|
|
'match_mode' => $matchMode,
|
|
|
|
// sorting widgets
|
|
'field_by' => array_shift($OrderVals),
|
|
'order_by' => array_shift($WayVals),
|
|
]);
|