seria/src/user.php
2022-07-03 23:44:11 +00:00

218 lines
7.3 KiB
PHP

<?php
class SeriaUserNotFoundException extends RuntimeException {}
class SeriaUserExtremelyNotFoundException extends SeriaUserNotFoundException {}
class SeriaUserColour {
public const INHERIT = 0x40000000;
private int $raw;
public function __construct(int $raw) {
$this->raw = $raw;
}
public function __toString(): string {
if($this->raw & self::INHERIT)
return 'inherit';
return '#' . str_pad(dechex($this->raw & 0xFFFFFF), 6, '0', STR_PAD_LEFT);
}
}
class SeriaUser {
private const KEY_CHARS = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789';
private const KEY_LENGTH = 48;
private ?PDO $pdo;
private string $user_id = '';
private string $user_name = 'Anonymous';
private int $user_colour = SeriaUserColour::INHERIT;
private int $user_rank = 0;
private int $user_permissions = 0;
private ?string $user_pass_key = null;
private int $user_bytes_downloaded = 0;
private int $user_bytes_uploaded = 0;
public function __construct(?PDO $pdo = null) {
$this->pdo = $pdo;
}
public function getId(): string {
return $this->user_id;
}
public function getName(): string {
return $this->user_name;
}
public function getColour(): SeriaUserColour {
return new SeriaUserColour($this->user_colour);
}
public function getColourRaw(): int {
return $this->user_colour;
}
public function getRank(): int {
return $this->user_rank;
}
public function getPermissionsRaw(): int {
return $this->user_permissions;
}
public function getPassKey(): string {
if(!$this->isLoggedIn())
return '';
if(($passKey = $this->user_pass_key) === null)
return $this->resetPassKey();
return $passKey;
}
public function getBytesDownloaded(): int {
return $this->user_bytes_downloaded;
}
public function getBytesUploaded(): int {
return $this->user_bytes_uploaded;
}
public function isLoggedIn() {
return !empty($this->user_id);
}
public function isFlash(): bool {
return $this->user_id === '1';
}
public function canCreateTorrents(): bool {
return $this->isFlash()
|| $this->user_id === '32'
|| $this->user_id === '145';
}
public function canApproveTorrents(): bool {
return $this->isFlash();
}
public function canRecalculateInfoHash(): bool {
return $this->isFlash();
}
public function calculateRatio(): float {
$bd = $this->getBytesDownloaded();
if($bd === 0)
return 0;
return $this->getBytesUploaded() / $bd;
}
public function getActiveTransferCounts(): stdClass {
return SeriaTorrentPeer::countUserStats($this->pdo, $this);
}
public function getProfileSubmissions(): array {
return $this->getSubmissions(-1, 3);
}
public function getSubmissions(int $startAt, int $take): array {
return SeriaTorrent::byUser($this->pdo, $this, $startAt, $take);
}
public static function generatePassKey(int $length): string {
$keyChars = strlen(self::KEY_CHARS) - 1;
$bytes = str_repeat("\0", $length);
for($i = 0; $i < $length; ++$i)
$bytes[$i] = self::KEY_CHARS[random_int(0, $keyChars)];
return $bytes;
}
public function resetPassKey(): string {
if(!$this->isLoggedIn())
return '';
$updatePassKey = $this->pdo->prepare('UPDATE `ser_users` SET `user_pass_key` = :pass WHERE `user_id` = :user');
$updatePassKey->bindValue('user', $this->user_id);
do {
$updatePassKey->bindValue('pass', $passKey = self::generatePassKey(self::KEY_LENGTH));
} while(!$updatePassKey->execute());
return $this->user_pass_key = $passKey;
}
public function incrementTransferCounts(int $bytesDownloaded, int $bytesUploaded): void {
if(!$this->isLoggedIn())
return;
$updateStats = $this->pdo->prepare('UPDATE `ser_users` SET `user_bytes_downloaded` = `user_bytes_downloaded` + :downloaded, `user_bytes_uploaded` = `user_bytes_uploaded` + :uploaded WHERE `user_id` = :user');
$updateStats->bindValue('downloaded', $bytesDownloaded);
$updateStats->bindValue('uploaded', $bytesUploaded);
$updateStats->bindValue('user', $this->user_id);
if($updateStats->execute()) {
$this->user_bytes_downloaded += $bytesDownloaded;
$this->user_bytes_uploaded += $bytesUploaded;
}
}
public static function anonymous(): self {
return new static;
}
public static function fromMisuzu(PDO $pdo, stdClass $info): self {
$update = $pdo->prepare('INSERT INTO `ser_users` (`user_id`, `user_name`, `user_colour`, `user_rank`, `user_permissions`) VALUES (:id, :name_1, :colour_1, :rank_1, :perms_1) ON DUPLICATE KEY UPDATE `user_name` = :name_2, `user_colour` = :colour_2, `user_rank` = :rank_2, `user_permissions` = :perms_2');
$update->bindValue('id', $info->user_id);
$update->bindValue('name_1', $info->username);
$update->bindValue('name_2', $info->username);
$update->bindValue('colour_1', $info->colour_raw);
$update->bindValue('colour_2', $info->colour_raw);
$update->bindValue('rank_1', $info->hierarchy);
$update->bindValue('rank_2', $info->hierarchy);
$update->bindValue('perms_1', $info->perms);
$update->bindValue('perms_2', $info->perms);
$update->execute();
return self::byId($pdo, $info->user_id);
}
public static function byId(PDO $pdo, string $userId): self {
$getUser = $pdo->prepare('SELECT `user_id`, `user_name`, `user_colour`, `user_rank`, `user_permissions`, `user_pass_key`, `user_bytes_downloaded`, `user_bytes_uploaded` FROM `ser_users` WHERE `user_id` = :user');
$getUser->bindValue('user', $userId);
if(!$getUser->execute())
throw new SeriaUserExtremelyNotFoundException;
if(($obj = $getUser->fetchObject(self::class, [$pdo])) === false)
throw new SeriaUserNotFoundException;
return $obj;
}
public static function byName(PDO $pdo, string $userName): self {
$getUser = $pdo->prepare('SELECT `user_id`, `user_name`, `user_colour`, `user_rank`, `user_permissions`, `user_pass_key`, `user_bytes_downloaded`, `user_bytes_uploaded` FROM `ser_users` WHERE `user_name` = :user');
$getUser->bindValue('user', $userName);
if(!$getUser->execute())
throw new SeriaUserExtremelyNotFoundException;
if(($obj = $getUser->fetchObject(self::class, [$pdo])) === false)
throw new SeriaUserNotFoundException;
return $obj;
}
public static function byPassKey(PDO $pdo, string $passKey): self {
$getUser = $pdo->prepare('SELECT `user_id`, `user_name`, `user_colour`, `user_rank`, `user_permissions`, `user_pass_key`, `user_bytes_downloaded`, `user_bytes_uploaded` FROM `ser_users` WHERE `user_pass_key` = :pass');
$getUser->bindValue('pass', $passKey);
if(!$getUser->execute())
throw new SeriaUserExtremelyNotFoundException;
if(($obj = $getUser->fetchObject(self::class, [$pdo])) === false)
throw new SeriaUserNotFoundException;
return $obj;
}
}