123 lines
3.7 KiB
PHP
123 lines
3.7 KiB
PHP
<?php
|
|
namespace YTKNS;
|
|
|
|
use Exception;
|
|
|
|
class UserInviteNotFoundException extends Exception {}
|
|
class UserInviteCreationFailedException extends Exception {}
|
|
|
|
final class UserInvite {
|
|
private const TOKEN_LENGTH = 16;
|
|
|
|
public function getToken(): string {
|
|
return $this->invite_token;
|
|
}
|
|
|
|
public function getCreatorId(): int {
|
|
return $this->created_by ?? 0;
|
|
}
|
|
public function getCreator(): User {
|
|
return User::byId($this->getCreatedById());
|
|
}
|
|
|
|
public function getUserId(): ?int {
|
|
return $this->used_by ?? null;
|
|
}
|
|
public function getUser(): ?User {
|
|
$userId = $this->getUserId();
|
|
|
|
if($userId === null)
|
|
return null;
|
|
|
|
try {
|
|
return User::byId($this->getUserId());
|
|
} catch(UserNotFoundException $ex) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public function getCreated(): int {
|
|
return $this->invite_created ?? 0;
|
|
}
|
|
|
|
public function getUsed(): ?int {
|
|
return $this->invite_used ?? null;
|
|
}
|
|
|
|
public function isUsed(): bool {
|
|
return !empty($this->used_by) || !empty($this->invite_used);
|
|
}
|
|
|
|
public function markUsed(User $user): void {
|
|
$markUsed = DB::prepare('
|
|
UPDATE `ytkns_users_invites`
|
|
SET `used_by` = :user
|
|
WHERE `invite_token` = UNHEX(:token)
|
|
');
|
|
$markUsed->bindValue('user', $user->getId());
|
|
$markUsed->bindValue('token', $this->getToken());
|
|
$markUsed->execute();
|
|
}
|
|
|
|
public static function fromCreator(User $creator): array {
|
|
$getInvites = DB::prepare('
|
|
SELECT `created_by`, `used_by`,
|
|
LOWER(HEX(`invite_token`)) AS `invite_token`,
|
|
UNIX_TIMESTAMP(`invite_created`) AS `invite_created`,
|
|
UNIX_TIMESTAMP(`invite_used`) AS `invite_used`
|
|
FROM `ytkns_users_invites`
|
|
WHERE `created_by` = :creator
|
|
');
|
|
$getInvites->bindValue('creator', $creator->getId());
|
|
$getInvites->execute();
|
|
$invites = [];
|
|
|
|
while($invite = $getInvites->fetchObject(self::class))
|
|
$invites[] = $invite;
|
|
|
|
return $invites;
|
|
}
|
|
|
|
public static function byToken(string $token, bool $isHex = true): self {
|
|
$getInvite = DB::prepare(sprintf('
|
|
SELECT `created_by`, `used_by`,
|
|
LOWER(HEX(`invite_token`)) AS `invite_token`,
|
|
UNIX_TIMESTAMP(`invite_created`) AS `invite_created`,
|
|
UNIX_TIMESTAMP(`invite_used`) AS `invite_used`
|
|
FROM `ytkns_users_invites`
|
|
WHERE `invite_token` = %s(:token)
|
|
', $isHex ? 'UNHEX' : ''));
|
|
$getInvite->bindValue('token', $token);
|
|
$invite = $getInvite->execute() ? $getInvite->fetchObject(self::class) : false;
|
|
|
|
if(!$invite)
|
|
throw new UserInviteNotFoundException;
|
|
|
|
return $invite;
|
|
}
|
|
|
|
public static function generateToken(): string {
|
|
return bin2hex(random_bytes(self::TOKEN_LENGTH));
|
|
}
|
|
|
|
public static function create(User $creator): self {
|
|
$inviteToken = self::generateToken();
|
|
$insertInvite = DB::prepare('
|
|
INSERT INTO `ytkns_users_invites` (
|
|
`invite_token`, `created_by`
|
|
) VALUES (
|
|
UNHEX(:token), :creator
|
|
)
|
|
');
|
|
$insertInvite->bindValue('token', $inviteToken);
|
|
$insertInvite->bindValue('creator', $creator->getId());
|
|
$insertInvite->execute();
|
|
|
|
try {
|
|
return self::byToken($inviteToken);
|
|
} catch(UserInviteNotFoundException $ex) {
|
|
throw new UserInviteCreationFailedException;
|
|
}
|
|
}
|
|
}
|