397 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			397 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
|     defined('BASEPATH') OR exit('No direct script access allowed');
 | |
| 
 | |
|     class PostsModel extends CI_Model
 | |
|     {
 | |
|         public function __construct()
 | |
|         {
 | |
|             parent::__construct();
 | |
|             $this->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 addMediaToPost($postID, $type, $fileID) {
 | |
|             $this->db->query('INSERT INTO user_posts_media (postID, mediaType, fileID) VALUES (?, ?, ?)', [$postID, $type, $fileID]);
 | |
|         }
 | |
| 
 | |
|         public function preparePostContent($content)
 | |
|         {
 | |
|             if ($this->endsWith($content, '<br> ')) {
 | |
|                 $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 m.mediaType type, f.name name FROM user_posts_media m LEFT JOIN files f ON f.ID = m.fileID 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 .= '<a href="' . base_url('user/' . $link['username']) . '">@' . $link['displayname'] . '</a>';
 | |
|                     $prevPos = $link['position'] + strlen($link['username']);
 | |
|                 } else { // Link is a hashtag
 | |
|                     $finalContent .= '<a href="' . base_url('posts/search?q=%23' . $link['hashtag'] . '&type=type-posts') . '">#' . $link['hashtag'] . '</a>';
 | |
|                     $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 p.*, username, displayname FROM user_posts p LEFT JOIN users ON users.ID = p.user_id WHERE p.ID = ?', [$post['reply_to']])->result_array();
 | |
|             $data = $this->preparePostList($data);
 | |
|             if(!empty($data)) {
 | |
|                 $post['replyToPost'] = $data[0];
 | |
|             } else {
 | |
|                 $post['replyToPost'] = [
 | |
|                     'username' => '',
 | |
|                     'displayname' => '',
 | |
|                     'content' => 'Nicht existent',
 | |
|                     'date' => '',
 | |
|                 ];
 | |
|             }
 | |
| 
 | |
|             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('#</([a-z]+)>#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 .= '</' . $openedtags[$i] . '>';
 | |
|                 } 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);
 | |
|         }
 | |
|     } |