replace uses of users_info.JoinDate with users_main.created

This commit is contained in:
Spine
2023-05-06 04:31:14 +00:00
parent aba49d6d47
commit fef50c2e6c
23 changed files with 287 additions and 148 deletions

View File

@@ -5,7 +5,6 @@ namespace Gazelle\Contest;
/* how many 100% flacs (any media) uploaded? */
class UploadFlac extends AbstractContest {
use TorrentLeaderboard;
public function ranker(): array {
@@ -42,11 +41,10 @@ class UploadFlac extends AbstractContest {
count(um.ID) AS total_users
FROM contest c,
users_main um
INNER JOIN users_info ui ON (ui.UserID = um.ID)
INNER JOIN torrents t ON (t.Userid = um.ID)
INNER JOIN xbt_files_users xfu ON (xfu.fid = t.ID AND xfu.uid = t.UserID)
WHERE um.Enabled = '1'
AND ui.JoinDate <= c.date_end
AND u.created <= c.date_end
AND xfu.remaining = 0
AND t.Time BETWEEN c.date_begin AND c.date_end
AND t.Format = 'FLAC'
@@ -72,11 +70,9 @@ class UploadFlac extends AbstractContest {
count(DISTINCT t.ID) * ? AS entries_bonus
FROM contest c,
users_main um
INNER JOIN users_info ui ON (ui.UserID = um.ID)
LEFT JOIN torrents t ON (t.UserID = um.ID)
LEFT JOIN xbt_files_users xfu ON (xfu.fid = t.ID AND xfu.uid = t.UserID)
WHERE um.Enabled = '1'
AND ui.JoinDate <= c.date_end
AND (t.ID IS NULL
OR (
xfu.remaining = 0

View File

@@ -3,7 +3,6 @@
namespace Gazelle\Manager;
class DuplicateIP extends \Gazelle\Base {
public function total(int $threshold): int {
return self::$db->scalar("
SELECT count(*)
@@ -21,16 +20,15 @@ class DuplicateIP extends \Gazelle\Base {
public function page(int $threshold, int $limit, int $offset): array {
self::$db->prepared_query("
SELECT um.ID AS user_id,
um.IP AS ipaddr,
ui.JoinDate AS joined,
SELECT um.ID AS user_id,
um.IP AS ipaddr,
um.created AS created,
(
SELECT count(DISTINCT h.UserID)
FROM users_history_ips AS h
WHERE h.IP = um.IP
) AS uses
FROM users_main AS um
INNER JOIN users_info AS ui ON (ui.UserID = um.ID)
WHERE um.Enabled = '1'
AND um.IP != '127.0.0.1'
AND (

View File

@@ -2,17 +2,18 @@
namespace Gazelle\Manager;
// TODO: This should be subsumed into Search\User
class Registration extends \Gazelle\Base {
protected string $beforeDate;
protected string $afterDate;
protected $beforeDate;
protected $afterDate;
public function setBeforeDate(string $date) {
public function setBeforeDate(string $date): Registration {
$this->beforeDate = $date;
return $this;
}
public function setAfterDate(string $date) {
public function setAfterDate(string $date): Registration {
$this->afterDate = $date;
return $this;
}
@@ -20,28 +21,28 @@ class Registration extends \Gazelle\Base {
public function configure(): array {
$cond = [];
$args = [];
if ($this->beforeDate) {
if ($this->afterDate) {
$cond[] = 'ui.JoinDate BETWEEN ? AND ?';
if (isset($this->beforeDate)) {
if (isset($this->afterDate)) {
$cond[] = 'um.created BETWEEN ? AND ?';
$args[] = $this->afterDate;
$args[] = $this->beforeDate;
} else {
$cond[] = 'ui.JoinDate < ?';
$cond[] = 'um.created < ?';
$args[] = $this->beforeDate;
}
} elseif ($this->afterDate) {
$cond[] = 'ui.JoinDate >= ?';
} elseif (isset($this->afterDate)) {
$cond[] = 'um.created >= ?';
$args[] = $this->afterDate;
} else {
$cond[] = 'ui.JoinDate > now() - INTERVAL 3 DAY';
$cond[] = 'um.created > now() - INTERVAL 3 DAY';
}
return [implode(' AND ', $cond), $args];
}
public function total(): int {
[$where, $args] = $this->configure();
return self::$db->scalar("
SELECT count(*) FROM users_info ui WHERE $where
return (int)self::$db->scalar("
SELECT count(*) FROM users_main um WHERE $where
", ...$args
);
}
@@ -49,12 +50,13 @@ class Registration extends \Gazelle\Base {
public function page(int $limit, int $offset): array {
[$where, $args] = $this->configure();
self::$db->prepared_query("
SELECT ui.UserID FROM users_info AS ui
SELECT um.ID
FROM users_main um
WHERE $where
ORDER BY ui.Joindate DESC
ORDER BY um.created DESC
LIMIT ? OFFSET ?
", ...array_merge($args, [$limit, $offset])
);
return self::$db->collect('UserID');
return self::$db->collect(0, false);
}
}

View File

@@ -315,8 +315,8 @@ class User extends \Gazelle\BaseManager {
self::$db->prepared_query("
SELECT J.Week, J.n as Joined, coalesce(D.n, 0) as Disabled
FROM (
SELECT DATE_FORMAT(JoinDate, '%X-%V') AS Week, count(*) AS n
FROM users_info
SELECT DATE_FORMAT(created, '%X-%V') AS Week, count(*) AS n
FROM users_main
GROUP BY Week
ORDER BY 1 DESC
LIMIT 52) J
@@ -341,8 +341,9 @@ class User extends \Gazelle\BaseManager {
return (int)self::$db->scalar("
SELECT count(*) FROM (
SELECT 1
FROM users_info
GROUP BY DATE_FORMAT(coalesce(BanDate, JoinDate), '%Y-%m-%d')
FROM users_main um
INNER JOIN users_info ui ON (ui.UserID = um.ID)
GROUP BY DATE_FORMAT(coalesce(ui.BanDate, um.created), '%Y-%m-%d')
) D
");
}
@@ -356,15 +357,15 @@ class User extends \Gazelle\BaseManager {
self::$db->prepared_query("
SELECT j.Date AS date,
DATE_FORMAT(j.Date, '%Y-%m') AS month,
coalesce(j.Flow, 0) AS joined,
coalesce(j.Flow, 0) AS created,
coalesce(m.Flow, 0) AS manual,
coalesce(r.Flow, 0) AS ratio,
coalesce(i.Flow, 0) AS inactivity
FROM (
SELECT
DATE_FORMAT(JoinDate, '%Y-%m-%d') AS Date,
DATE_FORMAT(created, '%Y-%m-%d') AS Date,
count(*) AS Flow
FROM users_info
FROM users_main
GROUP BY Date
) AS j
LEFT JOIN (
@@ -375,7 +376,7 @@ class User extends \Gazelle\BaseManager {
WHERE BanDate IS NOT NULL
AND BanReason = '1'
GROUP BY Date
) AS m ON j.Date = m.Date
) AS m ON (j.Date = m.Date)
LEFT JOIN (
SELECT
DATE_FORMAT(BanDate, '%Y-%m-%d') AS Date,
@@ -477,7 +478,7 @@ class User extends \Gazelle\BaseManager {
SELECT um.ID AS user_id,
uls.Uploaded AS uploaded,
uls.Downloaded AS downloaded,
ui.JoinDate AS join_date,
um.created AS created,
ui.RatioWatchEnds AS ratio_watch_ends,
ui.RatioWatchDownload AS ratio_watch_downloaded,
um.RequiredRatio AS required_ratio
@@ -907,7 +908,7 @@ class User extends \Gazelle\BaseManager {
AND um.PermissionID = ?
AND uls.Uploaded + us.request_bounty_size >= ?
AND (uls.Downloaded = 0 OR uls.Uploaded / uls.Downloaded >= ?)
AND ui.JoinDate < now() - INTERVAL ? WEEK
AND um.created < now() - INTERVAL ? WEEK
AND us.upload_total >= ?
";
$args = [$level['From'], $level['MinUpload'], $level['MinRatio'], $level['Weeks'], $level['MinUploads']];
@@ -1250,6 +1251,45 @@ class User extends \Gazelle\BaseManager {
return $processed;
}
public function disableUnconfirmedUsers(\Gazelle\Schedule\Task $task = null): int {
// get a list of user IDs for clearing cache keys
self::$db->prepared_query("
SELECT ID
FROM users_main um
LEFT JOIN user_last_access AS ula ON (ula.user_id = um.ID)
WHERE ula.user_id IS NULL
AND um.created < now() - INTERVAL 7 DAY
AND um.Enabled != '2'
"
);
$userIDs = self::$db->collect(0, false);
// disable the users
self::$db->prepared_query("
UPDATE users_info AS ui
INNER JOIN users_main AS um ON (um.ID = ui.UserID)
LEFT JOIN user_last_access AS ula ON (ula.user_id = um.ID)
SET um.Enabled = '2',
ui.BanDate = now(),
ui.BanReason = '3',
ui.AdminComment = CONCAT(now(), ' - Disabled for inactivity (never logged in)\n\n', ui.AdminComment)
WHERE ula.user_id IS NULL
AND um.created < now() - INTERVAL 7 DAY
AND um.Enabled != '2'
"
);
if (self::$db->has_results()) {
$this->flushEnabledUsersCount();
}
// clear the appropriate cache keys
foreach ($userIDs as $userID) {
self::$cache->delete_value("u_$userID");
$task?->debug("Disabled $userID", $userID);
}
return count($userIDs);
}
public function triggerRatioWatch(\Gazelle\Tracker $tracker, \Gazelle\Schedule\Task $task = null): int {
self::$db->prepared_query("
SELECT um.ID, um.torrent_pass
@@ -1290,9 +1330,7 @@ class User extends \Gazelle\BaseManager {
'Your downloading privileges have been suspended',
"As you did not raise your ratio in time, your downloading privileges have been revoked. You will not be able to download any torrents until your ratio is above your new required ratio."
);
if ($task) {
$task->debug("Disabled leech for $userId", $userId);
}
$task?->debug("Disabled leech for $userId", $userId);
}
foreach ($passkeys as $passkey) {

View File

@@ -4,43 +4,6 @@ namespace Gazelle\Schedule\Tasks;
class DisableUnconfirmedUsers extends \Gazelle\Schedule\Task {
public function run(): void {
// get a list of user IDs for clearing cache keys
self::$db->prepared_query("
SELECT UserID
FROM users_info AS ui
INNER JOIN users_main AS um ON (um.ID = ui.UserID)
LEFT JOIN user_last_access AS ula ON (ula.user_id = um.ID)
WHERE ula.user_id IS NULL
AND ui.JoinDate < now() - INTERVAL 7 DAY
AND um.Enabled != '2'
"
);
$userIDs = self::$db->collect('UserID');
// disable the users
self::$db->prepared_query("
UPDATE users_info AS ui
INNER JOIN users_main AS um ON (um.ID = ui.UserID)
LEFT JOIN user_last_access AS ula ON (ula.user_id = um.ID)
SET um.Enabled = '2',
ui.BanDate = now(),
ui.BanReason = '3',
ui.AdminComment = CONCAT(now(), ' - Disabled for inactivity (never logged in)\n\n', ui.AdminComment)
WHERE ula.user_id IS NULL
AND ui.JoinDate < now() - INTERVAL 7 DAY
AND um.Enabled != '2'
"
);
if (self::$db->has_results()) {
$userMan = new \Gazelle\Manager\User;
$userMan->flushEnabledUsersCount();
}
// clear the appropriate cache keys
foreach ($userIDs as $userID) {
self::$cache->delete_value("u_$userID");
$this->processed++;
$this->debug("Disabled $userID", $userID);
}
$this->processed = (new \Gazelle\Manager\User)->disableUnconfirmedUsers();
}
}

View File

@@ -87,17 +87,16 @@ class Email extends \Gazelle\Base {
}
public function liveList(int $limit, int $offset): array {
$column = ['um.Email', 'um.Username', 'ui.JoinDate', 'ui.JoinDate', 'inet_aton(um.IP)'][$this->column];
$column = ['um.Email', 'um.Username', 'um.created', 'um.created', 'inet_aton(um.IP)'][$this->column];
$direction = ['ASC', 'DESC'][$this->direction];
self::$db->prepared_query("
SELECT um.Email AS email,
um.Username AS username,
um.ID AS user_id,
ui.JoinDate AS join_date,
um.created AS created,
um.IP AS ipv4
FROM users_main um
INNER JOIN users_info ui ON (ui.UserID = um.ID)
INNER JOIN {$this->name} s ON (s.email = um.Email)
ORDER BY $column $direction
LIMIT ? OFFSET ?
@@ -123,20 +122,19 @@ class Email extends \Gazelle\Base {
}
public function historyList(int $limit, int $offset): array {
$column = ['uhe.Email', 'um.Username', 'ui.JoinDate', 'uhe.Time', 'inet_aton(uhe.IP)'][$this->column];
$column = ['uhe.Email', 'um.Username', 'um.created', 'uhe.Time', 'inet_aton(uhe.IP)'][$this->column];
$direction = ['ASC', 'DESC'][$this->direction];
self::$db->prepared_query("
SELECT uhe.Email AS email,
um.Username AS username,
um.ID AS user_id,
ui.JoinDate AS join_date,
um.created AS created,
uhe.Time AS change_date,
uhe.IP AS ipv4
FROM users_history_emails uhe
INNER JOIN {$this->name} s ON (s.email = uhe.Email)
INNER JOIN users_main um ON (um.ID = uhe.UserID)
INNER JOIN users_info ui ON (ui.UserID = um.ID)
WHERE ((ui.JoinDate = uhe.Time and uhe.Email != um.Email) OR ui.JoinDate != uhe.Time)
WHERE ((um.created = uhe.Time and uhe.Email != um.Email) OR um.created != uhe.Time)
ORDER BY $column $direction
LIMIT ? OFFSET ?
", $limit, $offset

View File

@@ -27,10 +27,10 @@ class Users extends \Gazelle\Base {
J.n AS new,
coalesce(D.n, 0) AS disabled
FROM (
SELECT DATE_FORMAT(JoinDate,'%Y%m') AS M,
DATE_FORMAT(JoinDate, '%b %Y') AS Mon,
count(*) AS n
FROM users_info
SELECT DATE_FORMAT(created,'%Y%m') AS M,
DATE_FORMAT(created, '%b %Y') AS Mon,
count(*) AS n
FROM users_main
GROUP BY M
ORDER BY 1 DESC
LIMIT 1, 12

View File

@@ -32,17 +32,16 @@ class User extends \Gazelle\Base {
$orderBy = $this->sortMap[$type];
self::$db->prepared_query(sprintf("
SELECT
um.ID AS id,
ui.JoinDate AS join_date,
uls.Uploaded AS uploaded,
uls.Downloaded AS downloaded,
um.ID AS id,
um.created AS created,
uls.Uploaded AS uploaded,
uls.Downloaded AS downloaded,
coalesce(bs.Bounty, 0) AS request_votes,
coalesce(bf.Fills, 0) AS request_fills,
abs(uls.Uploaded - ?) / (unix_timestamp() - unix_timestamp(ui.JoinDate)) AS up_speed,
uls.Downloaded / (unix_timestamp() - unix_timestamp(ui.JoinDate)) AS down_speed,
coalesce(bf.Fills, 0) AS request_fills,
abs(uls.Uploaded - ?) / (unix_timestamp() - unix_timestamp(um.created)) AS up_speed,
uls.Downloaded / (unix_timestamp() - unix_timestamp(um.created)) AS down_speed,
count(t.ID) AS num_uploads
FROM users_main AS um
INNER JOIN users_info AS ui ON (ui.UserID = um.ID)
INNER JOIN users_leech_stats AS uls ON (uls.UserID = um.ID)
LEFT JOIN torrents AS t ON (t.UserID = um.ID)
LEFT JOIN

View File

@@ -8,7 +8,7 @@ use \Gazelle\Util\Irc;
use \Gazelle\Util\Mail;
class User extends BaseObject {
final const CACHE_KEY = 'u2_%d';
final const CACHE_KEY = 'u3_%d';
final const CACHE_SNATCH_TIME = 'users_snatched_%d_time';
final const CACHE_NOTIFY = 'u_notify_%d';
final const USER_RECENT_SNATCH = 'u_recent_snatch_%d';
@@ -95,6 +95,7 @@ class User extends BaseObject {
self::$db->prepared_query("
SELECT um.Username,
um.can_leech,
um.created,
um.CustomPermissions,
um.IP,
um.Email,
@@ -117,7 +118,6 @@ class User extends BaseObject {
ui.Info,
ui.InfoTitle,
ui.Inviter,
ui.JoinDate,
ui.NavItems,
ui.NotifyOnDeleteSeeding,
ui.NotifyOnDeleteSnatched,
@@ -432,7 +432,7 @@ class User extends BaseObject {
}
public function created(): string {
return $this->info()['JoinDate'];
return $this->info()['created'];
}
public function disableAvatar(): bool {
@@ -1622,7 +1622,7 @@ class User extends BaseObject {
um.Email AS email,
uls.Uploaded AS uploaded,
uls.Downloaded AS downloaded,
ui.JoinDate AS join_date,
um.created AS created,
ula.last_access
FROM users_main AS um
LEFT JOIN user_last_access AS ula ON (ula.user_id = um.ID)
@@ -1644,10 +1644,10 @@ class User extends BaseObject {
public function passwordAge(): string {
$age = time_diff(
$this->getSingleValue('user_pw_age', '
SELECT coalesce(max(uhp.ChangeTime), ui.JoinDate)
FROM users_info ui
LEFT JOIN users_history_passwords uhp USING (UserID)
WHERE ui.UserID = ?
SELECT coalesce(max(uhp.ChangeTime), um.created)
FROM users_main um
LEFT JOIN users_history_passwords uhp ON (uhp.UserID = um.ID)
WHERE um.ID = ?
')
);
return substr($age, 0, (int)strpos($age, " ago"));

View File

@@ -2,7 +2,7 @@ From: Spine
To: Developers
Date: 2021-01-17
Subject: Orpheus Development Papers #4 - Witness Tables
Version: 1
Version: 2
This technique is a response to a problem that exists in the original
Gazelle implementation. There are many wide tables (that is, tables with
@@ -57,6 +57,10 @@ blog article that was written before they joined.
Going forward, all newly created accounts will be considered as having
read the most recent blog and news items.
Note: since the time this article was written, the column
users_info.JoinDate has been superceded by the column users_main.created
The follow queries must be adapted in light of that.
INSERT INTO user_read_blog (user_id, blog_id)
SELECT ui.UserID, ui.LastReadBlog
FROM users_info ui

View File

@@ -1595,31 +1595,6 @@ parameters:
count: 1
path: ../app/Manager/Referral.php
-
message: "#^Method Gazelle\\\\Manager\\\\Registration\\:\\:setAfterDate\\(\\) has no return type specified\\.$#"
count: 1
path: ../app/Manager/Registration.php
-
message: "#^Method Gazelle\\\\Manager\\\\Registration\\:\\:setBeforeDate\\(\\) has no return type specified\\.$#"
count: 1
path: ../app/Manager/Registration.php
-
message: "#^Method Gazelle\\\\Manager\\\\Registration\\:\\:total\\(\\) should return int but returns bool\\|float\\|int\\|string\\|null\\.$#"
count: 1
path: ../app/Manager/Registration.php
-
message: "#^Property Gazelle\\\\Manager\\\\Registration\\:\\:\\$afterDate has no type specified\\.$#"
count: 1
path: ../app/Manager/Registration.php
-
message: "#^Property Gazelle\\\\Manager\\\\Registration\\:\\:\\$beforeDate has no type specified\\.$#"
count: 1
path: ../app/Manager/Registration.php
-
message: "#^Binary operation \"\\+\\=\" between int\\|string\\|null and int results in an error\\.$#"
count: 1

View File

@@ -19,15 +19,14 @@ $BaseQuery = "
SELECT
um.ID,
um.Username,
ui.JoinDate,
um.created,
uls.Uploaded,
uls.Downloaded,
GREATEST(uls.Uploaded - ?, 0) / (unix_timestamp(now()) - unix_timestamp(ui.JoinDate)) AS UpSpeed,
uls.Downloaded / (unix_timestamp(now()) - unix_timestamp(ui.JoinDate)) AS DownSpeed,
GREATEST(uls.Uploaded - ?, 0) / (unix_timestamp(now()) - unix_timestamp(um.created)) AS UpSpeed,
uls.Downloaded / (unix_timestamp(now()) - unix_timestamp(um.created)) AS DownSpeed,
count(t.ID) AS NumUploads
FROM users_main AS um
INNER JOIN users_leech_stats AS uls ON (uls.UserID = um.ID)
INNER JOIN users_info AS ui ON (ui.UserID = um.ID)
LEFT JOIN torrents AS t ON (t.UserID = um.ID)
WHERE um.Enabled = '1'
AND uls.Uploaded > 5 * 1024 * 1024 * 1024
@@ -123,7 +122,7 @@ function generate_user_json(string $Caption, string $Tag, array $Details, int $L
'downloaded' => (float)$Detail['Downloaded'],
'downSpeed' => (float)$Detail['DownSpeed'],
'numUploads' => (int)$Detail['NumUploads'],
'joinDate' => $Detail['JoinDate']
'joinDate' => $Detail['created']
];
}
return [

View File

@@ -14,7 +14,7 @@ $userflowDetails = $userMan->userflowDetails($paginator->limit(), $paginator->of
echo $Twig->render('admin/userflow.twig', [
'category' => array_map(fn($x) => "'$x'", array_keys($userflow)),
'disabled' => array_map(fn($x) => $userflow[$x]['Joined'], array_keys($userflow)),
'disabled' => array_map(fn($x) => $userflow[$x]['created'], array_keys($userflow)),
'enabled' => array_map(fn($x) => -$userflow[$x]['Disabled'], array_keys($userflow)),
'paginator' => $paginator,
'show_flow' => $showFlow,

View File

@@ -86,7 +86,7 @@ $OrderTable = [
'Downloads' => 'Downloads',
'Email' => 'um1.Email',
'Invites' => 'um1.Invites',
'Joined' => 'ui1.JoinDate',
'Joined' => 'um1.created',
'Last Seen' => 'ula.last_access',
'Ratio' => '(uls1.Uploaded / uls1.Downloaded)',
'Seeding' => 'Seeding',
@@ -304,7 +304,7 @@ if (empty($_GET)) {
if (isset($_GET['joined']) && !empty($_GET['joined']) && isset($_GET['join1']) && !empty($_GET['join1'])) {
$op = $_GET['joined'];
$Where[] = $m->date('ui1.JoinDate', $op);
$Where[] = $m->date('um1.created', $op);
$Args[] = $_GET['join1'];
if ($op === 'on') {
$Args[] = $_GET['join1'];

View File

@@ -27,12 +27,12 @@ if (count($userSource)) {
$invSourceMan->modifyUserSource($userId, $userSource);
}
$heading = new \Gazelle\Util\SortableTableHeader('joined', [
$heading = new \Gazelle\Util\SortableTableHeader('created', [
// see Gazelle\User::inviteList() for these table aliases
'id' => ['dbColumn' => 'um.ID', 'defaultSort' => 'desc'],
'username' => ['dbColumn' => 'um.Username', 'defaultSort' => 'desc', 'text' => 'Username'],
'email' => ['dbColumn' => 'um.Email', 'defaultSort' => 'desc', 'text' => 'Email'],
'joined' => ['dbColumn' => 'ui.JoinDate', 'defaultSort' => 'desc', 'text' => 'Joined'],
'created' => ['dbColumn' => 'um.created' , 'defaultSort' => 'desc', 'text' => 'Joined'],
'lastseen' => ['dbColumn' => 'ula.last_access', 'defaultSort' => 'desc', 'text' => 'Last Seen'],
'uploaded' => ['dbColumn' => 'uls.Uploaded', 'defaultSort' => 'desc', 'text' => 'Uploaded'],
'downloaded' => ['dbColumn' => 'uls.Downloaded', 'defaultSort' => 'desc', 'text' => 'Downloaded'],

View File

@@ -18,7 +18,7 @@
<span style="float: left;">{{ item.ipaddr }} ({{ item.ipaddr }})</span><span style="float: right;"><a href="userhistory.php?action=ips&amp;userid={{ item.user_id }}" title="History" class="brackets tooltip">H</a> <a href="user.php?action=search&amp;ip_history=on&amp;ip={{ item.ipaddr }}" title="Search" class="brackets tooltip">S</a></span>
</td>
<td>{{ item.uses|number_format }}</td>
<td>{{ item.joined|time_diff }}</td>
<td>{{ item.created|time_diff }}</td>
</tr>
{% endfor %}
</table>

View File

@@ -39,7 +39,7 @@
<tr>
<td{% if r.is_tor %} class="tor"{% endif %}>{{ ip_search(r.ipv4) }}</td>
<td>{{ r.cc }}</td>
<td>{{ r.join_date }}</td>
<td>{{ r.created }}</td>
<td>{% if r.user_id %}{{ r.user_id|user_url }}{% else %}User #{{ r.user_id }}{% endif %} / {{ r.email }}</td>
<td>{{ asn(r.name, r.n) }}</td>
<td>{{ rdns(r.ipv4) }}</td>
@@ -73,7 +73,7 @@
<tr>
<td{% if r.is_tor %} class="tor"{% endif %}>{{ ip_search(r.ipv4) }}</td>
<td>{{ r.cc }}</td>
<td>{{ r.join_date }}</td>
<td>{{ r.created }}</td>
<td>{{ r.change_date }}</td>
<td>{% if r.user_id %}{{ r.user_id|user_url }}{% else %}User #{{ r.user_id }}{% endif %} / {{ r.email }}</td>
<td>{{ asn(r.name, r.n) }}</td>

View File

@@ -36,7 +36,7 @@
{%- endif -%}
</td>
<td class="number_column">{{ (u.downloaded - u.ratio_watch_downloaded)|octet_size }}</td>
<td>{{ u.join_date|time_diff }}</td>
<td>{{ u.created|time_diff }}</td>
<td>{{ u.ratio_watch_ends|time_diff }}</td>
</tr>
{% endfor %}

View File

@@ -49,7 +49,7 @@
<td class="number_column">{{ row.request_fills|number_format }}</td>
<td class="number_column">{{ row.num_uploads|number_format }}</td>
<td class="number_column">{{ ratio(row.uploaded, row.downloaded) }}</td>
<td class="number_column">{{ row.join_date|time_diff }}</td>
<td class="number_column">{{ row.created|time_diff }}</td>
</tr>
{% endfor %}
</table><br />

View File

@@ -138,7 +138,7 @@
<tr class="colhead">
<td class="m_th_left nobr">{{ heading|column('username') }}</td>
<td class="nobr">{{ heading|column('email') }}</td>
<td class="nobr">{{ heading|column('joined') }}</td>
<td class="nobr">{{ heading|column('created') }}</td>
<td class="nobr">{{ heading|column('lastseen') }}</td>
<td class="m_th_right nobr">{{ heading|column('uploaded') }}</td>
<td class="m_th_right nobr">{{ heading|column('downloaded') }}</td>
@@ -151,7 +151,7 @@
<tr class="row{{ cycle(['a', 'b'], loop.index0) }}">
<td class="td_username">{{ u.user_id|user_full|raw }}</td>
<td class="td_email">{{ u.email }}</td>
<td class="td_join_date">{{ u.join_date|time_diff }}</td>
<td class="td_join_date">{{ u.created|time_diff }}</td>
<td class="td_last_access">{{ u.last_access|time_diff }}</td>
<td class="td_up m_td_right">{{ u.uploaded|octet_size }}</td>
<td class="td_dl m_td_right">{{ u.downloaded|octet_size }}</td>

View File

@@ -0,0 +1,47 @@
<?php
use \PHPUnit\Framework\TestCase;
require_once(__DIR__ . '/../../lib/bootstrap.php');
require_once(__DIR__ . '/../helper.php');
class SearchEmailTest extends TestCase {
protected array $userList;
public function setUp(): void {
$this->userList = [
Helper::makeUser('email1.' . randomString(10), 'email-search'),
Helper::makeUser('email2.' . randomString(10), 'email-search'),
Helper::makeUser('email3.' . randomString(10), 'email-search'),
];
}
public function tearDown(): void {
foreach ($this->userList as $user) {
$user->remove();
}
}
public function testSearchEmail(): void {
$search = new \Gazelle\Search\Email(new \Gazelle\Search\ASN);
$search->create(randomString());
$text = "chaff {$this->userList[0]->email()} chaff {$this->userList[1]->email()} chaff {$this->userList[2]->email()} dup {$this->userList[0]->email()} ";
$list = $search->extract($text);
$this->assertCount(3, $list, 'search-email-extract');
$this->assertEquals(0, $search->add([]), 'search-add-empty');
$this->assertEquals(3, $search->add($list), 'search-add-list');
$emailList = array_map(fn($u) => $u->email(), $this->userList);
sort($emailList);
$this->assertEquals($emailList, $search->emailList(), 'search-email-list');
$search->setColumn(1); // Username
$search->setDirection(1); // DESC
$liveList = $search->liveList(3, 0);
$this->assertCount(3, $liveList, 'search-live-list-count');
$nameList = array_map(fn($u) => $u->username(), $this->userList);
rsort($nameList);
$this->assertEquals($nameList, array_map(fn($e) => $e['username'], $liveList), 'searach-live-page-order');
}
}

View File

@@ -0,0 +1,54 @@
<?php
use \PHPUnit\Framework\TestCase;
require_once(__DIR__ . '/../../../lib/bootstrap.php');
require_once(__DIR__ . '/../../helper.php');
class DuplicateIpTest extends TestCase {
protected array $userList;
public function setUp(): void {
$ip = '169.254.0.1';
$this->userList = [
Helper::makeUser('dupip.' . randomString(10), 'duplicate.ip')->setUpdate('IP', $ip)->setUpdate('Enabled', '1'),
Helper::makeUser('dupip.' . randomString(10), 'duplicate.ip')->setUpdate('IP', $ip)->setUpdate('Enabled', '1'),
Helper::makeUser('dupip.' . randomString(10), 'duplicate.ip')->setUpdate('IP', $ip)->setUpdate('Enabled', '1'),
Helper::makeUser('dupip.' . randomString(10), 'duplicate.ip')->setUpdate('IP', $ip)->setUpdate('Enabled', '1'),
Helper::makeUser('dupip.' . randomString(10), 'duplicate.ip')->setUpdate('IP', $ip)->setUpdate('Enabled', '1'),
];
foreach ($this->userList as $user) {
$user->modify();
}
\Gazelle\DB::DB()->prepared_query("
INSERT INTO users_history_ips (UserID, IP, StartTime, EndTime) VALUES
(?, '$ip', now() - interval 10 day, now() - interval 1 day),
(?, '$ip', now() - interval 10 day, now() - interval 1 day),
(?, '$ip', now() - interval 10 day, now() - interval 1 day),
(?, '$ip', now() - interval 10 day, now() - interval 1 day),
(?, '$ip', now() - interval 10 day, now() - interval 1 day)
", ...array_map(fn($u) => $u->id(), $this->userList)
);
}
public function tearDown(): void {
$idList = array_map(fn($u) => $u->id(), $this->userList);
\Gazelle\DB::DB()->prepared_query("
DELETE FROM users_history_ips WHERE UserID IN (" . placeholders($idList) . ")
", ...$idList
);
foreach ($this->userList as $user) {
$user->remove();
}
}
public function testDuplicateIpTotal(): void {
$dup = new \Gazelle\Manager\DuplicateIP;
$total = $dup->total(5);
$this->assertGreaterThan(1, $total, 'duplicate-ip-total');
$list = $dup->page(5, 1000, 0);
$this->assertCount(5, array_filter($list, fn($d) => $d['ipaddr'] == $this->userList[0]->ipaddr()), 'duplicate-ip-page');
}
}

View File

@@ -0,0 +1,66 @@
<?php
use \PHPUnit\Framework\TestCase;
require_once(__DIR__ . '/../../../lib/bootstrap.php');
require_once(__DIR__ . '/../../helper.php');
class UserRegistrationTest extends TestCase {
protected array $userList;
public function setUp(): void {
$this->userList = [
Helper::makeUser('reg1.' . randomString(10), 'registration')->setUpdate('created', '1600-01-15 13:01:05'),
Helper::makeUser('reg2.' . randomString(10), 'registration')->setUpdate('created', '1600-02-15 14:02:10'),
Helper::makeUser('reg3.' . randomString(10), 'registration')->setUpdate('created', '1600-03-15 15:03:15'),
Helper::makeUser('reg4.' . randomString(10), 'registration')->setUpdate('created', '2600-01-15 16:04:20'),
Helper::makeUser('reg5.' . randomString(10), 'registration')->setUpdate('created', '2600-01-15 17:05:25'),
];
foreach ($this->userList as $user) {
$user->modify();
}
}
public function tearDown(): void {
foreach ($this->userList as $user) {
$user->remove();
}
}
public function testUserRegistrationAfter(): void {
$reg = new Gazelle\Manager\Registration;
$reg->setAfterDate("2600-01-01 00:00:01");
$this->assertEquals(2, $reg->total(), 'user-reg-total-after');
$list = $reg->page(10, 0);
$this->assertCount(2, $list, 'user-reg-list-after');
$this->assertFalse(in_array($this->userList[2]->id(), $list), 'user-reg-after-not-2');
$this->assertTrue(in_array($this->userList[3]->id(), $list), 'user-reg-after-3');
}
public function testUserRegistrationBefore(): void {
$reg = new Gazelle\Manager\Registration;
$reg->setBeforeDate("1600-12-31");
$this->assertEquals(3, $reg->total(), 'user-reg-total-before');
$list = $reg->page(10, 0);
$this->assertCount(3, $list, 'user-reg-list-before');
$this->assertTrue(in_array($this->userList[0]->id(), $list), 'user-reg-before-0');
$this->assertTrue(in_array($this->userList[2]->id(), $list), 'user-reg-before-2');
$this->assertFalse(in_array($this->userList[3]->id(), $list), 'user-reg-before-not-3');
}
public function testUserRegistrationBetween(): void {
$reg = new Gazelle\Manager\Registration;
$reg->setAfterDate("1600-02-01")->setBeforeDate("1600-03-01");
$this->assertEquals(1, $reg->total(), 'user-reg-total-between');
$list = $reg->page(10, 0);
$this->assertCount(1, $list, 'user-reg-list-between');
$this->assertEquals([$this->userList[1]->id()], $list, 'user-reg-between-1');
}
public function testUserRegistrationUnconfirmed(): void {
$this->assertEquals(3, (new Gazelle\Manager\User)->disableUnconfirmedUsers(), 'user-reg-unconfirmed');
}
}