diff --git a/director.php b/director.php
index 727cdf6..bdec902 100644
--- a/director.php
+++ b/director.php
@@ -39,6 +39,12 @@ if (isset($_POST['ajaxId'])) {
case 'viewEssay':
handleViewEssay();
break;
+ case 'viewTodo':
+ handleViewTodo();
+ break;
+ case 'todoStatusChange':
+ handleTodoStatusChange();
+ break;
}
} else if (isset($_POST['formID'])) {
switch ($_POST['formID']) {
@@ -64,6 +70,21 @@ if (isset($_POST['ajaxId'])) {
header('Location: ' . $_POST['redirect']);
}
+function handleViewTodo()
+{
+ if (!isset($_POST['space']) || !is_int($_POST['space']))
+ return;
+
+ $user = unserialize($_SESSION['user']);
+ // TODO: Add checks here if the user is authorized. JWT stuff.
+}
+
+function handleTodoStatusChange()
+{
+ if (!isset($_POST['id']) || !isset($_POST['status']) || !is_int($_POST['id']) || !is_string($_POST['status']))
+ return;
+}
+
function handleViewEssay()
{
if (!isset($_POST['id']))
diff --git a/functions/init.php b/functions/init.php
index aef4482..8fb9f7c 100644
--- a/functions/init.php
+++ b/functions/init.php
@@ -16,6 +16,11 @@ require_once 'functions/space.php';
if (!isset($_SESSION['initialized'])) {
$_SESSION['initialized'] = true;
$_SESSION['theme'] = 'dark';
+ if (isset($_SESSION['user'])) {
+ $tmp = unserialize($_SESSION['user'])->getSpaces();
+ foreach ($tmp as $s)
+ $_SESSION['spaces'][] = serialize($s->getSpace());
+ }
} else if (isset($_POST['theme'])) {
$_SESSION['theme'] = $_POST['theme'];
unset($_POST['theme']);
@@ -26,3 +31,6 @@ if (!isset($_SESSION['initialized'])) {
define('owner', 1);
define('developer', 2);
define('user', 3);
+
+if (isset($_SESSION['user']) && !isset($GLOBALS['spaces'])) {
+}
diff --git a/functions/post.php b/functions/post.php
index 1c3d2e4..a618d90 100644
--- a/functions/post.php
+++ b/functions/post.php
@@ -45,6 +45,7 @@ class Post
public function __construct(int $space = 2025, ?int $id = null, User $creator, int $postType, int $status)
{
+ error_log('Instantiating a post');
$this->space = $space;
$this->id = $id;
$this->creator = $creator;
diff --git a/functions/relationships/spaceMember.php b/functions/relationships/spaceMember.php
new file mode 100644
index 0000000..236f73e
--- /dev/null
+++ b/functions/relationships/spaceMember.php
@@ -0,0 +1,41 @@
+getId()) || !Space::exists($space->getId()))
+ return;
+
+ $this->user = $user;
+ $this->space = $space;
+ $this->role = $role;
+ $this->addedAt = $addedAt;
+ $this->favorited = $favorited;
+
+ if ($id < 0) {
+ $this->id = $id * -1;
+
+ $stmt = 'INSERT INTO spaceMembers (id, user, space, role, favorited) VALUES (?, ?, ?, ?, ?)';
+ exec_stmt($stmt, 'iiiii', $this->id, $user->getId(), $space->getId(), $role, $favorited);
+ }
+ }
+
+ public function getUser()
+ {
+ return $this->user;
+ }
+
+ public function getSpace()
+ {
+ return $this->space;
+ }
+}
diff --git a/functions/space.php b/functions/space.php
index ed8f338..0befdb7 100644
--- a/functions/space.php
+++ b/functions/space.php
@@ -10,16 +10,15 @@ class Space
private string $name;
private string $description;
private int $visibility;
- private ?array $members;
private ?array $posts;
private ?Space $parent;
- public function __construct(int $id, string $name, string $description, int $visibility, ?array $members, ?array $posts, ?Space $parent = null, bool $favorited = false)
+ public function __construct(int $id, string $name, string $description, int $visibility, ?array $posts, ?Space $parent = null, bool $favorited = false)
{
+ error_log('Constructing a space with id: ' . $id);
$this->name = $name;
$this->description = $description;
$this->visibility = $visibility;
- $this->members = $members;
$this->posts[] = $posts;
$this->parent = $parent;
@@ -57,7 +56,7 @@ class Space
public function getSubSpaces(): ?array
{
- $stmt = 'SELECT id FROM space WHERE parentSpace = ?';
+ $stmt = 'SELECT id FROM space WHERE parent = ?';
$rawSubSpaces = exec_stmt($stmt, 'i', $this->id);
$subSpaces = [];
@@ -73,6 +72,11 @@ class Space
return $this->parent;
}
+ public function hasParent(): bool
+ {
+ return isset($this->parent);
+ }
+
public function getCardHTML(): string
{
$html = '
@@ -120,6 +124,7 @@ class Space
public static function retrieveFromDB(int $space, int $user = -1): ?Space
{
+ error_log('Retrieving a space from DB.');
if ($user != -1) {
$stmt = 'SELECT * FROM spaceMembers WHERE space = ? AND user = ?';
$isMember = exec_stmt($stmt, 'ii', $space, $user)->fetch_assoc();
@@ -141,28 +146,17 @@ class Space
else
$parent = null;
- $stmt = 'SELECT user FROM spaceMembers WHERE space = ?';
- $members = [];
- $rawMembers = exec_stmt($stmt, 'i', $rawSpace['id']);
- foreach ($rawMembers as $m)
- $members[] = User::retrieveFromDB($m['user']);
-
$stmt = 'SELECT post FROM spacePosts INNER JOIN post ON spacePosts.post = post.id WHERE post.space = ? ORDER BY post.createdAt DESC';
$posts = [];
$rawPosts = exec_stmt($stmt, 'i', $rawSpace['id']);
while ($row = $rawPosts->fetch_assoc())
$posts[] = Post::retrieveFromDB($row['post']);
- return new Space($rawSpace['id'], $rawSpace['name'], $rawSpace['description'], $rawSpace['visibility'], $members, $posts, $parent);
+ return new Space($rawSpace['id'], $rawSpace['name'], $rawSpace['description'], $rawSpace['visibility'], $posts, $parent);
} else
return null;
}
- public function allowUser(User $user)
- {
- return in_array($user, $this->members);
- }
-
public function getPosts()
{
return $this->posts;
diff --git a/functions/todo.php b/functions/todo.php
new file mode 100644
index 0000000..9d58f2d
--- /dev/null
+++ b/functions/todo.php
@@ -0,0 +1,48 @@
+title = $title;
+ $this->description = $description;
+ $this->due = $due;
+ $this->priority = $priority;
+ $this->link = $link;
+ $this->createdAt = $createdAt;
+
+ if ($id < 0) {
+ $this->id = $id * -1;
+ $stmt = 'INSERT INTO todo (id, space, title, description, due, priority, link) VALUES (?, ?, ?, ?, ?, ?, ?)';
+ exec_stmt($stmt, 'iisssiss', $this->id, $space, $title, $description, $due, $priority, $link);
+ } else
+ $this->id = $id;
+ }
+
+ public function getHTML()
+ {
+ $html = '
+
+
+
+ ';
+
+ return $html;
+ }
+}
diff --git a/functions/user.php b/functions/user.php
index 999e565..257e06d 100644
--- a/functions/user.php
+++ b/functions/user.php
@@ -1,4 +1,5 @@
website = $website;
$this->isActive = false;
$this->role = $role;
- $this->spaces = null;
+ $this->spaces = $spaces;
+ $this->passwordHash = $passwordHash;
if ($id < 0) {
$this->id = $id * -1;
@@ -66,7 +70,8 @@ class User
exec_stmt($stmt, 'isssss', $this->id, $this->username, $passwordHash, $this->profilePicture, $this->bio, $this->website);
Space::addUserToSpace($this->id, 2025);
- new Space($id, $this->username, $this->username . "'s private Space.", 5, [$this], [], null, true);
+ $space = new Space($id, $this->username, $this->username . "'s private Space.", 5, [], null, true);
+ $this->spaces[] = new SpaceMember(randomId(4), $this, $space, 1, new Datetime('now'), true);
} else
$this->id = $id;
}
@@ -98,15 +103,132 @@ class User
return true;
}
- public static function retrieveFromDB(int $userId): ?User
+ public function add(SpaceMember $sm)
{
- $stmt = 'SELECT id, username, profilePicture, bio, website, role FROM user WHERE id = ?';
- $user = exec_stmt($stmt, 'i', $userId)->fetch_assoc();
+ $this->spaces[] = $sm;
+ }
- if ($user)
- return new User($user['id'], null, $user['username'], $user['profilePicture'], $user['bio'], $user['website'], $user['role'], null);
- else
+ public static function retrieveFromDB($identifier): ?User
+ {
+ error_log('Instantiating a user');
+ if (is_int($identifier)) {
+ $stmt = 'SELECT id, username, profilePicture, bio, website, role, passwordHash FROM user WHERE id = ?';
+ $rawUser = exec_stmt($stmt, 'i', $identifier)->fetch_assoc();
+ if (!$rawUser)
+ return null;
+ } else if (is_string($identifier)) {
+ $stmt = 'SELECT id, username, profilePicture, bio, website, role, passwordHash FROM user WHERE username = ?';
+ $rawUser = exec_stmt($stmt, 'i', $identifier)->fetch_assoc();
+ if (!$rawUser)
+ return null;
+ } else {
return null;
+ }
+
+ $user = new User($rawUser['id'], null, $rawUser['username'], $rawUser['profilePicture'], $rawUser['bio'], $rawUser['website'], $rawUser['role'], $rawUser['passwordHash']);
+
+ $stmt = 'SELECT id, space, role, addedAt, favorited from spaceMembers WHERE user = ?';
+ $rels = exec_stmt($stmt, 'i', $user->getId());
+ if (!$rels)
+ return null;
+
+ while ($r = $rels->fetch_assoc())
+ $user->add(new SpaceMember($r['id'], $user, Space::retrieveFromDB($r['space'], $user->getId()), $r['role'], new DateTime($r['addedAt']), $r['favorited']));
+
+ return $user;
+ }
+
+ public static function login(LoginCredentials $credentials): ?User
+ {
+ $user = User::retrieveFromDB($credentials->getUsername());
+
+ if (!password_verify($credentials->getPassword(), $user->getPasswordHash()))
+ return null;
+ else
+ return $user;
+ }
+
+ public static function logout(): void
+ {
+ foreach (array_keys($_SESSION) as $key) {
+ unset($_SESSION[$key]);
+ }
+ // Consider destroying the session cookie as well: session_destroy();
+ header('Location: .'); // Redirect to the homepage or login page
+ exit();
+ }
+
+ public function getPasswordHash()
+ {
+ return $this->passwordHash;
+ }
+
+ public function getHomeSpace()
+ {
+ // TODO: Need to implement. Requires fleshing out additional space types.
+ return Space::retrieveFromDB(1, 1);
+ }
+
+ public function getSpaces()
+ {
+ $baseSpaces = [];
+
+ foreach ($this->spaces as $s)
+ if (!$s->getSpace()->hasParent())
+ $baseSpaces[] = $s;
+
+ return $baseSpaces;
+ }
+
+ public function getAllSpaces()
+ {
+ $stmt = 'SELECT space FROM spaceMembers WHERE user = ?';
+ $rawSpaces = exec_stmt($stmt, 'i', $this->id);
+ $spaces = [];
+ while ($r = $rawSpaces->fetch_assoc())
+ $spaces[] = Space::retrieveFromDB($r['space']);
+
+ return $spaces;
+ }
+
+ public function getRole(): int
+ {
+ return $this->role;
+ }
+
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ public function getUsername(): string
+ {
+ return $this->username;
+ }
+
+ public function isActive(): bool
+ {
+ return $this->isActive;
+ }
+
+ public function getProfilePicture(): ?string
+ {
+ return $this->profilePicture;
+ }
+
+ public function getBio(): ?string
+ {
+ return $this->bio;
+ }
+
+ public function getWebsite(): ?string
+ {
+ return $this->website;
+ }
+
+ public function setIsActive(bool $isActive): void
+ {
+ $this->isActive = $isActive;
}
public static function getSignupHTML()
@@ -190,271 +312,4 @@ class User
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 {
- $spaces = [];
- $stmt = 'SELECT space FROM spaceMembers WHERE user = ?';
- $rawSpaces = exec_stmt($stmt, 'i', $user['id'])->fetch_assoc();
-
- if ($rawSpaces)
- foreach ($rawSpaces as $s)
- $spaces[] = serialize(Space::retrieveFromDB($s));
-
- return new User($user['id'], $spaces, $user['username'], $user['profilePicture'], $user['bio'], $user['website'], $user['role'], null);
- }
- }
-
- public static function logout(): void
- {
- foreach (array_keys($_SESSION) as $key) {
- unset($_SESSION[$key]);
- }
- // Consider destroying the session cookie as well: session_destroy();
- header('Location: .'); // Redirect to the homepage or login page
- exit();
- }
-
- public function getHomeSpace()
- {
- // TODO: Need to implement. Requires fleshing out additional space types.
- return Space::retrieveFromDB(1, 1);
- }
-
- public function getSpaces()
- {
- $stmt = 'SELECT space FROM spaceMembers WHERE user = ?';
- $rawSpaces = exec_stmt($stmt, 'i', $this->id);
- $spaces = [];
- while ($r = $rawSpaces->fetch_assoc()) {
- $space = Space::retrieveFromDB($r['space']);
- if (!$space->getParentSpace())
- $spaces[] = $space;
- }
-
- return $spaces;
- }
-
- public function getAllSpaces()
- {
- $stmt = 'SELECT space FROM spaceMembers WHERE user = ?';
- $rawSpaces = exec_stmt($stmt, 'i', $this->id);
- $spaces = [];
- while ($r = $rawSpaces->fetch_assoc())
- $spaces[] = Space::retrieveFromDB($r['space']);
-
- return $spaces;
- }
-
- public function getRole(): int
- {
- return $this->role;
- }
-
- public function getId(): int
- {
- return $this->id;
- }
-
- public function getUsername(): string
- {
- return $this->username;
- }
-
- public function isActive(): bool
- {
- return $this->isActive;
- }
-
- public function getProfilePicture(): ?string
- {
- return $this->profilePicture;
- }
-
- public function getBio(): ?string
- {
- return $this->bio;
- }
-
- public function getWebsite(): ?string
- {
- return $this->website;
- }
-
- public function setIsActive(bool $isActive): void
- {
- $this->isActive = $isActive;
- }
-
- public function toggleActive(?mysqli $db): bool
- {
- if (!$db) {
- error_log('Database connection not provided for toggleActive.');
- return false;
- }
- $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->id);
- $result = $stmt->execute();
- $stmt->close();
- return $result;
- } else {
- error_log('Error preparing statement: ' . $db->error);
- return false;
- }
- }
-
- public function updateUsername(string $newUsername, ?mysqli $db): bool
- {
- $newUsername = htmlspecialchars($newUsername, ENT_QUOTES, 'UTF-8');
- if (preg_match('/[\'";\-\_]/', $newUsername)) {
- throw new InvalidArgumentException('Invalid characters in username.');
- }
- if (!$db) {
- error_log('Database connection not provided for updateUsername.');
- return false;
- }
- $stmt = $db->prepare('UPDATE user SET username = ? WHERE user_id = ?');
- if ($stmt) {
- $stmt->bind_param('si', $newUsername, $this->id);
- $result = $stmt->execute();
- $stmt->close();
- if ($result) {
- $this->username = $newUsername;
- return true;
- }
- } else {
- error_log('Error preparing statement: ' . $db->error);
- }
- return false;
- }
-
- public function updatePassword(string $newPassword, ?mysqli $db): bool
- {
- $newPasswordHash = hash('sha256', $newPassword);
- if (!$db) {
- error_log('Database connection not provided for updatePassword.');
- return false;
- }
- $stmt = $db->prepare('UPDATE user SET password_hash = ? WHERE user_id = ?');
- if ($stmt) {
- $stmt->bind_param('si', $newPasswordHash, $this->id);
- $result = $stmt->execute();
- $stmt->close();
- return $result;
- } else {
- error_log('Error preparing statement: ' . $db->error);
- }
- return false;
- }
-
- public function updateProfilePicture(?string $newProfilePicture, ?mysqli $db): bool
- {
- $newProfilePicture = htmlspecialchars($newProfilePicture ?? 'default-profile.png', ENT_QUOTES, 'UTF-8');
- if (preg_match('/[\'";\-\_]/', $newProfilePicture)) {
- throw new InvalidArgumentException('Invalid characters in profile picture filename.');
- }
- if (!$db) {
- error_log('Database connection not provided for updateProfilePicture.');
- return false;
- }
- $stmt = $db->prepare('UPDATE user SET profile_picture = ? WHERE user_id = ?');
- if ($stmt) {
- $stmt->bind_param('si', $newProfilePicture, $this->id);
- $result = $stmt->execute();
- $stmt->close();
- if ($result) {
- $this->profilePicture = $newProfilePicture;
- return true;
- }
- } else {
- error_log('Error preparing statement: ' . $db->error);
- }
- return false;
- }
-
- public function followUser(int $followingUserId, bool $notify = false, ?mysqli $db): bool
- {
- if (!$db) {
- error_log('Database connection not provided for followUser.');
- return false;
- }
- $stmt = $db->prepare('INSERT INTO follows (follower_user_id, following_user_id, notify_user) VALUES (?, ?, ?)');
- if ($stmt) {
- $stmt->bind_param('iii', $this->id, $followingUserId, (int) $notify);
- $result = $stmt->execute();
- $stmt->close();
- return $result;
- } else {
- error_log('Error preparing statement: ' . $db->error);
- return false;
- }
- }
-
- public function getFollowers(?mysqli $db): array
- {
- if (!$db) {
- error_log('Database connection not provided for getFollowers.');
- return [];
- }
- $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->id);
- $stmt->execute();
- $result = $stmt->get_result();
- $followers = [];
- while ($row = $result->fetch_assoc()) {
- $followers[] = new User(
- (int) $row['user_id'],
- $row['username'],
- $row['profile_picture'],
- $row['bio'],
- $row['website']
- );
- }
- $stmt->close();
- return $followers;
- } else {
- error_log('Error preparing statement: ' . $db->error);
- return [];
- }
- }
-
- public function getFollowing(?mysqli $db): array
- {
- if (!$db) {
- error_log('Database connection not provided for getFollowing.');
- return [];
- }
- $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->id);
- $stmt->execute();
- $result = $stmt->get_result();
- $following = [];
- while ($row = $result->fetch_assoc()) {
- $following[] = new User(
- (int) $row['user_id'],
- $row['username'],
- $row['profile_picture'],
- $row['bio'],
- $row['website']
- );
- }
- $stmt->close();
- return $following;
- } else {
- error_log('Error preparing statement: ' . $db->error);
- return [];
- }
- }
}
-
-class Creator extends User {}
diff --git a/spaces.php b/spaces.php
index 8712ef9..2756b32 100644
--- a/spaces.php
+++ b/spaces.php
@@ -23,23 +23,25 @@ if (isset($_GET['view'])) {
case 'show':
// TODO: After implementing the notification modal, notify the user on success/fail auth events.
if (isset($_GET['id'])) {
- $space = Space::retrieveFromDB($_GET['id']);
- if ($space) {
- if (isset($_SESSION['user']))
- if ($space->allowUser(unserialize($_SESSION['user'])))
+ if (isset($_SESSION['user'])) {
+ $availableSpaces = unserialize($_SESSION['user'])->getSpaces();
+ foreach ($availableSpaces as $s) {
+ $space = $s->getSpace();
+ if ($space->getId() == $_GET['id']) {
echo displaySpace($_GET['id']);
- else if ($space->getVisibility() == 1)
+ break;
+ } else if ($space->getVisibility() == 1) {
echo displaySpace($_GET['id']);
- else
+ break;
+ } else
echo 'TODO: Notification Modal -> User not a member';
- else {
- if ($space->getVisibility() == 1)
- echo displaySpace($_GET['id']);
- else
- echo 'TODO: Notification Modal -> Space is not Open';
}
- } else
- echo errorScreen('Space does not exist!', 'The Space ID provided does not exist in the database.');
+ } else {
+ if ($space->getVisibility() == 1)
+ echo displaySpace($_GET['id']);
+ else
+ echo 'TODO: Notification Modal -> Space is not Open';
+ }
} else
echo displaySpaceList();
break;
@@ -49,7 +51,6 @@ if (isset($_GET['view'])) {
else
echo displaySpace(2025);
break;
-
default:
echo displaySpaceList();
break;
@@ -134,22 +135,25 @@ function displayEssay(Essay $e)
function displaySpaceList()
{
+ if (!isset($_SESSION['user']))
+ return displaySpace();
+
$user = unserialize($_SESSION['user']);
$html = '
-
-
-
Spaces
-
-
+
+
+
Spaces
+
+
';
$spaces = $user->getSpaces();
foreach ($spaces as $s)
- $html .= $s->getCardHTML();
+ $html .= $s->getSpace()->getCardHTML();
$html .= '
-
+
';
return $html;
@@ -157,15 +161,25 @@ function displaySpaceList()
function displaySpace($id = 2025)
{
- $space = Space::retrieveFromDB($id);
+ $spaces = unserialize($_SESSION['user'])->getSpaces();
+ foreach ($spaces as $s) {
+ $space = $s->getSpace();
+ if ($space->getId() == $id) {
+ break;
+ }
+ }
+
+ if (!$space)
+ return;
+
if ($space) {
$html = '
-
-
-
' . $space->getName() . '
-
' . $space->getDescription() . '
-
-
+
+
+
' . $space->getName() . '
+
' . $space->getDescription() . '
+
+
';
$subspaces = $space->getSubSpaces();
@@ -175,11 +189,9 @@ function displaySpace($id = 2025)
// TODO: Need to investigate this bug in Posts
$posts = $space->getPosts();
- foreach ($posts as $post) {
- foreach ($post as $p) {
+ foreach ($posts as $post)
+ foreach ($post as $p)
$html .= $p->getCardHTML();
- }
- }
$html .= '