Added user name history beginnings.
This commit is contained in:
parent
7f7e644069
commit
cc37b7cad3
6 changed files with 207 additions and 1 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
20250208
|
||||
20250209
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
use Index\Db\DbConnection;
|
||||
use Index\Db\Migration\DbMigration;
|
||||
|
||||
final class CreatedUserNameHistoryTable_20250209_005714 implements DbMigration {
|
||||
public function migrate(DbConnection $conn): void {
|
||||
$conn->execute(<<<SQL
|
||||
CREATE TABLE msz_users_names_history (
|
||||
history_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id INT(10) UNSIGNED NULL DEFAULT NULL,
|
||||
history_name_before VARCHAR(255) NOT NULL COLLATE 'utf8mb4_unicode_520_ci',
|
||||
history_name_after VARCHAR(255) NOT NULL COLLATE 'utf8mb4_unicode_520_ci',
|
||||
history_private TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
|
||||
history_created TIMESTAMP NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (history_id),
|
||||
INDEX users_names_history_users_foreign (user_id),
|
||||
INDEX users_names_history_name_before_index (history_name_before),
|
||||
INDEX users_names_history_created_index (history_created),
|
||||
INDEX users_names_history_private_index (history_private),
|
||||
CONSTRAINT users_names_history_users_foreign
|
||||
FOREIGN KEY (user_id)
|
||||
REFERENCES msz_users (user_id)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE SET NULL
|
||||
) COLLATE='utf8mb4_bin';
|
||||
SQL);
|
||||
}
|
||||
}
|
|
@ -26,6 +26,12 @@ $viewerId = $viewingAsGuest ? '0' : $viewerInfo->id;
|
|||
try {
|
||||
$userInfo = $msz->usersCtx->getUserInfo($userId, 'profile');
|
||||
} catch(RuntimeException $ex) {
|
||||
$userId = $msz->usersCtx->namesHistory->resolvePastUserName($userId);
|
||||
if($userId !== null) {
|
||||
header(sprintf('Location: %s', $msz->urls->format('user-profile', ['user' => $userId])));
|
||||
return;
|
||||
}
|
||||
|
||||
http_response_code(404);
|
||||
Template::render('profile.index', [
|
||||
'profile_is_guest' => $viewingAsGuest,
|
||||
|
|
31
src/Users/UserNameHistoryInfo.php
Normal file
31
src/Users/UserNameHistoryInfo.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\Db\DbResult;
|
||||
|
||||
class UserNameHistoryInfo {
|
||||
public function __construct(
|
||||
public private(set) string $id,
|
||||
public private(set) string $userId,
|
||||
public private(set) string $nameBefore,
|
||||
public private(set) string $nameAfter,
|
||||
public private(set) bool $private,
|
||||
public private(set) int $createdTime
|
||||
) {}
|
||||
|
||||
public static function fromResult(DbResult $result): UserPasswordInfo {
|
||||
return new UserPasswordInfo(
|
||||
id: $result->getString(0),
|
||||
userId: $result->getString(1),
|
||||
nameBefore: $result->getString(2),
|
||||
nameAfter: $result->getString(3),
|
||||
private: $result->getBoolean(4),
|
||||
createdTime: $result->getInteger(5),
|
||||
);
|
||||
}
|
||||
|
||||
public CarbonImmutable $createdAt {
|
||||
get => CarbonImmutable::createFromTimestampUTC($this->createdTime);
|
||||
}
|
||||
}
|
139
src/Users/UserNamesHistoryData.php
Normal file
139
src/Users/UserNamesHistoryData.php
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use RuntimeException;
|
||||
use Index\Db\{DbConnection,DbStatementCache};
|
||||
|
||||
class UserNamesHistoryData {
|
||||
private DbStatementCache $cache;
|
||||
|
||||
public function __construct(DbConnection $dbConn) {
|
||||
$this->cache = new DbStatementCache($dbConn);
|
||||
}
|
||||
|
||||
/** @return iterable<UserNameHistoryInfo> */
|
||||
public function getUserNamesHistory(
|
||||
UserInfo|string|null $userInfo = null,
|
||||
?bool $private = null
|
||||
): iterable {
|
||||
$hasUserInfo = $userInfo !== null;
|
||||
|
||||
$args = 0;
|
||||
$query = <<<SQL
|
||||
SELECT history_id, user_id, history_name_before, history_name_after, history_private, UNIX_TIMESTAMP(history_created)
|
||||
FROM msz_users_names_history
|
||||
SQL;
|
||||
if($hasUserInfo) {
|
||||
++$args;
|
||||
$query .= ' WHERE user_id = ?';
|
||||
}
|
||||
if($private !== null)
|
||||
$query .= sprintf(' %s history_private %s 0', ++$args > 1 ? 'AND' : 'WHERE', $private ? '<>' : '=');
|
||||
|
||||
$stmt = $this->cache->get($query);
|
||||
if($hasUserInfo)
|
||||
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
|
||||
$stmt->execute();
|
||||
|
||||
return $stmt->getResultIterator(UserNameHistoryInfo::fromResult(...));
|
||||
}
|
||||
|
||||
public function getUserNameHistory(string $historyId): UserNameHistoryInfo {
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
SELECT history_id, user_id, history_name_before, history_name_after, history_private, UNIX_TIMESTAMP(history_created)
|
||||
FROM msz_users_names_history
|
||||
WHERE history_id = ?
|
||||
SQL);
|
||||
$stmt->nextParameter($historyId);
|
||||
$stmt->execute();
|
||||
|
||||
$result = $stmt->getResult();
|
||||
if(!$result->next())
|
||||
throw new RuntimeException('could not find that name history entry');
|
||||
|
||||
return UserNameHistoryInfo::fromResult($result);
|
||||
}
|
||||
|
||||
public function deleteUserNameHistory(UserNameHistoryInfo|string $historyInfo): void {
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
DELETE FROM msz_users_names_history
|
||||
WHERE history_id = ?
|
||||
SQL);
|
||||
$stmt->nextParameter($historyInfo instanceof UserNameHistoryInfo ? $historyInfo->id : $historyInfo);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
public function deleteUserNamesHistory(UserInfo|string $userInfo): void {
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
DELETE FROM msz_users_names_history
|
||||
WHERE user_id = ?
|
||||
SQL);
|
||||
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
public function setUserNameHistoryVisibility(
|
||||
UserNameHistoryInfo|string $historyInfo,
|
||||
bool $private
|
||||
): void {
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
UPDATE msz_users_names_history
|
||||
SET history_private = ?
|
||||
WHERE history_id = ?
|
||||
SQL);
|
||||
$stmt->nextParameter($private ? 1 : 0);
|
||||
$stmt->nextParameter($historyInfo instanceof UserNameHistoryInfo ? $historyInfo->id : $historyInfo);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
// this should probably let you specify a time period
|
||||
public function setUserNamesHistoryVisibility(
|
||||
UserInfo|string $userInfo,
|
||||
bool $private
|
||||
): void {
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
UPDATE msz_users_names_history
|
||||
SET history_private = ?
|
||||
WHERE user_id = ?
|
||||
SQL);
|
||||
$stmt->nextParameter($private ? 1 : 0);
|
||||
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
public function recordUserNameChange(
|
||||
UserInfo|string $userInfo,
|
||||
string $nameBefore,
|
||||
string $nameAfter,
|
||||
bool $private = false
|
||||
): UserNameHistoryInfo {
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
INSERT INTO msz_users_names_history (
|
||||
user_id, history_name_before, history_name_after, history_private
|
||||
) VALUES (?, ?, ?, ?)
|
||||
SQL);
|
||||
$stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo);
|
||||
$stmt->nextParameter($nameBefore);
|
||||
$stmt->nextParameter($nameAfter);
|
||||
$stmt->nextParameter($private ? 1 : 0);
|
||||
$stmt->execute();
|
||||
|
||||
return $this->getUserNameHistory($stmt->lastInsertId);
|
||||
}
|
||||
|
||||
public function resolvePastUserName(string $pastName): ?string {
|
||||
$stmt = $this->cache->get(<<<SQL
|
||||
SELECT IF(history_private, NULL, user_id)
|
||||
FROM msz_users_names_history
|
||||
WHERE user_id IS NOT NULL
|
||||
AND history_name_before = ?
|
||||
ORDER BY history_created DESC
|
||||
LIMIT 1
|
||||
SQL);
|
||||
$stmt->nextParameter($pastName);
|
||||
$stmt->execute();
|
||||
|
||||
$result = $stmt->getResult();
|
||||
return $result->next() ? $result->getStringOrNull(0) : null;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ class UsersContext {
|
|||
public private(set) UserPasswordsData $passwords;
|
||||
public private(set) UserTotpsData $totps;
|
||||
public private(set) UserBirthdatesData $birthdates;
|
||||
public private(set) UserNamesHistoryData $namesHistory;
|
||||
|
||||
/** @var array<string, UserInfo> */
|
||||
private array $userInfos = [];
|
||||
|
@ -35,6 +36,7 @@ class UsersContext {
|
|||
$this->passwords = new UserPasswordsData($dbConn);
|
||||
$this->totps = new UserTotpsData($dbConn);
|
||||
$this->birthdates = new UserBirthdatesData($dbConn);
|
||||
$this->namesHistory = new UserNamesHistoryData($dbConn);
|
||||
}
|
||||
|
||||
public function getUserInfo(string $value, int|string|null $select = null): UserInfo {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue