railpage/railpagecore

View on GitHub
lib/PrivateMessages/Message.php

Summary

Maintainability
F
3 days
Test Coverage
<?php

/**
 * Private Messages message
 * @since Version 3.8.7
 * @package Railpage
 * @author Michael Greenhill
 */

namespace Railpage\PrivateMessages;

use Exception;
use DateTime;
use Railpage\AppCore;
use Railpage\Users\User;
use Railpage\Users\Factory as UserFactory;
use Railpage\Notifications\Notifications;
use Railpage\Notifications\Notification;

use Swift_Message;
use Swift_Mailer;
use Swift_SmtpTransport;

/**
 * Load an individual message
 * @since Version 3.3
 * @version 3.3
 * @author Michael Greenhill
 */

class Message extends PrivateMessages {
    
    /** 
     * Message ID
     * @since Version 3.3
     * @var int $id
     */
    
    public $id; 
    
    /** 
     * Message subject
     * @since Version 3.3
     * @var string $subject
     */
    
    public $subject; 
    
    /** 
     * Message body
     * @since Version 3.3
     * @var string $body
     */
    
    public $body; 
    
    /** 
     * Message date
     * @since Version 3.3
     * @var int $date
     */
    
    public $date; 
    
    /** 
     * BBCode UID
     * @since Version 3.3
     * @var string $bbcode_uid
     */
    
    public $bbcode_uid; 
    
    /** 
     * Message type
     * @since Version 3.3
     * @var int $type
     */
    
    public $type; 
    
    /** 
     * Enable BBCode
     * @since Version 3.3
     * @var int $enable_bbcode
     */
    
    public $enable_bbcode; 
    
    /** 
     * Enable smilies
     * @since Version 3.3
     * @var int $enable_html
     */
    
    public $enable_html; 
    
    /** 
     * Enable smilies
     * @since Version 3.3
     * @var int $enable_smilies
     */
    
    public $enable_smilies; 
    
    /** 
     * Enable signature
     * @since Version 3.3
     * @var int $enable_signature
     */
    
    public $enable_signature; 
    
    /**
     * Message author User object
     * @since Version 3.8.7
     * @var \Railpage\Users\User $Author
     */
    
    public $Author;
    
    /**
     * From user ID
     * @since Version 3.3
     * @var int $from_user_id
     */
    
    public $from_user_id; 
    
    /**
     * From username
     * @since Version 3.3
     * @var string $from_username
     */
    
    public $from_username; 
    
    /**
     * From user avatar
     * @since Version 3.3
     * @var string $from_user_avatar
     */
    
    public $from_user_avatar; 
    
    /**
     * Can we show if this user is online?
     * @since Version 3.3
     * @var boolean $from_user_viewonline
     */
    
    public $from_user_viewonline;
    
    /**
     * Recipient user object
     * @since Version 3.8.7
     * @var \Railpage\Users\User $Recipient
     */
    
    public $Recipient;
    
    /**
     * To user ID
     * @since Version 3.3
     * @var int $to_user_id
     */
    
    public $to_user_id; 
    
    /**
     * To username
     * @since Version 3.3
     * @var string $to_username
     */
    
    public $to_username; 
    
    /**
     * To user avatar
     * @since Version 3.3
     * @var string $to_user_avatar
     */
    
    public $to_user_avatar; 
    
    /**
     * Can we show if this user is online?
     * @since Version 3.3
     * @var boolean $to_user_viewonline
     */
    
    public $to_user_viewonline;
    
    /**
     * Object ID
     * 
     * In the case of multi-user PMs, or when a PM is directly related to another event (eg new download notification), this object ID forms the link between that event and the PM.
     * @since Version 3.2
     * @var string $object_id
     */
    
    public $object_id;
    
    /**
     * Hide from sender
     * @since Version 3.2
     * @var boolean $hide_from
     */
    
    public $hide_from;
    
    /**
     * Hide from recipient
     * @since Version 3.2
     * @var boolean $hide_to
     */
    
    public $hide_to;
    
    /**
     * Constructor
     * @since Version 3.3
     * @version 3.3
     * @param object $db
     * @param int $id
     */
    
    public function __construct($id = false) {
        parent::__construct(); 
        
        if (filter_var($id, FILTER_VALIDATE_INT)) {
            $this->id = $id; 
            $this->fetch(); 
        }
    }
    
    /** 
     * Fetch the message
     * @since Version 3.3
     * @version 3.3
     * @return boolean
     */
    
    public function fetch() {
        if (!filter_var($this->id, FILTER_VALIDATE_INT)) {
            throw new Exception("Cannot fetch PM - no message ID provided");
        }
        
        $this->mckey = "railpage:messsages.message_id=" . $this->id;
        
        if (!$row = $this->Memcached->fetch($this->mckey)) {
            $query = "SELECT pm.*, pmt.*, ufrom.user_id AS user_id_from, ufrom.username AS username_from, ufrom.user_avatar AS from_user_avatar, ufrom.user_allow_viewonline AS from_user_viewonline, uto.user_id AS user_id_to, uto.username AS username_to, uto.user_allow_viewonline AS to_user_viewonline
                        FROM nuke_bbprivmsgs AS pm
                        LEFT JOIN nuke_bbprivmsgs_text AS pmt ON pm.privmsgs_id = pmt.privmsgs_text_id
                        LEFT JOIN nuke_users AS ufrom ON pm.privmsgs_from_userid = ufrom.user_id
                        LEFT JOIN nuke_users AS uto ON pm.privmsgs_to_userid = uto.user_id
                        WHERE pm.privmsgs_id = ?";
            
            $row = $this->db->fetchRow($query, $this->id); 
                
            $this->Memcached->save($this->mckey, $row);
        }
        
        if (!isset($row) || count($row) == 0) {
            return;
        }
        
        // Nasty way of doing it, but it should work for now.
        // Remember to extend BOTH open AND close when adding another bbcode to match
        //$bbcode_preg_open   = "@\[(img|url|list|b|i|u)\:([a-zA-Z0-9]+)\]@";
        //$bbcode_preg_close  = "@\[/(img|url|list|b|i|u)\:([a-zA-Z0-9]+)\]@";
        
        $this->id           = $row['privmsgs_id'];
        $this->date         = $row['privmsgs_date']; 
        $this->subject      = $row['privmsgs_subject'];
        $this->body         = trim($row['privmsgs_text']);
        $this->bbcode_uid   = $row['privmsgs_bbcode_uid'];
        $this->type         = $row['privmsgs_type'];
        
        $this->enable_bbcode    = $row['privmsgs_enable_bbcode']; 
        $this->enable_html      = $row['privmsgs_enable_html']; 
        $this->enable_smilies   = $row['privmsgs_enable_smilies']; 
        $this->enable_signature = $row['privmsgs_attach_sig']; 
        
        $this->object_id        = $row['object_id'];
        
        $this->hide_from        = $row['hide_from'];
        $this->hide_to          = $row['hide_to'];
        
        $this->setRecipient(UserFactory::CreateUser($row['privmsgs_to_userid']));
        $this->setAuthor(UserFactory::CreateUser($row['privmsgs_from_userid']));
        
    }
    
    /**
     * Validate a message before committing / sending
     * @since Version 3.3
     * @version 3.3
     * @return boolean
     */
    
    public function validate() {
        if (is_null($this->object_id)) {
            $this->object_id = "";
        }
        
        if (empty($this->subject)) {
            throw new Exception("PM subject cannot be empty"); 
        }
        
        if (!filter_var($this->id, FILTER_VALIDATE_INT) && empty($this->body)) {
            throw new Exception("PM body cannot be empty"); 
        }
        
        if (empty($this->to_user_id)) {
            throw new Exception("Cannot send PM - recipient user ID is empty"); 
        }
        
        if (empty($this->from_user_id)) {
            throw new Exception("Cannot send PM - sender user ID is empty"); 
        }
        
        if (empty($this->enable_bbcode)) {
            $this->enable_bbcode = true;
        }
        
        if (empty($this->enable_html)) {
            $this->enable_html = true;
        } 
        
        if (empty($this->enable_smilies)) {
            $this->enable_smilies = true;
        } 
        
        if (empty($this->enable_signature)) {
            $this->enable_signature = false;
        }
        
        if (empty($this->privmsgs_bbcode_uid)) {
            $this->privmsgs_bbcode_uid = "sausages";
        }
        
        if (empty($this->bbcode_uid)) {
            $this->bbcode_uid = "sausages";
        }
        
        return true;
    }
    
    /** 
     * Send this message
     * @since Version 3.3
     * @version 3.3
     * @return boolean
     */
    
    public function send() {
        
        $this->validate();
        
        $data = array(
            "privmsgs_type" => PRIVMSGS_UNREAD_MAIL,
            "privmsgs_subject" => $this->subject,
            "privmsgs_from_userid" => $this->from_user_id,
            "privmsgs_to_userid" => $this->to_user_id,
            "privmsgs_date" => time(),
            "privmsgs_ip" => encode_ip($_SERVER['REMOTE_ADDR']),
            "privmsgs_enable_bbcode" => $this->enable_bbcode,
            "privmsgs_enable_html" => $this->enable_html,
            "privmsgs_enable_smilies" => $this->enable_smilies,
            "privmsgs_attach_sig" => $this->enable_signature,
            "object_id" => $this->object_id
        );
        
        $this->db->insert("nuke_bbprivmsgs", $data);
        $pm_id = $this->db->lastInsertId();
        $this->id = $pm_id;
        
        $data = array(
            "privmsgs_text_id" => $pm_id,
            "privmsgs_bbcode_uid" => $this->bbcode_uid,
            "privmsgs_text" => function_exists("prepare_submit") ? prepare_submit($this->body) : $this->body
        );
        
        $rs = $this->db->insert("nuke_bbprivmsgs_text", $data); 
        
        /**
         * If the recipient doesn't want to be notified of a new message then return out
         */
        
        if ($this->Recipient->notify_privmsg != 1) {
            return;
        }
            
        /**
         * Send a push notification
         */
        
        $Push = new Notification;
        $Push->transport = Notifications::TRANSPORT_PUSH;
        $Push->subject = sprintf("[Private Messages] New message from %s", $this->Author->username);
        $Push->body = sprintf("%s has sent you a new private message in the conversation titled \"%s\"", $this->Author->username, $this->subject); 
        $Push->setActionUrl(sprintf("/messages/conversation/%d", $this->id))->addRecipient($this->Recipient->id, $this->Recipient->username, $this->Recipient->username);
        $Push->commit()->dispatch(); 
        
        /**
         * Template settings
         */
        
        $Smarty = AppCore::getSmarty(); 
        
        $Smarty->assign("server_addr", "www.railpage.com.au");
        $Smarty->assign("message_id", $this->id);
        $Smarty->assign("pm_from_username", $this->Author->username);
        $Smarty->assign("userdata_username", $this->Recipient->username);
        
        /**
         * Create a user notification
         */
        
        $Notification = new Notification;
        $Notification->transport = Notifications::TRANSPORT_EMAIL;
        $Notification->status = Notifications::STATUS_QUEUED;
        $Notification->subject = sprintf("[Private Messages] New message from %s", $this->Author->username);
        $Notification->addRecipient($this->Recipient->id, $this->Recipient->username, $this->Recipient->contact_email);
        
        $tpl = $Smarty->ResolveTemplate("template.generic");
        
        $email = array(
            "subject" => sprintf("New message from %s", $this->Author->username),
            "subtitle" => "Private Messages",
            "body" => nl2br(sprintf("Hi %s,\n\n<a href='http://www.railpage.com.au%s?utm_medium&email&utm_source=private-messages&utm_campain=user-%d'>%s</a> has sent you a new <a href='http://www.railpage.com.au/messages/conversation/%d?utm_medium=email&utm_source=private-messages&utm_campaign=user-%d#%d'>private message</a> in the conversation titled <em>%s</em>.",
                        $this->Recipient->username, $this->Author->url->url, $this->Author->id, $this->Author->username, $this->id, $this->Author->id, $this->id, $this->subject))
                            
        );
        
        $Smarty->Assign("email", $email);
        
        $Notification->body = $Smarty->fetch($tpl);
        
        $Notification->commit(); 
        
    }
    
    /**
     * Update a PM
     * @since Version 3.3
     * @version 3.3
     * @return boolean
     */
    
    public function commit() {
        if (!filter_var($this->id, FILTER_VALIDATE_INT)) {
            throw new Exception("Cannot commit changes to PM - PM does not exist!"); 
        } 
        
        $this->validate();
        
        // Theoretically nothing but the type should change. I'll leave the rest in for now...
        
        $dataArray = array(); 
        
        $dataArray['privmsgs_type']         = $this->type;
        $dataArray['privmsgs_subject']      = $this->subject;
        $dataArray['privmsgs_from_userid']  = $this->from_user_id; 
        $dataArray['privmsgs_to_userid']    = $this->to_user_id;
        $dataArray['privmsgs_ip']           = encode_ip($_SERVER['REMOTE_ADDR']); 
        $dataArray['privmsgs_enable_bbcode']    = $this->enable_bbcode; 
        $dataArray['privmsgs_enable_html']      = $this->enable_html; 
        $dataArray['privmsgs_enable_smilies']   = $this->enable_smilies; 
        $dataArray['privmsgs_attach_sig']       = $this->enable_signature;
        
        $dataArray['hide_from']     = $this->hide_from; 
        $dataArray['hide_to']       = $this->hide_to;
        
        if (filter_var($this->id, FILTER_VALIDATE_INT)) {
            // Update
            
            $where = array(
                "privmsgs_id = ?" => $this->id
            );
            
            $this->db->update("nuke_bbprivmsgs", $dataArray, $where);
            
            $data = array(
                'privmsgs_bbcode_uid' => $this->bbcode_uid,
                'privmsgs_text' => $this->body
            );
            
            $where = array(
                "privmsgs_text_id = ?" => $this->id
            );
            
            $this->db->update("nuke_bbprivmsgs_text", $data, $where);
            
            $this->Memcached->delete($this->mckey);
            
            return true;
        } else {
            // Insert
            
            $this->db->insert("nuke_bbprivmsgs", $dataArray); 
            $this->id = $this->db->lastInsertId(); 
            
            $data = array(
                'privmsgs_bbcode_uid' => $this->bbcode_uid,
                'privmsgs_text' => $this->body,
                'privmsgs_text_id' => $this->id
            );
            
            $this->db->insert("nuke_bbprivmsgs_text", $data);
            
            return true;
        }
    }
    
    /**
     * Delete a message (hide it from the user)
     * @since Version 3.4
     * @param int $user_id
     * @return boolean
     */
    
    public function delete($user_id = false) {
        if (!$user_id) {
            throw new Exception("Cannot delete message - no user ID given"); 
        }
        
        $data = array(
            "privmsgs_id" => $this->id,
            "user_id" => $user_id
        );
        
        return $this->db->insert("privmsgs_hidelist", $data); 
    }
    
    /**
     * Set the recipient of this message
     * @since Version 3.8.7
     * @param \Railpage\Users\User $User
     * @return $this
     */
    
    public function setRecipient(User $User = NULL) {
        if ($User instanceof User) {
            $this->Recipient = $User;
            
            $this->to_user_id = $this->Recipient->id;
            $this->to_username = $this->Recipient->username;
            $this->to_user_viewonline = $this->Recipient->hide;
            $this->to_user_avatar = $this->Recipient->avatar;
        }
        
        return $this;
    }
    
    /**
     * Set the author of this message
     * @since Version 3.8.7
     * @param \Railpage\Users\User $User
     * @return $this
     */
    
    public function setAuthor(User $User = NULL) {
        if ($User instanceof User) {
            $this->Author = $User;
            
            $this->from_user_id = $this->Author->id;
            $this->from_username = $this->Author->username;
            $this->from_user_viewonline = $this->Author->hide;
            $this->from_user_avatar = $this->Author->avatar;
        }
        
        return $this;
    }
    
    /**
     * Mark this message as read
     * @since Version 3.8.7
     * @return $this
     */
    
    public function markAsRead() {
        $this->type = PRIVMSGS_READ_MAIL;
        $this->commit(); 
        
        return $this;
    }
}