load->model('UserModel', '', TRUE); $this->load->model('NotificationModel', '', TRUE); } function addPost($userID, $content) { return $this->addReply($userID, $content, NULL); } public function addReply($userID, $content, $replyToUUID) { $content = $this->preparePostContent($content); $uuid = $this->generatePostUUID($userID, $content); $replyTo = NULL; if ($replyToUUID !== NULL) { $replyToID = $this->db->query('SELECT ID FROM user_posts WHERE uuid = ?', [$replyToUUID])->result_array(); $replyTo = !empty($replyToID) ? $replyToID[0]['ID'] : NULL; } $this->db->query('INSERT INTO user_posts (user_id, content, uuid, reply_to) VALUES (?, ?, ?, ?)', [$userID, $content, $uuid, $replyTo]); $insertedPost = $this->db->query('SELECT ID, user_id FROM user_posts WHERE uuid = ?', [$uuid])->result_array(); $this->addPostMentions($insertedPost[0]['ID'], $content, $uuid); $this->addPostHashtags($insertedPost[0]['ID'], $content); // Send notification to user whose post was replied to if ($userID != $insertedPost[0]['user_id']) { $this->NotificationModel->userNotificationPostReply($userID, $insertedPost[0]['user_id'], $insertedPost[0]['ID'], $uuid); } return $insertedPost[0]['ID']; } public function deletePost($userID, $uuid) { $postID = $this->db->query('SELECT ID FROM user_posts WHERE user_id = ? AND uuid = ?', [$userID, $uuid])->result_array()[0]['ID']; $this->db->query('DELETE FROM user_posts WHERE user_id = ? AND uuid = ?', [$userID, $uuid]); $this->db->query('DELETE FROM user_posts_hashtags WHERE postID = ?', [$postID]); $this->db->query('DELETE FROM user_posts_mentions WHERE postID = ?', [$postID]); $this->db->query('DELETE FROM user_posts_likes WHERE postID = ?', [$postID]); $this->db->query('DELETE FROM user_posts_media WHERE postID = ?', [$postID]); } public function addImageToPost($postID, $imageUrl) { $this->db->query('INSERT INTO user_posts_media (postID, mediaType, mediaUrl) VALUES (?, ?, ?)', [$postID, 'image', $imageUrl]); } public function preparePostContent($content) { if ($this->endsWith($content, '
 ')) { $content = substr($content, 0, strlen($content) - 10); } $content = htmlspecialchars($content); return $content; } function endsWith($haystack, $needle) { $length = strlen($needle); return $length === 0 || (substr($haystack, -$length) === $needle); } function generatePostUUID($userID, $content) { return md5($userID . $content . date("Y-m-d H:i:s")); } public function addPostMentions($postID, $content, $postUUID) { preg_match_all('/@([A-Za-z0-9._]+)/', $content, $mentions, PREG_OFFSET_CAPTURE); foreach ($mentions[1] as $mention) { $mentionedUser = $this->UserModel->getUserIDByUsername(strtolower($mention[0])); if ($mentionedUser == null) { continue; } $mentionedUser = $mentionedUser[0]; $this->addMention($postID, $_SESSION['user']['ID'], $mentionedUser['ID'], $mention[1], $postUUID); } } public function addMention($postID, $userID, $mentionedUserID, $position, $postUUID) { $this->db->query('INSERT INTO user_posts_mentions (userID, postID, mentionedUserID, position) VALUES (?, ?, ?, ?)', [$userID, $postID, $mentionedUserID, $position]); // Send notification $this->NotificationModel->userNotificationPostMentioned($userID, $mentionedUserID, $postID, $postUUID); } public function addPostHashtags($postID, $content) { preg_match_all('/#([A-Za-z0-9]+)/', $content, $hashtags, PREG_OFFSET_CAPTURE); foreach ($hashtags[1] as $hashtag) { $this->addHashtag($postID, $_SESSION['user']['ID'], $hashtag[0], $hashtag[1]); } } public function addHashtag($postID, $userID, $hashtag, $position) { $this->db->query('INSERT INTO user_posts_hashtags (userID, postID, hashtag, position) VALUES (?, ?, ?, ?)', [$userID, $postID, $hashtag, $position]); } function getUserPosts($id, $count, $offset, $maxLength = 250) { $this->db->cache_off(); $posts = $this->db->query('SELECT * FROM user_posts p WHERE user_id = ? ORDER BY date DESC LIMIT ? OFFSET ?', [$id, $count, $offset])->result_array(); $this->db->cache_on(); $posts = $this->preparePostList($posts, $maxLength); return $posts; } public function preparePostList($postList, $maxLength = 250) { foreach ($postList as $i => $post) { $post = $this->mergePostUserData($post); $post['replyCount'] = $this->getPostReplyCountByID($post['ID']); $post['likeCount'] = $this->getPostLikeCountByID($post['ID']); if ($maxLength > 0) { $post['content'] = strlen($post['content']) > $maxLength ? substr($post['content'], 0, $maxLength) . '...' : $post['content']; } $post['content'] = $this->mergePostMentionsHashtags($post['ID'], $post['content']); $post['media'] = $this->getPostMedia($post['ID']); if (isset($_SESSION['user']) && !empty($_SESSION['user'])) { $post = $this->mergeUserHasLiked($post, $_SESSION['user']['ID']); } if($post['reply_to'] != NULL) { $post = $this->mergeReplyData($post); } $postList[$i] = $post; } $postList = $this->UserModel->setDefaultImages($postList); return $postList; } public function getPostMedia($postID) { $result = $this->db->query('SELECT * FROM user_posts_media WHERE postID = ?', [$postID])->result_array(); return $result; } private function mergePostUserData($post) { $user = $this->UserModel->getUserByID($post['user_id']); $user = $user[0]; $post['username'] = $user['username']; $post['displayname'] = $user['displayname']; $post['profile_picture'] = $user['profile_picture']; return $post; } public function getPostReplyCountByID($postID) { $this->db->cache_off(); $data = $this->db->query('SELECT count(*) replyCount FROM user_posts WHERE reply_to = ?', [$postID])->result_array(); $this->db->cache_on(); return $data[0]['replyCount']; } public function getPostLikeCountByID($id) { $this->db->cache_off(); $data = $this->db->query('SELECT count(*) likeCount FROM user_posts_likes WHERE postID = ?', [$id])->result_array(); $this->db->cache_on(); return $data[0]['likeCount']; } private function mergePostMentionsHashtags($postID, $content) { $mentions = $this->db->query('SELECT m.*, u.username, u.displayname FROM user_posts_mentions m LEFT JOIN users u ON m.mentionedUserID = u.ID WHERE postID = ?', [$postID])->result_array(); $hashtags = $this->db->query('SELECT * FROM user_posts_hashtags WHERE postID = ?', [$postID])->result_array(); $links = array_merge($mentions, $hashtags); usort($links, function ($a, $b) { return $a['position'] - $b['position']; }); $finalContent = ''; $prevPos = 0; foreach ($links as $link) { $finalContent .= substr($content, $prevPos, $link['position'] - $prevPos - 1); if (isset($link['username'])) { // Is link a mention? $finalContent .= '@' . $link['displayname'] . ''; $prevPos = $link['position'] + strlen($link['username']); } else { // Link is a hashtag $finalContent .= '#' . $link['hashtag'] . ''; $prevPos = $link['position'] + strlen($link['hashtag']); } if ($prevPos > strlen($content)) { break; } } $finalContent .= substr($content, $prevPos, strlen($content) - $prevPos); return $finalContent; } private function mergeUserHasLiked($post, $userID) { $this->db->cache_off(); $data = $this->db->query('SELECT * FROM user_posts_likes WHERE postID = (SELECT ID FROM user_posts WHERE uuid = ?) AND likerUserID = ?', [$post['uuid'], $userID])->result_array(); $this->db->cache_on(); if (empty($data)) { $post['userHasLiked'] = FALSE; } else { $post['userHasLiked'] = TRUE; } return $post; } private function mergeReplyData($post) { $data = $this->db->query('SELECT uuid, username, displayname FROM user_posts LEFT JOIN users ON users.ID = user_posts.user_id WHERE user_posts.ID = ?', [$post['reply_to']])->result_array(); $post['replyToUuid'] = $data[0]['uuid']; $post['replyToUsername'] = $data[0]['username']; $post['replyToDisplayname'] = $data[0]['displayname']; return $post; } public function getNewestPosts($count, $maxLength = 250) { $this->db->cache_off(); $data = $this->db->query('SELECT * FROM user_posts ORDER BY date DESC LIMIT ?', [$count])->result_array(); $this->db->cache_on(); $data = $this->preparePostList($data, $maxLength); return $data; } public function getFeedPosts($userID, $amount, $offset) { $this->db->cache_off(); $data = $this->db->query('SELECT * FROM user_posts WHERE user_id IN (SELECT followedUserID FROM user_followers WHERE followerUserID = ?) OR ID IN(SELECT postID FROM user_posts_mentions WHERE mentionedUserID = ?) OR ID IN (SELECT postID FROM user_posts_likes WHERE likedUserID = ?) OR user_id = ? ORDER BY date DESC LIMIT ? OFFSET ?', [$userID, $userID, $userID, $userID, $amount, $offset])->result_array(); $this->db->cache_on(); $data = $this->preparePostList($data); return $data; } public function getPopularPosts($amount, $offset) { $this->db->cache_off(); $data = $this->db->query('SELECT * FROM user_posts p ORDER BY ((SELECT count(*) FROM user_posts_likes WHERE postID = p.ID) + (SELECT count(*) FROM user_posts WHERE reply_to = p.ID)) DESC, date DESC LIMIT ? OFFSET ?', [$amount, $offset])->result_array(); $this->db->cache_on(); $data = $this->preparePostList($data); return $data; } public function getPostDetails($userID, $uuid) { $this->db->cache_off(); $data = $this->db->query('SELECT * FROM user_posts WHERE user_id = ? AND uuid = ?', [$userID, $uuid])->result_array(); $this->db->cache_on(); $data = $this->preparePostList($data, -1); return $data; } public function getPostReplies($postID) { $this->db->cache_off(); $replies = $this->db->query('SELECT * FROM user_posts WHERE reply_to = ? ORDER BY date', [$postID])->result_array(); $this->db->cache_on(); $replies = $this->preparePostList($replies); return $replies; } public function getPostByUUID($uuid) { $this->db->cache_off(); $result = $this->db->query('SELECT * FROM user_posts WHERE uuid = ?', [$uuid])->result_array(); $this->db->cache_on(); return $result; } public function addPostLikeByUUID($uuid, $userID) { $this->db->cache_off(); $data = $this->db->query('SELECT * FROM user_posts_likes WHERE postID = (SELECT ID FROM user_posts WHERE uuid = ?) AND likerUserID = ?', [$uuid, $userID])->result_array(); $this->db->cache_on(); // IDs needed for handling notifications later $postUser = $this->db->query('SELECT ID FROM users WHERE ID = (SELECT user_id FROM user_posts WHERE uuid = ?)', [$uuid])->result_array(); $postID = $this->db->query('SELECT ID FROM user_posts WHERE uuid = ?', [$uuid])->result_array(); if (empty($data)) { $this->db->query('INSERT INTO user_posts_likes (postID, likedUserID, likerUserID) VALUES ((SELECT ID FROM user_posts WHERE uuid = ?), (SELECT user_id FROM user_posts WHERE uuid = ?), ?)', [$uuid, $uuid, $userID]); // Send like notification if ($postUser[0]['ID'] != $userID) { $this->NotificationModel->userNotificationPostLike($userID, $postUser[0]['ID'], $postID[0]['ID'], $uuid); } return true; } else { $this->db->query('DELETE FROM user_posts_likes WHERE postID = (SELECT ID FROM user_posts WHERE uuid = ?) AND likerUserID = ?', [$uuid, $userID]); // Remove existing notification $this->NotificationModel->removeNotification($userID, $postUser[0]['ID'], $postID[0]['ID'], 'users.likedPost'); return false; } } public function getPostLikeCountByUUID($uuid) { $this->db->cache_off(); $data = $this->db->query('SELECT count(*) likeCount FROM user_posts_likes WHERE postID = (SELECT ID FROM user_posts WHERE uuid = ?)', [$uuid])->result_array(); $this->db->cache_on(); return $data[0]['likeCount']; } public function isUUIDValid($uuid) { $this->db->cache_off(); $data = $this->db->query('SELECT ID FROM user_posts WHERE uuid = ?', [$uuid])->result_array(); $this->db->cache_on(); return !empty($data); } public function closeTags($html) { preg_match_all('#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?#iU', $html, $result); $openedtags = $result[1]; preg_match_all('##iU', $html, $result); $closedtags = $result[1]; $len_opened = count($openedtags); if (count($closedtags) == $len_opened) { return $html; } $openedtags = array_reverse($openedtags); for ($i = 0; $i < $len_opened; $i++) { if (!in_array($openedtags[$i], $closedtags)) { $html .= ''; } else { unset($closedtags[array_search($openedtags[$i], $closedtags)]); } } return $html; } public function searchPosts($query, $limit = 20, $offset = 0) { $this->db->cache_off(); $results = $this->db->query('SELECT * FROM user_posts WHERE content RLIKE ? OR (SELECT username FROM users WHERE ID = user_id) RLIKE ? ORDER BY (SELECT count(*) FROM user_posts_likes WHERE postID = ID) DESC, (SELECT count(*) FROM user_posts WHERE user_posts.reply_to = ID) DESC, date DESC LIMIT ? OFFSET ?', [$query, $query, $limit, $offset])->result_array(); $this->db->cache_on(); $results = $this->preparePostList($results); return $results; } public function reportPost($uuid, $reason, $reasonText) { $this->db->query('INSERT INTO user_posts_reports (postID, reason, reasonText) VALUES ((SELECT ID FROM user_posts WHERE uuid = ?), ?, ?)', [$uuid, $reason, $reasonText]); $this->db->cache_delete('admin', 'reports'); // Send notification $postID = $this->db->query('SELECT ID FROM user_posts WHERE uuid = ?', [$uuid])->result_array(); $this->NotificationModel->rankNotificationPostReport( isset($_SESSION['user']) ? $_SESSION['user']['ID'] : -1, 8, $postID[0]['ID'], $uuid); } }