* @link https://TheTempusProject.com * @license https://opensource.org/licenses/MIT [MIT LICENSE] */ namespace TheTempusProject\Models; use TheTempusProject\Classes\DatabaseModel; use TheTempusProject\Houdini\Classes\Components; use TheTempusProject\Houdini\Classes\Views; use TheTempusProject\Canary\Bin\Canary as Debug; use TheTempusProject\Bedrock\Functions\Check; use TheTempusProject\Bedrock\Functions\Sanitize; use TheTempusProject\TheTempusProject as App; use TheTempusProject\Canary\Classes\CustomException; class Message extends DatabaseModel { public $tableName = 'messages'; public $databaseMatrix = [ [ 'userTo', 'int', '11' ], [ 'userFrom', 'int', '11' ], [ 'parent', 'int', '11' ], [ 'sent', 'int', '10' ], [ 'lastReply', 'int', '10' ], [ 'senderDeleted', 'int', '1' ], [ 'recieverDeleted', 'int', '1' ], [ 'isRead', 'int', '1' ], [ 'message', 'text', '' ], [ 'subject', 'text', '' ], ]; private $messages; private $usernames; /** * The model constructor. */ public function __construct() { parent::__construct(); self::$message = $this; } /** * Retrieves the most recent relative message in a thread * * @param int $parent - the id of the parent message * @param string $user - the id of the relative user * @return object */ public function getLatestMessage( $parent, $user, $type = null ) { if ( !Check::id( $parent ) ) { Debug::info( 'Invalid message ID' ); return false; } if ( !Check::id( $user ) ) { Debug::info( 'Invalid user ID' ); return false; } $messageData = self::$db->get( $this->tableName, [ 'ID', '=', $parent ] ); if ( $messageData->count() == 0 ) { Debug::info( 'Message not found.' ); return false; } $message = $messageData->first(); $params = [ 'parent', '=', $parent ]; if ( $type !== null ) { $params = array_merge( $params, [ 'AND', $type, '=', $user ] ); } $messageData = self::$db->get( $this->tableName, $params, 'ID', 'DESC', [ 0, 1 ] ); if ( $messageData->count() != 0 ) { if ( $messageData->first()->recieverDeleted == 0 ) { $message = $messageData->first(); } else { $message->recieverDeleted = 1; } } return $message; } /** * This calls a view of the requested message. * * @param int $ID - The message ID you are looking for. * @return null */ public function getThread( $id, $markRead = false ) { if ( !Check::id( $id ) ) { Debug::info( 'Invalid ID' ); return false; } $messageData = self::$db->get( $this->tableName, [ 'ID', '=', $id ] ); if ( $messageData->count() == 0 ) { Debug::info( 'Message not found.' ); return false; } $message = $messageData->first(); if ( $message->userTo == App::$activeUser->ID ) { $permissionCheck = 1; if ( $message->recieverDeleted == 1 ) { Debug::info( 'User has already deleted this message.' ); return false; } } if ( $message->userFrom == App::$activeUser->ID ) { $permissionCheck = 1; if ( $message->senderDeleted == 1 ) { Debug::info( 'User has already deleted this message.' ); return false; } } if ( empty( $permissionCheck ) ) { Debug::info( 'You do not have permission to view this message.' ); return false; } if ( $message->parent != 0 ) { $find = $message->parent; } else { $find = $message->ID; } $messageData = self::$db->get( $this->tableName, [ 'ID', '=', $find, 'OR', 'Parent', '=', $find ], 'ID', 'ASC' )->results(); Components::set( 'PID', $find ); if ( $markRead == true ) { foreach ( $messageData as $instance ) { $this->markRead( $instance->ID ); } } return $this->filter( $messageData ); } public function getInbox( $limit = null ) { if ( empty( $limit ) ) { $limit = 10; } $limit = [ 0, $limit ]; $messageData = self::$db->get( $this->tableName, [ 'parent', '=', 0, 'AND', 'userFrom', '=', App::$activeUser->ID, 'OR', 'parent', '=', 0, 'AND', 'userTo', '=', App::$activeUser->ID, ], 'ID', 'DESC', $limit ); if ( $messageData->count() == 0 ) { Debug::info( 'getInbox: No messages found' ); return false; } $filters = [ 'importantUser' => App::$activeUser->ID, 'deleted' => false, 'type' => 'userTo', ]; return $this->filter( $messageData->results(), $filters ); } /** * This function calls the view for the message outbox. * * @return null */ public function getOutbox( $limit = null ) { if ( empty( $limit ) ) { $limit = 10; } $limit = [ 0, $limit ]; $messageData = self::$db->get( $this->tableName, [ 'parent', '=', 0, 'AND', 'userFrom', '=', App::$activeUser->ID, ], 'ID', 'DESC', $limit ); if ( $messageData->count() == 0 ) { Debug::info( 'getOutbox: No messages found' ); return false; } $filters = [ 'importantUser' => App::$activeUser->ID, 'deleted' => false, 'type' => 'userFrom', ]; return $this->filter( $messageData->results(), $filters ); } /** * This function is to prep our messages for display. An array of raw messages * sent through this function will automatically have all the user ID's filter * into actual usernames. * * @param $messageArray - This is an array of messages that need to be processed. * @return array - It will return the same message array after being processed. * @todo add filtering for BB-code. */ public function filter( $messageArray, $filters = [] ) { $out = []; foreach ( $messageArray as $message ) { if ( !is_object( $message ) ) { $message = $messageArray; $end = true; } if ( isset( $filters['type'] ) && isset( $filters['importantUser'] ) ) { $type = $filters['type']; } else { $type = null; } if ( isset( $filters['importantUser'] ) ) { $user = $filters['importantUser']; } else { $user = App::$activeUser->ID; } if ( $message->parent == 0 ) { $last = $this->getLatestMessage( $message->ID, $user, $type ); } else { $last = $message; } if ( $type != null && $message->$type != $user && $last->$type != $user ) { continue; } if ( isset( $filters['deleted'] ) && $filters['deleted'] == false ) { if ( $type == 'userFrom' ) { if ( $last->senderDeleted == 1 ) { continue; } } if ( $type == 'userTo' ) { if ( $last->recieverDeleted == 1 ) { continue; } } } $messageOut = (array) $message; $short = explode( ' ', Sanitize::contentShort( $message->message ) ); $summary = implode( ' ', array_splice( $short, 0, 25 ) ); if ( count( $short, 1 ) >= 25 ) { $messageOut['summary'] = $summary . '...'; } else { $messageOut['summary'] = $summary; } if ( $last->isRead == 0 ) { $messageOut['unreadBadge'] = Views::simpleView( 'messages.unreadBadge' ); } else { $messageOut['unreadBadge'] = ''; } $messageOut['fromAvatar'] = self::$user->getAvatar( $message->userFrom ); $messageOut['userTo'] = self::$user->getUsername( $message->userTo ); $messageOut['userFrom'] = self::$user->getUsername( $message->userFrom ); $out[] = (object) $messageOut; if ( !empty( $end ) ) { $out = $out[0]; break; } } return $out; } /** * Function to check input and save messages to the DB. * * @param string $data - Username of the person receiving the sent message. * @return function */ public function newThread( $to, $subject, $message ) { if ( !self::$user->usernameExists( $to ) ) { Debug::info( 'Message->sendMessage: User not found.' ); return false; } $fields = [ 'userTo' => self::$user->getID( $to ), 'userFrom' => App::$activeUser->ID, 'parent' => 0, 'sent' => time(), 'lastReply' => time(), 'senderDeleted' => 0, 'recieverDeleted' => 0, 'isRead' => 0, 'subject' => $subject, 'message' => $message, ]; if ( !self::$db->insert( $this->tableName, $fields ) ) { new CustomException( 'messageSend' ); return false; } return true; } public function getUnreadCount( $userId ) { $result = self::$db->get( $this->tableName, [ 'userTo', '=', $userId, 'AND', 'isRead', '=', 0, 'AND', 'parent', '=', 0, 'AND', 'recieverDeleted', '=', 0, ] ); return $result->count(); } public function unreadCount() { if ( empty( App::$activeUser->ID ) ) { return 0; } return $this->getUnreadCount( App::$activeUser->ID ); } public function hasPermission( $id ) { if ( !Check::id( $id ) ) { Debug::info( 'Invalid ID' ); return false; } $messageData = self::$db->get( 'messages', [ 'ID', '=', $id ] ); if ( $messageData->count() == 0 ) { Debug::info( 'Message not found.' ); return false; } $message = $messageData->first(); if ( $message->userTo != App::$activeUser->ID && $message->userFrom != App::$activeUser->ID ) { return false; } return true; } /** * Marks a message as read. This is setup to only work * if the message was sent to the active user. * * @param int - The message ID you are marking as read. * @return bool */ public function markRead( $id ) { if ( !Check::id( $id ) ) { Debug::info( 'Invalid ID' ); return false; } $result = self::$db->get( $this->tableName, [ 'ID', '=', $id, 'AND', 'userTo', '=', App::$activeUser->ID, 'AND', 'isRead', '=', '0' ] ); if ( $result->count() == 0 ) { Debug::info( 'Failed to mark message as read.' ); return false; } if ( !self::$db->update( $this->tableName, $id, [ 'isRead' => 1 ] ) ) { Debug::error( 'Failed to mark message as read.' ); return false; } return true; } public function newMessageReply( $id, $message ) { if ( !$this->hasPermission( $id ) ) { Debug::info( 'Permission Denied.' ); return false; } $messageData = self::$db->get( $this->tableName, [ 'ID', '=', $id ] )->first(); if ( $messageData->userTo == App::$activeUser->ID ) { $recipient = $messageData->userFrom; } else { $recipient = $messageData->userTo; } if ( $recipient === App::$activeUser->ID ) { Debug::info( 'Cannot send messages to yourself' ); return false; } if ( !self::$db->update( $this->tableName, $messageData->ID, [ 'lastReply' => time() ] ) ) { new CustomException( 'messagesReplyUpdate' ); return false; } $fields = [ 'senderDeleted' => 0, 'recieverDeleted' => 0, 'isRead' => 0, 'userTo' => $recipient, 'userFrom' => App::$activeUser->ID, 'message' => $message, 'subject' => 're: ' . $messageData->subject, 'sent' => time(), 'parent' => $messageData->ID, 'lastReply' => time(), ]; if ( !self::$db->insert( $this->tableName, $fields ) ) { new CustomException( 'messagesReplySend' ); return false; } return true; } public function messageTitle( $id ) { if ( !$this->hasPermission( $id ) ) { Debug::info( 'Permission Denied.' ); return false; } $message = self::$db->get( $this->tableName, [ 'ID', '=', $id ] )->first(); return $message->subject; } /** * Function to delete messages from the DB. * * @param int $data - The ID of the message you are trying to delete. * @todo - done at 5 am after no sleep. This can be simplified a lot, i just wanted a working solution ASAP * @return bool */ public function delete( $data ) { if ( !is_array( $data ) ) { $data = [ $data ]; } foreach ( $data as $instance ) { if ( !Check::id( $instance ) ) { $error = true; } if ( !$this->hasPermission( $instance ) ) { Debug::info( 'Permission Denied.' ); return false; } $message = self::$db->get( $this->tableName, [ 'ID', '=', $instance ] )->first(); if ( $message->userTo == App::$activeUser->ID ) { $fields = [ 'recieverDeleted' => '1' ]; } else { $fields = [ 'senderDeleted' => '1' ]; } if ( !self::$db->update( $this->tableName, $instance, $fields ) ) { $error = true; } Debug::info( "message Deleted: $instance" ); if ( !empty( $end ) ) { break; } } if ( !empty( $error ) ) { Debug::info( 'There was an error deleting one or more messages.' ); return false; } return true; } }