diff --git a/Changelog b/Changelog index b956c3b39..33aa90687 100755 --- a/Changelog +++ b/Changelog @@ -1,4 +1,5 @@ 2017-12-25 DariusIII + * Chg: Remove Users class and use models in its place * Chg: Update Settings model 2017-12-24 DariusIII * Chg: Remove sitewide sab/nzbget integration diff --git a/_install/install_nntmux.php b/_install/install_nntmux.php index 24c6f29a5..ef24660bd 100644 --- a/_install/install_nntmux.php +++ b/_install/install_nntmux.php @@ -6,8 +6,8 @@ if (! defined('NN_INSTALLER')) { require_once dirname(__DIR__).DIRECTORY_SEPARATOR.'bootstrap/autoload.php'; include_once dirname(__DIR__).DIRECTORY_SEPARATOR.'nntmux'.DIRECTORY_SEPARATOR.'constants.php'; +use App\Models\User; use nntmux\db\DB; -use nntmux\Users; use nntmux\ColorCLI; use nntmux\db\DbUpdate; use nntmux\config\Configure; @@ -168,21 +168,20 @@ if (env('ADMIN_USER') === '' || env('ADMIN_PASS') === '' || env('ADMIN_EMAIL') = ]); $capsule->bootEloquent(); -$user = new Users(); -if (! $user->isValidUsername(env('ADMIN_USER'))) { +if (! User::isValidUsername(env('ADMIN_USER'))) { $error = true; } else { - $usrCheck = $user->getByUsername(env('ADMIN_USER')); + $usrCheck = User::getByUsername(env('ADMIN_USER')); if ($usrCheck) { $error = true; } } -if (! $user->isValidEmail(env('ADMIN_EMAIL'))) { +if (! User::isValidEmail(env('ADMIN_EMAIL'))) { $error = true; } if (! $error) { - $adminCheck = $user->add(env('ADMIN_USER'), env('ADMIN_PASS'), env('ADMIN_EMAIL'), 2, '', ''); + $adminCheck = User::add(env('ADMIN_USER'), env('ADMIN_PASS'), env('ADMIN_EMAIL'), 2, '', ''); if (! is_numeric($adminCheck)) { $error = true; } diff --git a/app/Extensions/helper/helpers.php b/app/Extensions/helper/helpers.php index 6c3567eec..27a82e11f 100644 --- a/app/Extensions/helper/helpers.php +++ b/app/Extensions/helper/helpers.php @@ -74,4 +74,87 @@ if (! function_exists('makeFieldLinks')) { return implode(', ', $newArr); } + + if (! function_exists('getUserBrowseOrder')) { + /** + * @param string $orderBy + * + * @return array + */ + function getUserBrowseOrder($orderBy): array + { + $order = ($orderBy === '' ? 'username_desc' : $orderBy); + $orderArr = explode('_', $order); + switch ($orderArr[0]) { + case 'username': + $orderField = 'username'; + break; + case 'email': + $orderField = 'email'; + break; + case 'host': + $orderField = 'host'; + break; + case 'createdat': + $orderField = 'created_at'; + break; + case 'lastlogin': + $orderField = 'lastlogin'; + break; + case 'apiaccess': + $orderField = 'apiaccess'; + break; + case 'apirequests': + $orderField = 'apirequests'; + break; + case 'grabs': + $orderField = 'grabs'; + break; + case 'user_roles_id': + $orderField = 'users_role_id'; + break; + case 'rolechangedate': + $orderField = 'rolechangedate'; + break; + default: + $orderField = 'username'; + break; + } + $orderSort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc'; + + return [$orderField, $orderSort]; + } + } + + if (! function_exists('getUserBrowseOrdering')) { + + /** + * @return array + */ + function getUserBrowseOrdering(): array + { + return [ + 'username_asc', + 'username_desc', + 'email_asc', + 'email_desc', + 'host_asc', + 'host_desc', + 'createdat_asc', + 'createdat_desc', + 'lastlogin_asc', + 'lastlogin_desc', + 'apiaccess_asc', + 'apiaccess_desc', + 'apirequests_asc', + 'apirequests_desc', + 'grabs_asc', + 'grabs_desc', + 'role_asc', + 'role_desc', + 'rolechangedate_asc', + 'rolechangedate_desc' + ]; + } + } } diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php index 6189723a3..11b1a0382 100644 --- a/app/Models/Invitation.php +++ b/app/Models/Invitation.php @@ -3,9 +3,13 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Carbon; class Invitation extends Model { + public const DEFAULT_INVITES = 1; + public const DEFAULT_INVITE_EXPIRY_DAYS = 7; + /** * @var bool */ @@ -25,4 +29,35 @@ class Invitation extends Model { return $this->belongsTo(User::class, 'users_id'); } + + /** + * @param int $uid + * @param string $inviteToken + */ + public static function addInvite(int $uid, string $inviteToken) + { + self::query()->insertGetId(['guid' => $inviteToken, 'users_id' => $uid, 'created_at' => Carbon::now()]); + } + + /** + * @param $inviteToken + * @return \Illuminate\Database\Eloquent\Model|null|static + */ + public static function getInvite($inviteToken) + { + // + // Tidy any old invites sent greater than DEFAULT_INVITE_EXPIRY_DAYS days ago. + // + self::query()->where('created_at', '<', Carbon::now()->subDays(self::DEFAULT_INVITE_EXPIRY_DAYS)); + + return self::query()->where('guid', $inviteToken)->first(); + } + + /** + * @param $inviteToken + */ + public static function deleteInvite(string $inviteToken): void + { + self::query()->where('guid', $inviteToken)->delete(); + } } diff --git a/app/Models/RoleExcludedCategory.php b/app/Models/RoleExcludedCategory.php index add32ea14..e63a00a1d 100644 --- a/app/Models/RoleExcludedCategory.php +++ b/app/Models/RoleExcludedCategory.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Carbon; class RoleExcludedCategory extends Model { @@ -19,4 +20,42 @@ class RoleExcludedCategory extends Model { return $this->hasMany(Category::class, 'categories_id'); } + + /** + * @param $role + * + * @return array + */ + public static function getRoleCategoryExclusion($role): array + { + $ret = []; + $categories = self::query()->where('user_roles_id', $role)->get(['categories_id']); + foreach ($categories as $category) { + $ret[] = $category['categories_id']; + } + + return $ret; + } + + /** + * @param $role + * @param $catids + */ + public static function addRoleCategoryExclusions($role, array $catids): void + { + self::delRoleCategoryExclusions($role); + if (\count($catids) > 0) { + foreach ($catids as $catid) { + self::query()->insertGetId(['user_roles_id' => $role, 'categories_id' => $catid, 'created_at' => Carbon::now()]); + } + } + } + + /** + * @param $role + */ + public static function delRoleCategoryExclusions($role): void + { + self::query()->where('user_roles_id', $role)->delete(); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 4b28efec5..827d10904 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,13 +2,44 @@ namespace App\Models; +use App\Mail\AccountChange; +use App\Mail\SendInvite; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\Mail; +use Illuminate\Support\Facades\Password; +use Illuminate\Support\Str; +use nntmux\Users; +use nntmux\utility\Utility; class User extends Authenticatable { use Notifiable; + public const ERR_SIGNUP_BADUNAME = -1; + public const ERR_SIGNUP_BADPASS = -2; + public const ERR_SIGNUP_BADEMAIL = -3; + public const ERR_SIGNUP_UNAMEINUSE = -4; + public const ERR_SIGNUP_EMAILINUSE = -5; + public const ERR_SIGNUP_BADINVITECODE = -6; + public const ERR_SIGNUP_BADCAPTCHA = -7; + public const SUCCESS = 1; + + public const ROLE_GUEST = 0; + public const ROLE_USER = 1; + public const ROLE_ADMIN = 2; + public const ROLE_DISABLED = 3; + public const ROLE_MODERATOR = 4; + + /** + * Users SELECT queue type. + */ + public const QUEUE_NONE = 0; + public const QUEUE_SABNZBD = 1; + public const QUEUE_NZBGET = 2; + /** * @var string */ @@ -113,4 +144,829 @@ class User extends Authenticatable $user->request()->delete(); }); } + + /** + * @return array + */ + public static function get(): array + { + return self::all()->toArray(); + } + + /** + * Get the users selected theme. + * + * @param string|int $userID The id of the user. + * + * @return array|bool The users selected theme. + */ + public static function getStyle($userID) + { + $row = self::query()->where('id', $userID)->value('style'); + + return $row ?? 'None'; + } + + /** + * @param $id + * @throws \Exception + */ + public static function deleteUser($id): void + { + self::query()->where('id', $id)->delete(); + } + + /** + * @param string $role + * @param string $username + * @param string $host + * @param string $email + * @return int + */ + public static function getCount($role = '', $username = '', $host = '', $email = '') + { + $res = self::query()->where('email', '!=', 'sharing@nZEDb.com'); + + if ($role !== '') { + $res->where('user_roles_id', $role); + } + + if ($username !== '') { + $res->where('username', 'LIKE', '%'.$username.'%'); + } + + if ($host !== '') { + $res->where('host', 'LIKE', '%'.$host.'%'); + } + + if ($email !== '') { + $res->where('email', 'LIKE', '%'.$email.'%'); + } + + return $res->count(['id']); + } + + /** + * @param $id + * @param $userName + * @param $email + * @param $grabs + * @param $role + * @param $notes + * @param $invites + * @param $movieview + * @param $musicview + * @param $gameview + * @param $xxxview + * @param $consoleview + * @param $bookview + * @param string $queueType + * @param string $nzbgetURL + * @param string $nzbgetUsername + * @param string $nzbgetPassword + * @param string $saburl + * @param string $sabapikey + * @param string $sabpriority + * @param string $sabapikeytype + * @param bool $nzbvortexServerUrl + * @param bool $nzbvortexApiKey + * @param bool $cp_url + * @param bool $cp_api + * @param string $style + * + * @return int + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + public static function updateUser($id, $userName, $email, $grabs, $role, $notes, $invites, $movieview, $musicview, $gameview, $xxxview, $consoleview, $bookview, $queueType = '', $nzbgetURL = '', $nzbgetUsername = '', $nzbgetPassword = '', $saburl = '', $sabapikey = '', $sabpriority = '', $sabapikeytype = '', $nzbvortexServerUrl = false, $nzbvortexApiKey = false, $cp_url = false, $cp_api = false, $style = 'None'): int + { + $userName = trim($userName); + $email = trim($email); + + if (! self::isValidUsername($userName)) { + return self::ERR_SIGNUP_BADUNAME; + } + + if (! self::isValidEmail($email)) { + return self::ERR_SIGNUP_BADEMAIL; + } + + $res = self::getByUsername($userName); + if ($res) { + if ((int) $res['id'] !== (int) $id) { + return self::ERR_SIGNUP_UNAMEINUSE; + } + } + + $res = self::getByEmail($email); + if ($res) { + if ((int) $res['id'] !== (int) $id) { + return self::ERR_SIGNUP_EMAILINUSE; + } + } + + $sql = [ + 'username' => $userName, + 'email' => $email, + 'grabs' => $grabs, + 'user_roles_id' => $role, + 'notes' => substr($notes, 0, 255), + 'invites' => $invites, + 'movieview' => $movieview, + 'musicview' => $musicview, + 'gameview' => $gameview, + 'xxxview' => $xxxview, + 'consoleview' => $consoleview, + 'bookview' => $bookview, + 'style' => $style, + 'queuetype' => $queueType, + 'nzbgeturl' => $nzbgetURL, + 'nzbgetusername' => $nzbgetUsername, + 'nzbgetpassword' => $nzbgetPassword, + 'saburl' => $saburl, + 'sabapikey' => $sabapikey, + 'sabapikeytype' => $sabapikeytype, + 'sabpriority' => $sabpriority, + 'nzbvortex_server_url' => $nzbvortexServerUrl, + 'nzbvortex_api_key' => $nzbvortexApiKey, + 'cp_url' => $cp_url, + 'cp_api' => $cp_api, + ]; + + self::query()->where('id', $id)->update($sql); + + return self::SUCCESS; + } + + /** + * @param string $userName + * + * @return int + */ + public static function isValidUsername(string $userName): int + { + return preg_match('/^[a-z][a-z0-9_]{2,}$/i', $userName); + } + + /** + * When a user is registering or updating their profile, check if the email is valid. + * + * @param string $email + * + * @return bool + */ + public static function isValidEmail(string $email): bool + { + return (bool) preg_match('/^([\w\+-]+)(\.[\w\+-]+)*@([a-z0-9-]+\.)+[a-z]{2,6}$/i', $email); + } + + /** + * @param string $userName + * @return \Illuminate\Database\Eloquent\Model|null|static + */ + public static function getByUsername(string $userName) + { + return self::query()->where('username', $userName)->first(); + } + + /** + * @param string $email + * + * @return \Illuminate\Database\Eloquent\Model|static + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + public static function getByEmail(string $email) + { + return self::query()->where('email', $email)->first(); + } + + /** + * @param int $uid + * @param int $role + * @return int + */ + public static function updateUserRole(int $uid, int $role): int + { + return self::query()->where('id', $uid)->update(['user_roles_id' => $role]); + } + + /** + * @param $uid + * @param $date + * @return int + */ + public static function updateUserRoleChangeDate($uid, $date): int + { + return self::query()->where('id', $uid)->update(['rolechangedate' => $date]); + } + + /** + * @return int + */ + public static function updateExpiredRoles(): int + { + $data = self::query()->whereDate('rolechangedate', '<', Carbon::now())->get(); + + foreach ($data as $u) { + Mail::to($u['email'])->send(new AccountChange($u['id'])); + self::query()->where('id', $u['id'])->update(['user_roles_id' => self::ROLE_USER, 'rolechangedate' => null]); + } + + return self::SUCCESS; + } + + /** + * @param $start + * @param $offset + * @param $orderBy + * @param string $userName + * @param string $email + * @param string $host + * @param string $role + * @return \Illuminate\Database\Eloquent\Collection|static[] + * @throws \Exception + */ + public function getRange($start, $offset, $orderBy, $userName = '', $email = '', $host = '', $role = '') + { + UserRequest::clearApiRequests(false); + + $order = (new Users())->getBrowseOrder($orderBy); + + $users = self::query()->with('role', 'request')->where('id', '!=', 0)->groupBy(['id'])->orderBy($order[0], $order[1])->withCount('request as apirequests'); + if ($userName !== '') { + $users->where('username', 'LIKE', '%'.$userName.'%'); + } + + if ($email !== '') { + $users->where('email', 'LIKE', '%'.$email.'%'); + } + + if ($host !== '') { + $users->where('host', 'LIKE', '%'.$host.'%'); + } + + if ($role !== '') { + $users->where('user_roles_id', $role); + } + + if ($start !== false) { + $users->limit($offset)->offset($start); + } + + return $users->get(); + } + + /** + * Verify a password against a hash. + * + * Automatically update the hash if it needs to be. + * + * @param string $password Password to check against hash. + * @param string|bool $hash Hash to check against password. + * @param int $userID ID of the user. + * + * @return bool + */ + public static function checkPassword($password, $hash, $userID = -1): bool + { + if (Hash::check($password, $hash) === false) { + return false; + } + + // Update the hash if it needs to be. + if (is_numeric($userID) && $userID > 0 && Hash::needsRehash($hash)) { + $hash = self::hashPassword($password); + + if ($hash !== false) { + self::query()->where('id', $userID)->update(['password' => $hash]); + } + } + + return true; + } + + /** + * @param $uid + * + * @return int + */ + public static function updateRssKey($uid): int + { + self::query()->where('id', $uid)->update(['rsstoken' => md5(Password::getRepository()->createNewToken())]); + + return self::SUCCESS; + } + + /** + * @param $id + * @param $guid + * + * @return int + */ + public static function updatePassResetGuid($id, $guid): int + { + self::query()->where('id', $id)->update(['resetguid' => $guid]); + + return self::SUCCESS; + } + + /** + * @param int $id + * @param string $password + * + * @return int + */ + public static function updatePassword(int $id, string $password): int + { + self::query()->where('id', $id)->update(['password' => self::hashPassword($password), 'userseed' => md5(Utility::generateUuid())]); + + return self::SUCCESS; + } + + /** + * Hash a password using crypt. + * + * @param string $password + * + * @return string|bool + */ + public static function hashPassword($password) + { + return Hash::make($password); + } + + /** + * @param string $string + * + * @return string + */ + public static function hashSHA1(string $string): string + { + return sha1($string); + } + + /** + * @param $guid + * + * @return \Illuminate\Database\Eloquent\Model|static + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + public static function getByPassResetGuid(string $guid) + { + return self::query()->where('resetguid', $guid)->first(); + } + + /** + * @param $id + * @param int $num + */ + public static function incrementGrabs(int $id, $num = 1): void + { + self::query()->where('id', $id)->increment('grabs', $num); + } + + /** + * Check if the user is in the database, and if their API key is good, return user data if so. + * + * @param int $userID ID of the user. + * @param string $rssToken API key. + * + * @return bool|array + */ + public static function getByIdAndRssToken($userID, $rssToken) + { + $user = self::getById($userID); + if ($user === false) { + return false; + } + + return $user->rsstoken !== $rssToken ? false : $user; + } + + /** + * @param $id + * + * @return array|bool + */ + public static function getById($id) + { + $result = self::find($id); + + if (empty($result)) { + return false; + } + + return $result; + } + + /** + * @param string $rssToken + * @return \Illuminate\Database\Eloquent\Model|null|static + */ + public static function getByRssToken(string $rssToken) + { + return self::query()->where('rsstoken', $rssToken)->first(); + } + + /** + * @param $username + * + * @return bool + */ + public static function isDisabled($username): bool + { + return self::roleCheck(self::ROLE_DISABLED, $username); + } + + /** + * @param $url + * + * @return bool + */ + public static function isValidUrl($url): bool + { + return (! preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $url)) ? false : true; + } + + /** + * Generate a random username. + * + * + * @return string + */ + public static function generateUsername(): string + { + return Str::random(); + } + + /** + * @return string + */ + public static function generatePassword(): string + { + return Str::random(8); + } + + /** + * Register a new user. + * + * @param $userName + * @param $password + * @param $email + * @param $host + * @param int $role + * @param $notes + * @param int $invites + * @param string $inviteCode + * @param bool $forceInviteMode + * + * @return bool|int + * @throws \Exception + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + public static function signup($userName, $password, $email, $host, $role = self::ROLE_USER, $notes, $invites = self::DEFAULT_INVITES, $inviteCode = '', $forceInviteMode = false) + { + $userName = trim($userName); + $password = trim($password); + $email = trim($email); + + if (! self::isValidUsername($userName)) { + return self::ERR_SIGNUP_BADUNAME; + } + + if (! self::isValidPassword($password)) { + return self::ERR_SIGNUP_BADPASS; + } + + if (! self::isValidEmail($email)) { + return self::ERR_SIGNUP_BADEMAIL; + } + + $res = self::getByUsername($userName); + if ($res) { + return self::ERR_SIGNUP_UNAMEINUSE; + } + + $res = self::getByEmail($email); + if ($res) { + return self::ERR_SIGNUP_EMAILINUSE; + } + + // Make sure this is the last check, as if a further validation check failed, the invite would still have been used up. + $invitedBy = 0; + if (! $forceInviteMode && (int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_INVITE) { + if ($inviteCode === '') { + return self::ERR_SIGNUP_BADINVITECODE; + } + + $invitedBy = self::checkAndUseInvite($inviteCode); + if ($invitedBy < 0) { + return self::ERR_SIGNUP_BADINVITECODE; + } + } + + return self::add($userName, $password, $email, $role, $notes, $host, $invites, $invitedBy); + } + + /** + * @param $password + * + * @return bool + */ + public static function isValidPassword(string $password): bool + { + return \strlen($password) > 5; + } + + /** + * If a invite is used, decrement the person who invited's invite count. + * + * @param int $inviteCode + * + * @return int + */ + public static function checkAndUseInvite($inviteCode): int + { + $invite = Invitation::getInvite($inviteCode); + if (! $invite) { + return -1; + } + + self::query()->where('id', $invite['users_id'])->decrement('invites'); + Invitation::deleteInvite($inviteCode); + + return $invite['users_id']; + } + + /** + * Add a new user. + * + * @param $userName + * @param $password + * @param $email + * @param $role + * @param $notes + * @param $host + * @param int $invites + * @param int $invitedBy + * + * @return bool|int + * @throws \Exception + */ + public static function add($userName, $password, $email, $role, $notes, $host, $invites = self::DEFAULT_INVITES, $invitedBy = 0) + { + $password = self::hashPassword($password); + if (! $password) { + return false; + } + + return self::query()->insertGetId( + [ + 'username' => $userName, + 'password' => $password, + 'email' => $email, + 'user_roles_id' => $role, + 'created_at' => Carbon::now(), + 'host' => (int) Settings::settingValue('..storeuserips') === 1 ? $host : '', + 'rsstoken' => md5(Password::getRepository()->createNewToken()), + 'invites' => $invites, + 'invitedby' => (int) $invitedBy === 0 ? 'NULL' : $invitedBy, + 'userseed' => md5(Utility::generateUuid()), + 'notes' => $notes, + ] + ); + } + + /** + * Verify if the user is logged in. + * + * @return bool + * @throws \Exception + */ + public static function isLoggedIn(): bool + { + if (isset($_SESSION['uid'])) { + return true; + } + if (isset($_COOKIE['uid'], $_COOKIE['idh'])) { + $u = self::getById($_COOKIE['uid']); + + if ((int) $u['user_roles_id'] !== self::ROLE_DISABLED && $_COOKIE['idh'] === self::hashSHA1($u['userseed'].$_COOKIE['uid'])) { + self::login($_COOKIE['uid'], $_SERVER['REMOTE_ADDR']); + } + } + + return isset($_SESSION['uid']); + } + + /** + * Log in a user. + * + * @param int $userID ID of the user. + * @param string $host + * @param bool $remember Save the user in cookies to keep them logged in. + * + * @throws \Exception + */ + public static function login($userID, $host = '', $remember = false): void + { + $_SESSION['uid'] = $userID; + + if ((int) Settings::settingValue('..storeuserips') !== 1) { + $host = ''; + } + + self::updateSiteAccessed($userID, $host); + + if ($remember === true) { + self::setCookies($userID); + } + } + + /** + * When a user logs in, update the last time they logged in. + * + * @param int $userID ID of the user. + * @param string $host + */ + public static function updateSiteAccessed($userID, $host = ''): void + { + self::query()->where('id', $userID)->update( + [ + 'lastlogin' => Carbon::now(), + 'host' => $host, + ] + ); + } + + /** + * Set up cookies for a user. + * + * @param int $userID + */ + public static function setCookies($userID): void + { + $user = self::getById($userID); + $secure_cookie = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? '1' : '0'); + setcookie('uid', $userID, time() + 2592000, '/', null, $secure_cookie, true); + setcookie('idh', self::hashSHA1($user['userseed'].$userID), time() + 2592000, '/', null, $secure_cookie, true); + } + + /** + * Return the User ID of the user. + * + * @return int + */ + public static function currentUserId(): int + { + return $_SESSION['uid'] ?? -1; + } + + /** + * Logout the user, destroying his cookies and session. + */ + public static function logout(): void + { + session_unset(); + session_destroy(); + $secure_cookie = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? '1' : '0'); + setcookie('uid', null, -1, '/', null, $secure_cookie, true); + setcookie('idh', null, -1, '/', null, $secure_cookie, true); + } + + /** + * @param $uid + */ + public static function updateApiAccessed($uid): void + { + self::query()->where('id', $uid)->update(['apiaccess' => date('Y-m-d h:m:s')]); + } + + /** + * Get the list of categories the user has excluded. + * + * @param int $userID ID of the user. + * + * @return array + */ + public static function getCategoryExclusion($userID): array + { + $ret = []; + $categories = self::query()->where('id', $userID)->first(); + if ($categories !== null) { + foreach ($categories->excludedCategory as $category) { + $ret[] = $category['categories_id']; + } + } + + return $ret; + } + + /** + * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] + */ + public static function getTopGrabbers() + { + return self::query()->selectRaw('id, username, SUM(grabs) as grabs')->groupBy(['id', 'username'])->having('grabs', '>', 0)->orderBy('grabs', 'desc')->limit(10)->get(); + } + + /** + * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] + */ + public function getUsersByMonth() + { + return self::query()->whereNotNull('created_at')->where('created_at', '!=', '0000-00-00 00:00:00')->selectRaw("DATE_FORMAT(created_at, '%M %Y') as mth, COUNT(id) as num")->groupBy(['mth'])->orderBy('created_at', 'desc')->get(); + } + + /** + * @param $host + * @param string|null $siteseed + * + * @return string + * @throws \Exception + */ + public static function getHostHash($host, string $siteseed = ''): string + { + if ($siteseed === '') { + $siteseed = Settings::settingValue('..siteseed'); + } + + return self::hashSHA1($siteseed.$host.$siteseed); + } + + /** + * Checks if a user is a specific role. + * + * @notes Uses type of $user to denote identifier. if string: username, if int: users_id + * @param int $roleID + * @param string|int $user + * @return bool + */ + public static function roleCheck($roleID, $user): bool + { + $result = self::query()->where('username', $user)->orWhere('id', $user)->first(['user_roles_id']); + + if ($result !== null) { + return $result['user_roles_id'] === $roleID; + } + + return false; + } + + /** + * Wrapper for roleCheck specifically for Admins. + * + * @param int $userID + * @return bool + */ + public static function isAdmin($userID): bool + { + return self::roleCheck(self::ROLE_ADMIN, (int) $userID); + } + + /** + * Wrapper for roleCheck specifically for Moderators. + * + * @param int $userId + * @return bool + */ + public static function isModerator($userId): bool + { + return self::roleCheck(self::ROLE_MODERATOR, (int) $userId); + } + + /** + * @param $serverUrl + * @param $uid + * @param $emailTo + * @return string + */ + public function sendInvite($serverUrl, $uid, $emailTo): string + { + $token = self::hashSHA1(uniqid('', true)); + $url = $serverUrl.'register?invitecode='.$token; + + Mail::to($emailTo)->send(new SendInvite($uid, $url)); + Invitation::addInvite($uid, $token); + + return $url; + } + + /** + * deletes old rows FROM the user_requests and user_downloads tables. + * if site->userdownloadpurgedays SET to 0 then all release history is removed but + * the download/request rows must remain for at least one day to allow the role based + * limits to apply. + * + * @param int $days + */ + public static function pruneRequestHistory($days = 0): void + { + if ($days === 0) { + $days = 1; + UserDownload::query()->update(['releases_id' => null]); + } + + UserRequest::query()->where('timestamp', '<', Carbon::now()->subDays($days))->delete(); + UserDownload::query()->where('timestamp', '<', Carbon::now()->subDays($days))->delete(); + } } diff --git a/app/Models/UserExcludedCategory.php b/app/Models/UserExcludedCategory.php index de10fa6ca..288e21e17 100644 --- a/app/Models/UserExcludedCategory.php +++ b/app/Models/UserExcludedCategory.php @@ -6,17 +6,81 @@ use Illuminate\Database\Eloquent\Model; class UserExcludedCategory extends Model { + /** + * @var bool + */ protected $dateFormat = false; + /** + * @var array + */ protected $guarded = []; + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function user() { return $this->belongsTo(User::class, 'users_id'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ public function category() { return $this->belongsTo(Category::class, 'categories_id'); } + + /** + * @param $uid + */ + public static function delUserCategoryExclusions($uid): void + { + self::query()->where('users_id', $uid)->delete(); + } + + /** + * @param $uid + * @param array $catids + */ + public static function addCategoryExclusions($uid, array $catids): void + { + self::delUserCategoryExclusions($uid); + if (\count($catids) > 0) { + foreach ($catids as $catid) { + self::query()->insertGetId(['users_id' => $uid, 'categories_id' => $catid, 'created_at' => Carbon::now()]); + } + } + } + + /** + * Get list of category names excluded by the user. + * + * @param int $userID ID of the user. + * + * @return array + * @throws \Exception + */ + public static function getCategoryExclusionNames($userID): array + { + $categories = self::with('category')->where('users_id', $userID)->get(); + $ret = []; + if ($categories !== null) { + foreach ($categories as $cat) { + $ret[] = $cat->category->title; + } + } + + return $ret; + } + + /** + * @param $uid + * @param $catid + */ + public static function delCategoryExclusion($uid, $catid): void + { + self::query()->where(['users_id'=> $uid, 'categories_id' => $catid])->delete(); + } } diff --git a/nntmux/Users.php b/nntmux/Users.php deleted file mode 100755 index a258c7e13..000000000 --- a/nntmux/Users.php +++ /dev/null @@ -1,1057 +0,0 @@ - 0 && Hash::needsRehash($hash)) { - $hash = $this->hashPassword($password); - - if ($hash !== false) { - User::query()->where('id', $userID)->update(['password' => $hash]); - } - } - - return true; - } - - /** - * @return array - */ - public function get(): array - { - return User::all()->toArray(); - } - - /** - * Get the users selected theme. - * - * @param string|int $userID The id of the user. - * - * @return array|bool The users selected theme. - */ - public function getStyle($userID) - { - $row = User::query()->where('id', $userID)->value('style'); - - return $row ?? 'None'; - } - - /** - * @param $id - * @throws \Exception - */ - public function delete($id): void - { - User::query()->where('id', $id)->delete(); - } - - /** - * @param $uid - */ - public function delUserCategoryExclusions($uid): void - { - UserExcludedCategory::query()->where('users_id', $uid)->delete(); - } - - /** - * @param $start - * @param $offset - * @param $orderBy - * @param string $userName - * @param string $email - * @param string $host - * @param string $role - * @return \Illuminate\Database\Eloquent\Collection|static[] - * @throws \Exception - */ - public function getRange($start, $offset, $orderBy, $userName = '', $email = '', $host = '', $role = '') - { - UserRequest::clearApiRequests(false); - - $order = $this->getBrowseOrder($orderBy); - - $users = User::query()->with('role', 'request')->where('id', '!=', 0)->groupBy(['id'])->orderBy($order[0], $order[1])->withCount('request as apirequests'); - if ($userName !== '') { - $users->where('username', 'LIKE', '%'.$userName.'%'); - } - - if ($email !== '') { - $users->where('email', 'LIKE', '%'.$email.'%'); - } - - if ($host !== '') { - $users->where('host', 'LIKE', '%'.$host.'%'); - } - - if ($role !== '') { - $users->where('user_roles_id', $role); - } - - if ($start !== false) { - $users->limit($offset)->offset($start); - } - - return $users->get(); - } - - /** - * @param string $orderBy - * - * @return array - */ - public function getBrowseOrder($orderBy): array - { - $order = ($orderBy === '' ? 'username_desc' : $orderBy); - $orderArr = explode('_', $order); - switch ($orderArr[0]) { - case 'username': - $orderField = 'username'; - break; - case 'email': - $orderField = 'email'; - break; - case 'host': - $orderField = 'host'; - break; - case 'createdat': - $orderField = 'created_at'; - break; - case 'lastlogin': - $orderField = 'lastlogin'; - break; - case 'apiaccess': - $orderField = 'apiaccess'; - break; - case 'apirequests': - $orderField = 'apirequests'; - break; - case 'grabs': - $orderField = 'grabs'; - break; - case 'user_roles_id': - $orderField = 'users_role_id'; - break; - case 'rolechangedate': - $orderField = 'rolechangedate'; - break; - default: - $orderField = 'username'; - break; - } - $orderSort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc'; - - return [$orderField, $orderSort]; - } - - /** - * @param string $role - * @param string $username - * @param string $host - * @param string $email - * @return int - */ - public function getCount($role = '', $username = '', $host = '', $email = '') - { - $res = User::query()->where('email', '!=', 'sharing@nZEDb.com'); - - if ($role !== '') { - $res->where('user_roles_id', $role); - } - - if ($username !== '') { - $res->where('username', 'LIKE', '%'.$username.'%'); - } - - if ($host !== '') { - $res->where('host', 'LIKE', '%'.$host.'%'); - } - - if ($email !== '') { - $res->where('email', 'LIKE', '%'.$email.'%'); - } - - return $res->count(['id']); - } - - /** - * @param $id - * @param $userName - * @param $email - * @param $grabs - * @param $role - * @param $notes - * @param $invites - * @param $movieview - * @param $musicview - * @param $gameview - * @param $xxxview - * @param $consoleview - * @param $bookview - * @param string $queueType - * @param string $nzbgetURL - * @param string $nzbgetUsername - * @param string $nzbgetPassword - * @param string $saburl - * @param string $sabapikey - * @param string $sabpriority - * @param string $sabapikeytype - * @param bool $nzbvortexServerUrl - * @param bool $nzbvortexApiKey - * @param bool $cp_url - * @param bool $cp_api - * @param string $style - * - * @return int - * @throws \Illuminate\Database\Eloquent\ModelNotFoundException - */ - public function update($id, $userName, $email, $grabs, $role, $notes, $invites, $movieview, $musicview, $gameview, $xxxview, $consoleview, $bookview, $queueType = '', $nzbgetURL = '', $nzbgetUsername = '', $nzbgetPassword = '', $saburl = '', $sabapikey = '', $sabpriority = '', $sabapikeytype = '', $nzbvortexServerUrl = false, $nzbvortexApiKey = false, $cp_url = false, $cp_api = false, $style = 'None'): int - { - $userName = trim($userName); - $email = trim($email); - - if (! $this->isValidUsername($userName)) { - return self::ERR_SIGNUP_BADUNAME; - } - - if (! $this->isValidEmail($email)) { - return self::ERR_SIGNUP_BADEMAIL; - } - - $res = $this->getByUsername($userName); - if ($res) { - if ((int) $res['id'] !== (int) $id) { - return self::ERR_SIGNUP_UNAMEINUSE; - } - } - - $res = $this->getByEmail($email); - if ($res) { - if ((int) $res['id'] !== (int) $id) { - return self::ERR_SIGNUP_EMAILINUSE; - } - } - - $sql = [ - 'username' => $userName, - 'email' => $email, - 'grabs' => $grabs, - 'user_roles_id' => $role, - 'notes' => substr($notes, 0, 255), - 'invites' => $invites, - 'movieview' => $movieview, - 'musicview' => $musicview, - 'gameview' => $gameview, - 'xxxview' => $xxxview, - 'consoleview' => $consoleview, - 'bookview' => $bookview, - 'style' => $style, - 'queuetype' => $queueType, - 'nzbgeturl' => $nzbgetURL, - 'nzbgetusername' => $nzbgetUsername, - 'nzbgetpassword' => $nzbgetPassword, - 'saburl' => $saburl, - 'sabapikey' => $sabapikey, - 'sabapikeytype' => $sabapikeytype, - 'sabpriority' => $sabpriority, - 'nzbvortex_server_url' => $nzbvortexServerUrl, - 'nzbvortex_api_key' => $nzbvortexApiKey, - 'cp_url' => $cp_url, - 'cp_api' => $cp_api, - ]; - - User::query()->where('id', $id)->update($sql); - - return self::SUCCESS; - } - - /** - * @param string $userName - * - * @return int - */ - public function isValidUsername(string $userName): int - { - return preg_match('/^[a-z][a-z0-9_]{2,}$/i', $userName); - } - - /** - * When a user is registering or updating their profile, check if the email is valid. - * - * @param string $email - * - * @return bool - */ - public function isValidEmail(string $email): bool - { - return (bool) preg_match('/^([\w\+-]+)(\.[\w\+-]+)*@([a-z0-9-]+\.)+[a-z]{2,6}$/i', $email); - } - - /** - * @param string $userName - * @return \Illuminate\Database\Eloquent\Model|null|static - */ - public function getByUsername(string $userName) - { - return User::query()->where('username', $userName)->first(); - } - - /** - * @param string $email - * - * @return \Illuminate\Database\Eloquent\Model|static - * @throws \Illuminate\Database\Eloquent\ModelNotFoundException - */ - public function getByEmail(string $email) - { - return User::query()->where('email', $email)->first(); - } - - /** - * @param int $uid - * @param int $role - * @return int - */ - public function updateUserRole(int $uid, int $role): int - { - return User::query()->where('id', $uid)->update(['user_roles_id' => $role]); - } - - /** - * @param $uid - * @param $date - * @return int - */ - public function updateUserRoleChangeDate($uid, $date): int - { - return User::query()->where('id', $uid)->update(['rolechangedate' => $date]); - } - - /** - * @return int - */ - public function updateExpiredRoles(): int - { - $data = User::query()->whereDate('rolechangedate', '<', Carbon::now())->get(); - - foreach ($data as $u) { - Mail::to($u['email'])->send(new AccountChange($u['id'])); - User::query()->where('id', $u['id'])->update(['user_roles_id' => self::ROLE_USER, 'rolechangedate' => null]); - } - - return self::SUCCESS; - } - - /** - * @param $uid - * - * @return int - */ - public function updateRssKey($uid): int - { - User::query()->where('id', $uid)->update(['rsstoken' => md5(Password::getRepository()->createNewToken())]); - - return self::SUCCESS; - } - - /** - * @param $id - * @param $guid - * - * @return int - */ - public function updatePassResetGuid($id, $guid): int - { - User::query()->where('id', $id)->update(['resetguid' => $guid]); - - return self::SUCCESS; - } - - /** - * @param int $id - * @param string $password - * - * @return int - */ - public function updatePassword(int $id, string $password): int - { - User::query()->where('id', $id)->update(['password' => $this->hashPassword($password), 'userseed' => md5(Utility::generateUuid())]); - - return self::SUCCESS; - } - - /** - * Hash a password using crypt. - * - * @param string $password - * - * @return string|bool - */ - public function hashPassword($password) - { - return Hash::make($password); - } - - /** - * @param string $string - * - * @return string - */ - public static function hashSHA1(string $string): string - { - return sha1($string); - } - - /** - * @param $guid - * - * @return \Illuminate\Database\Eloquent\Model|static - * @throws \Illuminate\Database\Eloquent\ModelNotFoundException - */ - public function getByPassResetGuid(string $guid) - { - return User::query()->where('resetguid', $guid)->first(); - } - - /** - * @param $id - * @param int $num - */ - public function incrementGrabs(int $id, $num = 1): void - { - User::query()->where('id', $id)->increment('grabs', $num); - } - - /** - * Check if the user is in the database, and if their API key is good, return user data if so. - * - * @param int $userID ID of the user. - * @param string $rssToken API key. - * - * @return bool|array - */ - public function getByIdAndRssToken($userID, $rssToken) - { - $user = $this->getById($userID); - if ($user === false) { - return false; - } - - return $user->rsstoken !== $rssToken ? false : $user; - } - - /** - * @param $id - * - * @return array|bool - */ - public function getById($id) - { - $result = User::find($id); - - if (empty($result)) { - return false; - } - - return $result; - } - - /** - * @param string $rssToken - * @return \Illuminate\Database\Eloquent\Model|null|static - */ - public function getByRssToken(string $rssToken) - { - return User::query()->where('rsstoken', $rssToken)->first(); - } - - /** - * @return array - */ - public function getBrowseOrdering(): array - { - return ['username_asc', 'username_desc', 'email_asc', 'email_desc', 'host_asc', 'host_desc', 'createdat_asc', 'createdat_desc', 'lastlogin_asc', 'lastlogin_desc', 'apiaccess_asc', 'apiaccess_desc', 'apirequests_asc', 'apirequests_desc', 'grabs_asc', 'grabs_desc', 'role_asc', 'role_desc', 'rolechangedate_asc', 'rolechangedate_desc']; - } - - /** - * @param $username - * - * @return bool - */ - public function isDisabled($username): bool - { - return $this->roleCheck(self::ROLE_DISABLED, $username); - } - - /** - * @param $url - * - * @return bool - */ - public function isValidUrl($url): bool - { - return (! preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $url)) ? false : true; - } - - /** - * Generate a random username. - * - * - * @return string - */ - public function generateUsername(): string - { - return Str::random(); - } - - /** - * @return string - */ - public function generatePassword(): string - { - return Str::random(8); - } - - /** - * Register a new user. - * - * @param $userName - * @param $password - * @param $email - * @param $host - * @param int $role - * @param $notes - * @param int $invites - * @param string $inviteCode - * @param bool $forceInviteMode - * - * @return bool|int - * @throws \Exception - * @throws \Illuminate\Database\Eloquent\ModelNotFoundException - */ - public function signup($userName, $password, $email, $host, $role = self::ROLE_USER, $notes, $invites = self::DEFAULT_INVITES, $inviteCode = '', $forceInviteMode = false) - { - $userName = trim($userName); - $password = trim($password); - $email = trim($email); - - if (! $this->isValidUsername($userName)) { - return self::ERR_SIGNUP_BADUNAME; - } - - if (! $this->isValidPassword($password)) { - return self::ERR_SIGNUP_BADPASS; - } - - if (! $this->isValidEmail($email)) { - return self::ERR_SIGNUP_BADEMAIL; - } - - $res = $this->getByUsername($userName); - if ($res) { - return self::ERR_SIGNUP_UNAMEINUSE; - } - - $res = $this->getByEmail($email); - if ($res) { - return self::ERR_SIGNUP_EMAILINUSE; - } - - // Make sure this is the last check, as if a further validation check failed, the invite would still have been used up. - $invitedBy = 0; - if (! $forceInviteMode && (int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_INVITE) { - if ($inviteCode === '') { - return self::ERR_SIGNUP_BADINVITECODE; - } - - $invitedBy = $this->checkAndUseInvite($inviteCode); - if ($invitedBy < 0) { - return self::ERR_SIGNUP_BADINVITECODE; - } - } - - return $this->add($userName, $password, $email, $role, $notes, $host, $invites, $invitedBy); - } - - /** - * @param $password - * - * @return bool - */ - public function isValidPassword(string $password): bool - { - return \strlen($password) > 5; - } - - /** - * If a invite is used, decrement the person who invited's invite count. - * - * @param int $inviteCode - * - * @return int - */ - public function checkAndUseInvite($inviteCode): int - { - $invite = $this->getInvite($inviteCode); - if (! $invite) { - return -1; - } - - User::query()->where('id', $invite['users_id'])->decrement('invites'); - $this->deleteInvite($inviteCode); - - return $invite['users_id']; - } - - /** - * @param $inviteToken - * @return \Illuminate\Database\Eloquent\Model|null|static - */ - public function getInvite($inviteToken) - { - // - // Tidy any old invites sent greater than DEFAULT_INVITE_EXPIRY_DAYS days ago. - // - Invitation::query()->where('created_at', '<', Carbon::now()->subDays(self::DEFAULT_INVITE_EXPIRY_DAYS)); - - return Invitation::query()->where('guid', $inviteToken)->first(); - } - - /** - * @param $inviteToken - */ - public function deleteInvite(string $inviteToken): void - { - Invitation::query()->where('guid', $inviteToken)->delete(); - } - - /** - * Add a new user. - * - * @param $userName - * @param $password - * @param $email - * @param $role - * @param $notes - * @param $host - * @param int $invites - * @param int $invitedBy - * - * @return bool|int - * @throws \Exception - */ - public function add($userName, $password, $email, $role, $notes, $host, $invites = self::DEFAULT_INVITES, $invitedBy = 0) - { - $password = $this->hashPassword($password); - if (! $password) { - return false; - } - - return User::query()->insertGetId( - [ - 'username' => $userName, - 'password' => $password, - 'email' => $email, - 'user_roles_id' => $role, - 'created_at' => Carbon::now(), - 'host' => (int) Settings::settingValue('..storeuserips') === 1 ? $host : '', - 'rsstoken' => md5(Password::getRepository()->createNewToken()), - 'invites' => $invites, - 'invitedby' => (int) $invitedBy === 0 ? 'NULL' : $invitedBy, - 'userseed' => md5(Utility::generateUuid()), - 'notes' => $notes, - ] - ); - } - - /** - * Verify if the user is logged in. - * - * @return bool - * @throws \Exception - */ - public function isLoggedIn(): bool - { - if (isset($_SESSION['uid'])) { - return true; - } - if (isset($_COOKIE['uid'], $_COOKIE['idh'])) { - $u = $this->getById($_COOKIE['uid']); - - if ((int) $u['user_roles_id'] !== self::ROLE_DISABLED && $_COOKIE['idh'] === self::hashSHA1($u['userseed'].$_COOKIE['uid'])) { - $this->login($_COOKIE['uid'], $_SERVER['REMOTE_ADDR']); - } - } - - return isset($_SESSION['uid']); - } - - /** - * Log in a user. - * - * @param int $userID ID of the user. - * @param string $host - * @param bool $remember Save the user in cookies to keep them logged in. - * - * @throws \Exception - */ - public function login($userID, $host = '', $remember = false): void - { - $_SESSION['uid'] = $userID; - - if ((int) Settings::settingValue('..storeuserips') !== 1) { - $host = ''; - } - - $this->updateSiteAccessed($userID, $host); - - if ($remember === true) { - $this->setCookies($userID); - } - } - - /** - * When a user logs in, update the last time they logged in. - * - * @param int $userID ID of the user. - * @param string $host - */ - public function updateSiteAccessed($userID, $host = ''): void - { - User::query()->where('id', $userID)->update( - [ - 'lastlogin' => Carbon::now(), - 'host' => $host, - ] - ); - } - - /** - * Set up cookies for a user. - * - * @param int $userID - */ - public function setCookies($userID): void - { - $user = $this->getById($userID); - $secure_cookie = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? '1' : '0'); - setcookie('uid', $userID, time() + 2592000, '/', null, $secure_cookie, true); - setcookie('idh', self::hashSHA1($user['userseed'].$userID), time() + 2592000, '/', null, $secure_cookie, true); - } - - /** - * Return the User ID of the user. - * - * @return int - */ - public function currentUserId(): int - { - return $_SESSION['uid'] ?? -1; - } - - /** - * Logout the user, destroying his cookies and session. - */ - public function logout(): void - { - session_unset(); - session_destroy(); - $secure_cookie = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? '1' : '0'); - setcookie('uid', null, -1, '/', null, $secure_cookie, true); - setcookie('idh', null, -1, '/', null, $secure_cookie, true); - } - - /** - * @param $uid - */ - public function updateApiAccessed($uid): void - { - User::query()->where('id', $uid)->update(['apiaccess' => date('Y-m-d h:m:s')]); - } - - /** - * @param $uid - * @param array $catids - */ - public function addCategoryExclusions($uid, array $catids): void - { - $this->delUserCategoryExclusions($uid); - if (\count($catids) > 0) { - foreach ($catids as $catid) { - UserExcludedCategory::query()->insertGetId(['users_id' => $uid, 'categories_id' => $catid, 'created_at' => Carbon::now()]); - } - } - } - - /** - * @param $role - * - * @return array - */ - public function getRoleCategoryExclusion($role): array - { - $ret = []; - $categories = RoleExcludedCategory::query()->where('user_roles_id', $role)->get(['categories_id']); - foreach ($categories as $category) { - $ret[] = $category['categories_id']; - } - - return $ret; - } - - /** - * @param $role - * @param $catids - */ - public function addRoleCategoryExclusions($role, array $catids): void - { - $this->delRoleCategoryExclusions($role); - if (\count($catids) > 0) { - foreach ($catids as $catid) { - RoleExcludedCategory::query()->insertGetId(['user_roles_id' => $role, 'categories_id' => $catid, 'created_at' => Carbon::now()]); - } - } - } - - /** - * @param $role - */ - public function delRoleCategoryExclusions($role): void - { - RoleExcludedCategory::query()->where('user_roles_id', $role)->delete(); - } - - /** - * Get the list of categories the user has excluded. - * - * @param int $userID ID of the user. - * - * @return array - */ - public function getCategoryExclusion($userID): array - { - $ret = []; - $categories = User::query()->where('id', $userID)->first(); - if ($categories !== null) { - foreach ($categories->excludedCategory as $category) { - $ret[] = $category['categories_id']; - } - } - - return $ret; - } - - /** - * Get list of category names excluded by the user. - * - * @param int $userID ID of the user. - * - * @return array - * @throws \Exception - */ - public function getCategoryExclusionNames($userID): array - { - $categories = UserExcludedCategory::with('category')->where('users_id', $userID)->get(); - $ret = []; - if ($categories !== null) { - foreach ($categories as $cat) { - $ret[] = $cat->category->title; - } - } - - return $ret; - } - - /** - * @param $uid - * @param $catid - */ - public function delCategoryExclusion($uid, $catid): void - { - UserExcludedCategory::query()->where(['users_id'=> $uid, 'categories_id' => $catid])->delete(); - } - - /** - * @param $serverUrl - * @param $uid - * @param $emailTo - * @return string - */ - public function sendInvite($serverUrl, $uid, $emailTo): string - { - $token = self::hashSHA1(uniqid('', true)); - $url = $serverUrl.'register?invitecode='.$token; - - Mail::to($emailTo)->send(new SendInvite($uid, $url)); - $this->addInvite($uid, $token); - - return $url; - } - - /** - * @param int $uid - * @param string $inviteToken - */ - public function addInvite(int $uid, string $inviteToken) - { - Invitation::query()->insertGetId(['guid' => $inviteToken, 'users_id' => $uid, 'created_at' => Carbon::now()]); - } - - /** - * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] - */ - public function getTopGrabbers() - { - return User::query()->selectRaw('id, username, SUM(grabs) as grabs')->groupBy(['id', 'username'])->having('grabs', '>', 0)->orderBy('grabs', 'desc')->limit(10)->get(); - } - - /** - * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|static[] - */ - public function getUsersByMonth() - { - return User::query()->whereNotNull('created_at')->where('created_at', '!=', '0000-00-00 00:00:00')->selectRaw("DATE_FORMAT(created_at, '%M %Y') as mth, COUNT(id) as num")->groupBy(['mth'])->orderBy('created_at', 'desc')->get(); - } - - /** - * @param $host - * @param string|null $siteseed - * - * @return string - * @throws \Exception - */ - public function getHostHash($host, string $siteseed = ''): string - { - if ($siteseed === '') { - $siteseed = Settings::settingValue('..siteseed'); - } - - return self::hashSHA1($siteseed.$host.$siteseed); - } - - /** - * deletes old rows FROM the user_requests and user_downloads tables. - * if site->userdownloadpurgedays SET to 0 then all release history is removed but - * the download/request rows must remain for at least one day to allow the role based - * limits to apply. - * - * @param int $days - */ - public function pruneRequestHistory($days = 0): void - { - if ($days === 0) { - $days = 1; - UserDownload::query()->update(['releases_id' => null]); - } - - UserRequest::query()->where('timestamp', '<', Carbon::now()->subDays($days))->delete(); - UserDownload::query()->where('timestamp', '<', Carbon::now()->subDays($days))->delete(); - } - - /** - * Checks if a user is a specific role. - * - * @notes Uses type of $user to denote identifier. if string: username, if int: users_id - * @param int $roleID - * @param string|int $user - * @return bool - */ - public function roleCheck($roleID, $user): bool - { - $result = User::query()->where('username', $user)->orWhere('id', $user)->first(['user_roles_id']); - - if ($result !== null) { - return $result['user_roles_id'] === $roleID; - } - - return false; - } - - /** - * Wrapper for roleCheck specifically for Admins. - * - * @param int $userID - * @return bool - */ - public function isAdmin($userID): bool - { - return $this->roleCheck(self::ROLE_ADMIN, (int) $userID); - } - - /** - * Wrapper for roleCheck specifically for Moderators. - * - * @param int $userId - * @return bool - */ - public function isModerator($userId): bool - { - return $this->roleCheck(self::ROLE_MODERATOR, (int) $userId); - } -} diff --git a/public/admin/role-edit.php b/public/admin/role-edit.php index ba80d6f52..c00aa1dac 100644 --- a/public/admin/role-edit.php +++ b/public/admin/role-edit.php @@ -2,6 +2,7 @@ require_once dirname(__DIR__).DIRECTORY_SEPARATOR.'smarty.php'; +use App\Models\RoleExcludedCategory; use nntmux\Category; use App\Models\UserRole; @@ -61,7 +62,7 @@ switch ($_REQUEST['action'] ?? 'view') { header('Location:'.WWW_TOP.'/role-list.php'); $_POST['exccat'] = (! isset($_POST['exccat']) || ! is_array($_POST['exccat'])) ? [] : $_POST['exccat']; - $page->users->addRoleCategoryExclusions($_POST['id'], $_POST['exccat']); + RoleExcludedCategory::addRoleCategoryExclusions($_POST['id'], $_POST['exccat']); } $page->smarty->assign('role', $role); break; @@ -72,7 +73,7 @@ switch ($_REQUEST['action'] ?? 'view') { $page->title = 'User Roles Edit'; $role = UserRole::getRoleById($_GET['id']); $page->smarty->assign('role', $role); - $page->smarty->assign('roleexccat', $page->users->getRoleCategoryExclusion($_GET['id'])); + $page->smarty->assign('roleexccat', RoleExcludedCategory::getRoleCategoryExclusion($_GET['id'])); } break; } diff --git a/public/admin/user-delete.php b/public/admin/user-delete.php index 969964073..71b4a5dc5 100644 --- a/public/admin/user-delete.php +++ b/public/admin/user-delete.php @@ -2,13 +2,14 @@ require_once dirname(__DIR__).DIRECTORY_SEPARATOR.'smarty.php'; +use App\Models\User; use nntmux\Users; $page = new AdminPage(); if (isset($_GET['id'])) { $users = new Users(); - $users->delete($_GET['id']); + User::deleteUser($_GET['id']); } if (isset($_GET['redir'])) { diff --git a/public/admin/user-edit.php b/public/admin/user-edit.php index 05e973ad8..0179f1f19 100644 --- a/public/admin/user-edit.php +++ b/public/admin/user-edit.php @@ -2,20 +2,19 @@ require_once dirname(__DIR__).DIRECTORY_SEPARATOR.'smarty.php'; -use nntmux\Users; +use App\Models\User; use App\Models\UserRole; use App\Mail\AccountChange; use Illuminate\Support\Facades\Mail; $page = new AdminPage(); -$users = new Users(); $user = [ 'id' => '', 'username' => '', 'email' => '', 'password' => '', - 'role' => Users::ROLE_USER, + 'role' => User::ROLE_USER, 'notes' => '', ]; @@ -25,8 +24,8 @@ $action = $_REQUEST['action'] ?? 'view'; //get the user roles $userRoles = UserRole::getRoles(); $roles = []; -$defaultRole = Users::ROLE_USER; -$defaultInvites = Users::DEFAULT_INVITES; +$defaultRole = User::ROLE_USER; +$defaultInvites = User::DEFAULT_INVITES; foreach ($userRoles as $r) { $roles[$r['id']] = $r['name']; if ($r['isdefault'] === 1) { @@ -58,15 +57,15 @@ switch ($action) { $invites = $role['defaultinvites']; } } - $ret = $users->signup($_POST['username'], $_POST['password'], $_POST['email'], '', $_POST['role'], $_POST['notes'], $invites, '', true); + $ret = User::signup($_POST['username'], $_POST['password'], $_POST['email'], '', $_POST['role'], $_POST['notes'], $invites, '', true); $page->smarty->assign('role', $_POST['role']); } else { - $ret = $users->update($_POST['id'], $_POST['username'], $_POST['email'], $_POST['grabs'], $_POST['role'], $_POST['notes'], $_POST['invites'], (isset($_POST['movieview']) ? 1 : 0), (isset($_POST['musicview']) ? 1 : 0), (isset($_POST['gameview']) ? 1 : 0), (isset($_POST['xxxview']) ? 1 : 0), (isset($_POST['consoleview']) ? 1 : 0), (isset($_POST['bookview']) ? 1 : 0)); + $ret = User::updateUser($_POST['id'], $_POST['username'], $_POST['email'], $_POST['grabs'], $_POST['role'], $_POST['notes'], $_POST['invites'], (isset($_POST['movieview']) ? 1 : 0), (isset($_POST['musicview']) ? 1 : 0), (isset($_POST['gameview']) ? 1 : 0), (isset($_POST['xxxview']) ? 1 : 0), (isset($_POST['consoleview']) ? 1 : 0), (isset($_POST['bookview']) ? 1 : 0)); if ($_POST['password'] !== '') { - $users->updatePassword($_POST['id'], $_POST['password']); + User::updatePassword($_POST['id'], $_POST['password']); } if ($_POST['rolechangedate'] !== '') { - $users->updateUserRoleChangeDate($_POST['id'], $_POST['rolechangedate']); + User::updateUserRoleChangeDate($_POST['id'], $_POST['rolechangedate']); } if ($_POST['role'] !== '') { $newRole = UserRole::query()->where('id', $_POST['role'])->value('name'); @@ -79,19 +78,19 @@ switch ($action) { header('Location:'.WWW_TOP.'/user-list.php'); } else { switch ($ret) { - case Users::ERR_SIGNUP_BADUNAME: + case User::ERR_SIGNUP_BADUNAME: $page->smarty->assign('error', 'Bad username. Try a better one.'); break; - case Users::ERR_SIGNUP_BADPASS: + case User::ERR_SIGNUP_BADPASS: $page->smarty->assign('error', 'Bad password. Try a longer one.'); break; - case Users::ERR_SIGNUP_BADEMAIL: + case User::ERR_SIGNUP_BADEMAIL: $page->smarty->assign('error', 'Bad email.'); break; - case Users::ERR_SIGNUP_UNAMEINUSE: + case User::ERR_SIGNUP_UNAMEINUSE: $page->smarty->assign('error', 'Username in use.'); break; - case Users::ERR_SIGNUP_EMAILINUSE: + case User::ERR_SIGNUP_EMAILINUSE: $page->smarty->assign('error', 'Email in use.'); break; default: @@ -114,7 +113,7 @@ switch ($action) { if (isset($_GET['id'])) { $page->title = 'User Edit'; $id = $_GET['id']; - $user = $users->getById($id); + $user = User::getById($id); $page->smarty->assign('user', $user); } diff --git a/public/admin/user-list.php b/public/admin/user-list.php index 61d921ecb..5fa018ca1 100644 --- a/public/admin/user-list.php +++ b/public/admin/user-list.php @@ -1,5 +1,6 @@ smarty->assign( 'role_ids' => array_keys($roles), 'role_names' => $roles, 'pagerquerysuffix' => '#results', - 'pagertotalitems' => $page->users->getCount($variables['role'], $variables['username'], $variables['host'], $variables['email']), + 'pagertotalitems' => User::getCount($variables['role'], $variables['username'], $variables['host'], $variables['email']), 'pageroffset' => $offset, 'pageritemsperpage' => ITEMS_PER_PAGE, 'pagerquerybase' => WWW_TOP.'/user-list.php?ob='.$orderBy.$uSearch.'&offset=', - 'userlist' => $page->users->getRange( + 'userlist' => User::getRange( $offset, ITEMS_PER_PAGE, $orderBy, @@ -48,7 +49,7 @@ $page->smarty->assign( ] ); -$page->users->updateExpiredRoles('Role changed', 'Your role has expired and has been downgraded to user'); +User::updateExpiredRoles('Role changed', 'Your role has expired and has been downgraded to user'); foreach ($ordering as $orderType) { $page->smarty->assign('orderby'.$orderType, WWW_TOP.'/user-list.php?ob='.$orderType.'&offset=0'); diff --git a/public/pages/BasePage.php b/public/pages/BasePage.php index 5ad200ecd..9a6eb457c 100644 --- a/public/pages/BasePage.php +++ b/public/pages/BasePage.php @@ -2,6 +2,8 @@ require_once NN_LIB.'utility'.DS.'SmartyUtils.php'; +use App\Models\RoleExcludedCategory; +use App\Models\User; use nntmux\db\DB; use nntmux\Users; use nntmux\SABnzbd; @@ -10,17 +12,17 @@ use App\Models\Settings; class BasePage { /** - * @var DB + * @var \App\Models\Settings|null */ public $settings = null; /** - * @var Users + * @var \nntmux\Users|null */ public $users = null; /** - * @var Smarty + * @var null|\Smarty */ public $smarty = null; @@ -145,7 +147,7 @@ class BasePage $this->page = $_GET['page'] ?? 'content'; $this->users = new Users(); - if ($this->users->isLoggedIn()) { + if (User::isLoggedIn()) { $this->setUserPreferences(); } else { $this->theme = $this->getSettingValue('site.main.style'); @@ -333,9 +335,9 @@ class BasePage protected function setUserPreferences(): void { - $this->userdata = $this->users->getById($this->users->currentUserId()); - $this->userdata['categoryexclusions'] = $this->users->getCategoryExclusion($this->users->currentUserId()); - $this->userdata['rolecategoryexclusions'] = $this->users->getRoleCategoryExclusion($this->userdata['user_roles_id']); + $this->userdata = User::getById(User::currentUserId()); + $this->userdata['categoryexclusions'] = User::getCategoryExclusion(User::currentUserId()); + $this->userdata['rolecategoryexclusions'] = RoleExcludedCategory::getRoleCategoryExclusion($this->userdata['user_roles_id']); // Change the theme to user's selected theme if they selected one, else use the admin one. if ((int) Settings::settingValue('site.main.userselstyle') === 1) { @@ -351,7 +353,7 @@ class BasePage if ((strtotime($this->userdata['now']) - 900) > strtotime($this->userdata['lastlogin']) ) { - $this->users->updateSiteAccessed($this->userdata['id']); + User::updateSiteAccessed($this->userdata['id']); } $this->smarty->assign('userdata', $this->userdata); @@ -369,10 +371,10 @@ class BasePage $this->smarty->assign('sabapikeytype', $sab->apikeytype); } switch ((int) $this->userdata['user_roles_id']) { - case Users::ROLE_ADMIN: + case User::ROLE_ADMIN: $this->smarty->assign('isadmin', 'true'); break; - case Users::ROLE_MODERATOR: + case User::ROLE_MODERATOR: $this->smarty->assign('ismod', 'true'); } } diff --git a/public/pages/api.php b/public/pages/api.php index 98871d3c7..adeb5c1f7 100644 --- a/public/pages/api.php +++ b/public/pages/api.php @@ -1,5 +1,6 @@ users->getByRssToken($apiKey); + $res = User::getByRssToken($apiKey); if ($res === null) { Utility::showApiError(100, 'Incorrect user credentials (wrong API key)'); } } - if ($page->users->isDisabled($res['username'])) { + if (User::isDisabled($res['username'])) { Utility::showApiError(101); } $uid = $res['id']; - $catExclusions = $page->users->getCategoryExclusion($uid); + $catExclusions = User::getCategoryExclusion($uid); $maxRequests = $res->role->apirequests; } // Record user access to the api, if its been called by a user (i.e. capabilities request do not require a user to be logged in or key provided). if ($uid !== '') { - $page->users->updateApiAccessed($uid); + User::updateApiAccessed($uid); $apiRequests = UserRequest::getApiRequests($uid); if ($apiRequests > $maxRequests) { Utility::showApiError(500, 'Request limit reached ('.$apiRequests.'/'.$maxRequests.')'); diff --git a/public/pages/btc_payment_callback.php b/public/pages/btc_payment_callback.php index 537aeccf8..e0a1af077 100644 --- a/public/pages/btc_payment_callback.php +++ b/public/pages/btc_payment_callback.php @@ -1,12 +1,11 @@ check_order_callback(); @@ -18,7 +17,7 @@ if ($order !== false) { $addYear = $callback_data['addyears']; // If order was paid in full (2) or overpaid (4) if ((int) $order['status'] === 2 || (int) $order['status'] === 4) { - $users->updateUserRole($callback_data['user_id'], $newRole); - $users->updateUserRoleChangeDate($callback_data['user_id'], \Carbon\Carbon::now()->addYears($addYear)); + User::updateUserRole($callback_data['user_id'], $newRole); + User::updateUserRoleChangeDate($callback_data['user_id'], \Carbon\Carbon::now()->addYears($addYear)); } } diff --git a/public/pages/forgottenpassword.php b/public/pages/forgottenpassword.php index 9d9ac863d..2aba0cf41 100644 --- a/public/pages/forgottenpassword.php +++ b/public/pages/forgottenpassword.php @@ -1,11 +1,12 @@ users->isLoggedIn()) { +if (User::isLoggedIn()) { header('Location: '.WWW_TOP.'/'); } @@ -21,7 +22,7 @@ switch ($action) { break; } - $ret = $page->users->getByPassResetGuid($_REQUEST['guid']); + $ret = User::getByPassResetGuid($_REQUEST['guid']); if (! $ret) { $page->smarty->assign('error', 'Bad reset code provided.'); break; @@ -30,9 +31,9 @@ switch ($action) { // // reset the password, inform the user, send out the email // - $page->users->updatePassResetGuid($ret['id'], ''); - $newpass = $page->users->generatePassword(); - $page->users->updatePassword($ret['id'], $newpass); + User::updatePassResetGuid($ret['id'], ''); + $newpass = User::generatePassword(); + User::updatePassword($ret['id'], $newpass); $to = $ret['email']; $onscreen = 'Your password has been reset to '.$newpass.' and sent to your e-mail address.'; @@ -53,11 +54,7 @@ switch ($action) { // // Check users exists and send an email // - if (! empty($rssToken)) { - $ret = $page->users->getByRssToken($rssToken); - } else { - $ret = $page->users->getByEmail($email); - } + $ret = ! empty($rssToken) ? User::getByRssToken($rssToken) : User::getByEmail($email); if ($ret === null) { $page->smarty->assign('error', 'The email or apikey are not recognised.'); $sent = true; @@ -67,7 +64,7 @@ switch ($action) { // Generate a forgottenpassword guid, store it in the user table // $guid = md5(uniqid('', false)); - $page->users->updatePassResetGuid($ret['id'], $guid); + User::updatePassResetGuid($ret['id'], $guid); // // Send the email // diff --git a/public/pages/getnzb.php b/public/pages/getnzb.php index 354b404d3..a4aaded76 100644 --- a/public/pages/getnzb.php +++ b/public/pages/getnzb.php @@ -10,22 +10,22 @@ use App\Models\UsersRelease; $uid = 0; // Page is accessible only by the rss token, or logged in users. -if ($page->users->isLoggedIn()) { - $uid = $page->users->currentUserId(); +if (User::isLoggedIn()) { + $uid = User::currentUserId(); $maxDownloads = $page->userdata->role->downloadrequests; $rssToken = $page->userdata['rsstoken']; - if ($page->users->isDisabled($page->userdata['username'])) { + if (User::isDisabled($page->userdata['username'])) { Utility::showApiError(101); } } else { if ((int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_API_ONLY) { - $res = $page->users->getById(0); + $res = User::getById(0); } else { if (! isset($_GET['i']) || ! isset($_GET['r'])) { Utility::showApiError(200); } - $res = $page->users->getByIdAndRssToken($_GET['i'], $_GET['r']); + $res = User::getByIdAndRssToken($_GET['i'], $_GET['r']); if (! $res) { Utility::showApiError(100); } @@ -33,7 +33,7 @@ if ($page->users->isLoggedIn()) { $uid = $res['id']; $rssToken = $res['rsstoken']; $maxDownloads = $res->role->downloadrequests; - if ($page->users->isDisabled($res['username'])) { + if (User::isDisabled($res['username'])) { Utility::showApiError(101); } } @@ -47,7 +47,7 @@ if (isset($_GET['id'])) { // $hosthash = ''; if ((int) Settings::settingValue('..storeuserips') === 1) { - $hosthash = $page->users->getHostHash($_SERVER['REMOTE_ADDR'], Settings::settingValue('..siteseed')); + $hosthash = User::getHostHash($_SERVER['REMOTE_ADDR'], Settings::settingValue('..siteseed')); } // Check download limit on user role. @@ -73,7 +73,7 @@ if (isset($_GET['zip']) && $_GET['zip'] === '1') { $zip = $rel->getZipped($guids); if (strlen($zip) > 0) { - $page->users->incrementGrabs($uid, count($guids)); + User::incrementGrabs($uid, count($guids)); foreach ($guids as $guid) { $rel->updateGrab($guid); UserDownload::addDownloadRequest($uid, $guid); @@ -100,7 +100,7 @@ $relData = $rel->getByGuid($_GET['id']); if ($relData) { $rel->updateGrab($_GET['id']); UserDownload::addDownloadRequest($uid, $relData['id']); - $page->users->incrementGrabs($uid); + User::incrementGrabs($uid); if (isset($_GET['del']) && (int) $_GET['del'] === 1) { UsersRelease::delCartByUserAndRelease($_GET['id'], $uid); } diff --git a/public/pages/login.php b/public/pages/login.php index a45778648..0ff3ba523 100644 --- a/public/pages/login.php +++ b/public/pages/login.php @@ -1,5 +1,6 @@ smarty->assign(['error' => '', 'username' => '', 'rememberme' => '']); $captcha = new Captcha($page); -if (! $page->users->isLoggedIn()) { +if (! User::isLoggedIn()) { if (! isset($_POST['username'], $_POST['password'])) { $page->smarty->assign('error', 'Please enter your username and password.'); } elseif ($captcha->getError() === false) { @@ -17,18 +18,18 @@ if (! $page->users->isLoggedIn()) { $page->smarty->assign('username', $username); if (Utility::checkCsrfToken() === true) { $logging = new Logging(['Settings' => $page->settings]); - $res = $page->users->getByUsername($username); + $res = User::getByUsername($username); if ($res === null) { - $res = $page->users->getByEmail($username); + $res = User::getByEmail($username); } if ($res !== null) { - $dis = $page->users->isDisabled($username); + $dis = User::isDisabled($username); if ($dis) { $page->smarty->assign('error', 'Your account has been disabled.'); - } elseif ($page->users->checkPassword($_POST['password'], $res['password'], $res['id'])) { + } elseif (User::checkPassword($_POST['password'], $res['password'], $res['id'])) { $rememberMe = (isset($_POST['rememberme']) && $_POST['rememberme'] === 'on'); - $page->users->login($res['id'], $_SERVER['REMOTE_ADDR'], $rememberMe); + User::login($res['id'], $_SERVER['REMOTE_ADDR'], $rememberMe); if (isset($_POST['redirect']) && $_POST['redirect'] !== '') { header('Location: '.$_POST['redirect']); diff --git a/public/pages/profile.php b/public/pages/profile.php index 54579022b..814af6afc 100644 --- a/public/pages/profile.php +++ b/public/pages/profile.php @@ -1,5 +1,7 @@ users->isLoggedIn()) { +if (! User::isLoggedIn()) { $page->show403(); } @@ -15,8 +17,8 @@ $rc = new ReleaseComments; $sab = new SABnzbd($page); $nzbget = new NZBGet($page); -$userID = $page->users->currentUserId(); -$privileged = $page->users->isAdmin($userID) || $page->users->isModerator($userID); +$userID = User::currentUserId(); +$privileged = User::isAdmin($userID) || User::isModerator($userID); $privateProfiles = (int) Settings::settingValue('..privateprofiles') === 1; $publicView = false; @@ -26,7 +28,7 @@ if ($privileged || ! $privateProfiles) { // If both 'id' and 'name' are specified, 'id' should take precedence. if ($altID === false && $altUsername !== false) { - $user = $page->users->getByUsername($altUsername); + $user = User::getByUsername($altUsername); if ($user) { $altID = $user['id']; $userID = $altID; @@ -40,7 +42,7 @@ if ($privileged || ! $privateProfiles) { $downloadlist = UserDownload::getDownloadRequestsForUser($userID); $page->smarty->assign('downloadlist', $downloadlist); -$data = $page->users->getById($userID); +$data = User::getById($userID); if (! $data) { $page->show404(); } @@ -55,7 +57,7 @@ $page->smarty->assign( [ 'apirequests' => UserRequest::getApiRequests($userID), 'grabstoday' => UserDownload::getDownloadRequests($userID), - 'userinvitedby' => $data['invitedby'] !== '' ? $page->users->getById($data['invitedby']) : '', + 'userinvitedby' => $data['invitedby'] !== '' ? User::getById($data['invitedby']) : '', 'user' => $data, 'privateprofiles' => $privateProfiles, 'publicview' => $publicView, @@ -83,7 +85,7 @@ $page->smarty->assign( [ 'pager' => $page->smarty->fetch('pager.tpl'), 'commentslist' => $rc->getCommentsForUserRange($userID, $offset, ITEMS_PER_PAGE), - 'exccats' => implode(',', $page->users->getCategoryExclusionNames($userID)), + 'exccats' => implode(',', UserExcludedCategory::getCategoryExclusionNames($userID)), 'saburl' => $sab->url, 'sabapikey' => $sab->apikey, 'sabapikeytype' => $sab->apikeytype !== '' ? $sabApiKeyTypes[$sab->apikeytype] : '', diff --git a/public/pages/profileedit.php b/public/pages/profileedit.php index f007c17e6..789d6fcf4 100644 --- a/public/pages/profileedit.php +++ b/public/pages/profileedit.php @@ -1,5 +1,7 @@ users = new Users(); -if (! $page->users->isLoggedIn()) { +if (! User::isLoggedIn()) { $page->show403(); } $action = $_REQUEST['action'] ?? 'view'; -$userid = $page->users->currentUserId(); -$data = $page->users->getById($userid); +$userid = User::currentUserId(); +$data = User::getById($userid); if (! $data) { $page->show404(); } @@ -28,7 +30,7 @@ $errorStr = ''; switch ($action) { case 'newapikey': - $page->users->updateRssKey($userid); + User::updateRssKey($userid); header('Location: profileedit'); break; case 'clearcookies': @@ -44,14 +46,14 @@ switch ($action) { if ($_POST['password'] !== '' && $_POST['password'] !== $_POST['confirmpassword']) { $errorStr = 'Password Mismatch'; - } elseif ($_POST['password'] !== '' && ! $page->users->isValidPassword($_POST['password'])) { + } elseif ($_POST['password'] !== '' && ! User::isValidPassword($_POST['password'])) { $errorStr = 'Your password must be longer than five characters.'; } elseif (! empty($_POST['nzbgeturl']) && $nzbGet->verifyURL($_POST['nzbgeturl']) === false) { $errorStr = 'The NZBGet URL you entered is invalid!'; - } elseif (! $page->users->isValidEmail($_POST['email'])) { + } elseif (! User::isValidEmail($_POST['email'])) { $errorStr = 'Your email is not a valid format.'; } else { - $res = $page->users->getByEmail($_POST['email']); + $res = User::getByEmail($_POST['email']); if ($res && (int) $res['id'] !== (int) $userid) { $errorStr = 'Sorry, the email is already in use.'; } elseif ((empty($_POST['saburl']) && ! empty($_POST['sabapikey'])) || (! empty($_POST['saburl']) && empty($_POST['sabapikey']))) { @@ -62,7 +64,7 @@ switch ($action) { $_POST['saburl'] = $_POST['sabapikey'] = $_POST['sabpriority'] = $_POST['sabapikeytype'] = false; } - $page->users->update( + User::updateUser( $userid, $data['username'], $_POST['email'], @@ -92,10 +94,10 @@ switch ($action) { ); $_POST['exccat'] = (! isset($_POST['exccat']) || ! is_array($_POST['exccat'])) ? [] : $_POST['exccat']; - $page->users->addCategoryExclusions($userid, $_POST['exccat']); + UserExcludedCategory::addCategoryExclusions($userid, $_POST['exccat']); if ($_POST['password'] !== '') { - $page->users->updatePassword($userid, $_POST['password']); + User::updatePassword($userid, $_POST['password']); } header('Location:'.WWW_TOP.'/profile'); @@ -115,7 +117,7 @@ if ((int) Settings::settingValue('site.main.userselstyle') === 1) { $page->smarty->assign('error', $errorStr); $page->smarty->assign('user', $data); -$page->smarty->assign('userexccat', $page->users->getCategoryExclusion($userid)); +$page->smarty->assign('userexccat', User::getCategoryExclusion($userid)); $page->smarty->assign('saburl_selected', $sab->url); $page->smarty->assign('sabapikey_selected', $sab->apikey); diff --git a/public/pages/register.php b/public/pages/register.php index e63091955..bc6d630c9 100644 --- a/public/pages/register.php +++ b/public/pages/register.php @@ -1,19 +1,21 @@ users->isLoggedIn()) { +if (User::isLoggedIn()) { header('Location: '.WWW_TOP.'/'); } $error = $userName = $password = $confirmPassword = $email = $inviteCode = $inviteCodeQuery = ''; $showRegister = 1; -if ((int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_CLOSED || (int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_API_ONLY) { +if ((int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_CLOSED) { $error = 'Registrations are currently disabled.'; $showRegister = 0; } elseif (Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_INVITE && (! isset($_REQUEST['invitecode']) || empty($_REQUEST['invitecode']))) { @@ -50,7 +52,7 @@ if ($showRegister === 1) { // Get the default user role. $userDefault = UserRole::getDefaultRole(); - $ret = $page->users->signup( + $ret = User::signup( $userName, $password, $email, @@ -62,26 +64,26 @@ if ($showRegister === 1) { ); if ($ret > 0) { - $page->users->login($ret, $_SERVER['REMOTE_ADDR']); + User::login($ret, $_SERVER['REMOTE_ADDR']); header('Location: '.WWW_TOP.'/'); } else { switch ($ret) { - case Users::ERR_SIGNUP_BADUNAME: + case User::ERR_SIGNUP_BADUNAME: $error = 'Your username must be at least five characters.'; break; - case Users::ERR_SIGNUP_BADPASS: + case User::ERR_SIGNUP_BADPASS: $error = 'Your password must be longer than eight characters.'; break; - case Users::ERR_SIGNUP_BADEMAIL: + case User::ERR_SIGNUP_BADEMAIL: $error = 'Your email is not a valid format.'; break; - case Users::ERR_SIGNUP_UNAMEINUSE: + case User::ERR_SIGNUP_UNAMEINUSE: $error = 'Sorry, the username is already taken.'; break; - case Users::ERR_SIGNUP_EMAILINUSE: + case User::ERR_SIGNUP_EMAILINUSE: $error = 'Sorry, the email is already in use.'; break; - case Users::ERR_SIGNUP_BADINVITECODE: + case User::ERR_SIGNUP_BADINVITECODE: $error = 'Sorry, the invite code is old or has been used.'; break; default: @@ -99,9 +101,9 @@ if ($showRegister === 1) { $inviteCode = $_GET['invitecode'] ?? null; if (isset($inviteCode)) { // See if it is a valid invite. - $invite = $page->users->getInvite($inviteCode); + $invite = Invitation::getInvite($inviteCode); if (! $invite) { - $error = sprintf('Bad or invite code older than %d days.', Users::DEFAULT_INVITE_EXPIRY_DAYS); + $error = sprintf('Bad or invite code older than %d days.', Invitation::DEFAULT_INVITE_EXPIRY_DAYS); $showRegister = 0; } else { $inviteCode = $invite['guid']; diff --git a/public/pages/rss.php b/public/pages/rss.php index 33b2d50a9..106b075a5 100755 --- a/public/pages/rss.php +++ b/public/pages/rss.php @@ -1,5 +1,6 @@ users->isLoggedIn()) { + if (! User::isLoggedIn()) { if ((int) Settings::settingValue('..registerstatus') !== Settings::REGISTER_STATUS_API_ONLY) { Utility::showApiError(100); } else { @@ -53,19 +54,19 @@ if (! isset($_GET['t']) && ! isset($_GET['show']) && ! isset($_GET['anidb'])) { } else { $rssToken = $uid = -1; // User requested a feed, ensure either logged in or passing a valid token. - if ($page->users->isLoggedIn()) { + if (User::isLoggedIn()) { $uid = $page->userdata['id']; $rssToken = $page->userdata['rsstoken']; $maxRequests = $page->userdata->role->apirequests; } else { if ((int) Settings::settingValue('..registerstatus') === Settings::REGISTER_STATUS_API_ONLY) { - $res = $page->users->getById(0); + $res = User::getById(0); } else { if (! isset($_GET['i']) || ! isset($_GET['r'])) { Utility::showApiError(100, 'Both the User ID and API key are required for viewing the RSS!'); } - $res = $page->users->getByIdAndRssToken($_GET['i'], $_GET['r']); + $res = User::getByIdAndRssToken($_GET['i'], $_GET['r']); } if (! $res) { @@ -77,7 +78,7 @@ if (! isset($_GET['t']) && ! isset($_GET['show']) && ! isset($_GET['anidb'])) { $maxRequests = $res->role->apirequests; $username = $res['username']; - if ($page->users->isDisabled($username)) { + if (User::isDisabled($username)) { Utility::showApiError(101); } } @@ -112,9 +113,9 @@ if (! isset($_GET['t']) && ! isset($_GET['show']) && ! isset($_GET['anidb'])) { ]; if ((int) $userCat === -3) { - $relData = $rss->getShowsRss($userNum, $uid, $page->users->getCategoryExclusion($uid), $userAirDate); + $relData = $rss->getShowsRss($userNum, $uid, User::getCategoryExclusion($uid), $userAirDate); } elseif ((int) $userCat === -4) { - $relData = $rss->getMyMoviesRss($userNum, $uid, $page->users->getCategoryExclusion($uid)); + $relData = $rss->getMyMoviesRss($userNum, $uid, User::getCategoryExclusion($uid)); } else { $relData = $rss->getRss(explode(',', $userCat), $userNum, $userShow, $userAnidb, $uid, $userAirDate); } diff --git a/tests/Install/InstallTest.php b/tests/Install/InstallTest.php index 2c1d73531..bb22f5d33 100644 --- a/tests/Install/InstallTest.php +++ b/tests/Install/InstallTest.php @@ -17,11 +17,11 @@ require_once \dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'bootstrap/autoload.ph include_once \dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'nntmux' . DIRECTORY_SEPARATOR . 'constants.php'; use App\Extensions\util\Versions; +use App\Models\User; use nntmux\config\Configure; use nntmux\db\DB; use nntmux\db\DbUpdate; use nntmux\ColorCLI; -use nntmux\Users; use Illuminate\Database\Capsule\Manager as Capsule; /** @@ -204,21 +204,20 @@ class InstallTest extends \PHPUnit\Framework\TestCase ); $capsule->bootEloquent(); - $user = new Users(); - if (!$user->isValidUsername(env('ADMIN_USER'))) { + if (!User::isValidUsername(env('ADMIN_USER'))) { $error = true; } else { - $usrCheck = $user->getByUsername(env('ADMIN_USER')); + $usrCheck = User::getByUsername(env('ADMIN_USER')); if ($usrCheck) { $error = true; } } - if (!$user->isValidEmail(env('ADMIN_EMAIL'))) { + if (!User::isValidEmail(env('ADMIN_EMAIL'))) { $error = true; } if (!$error) { - $adminCheck = $user->add(env('ADMIN_USER'), env('ADMIN_PASS'), env('ADMIN_EMAIL'), 2, '', ''); + $adminCheck = User::add(env('ADMIN_USER'), env('ADMIN_PASS'), env('ADMIN_EMAIL'), 2, '', ''); if (!is_numeric($adminCheck)) { $error = true; }