From 8beb9af7d159b4646b8f21314ae4b8d508b0fec8 Mon Sep 17 00:00:00 2001 From: Zi Xing Date: Fri, 21 Jan 2022 19:04:27 -0500 Subject: [PATCH] Added UserWarningManager --- database/user_warning.sql | 22 ++ .../Exceptions/TooManyWarningsException.php | 20 ++ .../UserWarningRecordNotFoundException.php | 21 ++ src/Synical/Managers/UserWarningManager.php | 200 ++++++++++++++++++ src/Synical/Objects/ChatMemberCache.php | 6 +- src/Synical/Objects/UserWarning.php | 96 +++++++++ src/Synical/Objects/UserWarning/Warning.php | 65 ++++++ 7 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 database/user_warning.sql create mode 100644 src/Synical/Exceptions/TooManyWarningsException.php create mode 100644 src/Synical/Exceptions/UserWarningRecordNotFoundException.php create mode 100644 src/Synical/Managers/UserWarningManager.php create mode 100644 src/Synical/Objects/UserWarning.php create mode 100644 src/Synical/Objects/UserWarning/Warning.php diff --git a/database/user_warning.sql b/database/user_warning.sql new file mode 100644 index 0000000..fcb715f --- /dev/null +++ b/database/user_warning.sql @@ -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); + diff --git a/src/Synical/Exceptions/TooManyWarningsException.php b/src/Synical/Exceptions/TooManyWarningsException.php new file mode 100644 index 0000000..5f3fbcd --- /dev/null +++ b/src/Synical/Exceptions/TooManyWarningsException.php @@ -0,0 +1,20 @@ +message = $message; + $this->code = $code; + } + } \ No newline at end of file diff --git a/src/Synical/Exceptions/UserWarningRecordNotFoundException.php b/src/Synical/Exceptions/UserWarningRecordNotFoundException.php new file mode 100644 index 0000000..07670d1 --- /dev/null +++ b/src/Synical/Exceptions/UserWarningRecordNotFoundException.php @@ -0,0 +1,21 @@ +message = $message; + $this->code = $code; + } + } \ No newline at end of file diff --git a/src/Synical/Managers/UserWarningManager.php b/src/Synical/Managers/UserWarningManager.php new file mode 100644 index 0000000..d17b4ea --- /dev/null +++ b/src/Synical/Managers/UserWarningManager.php @@ -0,0 +1,200 @@ +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; + } + } \ No newline at end of file diff --git a/src/Synical/Objects/ChatMemberCache.php b/src/Synical/Objects/ChatMemberCache.php index 22651ef..c14f7c0 100644 --- a/src/Synical/Objects/ChatMemberCache.php +++ b/src/Synical/Objects/ChatMemberCache.php @@ -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; } diff --git a/src/Synical/Objects/UserWarning.php b/src/Synical/Objects/UserWarning.php new file mode 100644 index 0000000..52c2c10 --- /dev/null +++ b/src/Synical/Objects/UserWarning.php @@ -0,0 +1,96 @@ +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; + } + } \ No newline at end of file diff --git a/src/Synical/Objects/UserWarning/Warning.php b/src/Synical/Objects/UserWarning/Warning.php new file mode 100644 index 0000000..3307dd1 --- /dev/null +++ b/src/Synical/Objects/UserWarning/Warning.php @@ -0,0 +1,65 @@ + $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; + } + } \ No newline at end of file