Rewrote warnings system to be OOP, also added permanent warnings.
This commit is contained in:
parent
8602e6a87e
commit
73d3552dcb
23 changed files with 453 additions and 397 deletions
|
@ -221,8 +221,6 @@ if($authToken->isValid()) {
|
|||
user_bump_last_active($userInfo->getId());
|
||||
|
||||
$userDisplayInfo['perms'] = perms_get_user($userInfo->getId());
|
||||
$userDisplayInfo['ban_expiration'] = user_warning_check_expiration($userInfo->getId(), MSZ_WARN_BAN);
|
||||
$userDisplayInfo['silence_expiration'] = $userDisplayInfo['ban_expiration'] > 0 ? 0 : user_warning_check_expiration($userInfo->getId(), MSZ_WARN_SILENCE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,12 +252,15 @@ if(Config::get('private.enabled', Config::TYPE_BOOL)) {
|
|||
}
|
||||
}
|
||||
|
||||
if(!empty($userDisplayInfo)) // delete this
|
||||
// delete these
|
||||
if(!empty($userDisplayInfo))
|
||||
Template::set('current_user', $userDisplayInfo);
|
||||
if(!empty($userInfo))
|
||||
Template::set('current_user2', $userInfo);
|
||||
|
||||
$inManageMode = starts_with($_SERVER['REQUEST_URI'], '/manage');
|
||||
$hasManageAccess = User::hasCurrent()
|
||||
&& !user_warning_check_restriction(User::getCurrent()->getId())
|
||||
&& !User::getCurrent()->hasActiveWarning()
|
||||
&& perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);
|
||||
Template::set('has_manage_access', $hasManageAccess);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use Misuzu\Net\IPAddressBlacklist;
|
|||
use Misuzu\Users\User;
|
||||
use Misuzu\Users\UserLoginAttempt;
|
||||
use Misuzu\Users\UserSession;
|
||||
use Misuzu\Users\UserWarning;
|
||||
|
||||
require_once '../../misuzu.php';
|
||||
|
||||
|
@ -19,7 +20,7 @@ $notices = [];
|
|||
$ipAddress = IPAddress::remote();
|
||||
$remainingAttempts = UserLoginAttempt::remaining();
|
||||
$restricted = IPAddressBlacklist::check($ipAddress) ? 'blacklist'
|
||||
: (user_warning_check_ip($ipAddress) ? 'ban' : '');
|
||||
: (UserWarning::countByRemoteAddress() > 0 ? 'ban' : '');
|
||||
|
||||
while(!$restricted && !empty($register)) {
|
||||
if(!CSRF::validateRequest()) {
|
||||
|
|
|
@ -36,11 +36,11 @@ if($currentUserInfo === null) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(user_warning_check_expiration($currentUserInfo->getId(), MSZ_WARN_BAN) > 0) {
|
||||
if($currentUserInfo->isBanned()) {
|
||||
echo render_info_or_json($isXHR, 'You have been banned, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
if(user_warning_check_expiration($currentUserInfo->getId(), MSZ_WARN_SILENCE) > 0) {
|
||||
if($currentUserInfo->isSilenced()) {
|
||||
echo render_info_or_json($isXHR, 'You have been silenced, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -29,9 +29,8 @@ if(!perms_check($perms, MSZ_FORUM_PERM_VIEW_FORUM)) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(user_warning_check_restriction($forumUserId)) {
|
||||
if($forumUser->hasActiveWarning())
|
||||
$perms &= ~MSZ_FORUM_PERM_SET_WRITE;
|
||||
}
|
||||
|
||||
Template::set('forum_perms', $perms);
|
||||
|
||||
|
|
|
@ -29,11 +29,11 @@ if($currentUser === null) {
|
|||
|
||||
$currentUserId = $currentUser->getId();
|
||||
|
||||
if(user_warning_check_expiration($currentUserId, MSZ_WARN_BAN) > 0) {
|
||||
if($currentUser->isBanned()) {
|
||||
echo render_info_or_json($isXHR, 'You have been banned, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
if(user_warning_check_expiration($currentUserId, MSZ_WARN_SILENCE) > 0) {
|
||||
if($currentUser->isSilenced()) {
|
||||
echo render_info_or_json($isXHR, 'You have been silenced, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ if(!empty($postMode) && !UserSession::hasCurrent()) {
|
|||
$currentUser = User::getCurrent():
|
||||
$currentUserId = $currentUser === null ? 0 : $currentUser->getId();
|
||||
|
||||
if(user_warning_check_expiration($currentUserId, MSZ_WARN_BAN) > 0) {
|
||||
if($currentUser->isBanned()) {
|
||||
echo render_info_or_json($isXHR, 'You have been banned, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
if(user_warning_check_expiration($currentUserId, MSZ_WARN_SILENCE) > 0) {
|
||||
if($currentUser->isSilenced()) {
|
||||
echo render_info_or_json($isXHR, 'You have been silenced, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ if($currentUser === null) {
|
|||
|
||||
$currentUserId = $currentUser->getId();
|
||||
|
||||
if(user_warning_check_restriction($currentUserId)) {
|
||||
if($currentUser->hasActiveWarning()) {
|
||||
echo render_error(403);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
namespace Misuzu;
|
||||
|
||||
use Misuzu\Users\User;
|
||||
use Misuzu\Users\UserNotFoundException;
|
||||
|
||||
require_once '../../misuzu.php';
|
||||
|
||||
|
@ -22,9 +23,8 @@ $perms = $topic
|
|||
? forum_perms_get_user($topic['forum_id'], $topicUserId)[MSZ_FORUM_PERMS_GENERAL]
|
||||
: 0;
|
||||
|
||||
if(user_warning_check_restriction($topicUserId)) {
|
||||
if($topicUser->hasActiveWarning())
|
||||
$perms &= ~MSZ_FORUM_PERM_SET_WRITE;
|
||||
}
|
||||
|
||||
$topicIsDeleted = !empty($topic['topic_deleted']);
|
||||
$canDeleteAny = perms_check($perms, MSZ_FORUM_PERM_DELETE_ANY_POST);
|
||||
|
|
|
@ -28,9 +28,8 @@ $perms = $topic
|
|||
? forum_perms_get_user($topic['forum_id'], $topicUserId)[MSZ_FORUM_PERMS_GENERAL]
|
||||
: 0;
|
||||
|
||||
if(user_warning_check_restriction($topicUserId)) {
|
||||
if($topicUser->hasActiveWarning())
|
||||
$perms &= ~MSZ_FORUM_PERM_SET_WRITE;
|
||||
}
|
||||
|
||||
$topicIsDeleted = !empty($topic['topic_deleted']);
|
||||
$canDeleteAny = perms_check($perms, MSZ_FORUM_PERM_DELETE_ANY_POST);
|
||||
|
@ -99,11 +98,11 @@ if(in_array($moderationMode, $validModerationModes, true)) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(user_warning_check_expiration($topicUserId, MSZ_WARN_BAN) > 0) {
|
||||
if($topicUser->isBanned()) {
|
||||
echo render_info_or_json($isXHR, 'You have been banned, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
if(user_warning_check_expiration($topicUserId, MSZ_WARN_SILENCE) > 0) {
|
||||
if($topicUser->isSilenced()) {
|
||||
echo render_info_or_json($isXHR, 'You have been silenced, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Misuzu\Net\IPAddress;
|
||||
use Misuzu\Users\User;
|
||||
use Misuzu\Users\UserNotFoundException;
|
||||
use Misuzu\Users\UserWarning;
|
||||
use Misuzu\Users\UserWarningNotFoundException;
|
||||
use Misuzu\Users\UserWarningCreationFailedException;
|
||||
|
||||
require_once '../../../misuzu.php';
|
||||
|
||||
|
@ -22,111 +27,89 @@ if(!empty($_POST['lookup']) && is_string($_POST['lookup'])) {
|
|||
// instead of just kinda taking $_GET['w'] this should really fetch the info from the database
|
||||
// and make sure that the user has authority
|
||||
if(!empty($_GET['delete'])) {
|
||||
user_warning_remove((int)($_GET['w'] ?? 0));
|
||||
try {
|
||||
UserWarning::byId((int)filter_input(INPUT_GET, 'w', FILTER_SANITIZE_NUMBER_INT))->delete();
|
||||
} catch(UserWarningNotFoundException $ex) {}
|
||||
redirect($_SERVER['HTTP_REFERER'] ?? url('manage-users-warnings'));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!empty($_POST['warning']) && is_array($_POST['warning'])) {
|
||||
$warningType = (int)($_POST['warning']['type'] ?? 0);
|
||||
$warningDuration = 0;
|
||||
$warningDuration = (int)($_POST['warning']['duration'] ?? 0);
|
||||
|
||||
if(user_warning_type_is_valid($warningType)) {
|
||||
$warningDuration = 0;
|
||||
if($warningDuration < -1) {
|
||||
$customDuration = $_POST['warning']['duration_custom'] ?? '';
|
||||
|
||||
if(user_warning_has_duration($warningType)) {
|
||||
$duration = (int)($_POST['warning']['duration'] ?? 0);
|
||||
if(!empty($customDuration)) {
|
||||
switch($warningDuration) {
|
||||
case -100: // YYYY-MM-DD
|
||||
$splitDate = array_apply(explode('-', $customDuration, 3), function ($a) {
|
||||
return (int)$a;
|
||||
});
|
||||
|
||||
if($duration > 0) {
|
||||
$warningDuration = time() + $duration;
|
||||
} elseif($duration < 0) {
|
||||
$customDuration = $_POST['warning']['duration_custom'] ?? '';
|
||||
|
||||
if(!empty($customDuration)) {
|
||||
switch($duration) {
|
||||
case -1: // YYYY-MM-DD
|
||||
$splitDate = array_apply(explode('-', $customDuration, 3), function ($a) {
|
||||
return (int)$a;
|
||||
});
|
||||
|
||||
if(checkdate($splitDate[1], $splitDate[2], $splitDate[0])) {
|
||||
$warningDuration = mktime(0, 0, 0, $splitDate[1], $splitDate[2], $splitDate[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
case -2: // Raw seconds
|
||||
$warningDuration = time() + (int)$customDuration;
|
||||
break;
|
||||
|
||||
case -3: // strtotime
|
||||
$warningDuration = strtotime($customDuration);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($warningDuration <= time()) {
|
||||
$notices[] = 'The duration supplied was invalid.';
|
||||
}
|
||||
}
|
||||
|
||||
$warningsUser = (int)($_POST['warning']['user'] ?? 0);
|
||||
|
||||
if(!user_check_super($currentUserId) && !user_check_authority($currentUserId, $warningsUser)) {
|
||||
$notices[] = 'You do not have authority over this user.';
|
||||
}
|
||||
|
||||
if(empty($notices) && $warningsUser > 0) {
|
||||
$warningId = user_warning_add(
|
||||
$warningsUser,
|
||||
user_get_last_ip($warningsUser),
|
||||
$currentUserId,
|
||||
IPAddress::remote(),
|
||||
$warningType,
|
||||
$_POST['warning']['note'],
|
||||
$_POST['warning']['private'],
|
||||
$warningDuration
|
||||
);
|
||||
}
|
||||
|
||||
if(!empty($warningId) && $warningId < 0) {
|
||||
switch($warningId) {
|
||||
case MSZ_E_WARNING_ADD_DB:
|
||||
$notices[] = 'Failed to record the warning in the database.';
|
||||
if(checkdate($splitDate[1], $splitDate[2], $splitDate[0]))
|
||||
$warningDuration = mktime(0, 0, 0, $splitDate[1], $splitDate[2], $splitDate[0]) - time();
|
||||
break;
|
||||
|
||||
case MSZ_E_WARNING_ADD_TYPE:
|
||||
$notices[] = 'The warning type provided was invalid.';
|
||||
case -200: // Raw seconds
|
||||
$warningDuration = (int)$customDuration;
|
||||
break;
|
||||
|
||||
case MSZ_E_WARNING_ADD_USER:
|
||||
$notices[] = 'The User ID provided was invalid.';
|
||||
break;
|
||||
|
||||
case MSZ_E_WARNING_ADD_DURATION:
|
||||
$notices[] = 'The duration specified was invalid.';
|
||||
case -300: // strtotime
|
||||
$warningDuration = strtotime($customDuration) - time();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$warningsUserInfo = User::byId((int)($_POST['warning']['user'] ?? 0));
|
||||
$warningsUser = $warningsUserInfo->getId();
|
||||
} catch(UserNotFoundException $ex) {
|
||||
$warningsUserInfo = null;
|
||||
}
|
||||
|
||||
if(!user_check_super($currentUserId) && !user_check_authority($currentUserId, $warningsUser)) {
|
||||
$notices[] = 'You do not have authority over this user.';
|
||||
}
|
||||
|
||||
if(empty($notices) && $warningsUser > 0) {
|
||||
try {
|
||||
$warningInfo = UserWarning::create(
|
||||
$warningsUserInfo,
|
||||
User::getCurrent(),
|
||||
$warningType,
|
||||
$warningDuration,
|
||||
$_POST['warning']['note'],
|
||||
$_POST['warning']['private']
|
||||
);
|
||||
} catch(InvalidArgumentException $ex) {
|
||||
$notices[] = $ex->getMessage();
|
||||
} catch(UserWarningCreationFailedException $ex) {
|
||||
$notices[] = 'Warning creation failed.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($warningsUser)) {
|
||||
if(empty($warningsUser))
|
||||
$warningsUser = max(0, (int)($_GET['u'] ?? 0));
|
||||
}
|
||||
|
||||
$warningsPagination = new Pagination(user_warning_global_count($warningsUser), 50);
|
||||
if(empty($warningsUserInfo))
|
||||
try {
|
||||
$warningsUserInfo = User::byId($warningsUser);
|
||||
} catch(UserNotFoundException $ex) {
|
||||
$warningsUserInfo = null;
|
||||
}
|
||||
|
||||
$warningsPagination = new Pagination(UserWarning::countAll($warningsUserInfo), 10);
|
||||
|
||||
if(!$warningsPagination->hasValidOffset()) {
|
||||
echo render_error(404);
|
||||
return;
|
||||
}
|
||||
|
||||
$warningsList = user_warning_global_fetch(
|
||||
$warningsPagination->getOffset(),
|
||||
$warningsPagination->getRange(),
|
||||
$warningsUser
|
||||
);
|
||||
|
||||
// calling array_flip since the input_select macro wants value => display, but this looks cuter
|
||||
$warningDurations = array_flip([
|
||||
'Pick a duration...' => 0,
|
||||
|
@ -148,19 +131,24 @@ $warningDurations = array_flip([
|
|||
'6 Months' => 60 * 60 * 24 * 365 / 12 * 6,
|
||||
'9 Months' => 60 * 60 * 24 * 365 / 12 * 9,
|
||||
'1 Year' => 60 * 60 * 24 * 365,
|
||||
'Until (YYYY-MM-DD) ->' => -1,
|
||||
'Until (Seconds) ->' => -2,
|
||||
'Until (strtotime) ->' => -3,
|
||||
'Permanent' => -1,
|
||||
'Until (YYYY-MM-DD) ->' => -100,
|
||||
'Until (Seconds) ->' => -200,
|
||||
'Until (strtotime) ->' => -300,
|
||||
]);
|
||||
|
||||
Template::render('manage.users.warnings', [
|
||||
'warnings' => [
|
||||
'notices' => $notices,
|
||||
'pagination' => $warningsPagination,
|
||||
'list' => $warningsList,
|
||||
'user_id' => $warningsUser,
|
||||
'username' => user_username_from_id($warningsUser),
|
||||
'types' => user_warning_get_types(),
|
||||
'list' => UserWarning::all($warningsUserInfo, $warningsPagination),
|
||||
'user' => $warningsUserInfo,
|
||||
'durations' => $warningDurations,
|
||||
'types' => [
|
||||
UserWarning::TYPE_NOTE => 'Note',
|
||||
UserWarning::TYPE_WARN => 'Warning',
|
||||
UserWarning::TYPE_MUTE => 'Silence',
|
||||
UserWarning::TYPE_BAHN => 'Ban',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
|
|
@ -26,8 +26,8 @@ $currentUser = User::getCurrent();
|
|||
$viewingAsGuest = $currentUser === null;
|
||||
$currentUserId = $viewingAsGuest ? 0 : $currentUser->getId();
|
||||
$viewingOwnProfile = $currentUserId === $profileUser->getId();
|
||||
|
||||
$isBanned = user_warning_check_restriction($profileUser->getId());
|
||||
define('DUMB_SHIT', true);
|
||||
$isBanned = $profileUser->hasActiveWarning();
|
||||
$userPerms = perms_get_user($currentUserId)[MSZ_PERMS_USER];
|
||||
$canManageWarnings = perms_check($userPerms, MSZ_PERM_USER_MANAGE_WARNINGS);
|
||||
$canEdit = !$isBanned
|
||||
|
@ -406,23 +406,11 @@ switch($profileMode) {
|
|||
|
||||
case '':
|
||||
$template = 'profile.index';
|
||||
$warnings = $viewingAsGuest
|
||||
? []
|
||||
: user_warning_fetch(
|
||||
$profileUser->getId(),
|
||||
90,
|
||||
$canManageWarnings
|
||||
? MSZ_WARN_TYPES_VISIBLE_TO_STAFF
|
||||
: (
|
||||
$viewingOwnProfile
|
||||
? MSZ_WARN_TYPES_VISIBLE_TO_USER
|
||||
: MSZ_WARN_TYPES_VISIBLE_TO_PUBLIC
|
||||
)
|
||||
);
|
||||
$warnings = $profileUser->getProfileWarnings($currentUser);
|
||||
|
||||
Template::set([
|
||||
'profile_warnings' => $warnings,
|
||||
'profile_warnings_view_private' => $viewingOwnProfile,
|
||||
'profile_warnings_view_private' => $canManageWarnings,
|
||||
'profile_warnings_can_manage' => $canManageWarnings,
|
||||
]);
|
||||
break;
|
||||
|
|
|
@ -34,7 +34,7 @@ if($currentUser === null) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(user_warning_check_expiration($currentUser->getId(), MSZ_WARN_BAN) > 0) {
|
||||
if($currentUser->isBanned()) {
|
||||
echo render_info_or_json($isXHR, 'You have been banned, check your profile for more information.', 403);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ if(!UserSession::hasCurrent()) {
|
|||
$errors = [];
|
||||
$currentUser = User::getCurrent();
|
||||
$currentUserId = $currentUser->getId();
|
||||
$isRestricted = user_warning_check_restriction($currentUserId);
|
||||
$isRestricted = $currentUser->hasActiveWarning();
|
||||
$twoFactorInfo = user_totp_info($currentUserId);
|
||||
$isVerifiedRequest = CSRF::validateRequest();
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ try {
|
|||
$userId = $userExists ? $userInfo->getId() : 0;
|
||||
|
||||
$canViewImages = !$userExists
|
||||
|| !user_warning_check_expiration($userId, MSZ_WARN_BAN)
|
||||
|| !$userInfo->isBanned()
|
||||
|| (
|
||||
parse_url($_SERVER['HTTP_REFERER'] ?? '', PHP_URL_PATH) === url('user-profile')
|
||||
&& perms_check_user(MSZ_PERMS_USER, User::hasCurrent() ? User::getCurrent()->getId() : 0, MSZ_PERM_USER_MANAGE_USERS)
|
||||
|
|
|
@ -143,7 +143,7 @@ final class SockChatHandler extends Handler {
|
|||
|
||||
try {
|
||||
$token = UserChatToken::create($currentUser);
|
||||
} catch(UserChatTokenNotFoundException $ex) {
|
||||
} catch(UserChatTokenCreationFailedException $ex) {
|
||||
return 500;
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ final class SockChatHandler extends Handler {
|
|||
} else {
|
||||
try {
|
||||
$token = UserChatToken::byExact($userInfo, $authInfo->token);
|
||||
} catch(UserChatTokenCreationFailedException $ex) {
|
||||
} catch(UserChatTokenNotFoundException $ex) {
|
||||
return ['success' => false, 'reason' => 'token'];
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ final class SockChatHandler extends Handler {
|
|||
'username' => $userInfo->getUsername(),
|
||||
'colour_raw' => $userInfo->getColourRaw(),
|
||||
'hierarchy' => $userInfo->getHierarchy(),
|
||||
'is_silenced' => date('c', user_warning_check_expiration($userInfo->getId(), MSZ_WARN_SILENCE)),
|
||||
'is_silenced' => date('c', $userInfo->isSilenced() || $userInfo->isBanned() ? ($userInfo->isActiveWarningPermanent() ? strtotime('10 years') : $userInfo->getActiveWarningExpiration()) : 0),
|
||||
'perms' => $perms,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ final class TwigMisuzu extends Twig_Extension {
|
|||
public function getFunctions() {
|
||||
return [
|
||||
new Twig_Function('url_construct', 'url_construct'),
|
||||
new Twig_Function('warning_has_duration', 'user_warning_has_duration'),
|
||||
new Twig_Function('url', 'url'),
|
||||
new Twig_Function('url_list', 'url_list'),
|
||||
new Twig_Function('html_avatar', 'html_avatar'),
|
||||
|
|
|
@ -301,6 +301,32 @@ class User {
|
|||
return $this->forumPostCount;
|
||||
}
|
||||
|
||||
private $activeWarning = -1;
|
||||
|
||||
public function getActiveWarning(): ?UserWarning {
|
||||
if($this->activeWarning === -1)
|
||||
$this->activeWarning = UserWarning::byUserActive($this);
|
||||
return $this->activeWarning;
|
||||
}
|
||||
public function hasActiveWarning(): bool {
|
||||
return $this->getActiveWarning() !== null && !$this->getActiveWarning()->hasExpired();
|
||||
}
|
||||
public function isSilenced(): bool {
|
||||
return $this->hasActiveWarning() && $this->getActiveWarning()->isSilence();
|
||||
}
|
||||
public function isBanned(): bool {
|
||||
return $this->hasActiveWarning() && $this->getActiveWarning()->isBan();
|
||||
}
|
||||
public function getActiveWarningExpiration(): int {
|
||||
return !$this->hasActiveWarning() ? 0 : $this->getActiveWarning()->getExpirationTime();
|
||||
}
|
||||
public function isActiveWarningPermanent(): bool {
|
||||
return $this->hasActiveWarning() && $this->getActiveWarning()->isPermanent();
|
||||
}
|
||||
public function getProfileWarnings(?self $viewer): array {
|
||||
return UserWarning::byProfile($this, $viewer);
|
||||
}
|
||||
|
||||
public function setCurrent(): void {
|
||||
self::$localUser = $this;
|
||||
}
|
||||
|
|
281
src/Users/UserWarning.php
Normal file
281
src/Users/UserWarning.php
Normal file
|
@ -0,0 +1,281 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Misuzu\DB;
|
||||
use Misuzu\Pagination;
|
||||
use Misuzu\Net\IPAddress;
|
||||
|
||||
class UserWarningException extends UsersException {}
|
||||
class UserWarningNotFoundException extends UserWarningException {}
|
||||
class UserWarningCreationFailedException extends UserWarningException {}
|
||||
|
||||
class UserWarning {
|
||||
// Informational notes on profile, only show up for moderators
|
||||
public const TYPE_NOTE = 0;
|
||||
|
||||
// Warning, only shows up to moderators and the user themselves
|
||||
public const TYPE_WARN = 1;
|
||||
|
||||
// Silences, prevent a user from speaking and is visible to any logged in user
|
||||
public const TYPE_MUTE = 2;
|
||||
|
||||
// Banning, prevents a user from interacting in general
|
||||
// User will still be able to log in and change certain details but can no longer partake in community things
|
||||
public const TYPE_BAHN = 3;
|
||||
|
||||
private const TYPES = [self::TYPE_NOTE, self::TYPE_WARN, self::TYPE_MUTE, self::TYPE_BAHN];
|
||||
|
||||
private const VISIBLE_TO_STAFF = self::TYPES;
|
||||
private const VISIBLE_TO_USER = [self::TYPE_WARN, self::TYPE_MUTE, self::TYPE_BAHN];
|
||||
private const VISIBLE_TO_PUBLIC = [self::TYPE_MUTE, self::TYPE_BAHN];
|
||||
|
||||
private const HAS_DURATION = [self::TYPE_MUTE, self::TYPE_BAHN];
|
||||
|
||||
private const PROFILE_BACKLOG = 90;
|
||||
|
||||
// Database fields
|
||||
private $warning_id = -1;
|
||||
private $user_id = -1;
|
||||
private $user_ip = '::1';
|
||||
private $issuer_id = -1;
|
||||
private $issuer_ip = '::1';
|
||||
private $warning_created = null;
|
||||
private $warning_duration = null;
|
||||
private $warning_type = 0;
|
||||
private $warning_note = '';
|
||||
private $warning_note_private = '';
|
||||
|
||||
private $user = null;
|
||||
private $issuer = null;
|
||||
|
||||
public const TABLE = 'user_warnings';
|
||||
private const QUERY_SELECT = 'SELECT %1$s FROM `' . DB::PREFIX . self::TABLE . '` AS '. self::TABLE;
|
||||
private const SELECT = '%1$s.`warning_id`, %1$s.`user_id`, %1$s.`issuer_id`, %1$s.`warning_type`, %1$s.`warning_note`, %1$s.`warning_note_private`'
|
||||
. ', UNIX_TIMESTAMP(%1$s.`warning_created`) AS `warning_created`'
|
||||
. ', UNIX_TIMESTAMP(%1$s.`warning_duration`) AS `warning_duration`'
|
||||
. ', INET6_NTOA(%1$s.`user_ip`) AS `user_ip`'
|
||||
. ', INET6_NTOA(%1$s.`issuer_ip`) AS `issuer_ip`';
|
||||
|
||||
public function getId(): int {
|
||||
return $this->warning_id;
|
||||
}
|
||||
|
||||
public function getUserId(): int {
|
||||
return $this->user_id;
|
||||
}
|
||||
public function getUser(): User {
|
||||
if($this->user === null)
|
||||
$this->user = User::byId($this->getUserId());
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function getUserRemoteAddress(): string {
|
||||
return $this->user_ip;
|
||||
}
|
||||
|
||||
public function getIssuerId(): int {
|
||||
return $this->issuer_id;
|
||||
}
|
||||
public function getIssuer(): User {
|
||||
if($this->issuer === null)
|
||||
$this->issuer = User::byId($this->getIssuerId());
|
||||
return $this->issuer;
|
||||
}
|
||||
|
||||
public function getIssuerRemoteAddress(): string {
|
||||
return $this->issuer_ip;
|
||||
}
|
||||
|
||||
public function getCreatedTime(): int {
|
||||
return $this->warning_created === null ? -1 : $this->warning_created;
|
||||
}
|
||||
|
||||
public function getExpirationTime(): int {
|
||||
return $this->warning_duration === null ? -1 : $this->warning_duration;
|
||||
}
|
||||
public function hasExpired(): bool {
|
||||
return $this->hasDuration() && ($this->getExpirationTime() > 0 && $this->getExpirationTime() < time());
|
||||
}
|
||||
|
||||
public function hasDuration(): bool {
|
||||
return in_array($this->getType(), self::HAS_DURATION);
|
||||
}
|
||||
public function getDuration(): int {
|
||||
return max(-1, $this->getExpirationTime() - $this->getCreatedTime());
|
||||
}
|
||||
|
||||
private const DURATION_DIVS = [
|
||||
31536000 => 'year',
|
||||
2592000 => 'month',
|
||||
604800 => 'week',
|
||||
86400 => 'day',
|
||||
3600 => 'hour',
|
||||
60 => 'minute',
|
||||
1 => 'second',
|
||||
];
|
||||
|
||||
public function getDurationString(): string {
|
||||
$duration = $this->getDuration();
|
||||
if($duration < 1)
|
||||
return 'permanent';
|
||||
|
||||
foreach(self::DURATION_DIVS as $span => $name) {
|
||||
$display = floor($duration / $span);
|
||||
if($display > 0)
|
||||
return number_format($display) . ' ' . $name . ($display == 1 ? '' : 's');
|
||||
}
|
||||
|
||||
return 'an amount of time';
|
||||
}
|
||||
|
||||
public function isPermanent(): bool {
|
||||
return $this->hasDuration() && $this->getDuration() < 0;
|
||||
}
|
||||
|
||||
public function getType(): int { return $this->warning_type; }
|
||||
public function isNote(): bool { return $this->getType() === self::TYPE_NOTE; }
|
||||
public function isWarning(): bool { return $this->getType() === self::TYPE_WARN; }
|
||||
public function isSilence(): bool { return $this->getType() === self::TYPE_MUTE; }
|
||||
public function isBan(): bool { return $this->getType() === self::TYPE_BAHN; }
|
||||
|
||||
public function isVisibleToUser(): bool {
|
||||
return in_array($this->getType(), self::VISIBLE_TO_USER);
|
||||
}
|
||||
public function isVisibleToPublic(): bool {
|
||||
return in_array($this->getType(), self::VISIBLE_TO_PUBLIC);
|
||||
}
|
||||
|
||||
public function getPublicNote(): string {
|
||||
return $this->warning_note;
|
||||
}
|
||||
|
||||
public function getPrivateNote(): string {
|
||||
return $this->warning_note_private ?? '';
|
||||
}
|
||||
public function hasPrivateNote(): bool {
|
||||
return !empty($this->warning_note_private);
|
||||
}
|
||||
|
||||
public function delete(): void {
|
||||
DB::prepare('DELETE FROM `' . DB::PREFIX . self::TABLE . '` WHERE `warning_id` = :warning')
|
||||
->bind('warning', $this->warning_id)
|
||||
->execute();
|
||||
}
|
||||
|
||||
public static function create(User $user, User $issuer, int $type, int $duration, string $publicNote, ?string $privateNote = null): self {
|
||||
if(!in_array($type, self::TYPES))
|
||||
throw new InvalidArgumentException('Type was invalid.');
|
||||
|
||||
if(!in_array($type, self::HAS_DURATION))
|
||||
$duration = 0;
|
||||
else {
|
||||
if($duration === 0)
|
||||
throw new InvalidArgumentException('Duration must be non-zero.');
|
||||
if($duration < 0)
|
||||
$duration = -1;
|
||||
}
|
||||
|
||||
$warningId = DB::prepare(
|
||||
'INSERT INTO `' . DB::PREFIX . self::TABLE . '` (`user_id`, `user_ip`, `issuer_id`, `issuer_ip`, `warning_created`, `warning_duration`, `warning_type`, `warning_note`, `warning_note_private`)'
|
||||
. ' VALUES (:user, INET6_ATON(:user_addr), :issuer, INET6_ATON(:issuer_addr), NOW(), IF(:set_duration, NOW() + INTERVAL :duration SECOND, NULL), :type, :public_note, :private_note)'
|
||||
) ->bind('user', $user->getId())
|
||||
->bind('user_addr', $user->getLastRemoteAddress())
|
||||
->bind('issuer', $issuer->getId())
|
||||
->bind('issuer_addr', $issuer->getLastRemoteAddress())
|
||||
->bind('set_duration', $duration > 0 ? 1 : 0)
|
||||
->bind('duration', $duration)
|
||||
->bind('type', $type)
|
||||
->bind('public_note', $publicNote)
|
||||
->bind('private_note', $privateNote)
|
||||
->executeGetId();
|
||||
|
||||
if($warningId < 1)
|
||||
throw new UserWarningCreationFailedException;
|
||||
|
||||
return self::byId($warningId);
|
||||
}
|
||||
|
||||
private static function countQueryBase(): string {
|
||||
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
|
||||
}
|
||||
public static function countByRemoteAddress(?string $address = null, bool $withDuration = true): int {
|
||||
$address = $address ?? IPAddress::remote();
|
||||
return (int)DB::prepare(
|
||||
self::countQueryBase()
|
||||
. ' WHERE `user_ip` = INET6_ATON(:address)'
|
||||
. ' AND `warning_duration` >= NOW()'
|
||||
. ($withDuration ? ' AND `warning_type` IN (' . implode(',', self::HAS_DURATION) . ')' : '')
|
||||
)->bind('address', $address)->fetchColumn();
|
||||
}
|
||||
public static function countAll(?User $user = null): int {
|
||||
$getCount = DB::prepare(self::countQueryBase() . ($user === null ? '' : ' WHERE `user_id` = :user'));
|
||||
if($user !== null)
|
||||
$getCount->bind('user', $user->getId());
|
||||
return (int)$getCount->fetchColumn();
|
||||
}
|
||||
|
||||
private static function byQueryBase(): string {
|
||||
return sprintf(self::QUERY_SELECT, sprintf(self::SELECT, self::TABLE));
|
||||
}
|
||||
public static function byId(int $warningId): self {
|
||||
$object = DB::prepare(
|
||||
self::byQueryBase() . ' WHERE `warning_id` = :warning'
|
||||
) ->bind('warning', $warningId)
|
||||
->fetchObject(self::class);
|
||||
if(!$object)
|
||||
throw new UserWarningNotFoundException;
|
||||
return $object;
|
||||
}
|
||||
public static function byUserActive(User $user): ?self {
|
||||
return DB::prepare(
|
||||
self::byQueryBase()
|
||||
. ' WHERE `user_id` = :user'
|
||||
. ' AND `warning_type` IN (' . implode(',', self::HAS_DURATION) . ')'
|
||||
. ' AND (`warning_duration` IS NULL OR `warning_duration` >= NOW())'
|
||||
. ' ORDER BY `warning_type` DESC, `warning_duration` DESC'
|
||||
) ->bind('user', $user->getId())
|
||||
->fetchObject(self::class);
|
||||
}
|
||||
public static function byProfile(User $user, ?User $viewer = null): array {
|
||||
if($viewer === null)
|
||||
return [];
|
||||
|
||||
$types = self::VISIBLE_TO_PUBLIC;
|
||||
if(perms_check_user(MSZ_PERMS_USER, $viewer->getId(), MSZ_PERM_USER_MANAGE_WARNINGS))
|
||||
$types = self::VISIBLE_TO_STAFF;
|
||||
elseif($user->getId() === $viewer->getId())
|
||||
$types = self::VISIBLE_TO_USER;
|
||||
|
||||
$getObjects = DB::prepare(
|
||||
self::byQueryBase()
|
||||
. ' WHERE `user_id` = :user'
|
||||
. ' AND `warning_type` IN (' . implode(',', $types) . ')'
|
||||
. ' AND (`warning_type` = 0 OR `warning_created` >= NOW() - INTERVAL ' . self::PROFILE_BACKLOG . ' DAY OR (`warning_duration` IS NOT NULL AND `warning_duration` >= NOW()))'
|
||||
. ' ORDER BY `warning_created` DESC'
|
||||
);
|
||||
|
||||
$getObjects->bind('user', $user->getId());
|
||||
|
||||
return $getObjects->fetchObjects(self::class);
|
||||
}
|
||||
public static function all(?User $user = null, ?Pagination $pagination = null): array {
|
||||
$query = self::byQueryBase()
|
||||
. ($user === null ? '' : ' WHERE `user_id` = :user')
|
||||
. ' ORDER BY `warning_created` DESC';
|
||||
|
||||
if($pagination !== null)
|
||||
$query .= ' LIMIT :range OFFSET :offset';
|
||||
|
||||
$getObjects = DB::prepare($query);
|
||||
|
||||
if($user !== null)
|
||||
$getObjects->bind('user', $user->getId());
|
||||
|
||||
if($pagination !== null)
|
||||
$getObjects->bind('range', $pagination->getRange())
|
||||
->bind('offset', $pagination->getOffset());
|
||||
|
||||
return $getObjects->fetchObjects(self::class);
|
||||
}
|
||||
}
|
|
@ -1,211 +1,11 @@
|
|||
<?php
|
||||
define('MSZ_WARN_NOTE', 0);
|
||||
define('MSZ_WARN_WARNING', 1);
|
||||
define('MSZ_WARN_SILENCE', 2);
|
||||
define('MSZ_WARN_BAN', 3);
|
||||
|
||||
define('MSZ_WARN_TYPES', [
|
||||
MSZ_WARN_NOTE, MSZ_WARN_WARNING, MSZ_WARN_SILENCE, MSZ_WARN_BAN,
|
||||
]);
|
||||
|
||||
define('MSZ_WARN_TYPES_HAS_DURATION', [
|
||||
MSZ_WARN_SILENCE, MSZ_WARN_BAN,
|
||||
]);
|
||||
|
||||
define('MSZ_WARN_TYPES_VISIBLE_TO_STAFF', MSZ_WARN_TYPES);
|
||||
define('MSZ_WARN_TYPES_VISIBLE_TO_USER', [
|
||||
MSZ_WARN_WARNING, MSZ_WARN_SILENCE, MSZ_WARN_BAN,
|
||||
]);
|
||||
define('MSZ_WARN_TYPES_VISIBLE_TO_PUBLIC', [
|
||||
MSZ_WARN_SILENCE, MSZ_WARN_BAN,
|
||||
]);
|
||||
|
||||
define('MSZ_WARN_TYPE_NAMES', [
|
||||
MSZ_WARN_NOTE => 'Note',
|
||||
MSZ_WARN_WARNING => 'Warning',
|
||||
MSZ_WARN_SILENCE => 'Silence',
|
||||
MSZ_WARN_BAN => 'Ban',
|
||||
]);
|
||||
|
||||
function user_warning_type_is_valid(int $type): bool {
|
||||
return in_array($type, MSZ_WARN_TYPES, true);
|
||||
}
|
||||
|
||||
function user_warning_type_get_name(int $type): string {
|
||||
return user_warning_type_is_valid($type) ? MSZ_WARN_TYPE_NAMES[$type] : '';
|
||||
}
|
||||
|
||||
function user_warning_get_types(): array {
|
||||
return MSZ_WARN_TYPE_NAMES;
|
||||
}
|
||||
|
||||
function user_warning_has_duration(int $type): bool {
|
||||
return in_array($type, MSZ_WARN_TYPES_HAS_DURATION, true);
|
||||
}
|
||||
|
||||
define('MSZ_E_WARNING_ADD_DB', -1);
|
||||
define('MSZ_E_WARNING_ADD_TYPE', -2);
|
||||
define('MSZ_E_WARNING_ADD_USER', -3);
|
||||
define('MSZ_E_WARNING_ADD_DURATION', -4);
|
||||
|
||||
function user_warning_add(
|
||||
int $userId,
|
||||
string $userIp,
|
||||
int $issuerId,
|
||||
string $issuerIp,
|
||||
int $type,
|
||||
string $publicNote,
|
||||
string $privateNote,
|
||||
?int $duration = null
|
||||
): int {
|
||||
if(!user_warning_type_is_valid($type))
|
||||
return MSZ_E_WARNING_ADD_TYPE;
|
||||
|
||||
if($userId < 1)
|
||||
return MSZ_E_WARNING_ADD_USER;
|
||||
|
||||
if(user_warning_has_duration($type)) {
|
||||
if($duration <= time())
|
||||
return MSZ_E_WARNING_ADD_DURATION;
|
||||
} else
|
||||
$duration = 0;
|
||||
|
||||
$addWarning = \Misuzu\DB::prepare('
|
||||
INSERT INTO `msz_user_warnings`
|
||||
(`user_id`, `user_ip`, `issuer_id`, `issuer_ip`, `warning_type`, `warning_note`, `warning_note_private`, `warning_duration`)
|
||||
VALUES
|
||||
(:user_id, INET6_ATON(:user_ip), :issuer_id, INET6_ATON(:issuer_ip), :type, :note, :note_private, :duration)
|
||||
');
|
||||
$addWarning->bind('user_id', $userId);
|
||||
$addWarning->bind('user_ip', $userIp);
|
||||
$addWarning->bind('issuer_id', $issuerId);
|
||||
$addWarning->bind('issuer_ip', $issuerIp);
|
||||
$addWarning->bind('type', $type);
|
||||
$addWarning->bind('note', $publicNote);
|
||||
$addWarning->bind('note_private', $privateNote);
|
||||
$addWarning->bind('duration', $duration < 1 ? null : date('Y-m-d H:i:s', $duration));
|
||||
|
||||
if(!$addWarning->execute())
|
||||
return MSZ_E_WARNING_ADD_DB;
|
||||
|
||||
return \Misuzu\DB::lastId();
|
||||
}
|
||||
|
||||
function user_warning_count(int $userId): int {
|
||||
if($userId < 1)
|
||||
return 0;
|
||||
|
||||
$countWarnings = \Misuzu\DB::prepare('
|
||||
SELECT COUNT(`warning_id`)
|
||||
FROM `msz_user_warnings`
|
||||
WHERE `user_id` = :user_id
|
||||
');
|
||||
$countWarnings->bind('user_id', $userId);
|
||||
return (int)$countWarnings->fetchColumn(0, 0);
|
||||
}
|
||||
|
||||
function user_warning_remove(int $warningId): bool {
|
||||
if($warningId < 1)
|
||||
return false;
|
||||
|
||||
$removeWarning = \Misuzu\DB::prepare('
|
||||
DELETE FROM `msz_user_warnings`
|
||||
WHERE `warning_id` = :warning_id
|
||||
');
|
||||
$removeWarning->bind('warning_id', $warningId);
|
||||
return $removeWarning->execute();
|
||||
}
|
||||
|
||||
function user_warning_fetch(
|
||||
int $userId,
|
||||
?int $days = null,
|
||||
array $displayTypes = MSZ_WARN_TYPES
|
||||
): array {
|
||||
$fetchWarnings = \Misuzu\DB::prepare(sprintf(
|
||||
'
|
||||
SELECT
|
||||
uw.`warning_id`, uw.`warning_created`, uw.`warning_type`, uw.`warning_note`,
|
||||
uw.`warning_note_private`, uw.`user_id`, uw.`issuer_id`, uw.`warning_duration`,
|
||||
INET6_NTOA(uw.`user_ip`) AS `user_ip`, INET6_NTOA(uw.`issuer_ip`) AS `issuer_ip`,
|
||||
iu.`username` AS `issuer_username`
|
||||
FROM `msz_user_warnings` AS uw
|
||||
LEFT JOIN `msz_users` AS iu
|
||||
ON iu.`user_id` = uw.`issuer_id`
|
||||
WHERE uw.`user_id` = :user_id
|
||||
AND uw.`warning_type` IN (%1$s)
|
||||
%2$s
|
||||
ORDER BY uw.`warning_id` DESC
|
||||
',
|
||||
implode(',', array_apply($displayTypes, 'intval')),
|
||||
$days !== null ? 'AND (uw.`warning_created` >= NOW() - INTERVAL :days DAY OR (uw.`warning_duration` IS NOT NULL AND uw.`warning_duration` > NOW()))' : ''
|
||||
));
|
||||
$fetchWarnings->bind('user_id', $userId);
|
||||
|
||||
if($days !== null)
|
||||
$fetchWarnings->bind('days', $days);
|
||||
|
||||
return $fetchWarnings->fetchAll();
|
||||
}
|
||||
|
||||
function user_warning_global_count(?int $userId = null): int {
|
||||
$countWarnings = \Misuzu\DB::prepare(sprintf('
|
||||
SELECT COUNT(`warning_id`)
|
||||
FROM `msz_user_warnings`
|
||||
%s
|
||||
', $userId > 0 ? 'WHERE `user_id` = :user_id' : ''));
|
||||
|
||||
if($userId > 0)
|
||||
$countWarnings->bind('user_id', $userId);
|
||||
|
||||
return (int)$countWarnings->fetchColumn(0, 0);
|
||||
}
|
||||
|
||||
function user_warning_global_fetch(int $offset = 0, int $take = 50, ?int $userId = null): array {
|
||||
$fetchWarnings = \Misuzu\DB::prepare(sprintf(
|
||||
'
|
||||
SELECT
|
||||
uw.`warning_id`, uw.`warning_created`, uw.`warning_type`, uw.`warning_note`,
|
||||
uw.`warning_note_private`, uw.`user_id`, uw.`issuer_id`, uw.`warning_duration`,
|
||||
INET6_NTOA(uw.`user_ip`) AS `user_ip`, INET6_NTOA(uw.`issuer_ip`) AS `issuer_ip`,
|
||||
iu.`username` AS `issuer_username`, wu.`username` AS `username`
|
||||
FROM `msz_user_warnings` AS uw
|
||||
LEFT JOIN `msz_users` AS iu
|
||||
ON iu.`user_id` = uw.`issuer_id`
|
||||
LEFT JOIN `msz_users` AS wu
|
||||
ON wu.`user_id` = uw.`user_id`
|
||||
%1$s
|
||||
ORDER BY uw.`warning_id` DESC
|
||||
LIMIT :offset, :take
|
||||
',
|
||||
$userId > 0 ? 'WHERE uw.`user_id` = :user_id' : ''
|
||||
));
|
||||
$fetchWarnings->bind('offset', $offset);
|
||||
$fetchWarnings->bind('take', $take);
|
||||
|
||||
if($userId > 0)
|
||||
$fetchWarnings->bind('user_id', $userId);
|
||||
|
||||
return $fetchWarnings->fetchAll();
|
||||
}
|
||||
|
||||
function user_warning_check_ip(string $address): bool {
|
||||
$checkAddress = \Misuzu\DB::prepare(sprintf(
|
||||
'
|
||||
SELECT COUNT(`warning_id`) > 0
|
||||
FROM `msz_user_warnings`
|
||||
WHERE `warning_type` IN (%s)
|
||||
AND `user_ip` = INET6_ATON(:address)
|
||||
AND `warning_duration` IS NOT NULL
|
||||
AND `warning_duration` >= NOW()
|
||||
',
|
||||
implode(',', MSZ_WARN_TYPES_HAS_DURATION)
|
||||
));
|
||||
$checkAddress->bind('address', $address);
|
||||
return (bool)$checkAddress->fetchColumn(0, false);
|
||||
}
|
||||
define('MSZ_WARN_TYPES_HAS_DURATION', [MSZ_WARN_SILENCE, MSZ_WARN_BAN]);
|
||||
|
||||
function user_warning_check_expiration(int $userId, int $type): int {
|
||||
if($userId < 1 || !user_warning_has_duration($type))
|
||||
if($userId < 1 || !in_array($type, MSZ_WARN_TYPES_HAS_DURATION, true))
|
||||
return 0;
|
||||
|
||||
static $memo = [];
|
||||
|
@ -230,27 +30,3 @@ function user_warning_check_expiration(int $userId, int $type): int {
|
|||
|
||||
return $memo[$memoId] = (empty($expiration) ? 0 : strtotime($expiration));
|
||||
}
|
||||
|
||||
function user_warning_check_restriction(int $userId): bool {
|
||||
if($userId < 1)
|
||||
return false;
|
||||
|
||||
static $memo = [];
|
||||
|
||||
if(array_key_exists($userId, $memo))
|
||||
return $memo[$userId];
|
||||
|
||||
$checkAddress = \Misuzu\DB::prepare(sprintf(
|
||||
'
|
||||
SELECT COUNT(`warning_id`) > 0
|
||||
FROM `msz_user_warnings`
|
||||
WHERE `warning_type` IN (%s)
|
||||
AND `user_id` = :user
|
||||
AND `warning_duration` IS NOT NULL
|
||||
AND `warning_duration` >= NOW()
|
||||
',
|
||||
implode(',', MSZ_WARN_TYPES_HAS_DURATION)
|
||||
));
|
||||
$checkAddress->bind('user', $userId);
|
||||
return $memo[$userId] = (bool)$checkAddress->fetchColumn(0, false);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% block manage_content %}
|
||||
<form class="container container--lazy" action="{{ url('manage-users-warnings') }}" method="post">
|
||||
{{ container_title('<i class="fas fa-users fa-fw"></i> Filters') }}
|
||||
{{ input_text('lookup', null, warnings.username, 'text', 'Enter a username') }}
|
||||
{{ input_text('lookup', null, warnings.user.username|default(''), 'text', 'Enter a username') }}
|
||||
<button class="input__button">Filter</button>
|
||||
</form>
|
||||
|
||||
|
@ -20,11 +20,11 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if warnings.user_id > 0 and warnings.username|length > 0 %}{# shittiest validation in the world, but it should work #}
|
||||
{% if warnings.user is not null %}
|
||||
<form class="container container--lazy" method="post" action="">
|
||||
{{ container_title('<i class="fas fa-user-shield fa-fw"></i> Warn ' ~ warnings.username) }}
|
||||
{{ container_title('<i class="fas fa-user-shield fa-fw"></i> Warn ' ~ warnings.user.username) }}
|
||||
{{ input_csrf() }}
|
||||
{{ input_hidden('warning[user]', warnings.user_id) }}
|
||||
{{ input_hidden('warning[user]', warnings.user.id) }}
|
||||
|
||||
{{ input_select('warning[type]', warnings.types) }}
|
||||
{{ input_text('warning[note]', '', '', 'text', 'Public note') }}
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
<div class="container container--lazy">
|
||||
{{ container_title('<i class="fas fa-exclamation-circle fa-fw"></i> Warnings') }}
|
||||
{% set warnpag = pagination(warnings.pagination, url('manage-users-warnings')) %}
|
||||
{% set warnpag = pagination(warnings.pagination, url('manage-users-warnings', {'user': warnings.user.id|default(0)})) %}
|
||||
|
||||
{{ warnpag }}
|
||||
|
||||
|
@ -76,7 +76,7 @@
|
|||
</div>
|
||||
|
||||
<div class="profile__warning__duration">
|
||||
Expires
|
||||
Duration
|
||||
</div>
|
||||
|
||||
<div class="profile__warning__note">
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
{% include '_layout/header.twig' %}
|
||||
|
||||
<div class="main__wrapper">
|
||||
{% if current_user.ban_expiration|default(0) > 0 or current_user.silence_expiration|default(0) > 0 %}
|
||||
{% if current_user2.hasActiveWarning|default(false) %}
|
||||
<div class="warning">
|
||||
<div class="warning__content">
|
||||
You have been {{ current_user.silence_expiration ? 'silenced' : 'banned' }} until <strong>{{ (current_user.silence_expiration ? current_user.silence_expiration : current_user.ban_expiration)|date('r') }}</strong>, view the account standing table on <a href="{{ url('user-account-standing', {'user': current_user.user_id}) }}" class="warning__link">your profile</a> to view why.
|
||||
You have been {{ current_user2.isSilenced ? 'silenced' : 'banned' }} {% if current_user2.isActiveWarningPermanent %}<strong>permanently</strong>{% else %}until <strong>{{ current_user2.activeWarningExpiration|date('r') }}</strong>{% endif %}, view the account standing table on <a href="{{ url('user-account-standing', {'user': current_user2.id}) }}" class="warning__link">your profile</a> to view why.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -245,7 +245,7 @@
|
|||
</div>
|
||||
|
||||
<div class="profile__warning__duration">
|
||||
Expires
|
||||
Duration
|
||||
</div>
|
||||
|
||||
<div class="profile__warning__note">
|
||||
|
|
|
@ -433,13 +433,13 @@
|
|||
|
||||
{% macro user_profile_warning(warning, show_private_note, show_user_info, delete_csrf) %}
|
||||
{% from 'macros.twig' import avatar %}
|
||||
{% if warning.warning_type == constant('MSZ_WARN_SILENCE') %}
|
||||
{% if warning.isSilence %}
|
||||
{% set warning_text = 'Silence' %}
|
||||
{% set warning_class = 'silence' %}
|
||||
{% elseif warning.warning_type == constant('MSZ_WARN_BAN') %}
|
||||
{% elseif warning.isBan %}
|
||||
{% set warning_text = 'Ban' %}
|
||||
{% set warning_class = 'ban' %}
|
||||
{% elseif warning.warning_type == constant('MSZ_WARN_WARNING') %}
|
||||
{% elseif warning.isWarning %}
|
||||
{% set warning_text = 'Warning' %}
|
||||
{% set warning_class = 'warning' %}
|
||||
{% else %}
|
||||
|
@ -453,41 +453,35 @@
|
|||
{% if show_user_info or delete_csrf %}
|
||||
<div class="profile__warning__tools">
|
||||
{% if show_user_info %}
|
||||
{% if warning.username is defined or warning.user_ip is defined %}
|
||||
<div class="profile__warning__user">
|
||||
{% if warning.username is defined %}
|
||||
<div class="profile__warning__user__avatar">
|
||||
{{ avatar(warning.user_id, 20, warning.username) }}
|
||||
</div>
|
||||
<a class="profile__warning__user__username" href="{{ url('user-profile', {'user': warning.user_id}) }}">
|
||||
{{ warning.username }}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if warning.user_ip is defined %}
|
||||
<div class="profile__warning__user__ip">
|
||||
{{ warning.user_ip }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="profile__warning__user">
|
||||
<div class="profile__warning__user__avatar">
|
||||
{{ avatar(warning.user.id, 20, warning.user.username) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<a class="profile__warning__user__username" href="{{ url('user-profile', {'user': warning.user.id}) }}">
|
||||
{{ warning.user.username }}
|
||||
</a>
|
||||
|
||||
<div class="profile__warning__user__ip">
|
||||
{{ warning.userRemoteAddress }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="profile__warning__user">
|
||||
<div class="profile__warning__user__avatar">
|
||||
{{ avatar(warning.issuer_id, 20, warning.issuer_username) }}
|
||||
{{ avatar(warning.issuer.id, 20, warning.issuer.username) }}
|
||||
</div>
|
||||
<a class="profile__warning__user__username" href="{{ url('user-profile', {'user': warning.user_id}) }}">
|
||||
{{ warning.issuer_username }}
|
||||
<a class="profile__warning__user__username" href="{{ url('user-profile', {'user': warning.issuer.id}) }}">
|
||||
{{ warning.issuer.username }}
|
||||
</a>
|
||||
<div class="profile__warning__user__ip">
|
||||
{{ warning.issuer_ip }}
|
||||
{{ warning.issuerRemoteAddress }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if delete_csrf %}
|
||||
<div class="profile__warning__options">
|
||||
<a href="{{ url('manage-users-warning-delete', {'warning': warning.warning_id}) }}" class="profile__warning__option"><i class="far fa-trash-alt"></i> Delete</a>
|
||||
<a href="{{ url('manage-users-warning-delete', {'warning': warning.id}) }}" class="profile__warning__option"><i class="far fa-trash-alt"></i> Delete</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -498,24 +492,28 @@
|
|||
{{ warning_text }}
|
||||
</div>
|
||||
|
||||
<time datetime="{{ warning.warning_created|date('c') }}" title="{{ warning.warning_created|date('r') }}" class="profile__warning__created">
|
||||
{{ warning.warning_created|time_diff }}
|
||||
<time datetime="{{ warning.createdTime|date('c') }}" title="{{ warning.createdTime|date('r') }}" class="profile__warning__created">
|
||||
{{ warning.createdTime|time_diff }}
|
||||
</time>
|
||||
|
||||
{% if warning_has_duration(warning.warning_type) %}
|
||||
<time datetime="{{ warning.warning_duration|date('c') }}" title="{{ warning.warning_duration|date('r') }}" class="profile__warning__duration">
|
||||
{{ warning.warning_duration|time_diff }}
|
||||
</time>
|
||||
{% if warning.isPermanent %}
|
||||
<div class="profile__warning__duration">
|
||||
<b>PERMANENT</b>
|
||||
</div>
|
||||
{% elseif warning.hasDuration %}
|
||||
<div class="profile__warning__duration">
|
||||
{{ warning.durationString }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="profile__warning__duration"></div>
|
||||
{% endif %}
|
||||
|
||||
<div class="profile__warning__note">
|
||||
{{ warning.warning_note }}
|
||||
{{ warning.publicNote }}
|
||||
|
||||
{% if show_private_note and warning.warning_note_private|length > 0 %}
|
||||
{% if show_private_note and warning.hasPrivateNote %}
|
||||
<div class="profile__warning__private">
|
||||
{{ warning.warning_note_private|nl2br }}
|
||||
{{ warning.privateNote|nl2br }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
Loading…
Add table
Reference in a new issue