This commit is contained in:
2024-07-29 22:06:57 +02:00
parent 5ce2215e44
commit 6a62ae58fc
22 changed files with 670 additions and 7 deletions
+163 -3
View File
@@ -11,8 +11,12 @@ use JsonSerializable;
use Khofmann\ApiError\ApiError;
use Khofmann\GUID\GUID;
use Khofmann\Models\Post\Post;
use PDOException;
/**
* User database model
*
* Abstracts database access
*/
class User implements JsonSerializable
{
private int $id;
@@ -36,6 +40,13 @@ class User implements JsonSerializable
$this->postCount = $postCount;
}
/**
* Get a user by their confirmation code.
*
* @param string $code Confirmation code
*
* @throws NotFound User not found
*/
private static function getByConfirmCode(string $code): User
{
$db = Database::getInstance();
@@ -62,6 +73,13 @@ class User implements JsonSerializable
* Statics
*/
/**
* Get a user by ID.
*
* @param int $id User ID
*
* @throws NotFound User not found
*/
public static function getByID(int $id): User
{
$db = Database::getInstance();
@@ -83,6 +101,13 @@ class User implements JsonSerializable
return new User($id, $data["benutzer"], $data["status"], $data["email"], $data["zeitstempel"], $data["image"], $data["isadmin"] === 1, $data["postCount"]);
}
/**
* Get a user by their email.
*
* @param string $email User email
*
* @throws NotFound User not found
*/
public static function getByEmail(string $email): User
{
$db = Database::getInstance();
@@ -104,6 +129,13 @@ class User implements JsonSerializable
return new User($data["id"], $data["benutzer"], $data["status"], $email, $data["zeitstempel"], $data["image"], $data["isadmin"] === 1, $data["postCount"]);
}
/**
* Get a user by their authentication token.
*
* @param string $token Authentication token
*
* @throws NotFound User not found
*/
public static function getByToken(string $token): User
{
$db = Database::getInstance();
@@ -126,6 +158,18 @@ class User implements JsonSerializable
return new User($data["id"], $data["benutzer"], $data["status"], $data["email"], $data["zeitstempel"], $data["image"], $data["isadmin"] === 1, $data["postCount"]);
}
/**
* Log in a user
*
* @param string $email User email
* @param string $password USer password
*
* @return array Tokens and user
*
* @throws Failed Could not generate tokens
* @throws Invalid Password was wrong
* @throws NotFound User not found (email wrong)
*/
public static function logIn(string $email, string $password): array
{
$db = Database::getInstance();
@@ -191,6 +235,15 @@ class User implements JsonSerializable
}
}
/**
* Create a user
*
* @param string $username Username
* @param string $email User email
* @param string $password User password
*
* @throws Duplicate User with this username or email already exists
*/
public static function create(string $username, string $email, string $password): User
{
$db = Database::getInstance();
@@ -225,6 +278,13 @@ class User implements JsonSerializable
}
}
/**
* Confirm a user
*
* @param string $confirmCode Confirmation code
*
* @throws NotFound User not found (invalid code or already confirmed)
*/
public static function confirm(string $confirmCode): User
{
$db = Database::getInstance();
@@ -243,6 +303,14 @@ class User implements JsonSerializable
return User::getByID($user->getID());
}
/**
* List of users
*
* @param int $page Current page (offset)
* @param int $limit Users per page
*
* @return array Number of pages and posts of selected page
*/
public static function list(int $page, int $limit)
{
$db = Database::getInstance();
@@ -274,6 +342,15 @@ class User implements JsonSerializable
return ["pages" => intdiv($count, $limit + 1), "data" => $list];
}
/**
* Refresh a user session
*
* @param string $token Authentication token
* @param string $refreshToken Refresh token
*
* @throws NotFound User not found (tokens do not exist, refresh token expired)
* @throws Failed Could not regenerate tokens
*/
public static function refresh(string $token, string $refreshToken)
{
$db = Database::getInstance();
@@ -347,10 +424,22 @@ class User implements JsonSerializable
return $stmt->execute();
}
/**
* Update post
*
* Does nothing if new all fields are empty
*
* @param ?string $username New username
* @param ?string $password New password
* @param ?string $email New email
*
* @throws Failed At least one field failed to update
*/
public function update(?string $username, ?string $password, ?string $email): User
{
$db = Database::getInstance();
// Make sure we do all changes or none
$db->beginTransaction();
$failed = [];
@@ -413,20 +502,33 @@ class User implements JsonSerializable
}
if (count($failed) > 0) {
// We failed, go back
$db->rollBack();
throw ApiError::failedUpdate($failed, $reasons);
}
// Commit the changes
$db->commit();
return User::getByID($this->id);
}
/**
* Update post
*
* Does nothing if all fields are empty
*
* @param mixed $image New file upload
* @param ?string $predefined Predefined avatar
*
* @param Failed Image failed to update
*/
public function updateImage($image, ?string $predefined): User
{
$db = Database::getInstance();
// Make sure we do all changes or none
$db->beginTransaction();
$failed = [];
@@ -442,6 +544,7 @@ class User implements JsonSerializable
}
if (!empty($image)) {
// Move file and grab filename
$destinationFilename = sprintf('%s.%s', uniqid(), $image->getExtension());
$image->move(Config::getStorageFSPath() . "profilbilder/$destinationFilename");
@@ -482,25 +585,52 @@ class User implements JsonSerializable
}
if (count($failed) > 0) {
// We failed, go back
$db->rollBack();
throw ApiError::failedUpdate($failed, $reasons);
}
// Commit the changes
$db->commit();
return User::getByID($this->id);
}
public function delete(): User
/**
* Delete user
*
* @param int $limit Limit of list for which the returned pages is calculated.
*
* @return array Returns deleted user and resulting amount of pages for a given limit.
*/
public function delete(int $limit): array
{
$db = Database::getInstance();
$stmt = $db->prepare("DELETE FROM egb_benutzer WHERE id = :ID");
$stmt->bindValue(":ID", $this->id);
return $this;
$stmt = $db->prepare(
"SELECT
COUNT(*)
FROM
egb_benutzer"
);
$stmt->execute();
$count = $stmt->fetch(PDO::FETCH_COLUMN, 0);
return ["pages" => intdiv($count, $limit + 1) + 1, "data" => $this];
}
/**
* List of posts by user
*
* @param int $page Current page (offset)
* @param int $limit Users per page
* @param string $sort Sort direction
*
* @return array Number of pages and posts of selected page
*/
public function posts(int $page, int $limit, string $sort)
{
$db = Database::getInstance();
@@ -543,6 +673,9 @@ class User implements JsonSerializable
return ["pages" => intdiv($count, $limit + 1) + 1, "data" => $list];
}
/**
* Refresh user token expiry
*/
public function keepFresh()
{
try {
@@ -565,41 +698,68 @@ class User implements JsonSerializable
* Getters
*/
/**
* Get user ID
*/
public function getID(): int
{
return $this->id;
}
/**
* Get username
*/
public function getUsername(): string
{
return $this->username;
}
/**
* Get user status
*
* * 0: Not confirmed
* * 1: Confirmed
*/
public function getStatus(): int
{
return $this->status;
}
/**
* Get user email
*/
public function getEmail(): string
{
return $this->email;
}
/**
* Get user image path
*/
public function getImage(): ?string
{
return $this->image;
}
/**
* Get user admin status
*/
public function getIsAdmin(): bool
{
return $this->isAdmin;
}
/**
* Get time of user creation
*/
public function getMemberSince(): DateTime
{
return $this->memberSince;
}
/**
* Get count of posts by user
*/
public function getPostCount(): int
{
return $this->postCount;