still some bugs and auth issues to iron out. need to implement a new action button/bar, the card for moments in a space, creating new moments and essays, dynamically refreshing the spaces view when a new post is created.

This commit is contained in:
2025-05-20 19:46:09 -06:00
parent a93c30c40f
commit 54a01f0f1f
20 changed files with 1018 additions and 1191 deletions
+156 -88
View File
@@ -30,7 +30,8 @@ class LoginCredentials
class User
{
private int $userId;
private int $id;
private ?array $spaces;
private string $username;
private ?DateTime $createdAt;
private ?DateTime $lastActive;
@@ -38,8 +39,9 @@ class User
private ?string $profilePicture;
private ?string $bio;
private ?string $website;
private int $role;
public function __construct(int $userId, string $username, ?string $profilePicture = null, ?string $bio = null, ?string $website = null, ?mysqli $db = null)
public function __construct(int $id = -1, ?array $spaces, string $username, ?string $profilePicture = null, ?string $bio = null, ?string $website = null, int $role = 3)
{
// Basic XSS prevention on construction (can be enhanced)
$username = htmlspecialchars($username, ENT_QUOTES, 'UTF-8');
@@ -52,7 +54,6 @@ class User
throw new InvalidArgumentException('Invalid characters in user data.');
}
$this->userId = $userId;
$this->username = $username;
$this->profilePicture = $profilePicture;
$this->bio = $bio;
@@ -60,58 +61,130 @@ class User
$this->createdAt = new DateTime();
$this->lastActive = null;
$this->isActive = false;
$this->role = $role;
$this->spaces = null;
if ($db) {
$stmt = $db->prepare('INSERT INTO user (user_id, username, profile_picture, bio, website) VALUES (?, ?, ?, ?, ?)');
if ($stmt) {
$stmt->bind_param('issss', $this->userId, $this->username, $this->profilePicture, $this->bio, $this->website);
$stmt->execute();
$stmt->close();
} else {
error_log('Error preparing statement: ' . $db->error);
}
if ($id == -1) {
$this->id = randomId(0);
$stmt = 'INSERT INTO user (userId, username, profilePicture, bio, website) VALUES (?, ?, ?, ?, ?)';
exec_stmt($stmt, 'issss', $this->id, $this->username, $this->profilePicture, $this->bio, $this->website);
} else
$this->id = $id;
}
public static function exists(int $id): bool
{
$stmt = 'SELECT count(id) FROM user WHERE id = ?';
$result = exec_stmt($stmt, 'i', $id)->fetch_assoc();
if ($result['count(id)'] == 1)
return true;
else if ($result['count(id)'] > 1)
return true;
else
return false;
}
public static function retrieveFromDB(int $userId): ?User
{
$stmt = 'SELECT id, username, profilePicture, bio, website FROM user WHERE id = ?';
$user = exec_stmt($stmt, 'i', $userId)->fetch_assoc();
if ($user) {
return new User($user['id'], null, $user['username'], $user['profilePicture'], $user['bio'], $user['website']);
} else {
// Consider logging or throwing an exception if no database connection is provided
error_log('Database connection not provided during User creation.');
}
}
public static function exists(int $id)
{
$stmt = 'SELECT count(username) FROM user WHERE id = ?';
echo pretty_dump(exec_stmt($stmt, 'i', $id)->fetch_assoc());
}
public static function login(LoginCredentials $credentials, ?mysqli $db): ?User
{
if (!$db) {
error_log('Database connection not provided for login.');
return null;
}
$username = $credentials->getUsername();
$password = $credentials->getPassword();
}
$stmt = $db->prepare('SELECT user_id, username, password_hash, profile_picture, bio, website FROM user WHERE username = ?');
if ($stmt) {
$stmt->bind_param('s', $username);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
$stmt->close();
public static function getSignupHTML()
{
$html = '
<div class="form_card">
<h3 class="underline">Sign Up</h3>
<form method="post" enctype="multipart/form-data">
<input type="hidden" name="form_id" value="signup_form">
<input type="hidden" name="crop_x" value="" id="crop_x">
<input type="hidden" name="crop_y" value="" id="crop_y">
<input type="hidden" name="crop_width" value="" id="crop_width">
<input name="required_field" id="required_field" value="">
if ($user && hash('sha256', $password) === $user['password_hash']) {
return new User(
(int) $user['user_id'],
$user['username'],
$user['profile_picture'],
$user['bio'],
$user['website']
);
}
} else {
error_log('Error preparing statement: ' . $db->error);
}
return null;
<label for="username">Username</label>
<input id="username" name="username" required>
<label for="email">Email Address</label>
<input id="email" name="email" required>
<label for="password">Password</label>
<input id="password" name="password" type="password" required>
<label for="verify_password">Verify Password</label>
<input id="verify_password" name="verify_password" type="password" required>
<label for="profile_picture_input" class="upload_button modal_button" id="profile_cropper_button">Upload a Profile Picture</label>
<input id="profile_picture_input" class="file_input" name="profile_picture" type="file" accept="image/png, image/jpeg, image/jpg">
<small class="file_input_feedback">No file selected.</small>
<label class="form_checkbox_container">Stay Logged In?
<input name="stay_logged_in" type="checkbox" value="true">
<span class="checkmark"></span>
</label>
<input class="button" type="submit" value="Sign Up">
</form>
<div id="modal" class="modal">
<div id="display_modal"></div>
</div>
<div style="display: none;">
<div id="profile_cropper" class="modal_form">' . profile_cropper() . '</div>
</div>
</div>
';
return $html;
}
public static function getLoginHTML()
{
$html = '
<div class="form_card">
<h3 class="underline">Log In</h3>
<form method="post" id="login_form" action="director.php">
<input type="hidden" name="form_id" value="login_form">
<input type="hidden" name="password_hash" value="" id="password_hash">
<label for="username">Username / Email</label>
<input id="username" name="username" spellcheck="false" required autofocus>
<label for="password">Password</label>
<input id="password" name="password" type="password" spellcheck="false" required>
<label class="form_checkbox_container">Stay Logged In?
<input name="stay_logged_in" type="checkbox" value="true">
<span class="checkmark"></span>
</label>
<input class="button" type="submit" value="Log In">
</form>
<script src="js/login.js" defer></script>
</div>
';
return $html;
}
public static function login(LoginCredentials $credentials): ?User
{
$stmt = 'SELECT id, username, email, passwordHash, role, profilePicture, bio, website FROM user WHERE username = ?';
$user = exec_stmt($stmt, 's', $credentials->getUsername())->fetch_assoc();
if (!password_verify($credentials->getPassword(), $user['passwordHash']))
return null;
else
return new User($user['id'], null, $user['username'], $user['profilePicture'], $user['bio'], $user['website']);
}
public static function logout(): void
@@ -124,9 +197,33 @@ class User
exit();
}
public function getUserId(): int
public function getHomeSpace()
{
return $this->userId;
// TODO: Need to implement. Requires fleshing out additional space types.
return Space::retrieveFromDB(1, 1);
}
public function getSpaces()
{
$stmt = 'SELECT * FROM spaceMembers WHERE user = ?';
$spaces = [];
$rawSpaces = exec_stmt($stmt, 'i', $this->id);
while ($row = $rawSpaces->fetch_assoc()) {
$spaces[] = Space::retrieveFromDB($row['space'], $row['user']);
}
$this->spaces = $spaces;
return $spaces;
}
public function getRole(): int
{
return $this->role;
}
public function getId(): int
{
return $this->id;
}
public function getUsername(): string
@@ -183,7 +280,7 @@ class User
$this->isActive = !$this->isActive;
$stmt = $db->prepare('UPDATE user SET is_active = ? WHERE user_id = ?');
if ($stmt) {
$stmt->bind_param('ii', (int) $this->isActive, $this->userId);
$stmt->bind_param('ii', (int) $this->isActive, $this->id);
$result = $stmt->execute();
$stmt->close();
return $result;
@@ -205,7 +302,7 @@ class User
}
$stmt = $db->prepare('UPDATE user SET username = ? WHERE user_id = ?');
if ($stmt) {
$stmt->bind_param('si', $newUsername, $this->userId);
$stmt->bind_param('si', $newUsername, $this->id);
$result = $stmt->execute();
$stmt->close();
if ($result) {
@@ -227,7 +324,7 @@ class User
}
$stmt = $db->prepare('UPDATE user SET password_hash = ? WHERE user_id = ?');
if ($stmt) {
$stmt->bind_param('si', $newPasswordHash, $this->userId);
$stmt->bind_param('si', $newPasswordHash, $this->id);
$result = $stmt->execute();
$stmt->close();
return $result;
@@ -249,7 +346,7 @@ class User
}
$stmt = $db->prepare('UPDATE user SET profile_picture = ? WHERE user_id = ?');
if ($stmt) {
$stmt->bind_param('si', $newProfilePicture, $this->userId);
$stmt->bind_param('si', $newProfilePicture, $this->id);
$result = $stmt->execute();
$stmt->close();
if ($result) {
@@ -270,7 +367,7 @@ class User
}
$stmt = $db->prepare('INSERT INTO follows (follower_user_id, following_user_id, notify_user) VALUES (?, ?, ?)');
if ($stmt) {
$stmt->bind_param('iii', $this->userId, $followingUserId, (int) $notify);
$stmt->bind_param('iii', $this->id, $followingUserId, (int) $notify);
$result = $stmt->execute();
$stmt->close();
return $result;
@@ -288,7 +385,7 @@ class User
}
$stmt = $db->prepare('SELECT u.user_id, u.username, u.profile_picture, u.bio, u.website FROM follows f JOIN user u ON f.follower_user_id = u.user_id WHERE f.following_user_id = ?');
if ($stmt) {
$stmt->bind_param('i', $this->userId);
$stmt->bind_param('i', $this->id);
$stmt->execute();
$result = $stmt->get_result();
$followers = [];
@@ -317,7 +414,7 @@ class User
}
$stmt = $db->prepare('SELECT u.user_id, u.username, u.profile_picture, u.bio, u.website FROM follows f JOIN user u ON f.following_user_id = u.user_id WHERE f.follower_user_id = ?');
if ($stmt) {
$stmt->bind_param('i', $this->userId);
$stmt->bind_param('i', $this->id);
$stmt->execute();
$result = $stmt->get_result();
$following = [];
@@ -337,35 +434,6 @@ class User
return [];
}
}
// Static method to fetch a User by ID (example using mysqli)
public static function findById(int $userId, ?mysqli $db): ?User
{
if (!$db) {
error_log('Database connection not provided for findById.');
return null;
}
$stmt = $db->prepare('SELECT user_id, username, profile_picture, bio, website FROM user WHERE user_id = ?');
if ($stmt) {
$stmt->bind_param('i', $userId);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
$stmt->close();
if ($user) {
return new User(
(int) $user['user_id'],
$user['username'],
$user['profile_picture'],
$user['bio'],
$user['website']
);
}
} else {
error_log('Error preparing statement: ' . $db->error);
}
return null;
}
}
class Author extends User {}
class Creator extends User {}