Added UserWarningManager

This commit is contained in:
Zi Xing 2022-01-21 19:04:27 -05:00
parent 72006301a5
commit 8beb9af7d1
7 changed files with 427 additions and 3 deletions

22
database/user_warning.sql Normal file
View File

@ -0,0 +1,22 @@
create table if not exists user_warning
(
id varchar(64) not null comment 'A unique ID index hash'
primary key,
chat_id varchar(126) null comment 'The Chat ID associated with the user that is issued warnings',
user_id int null comment 'The User ID that is issued the warning',
warnings blob null comment 'ZiProto encoded blob of warnings issued to the user',
last_updated_timestamp int null comment 'The Unix Timestamp for when this record was last updated',
created_timestamp int null comment 'Unix timestamp for when this record was first created',
constraint user_warning_chat_id_user_id_uindex
unique (chat_id, user_id),
constraint user_warning_id_uindex
unique (id)
)
comment 'A table used for storing user warnings';
create index user_warning_chat_id_index
on user_warning (chat_id);
create index user_warning_user_id_index
on user_warning (user_id);

View File

@ -0,0 +1,20 @@
<?php
namespace Synical\Exceptions;
use Throwable;
class TooManyWarningsException extends \Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->message = $message;
$this->code = $code;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Synical\Exceptions;
use Exception;
use Throwable;
class UserWarningRecordNotFoundException extends Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->message = $message;
$this->code = $code;
}
}

View File

@ -0,0 +1,200 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace Synical\Managers;
use msqg\QueryBuilder;
use Synical\Exceptions\DatabaseException;
use Synical\Exceptions\TooManyWarningsException;
use Synical\Exceptions\UserWarningRecordNotFoundException;
use Synical\Objects\UserWarning;
use Synical\Objects\UserWarning\Warning;
use Synical\Synical;
use ZiProto\ZiProto;
class UserWarningManager
{
private $synical;
/**
* @param Synical $synical
*/
public function __construct(Synical $synical)
{
$this->synical = $synical;
}
/**
* Issues a warning to the user
*
* @param string $chat_id
* @param int $user_id
* @param int $issuer_user_id
* @param string $reason
* @return Warning
* @throws DatabaseException
* @throws TooManyWarningsException
* @throws UserWarningRecordNotFoundException
*/
public function issueWarning(string $chat_id, int $user_id, int $issuer_user_id, string $reason): Warning
{
$UserWarning = $this->getRecord($chat_id, $user_id);
if(count($UserWarning->Warnings) >= 25)
throw new TooManyWarningsException();
$Warning = new Warning();
$Warning->ID = hash('crc32', $chat_id . $user_id . $issuer_user_id . $reason . time());
$Warning->UserIssuerID = $issuer_user_id;;
$Warning->Timestamp = time();
$UserWarning->Warnings[$Warning->ID] = $Warning;
$this->updateRecord($UserWarning);
return $Warning;
}
/**
* Removes an existing warning from the user
*
* @param string $chat_id
* @param int $user_id
* @param string $warning_id
* @return bool
* @throws DatabaseException
* @throws UserWarningRecordNotFoundException
*/
public function removeWarning(string $chat_id, int $user_id, string $warning_id): bool
{
$UserWarning = $this->getRecord($chat_id, $user_id);
if(isset($UserWarning[$warning_id]))
{
unset($UserWarning->Warnings[$warning_id]);
$this->updateRecord($UserWarning);
return true;
}
return false;
}
/**
* Purges all existing warnings from a user
*
* @param string $chat_id
* @param int $user_id
* @return bool
* @throws DatabaseException
* @throws UserWarningRecordNotFoundException
*/
public function clearWarnings(string $chat_id, int $user_id): bool
{
$UserWarning = $this->getRecord($chat_id, $user_id);
$UserWarning->Warnings = [];
$this->updateRecord($UserWarning);
return true;
}
/**
* Creates a record if it doesn't exist
*
* @param string $chat_id
* @param int $user_id
* @return UserWarning
* @throws DatabaseException
* @noinspection PhpCastIsUnnecessaryInspection
*/
public function createRecord(string $chat_id, int $user_id): UserWarning
{
$UserWarning = new UserWarning();
$UserWarning->ChatID = $chat_id;
$UserWarning->UserID = $user_id;
$UserWarning->Warnings = [];
$UserWarning->CreatedTimestamp = time();
$UserWarning->LastUpdatedTimestamp = time();
$ID = hash('crc32', $chat_id . $user_id);
$Query = QueryBuilder::insert_into('user_warnings', [
'id' => $this->synical->getDatabase()->real_escape_string($ID),
'chat_id' => $this->synical->getDatabase()->real_escape_string($chat_id),
'user_id' => (int)$user_id,
'created_timestamp' => (int)$UserWarning->CreatedTimestamp,
'last_updated_timestamp' => (int)$UserWarning->LastUpdatedTimestamp
]);
$QueryResults = $this->synical->getDatabase()->query($Query);
if($QueryResults == false)
throw new DatabaseException($this->synical->getDatabase()->error, $Query, $this->synical->getDatabase()->errno);
return $UserWarning;
}
/**
* Gets an existing record from the database, optionally creates if it doesn't exist
*
* @param string $chat_id
* @param int $user_id
* @param bool $create
* @return UserWarning
* @throws DatabaseException
* @throws UserWarningRecordNotFoundException
*/
public function getRecord(string $chat_id, int $user_id, bool $create=true): UserWarning
{
$ID = hash('sha1', $chat_id . $user_id);
$Query = QueryBuilder::select('user_warnings', [
'chat_id',
'user_id',
'warnings',
'last_updated_timestamp',
'created_timestamp'
], 'id', $ID);
$QueryResults = $this->synical->getDatabase()->query($Query);
if($QueryResults == false)
throw new DatabaseException($this->synical->getDatabase()->error, $Query, $this->synical->getDatabase()->errno);
if($QueryResults->num_rows == 0)
{
if($create)
return $this->createRecord($chat_id, $user_id);
throw new UserWarningRecordNotFoundException();
}
$Row = $QueryResults->fetch_array(MYSQLI_ASSOC);
$Row['warnings'] = ZiProto::decode($Row['warnings']);
return UserWarning::fromArray($Row);
}
/**
* Updates an existing user warning record
*
* @param UserWarning $userWarning
* @return UserWarning
* @throws DatabaseException
* @noinspection PhpCastIsUnnecessaryInspection
*/
public function updateRecord(UserWarning $userWarning): UserWarning
{
$ID = hash('sha1', $userWarning->ChatID . $userWarning->UserID);
$Warnings = $userWarning->toArray()['warnings'];
$userWarning->LastUpdatedTimestamp = (int)time();
$Query = QueryBuilder::update('user_warnings', [
'warnings' => $this->synical->getDatabase()->real_escape_string(ZiProto::encode($Warnings)),
'last_updated_timestamp' => (int)$userWarning->LastUpdatedTimestamp
], 'id', $this->synical->getDatabase()->real_escape_string($ID));
$QueryResults = $this->synical->getDatabase()->query($Query);
if($QueryResults == false)
throw new DatabaseException($this->synical->getDatabase()->error, $Query, $this->synical->getDatabase()->errno);
return $userWarning;
}
}

View File

@ -53,14 +53,14 @@
/**
* Returns an existing administrator permission if available
*
* @param User $user
* @param int $id
* @return AdministratorPermissions|null
*/
public function getAdministratorUser(User $user): ?AdministratorPermissions
public function getAdministratorUser(int $id): ?AdministratorPermissions
{
foreach($this->AdministratorPermissions as $permission)
{
if($user->getId() == $permission->ID)
if($id == $permission->ID)
return $permission;
}

View File

@ -0,0 +1,96 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace Synical\Objects;
use Synical\Objects\UserWarning\Warning;
class UserWarning
{
/**
* The chat ID associated with the warnings
*
* @var string
*/
public $ChatID;
/**
* The User ID associated with the warnings
*
* @var int
*/
public $UserID;
/**
* An array of warning objects that has been issued so far
*
* @var Warning[]
*/
public $Warnings;
/**
* @var int
*/
public $LastUpdatedTimestamp;
/**
* The Unix Timestamp for when
*
* @var int
*/
public $CreatedTimestamp;
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
$warnings = [];
foreach($this->Warnings as $warning)
$warnings[] = $warning->toArray();
return [
'chat_id' => $this->ChatID,
'user_id' => $this->UserID,
'warnings' => $warnings,
'last_updated_timestamp' => $this->LastUpdatedTimestamp,
'created_timestamp' => $this->CreatedTimestamp,
];
}
/**
* Constructs object from an array representation of the object
*
* @param array $data
* @return UserWarning
*/
public static function fromArray(array $data): UserWarning
{
$UserWarningsObject = new UserWarning();
if(isset($data['chat_id']))
$UserWarningsObject->ChatID = $data['chat_id'];
if(isset($data['user_id']))
$UserWarningsObject->UserID = $data['user_id'];
if(isset($data['warnings']))
{
$UserWarningsObject->Warnings = [];
foreach($data['warnings'] as $warning)
$UserWarningsObject->Warnings[] = Warning::fromArray($warning);
}
if(isset($data['last_updated_timestamp']))
$UserWarningsObject->LastUpdatedTimestamp = $data['last_updated_timestamp'];
if(isset($data['created_timestamp']))
$UserWarningsObject->CreatedTimestamp = $data['created_timestamp'];
return $UserWarningsObject;
}
}

View File

@ -0,0 +1,65 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace Synical\Objects\UserWarning;
class Warning
{
/**
* The Unique ID of the warning issued to the user
*
* @var string
*/
public $ID;
/**
* The user ID of the admin who issued the warning
*
* @var int
*/
public $UserIssuerID;
/**
* The Unix Timestamp for when this warning was issued
*
* @var int
*/
public $Timestamp;
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
return [
'id' => $this->ID,
'user_issuer_id' => $this->UserIssuerID,
'timestamp' => $this->Timestamp
];
}
/**
* Constructs object form an array representation
*
* @param array $data
* @return Warning
*/
public static function fromArray(array $data): Warning
{
$WarningObject = new Warning();
if(isset($data['id']))
$WarningObject->ID = $data['id'];
if(isset($data['user_issuer_id']))
$WarningObject->UserIssuerID = $data['user_issuer_id'];
if(isset($data['timestamp']))
$WarningObject = (int)$data['timestamp'];
return $WarningObject;
}
}