summaryrefslogblamecommitdiffstats
path: root/app/class/mesg.class.php
blob: 1a864c08f6b5827643f3df5d24a76cc76c4e1999 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14













                                                                         
                                   

                                    

                                     




                                                                        
                      

      




                                                     

























                                                     
                                                                                     
















































                                                                                         
                                                                                        













































































































































                                                                                           






                                                                             
     
























                                                                         














                                                                            

                                      




                                  
                                                                                                          















                                                                                                        
                                        

                                                                                                    
                                                                                       

                                                                                              


                             
                                                                             




                             


  
<?php

/*
 * SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * For more information, please refer to UNLICENSE
 */

require_once "class/obj.class.php";
require_once "class/user.class.php";
require_once "class/pad.class.php";
require_once "class/stage.class.php";
require_once "class/issue.class.php";

/*
 * This class models issue activity, private messaging, pad discussions,
 * and system and object log messages.
 */
class mesg extends obj
{
    /*
     * Constants used for uploading attachments
     */
    public const ATTACH_MAXSIZE = 536870912; // 512Mb

    /*
     * Constructor
     */
    public function __construct(?string $guid = NULL)
    {
        $this->fields['mesgs'] = array(
            "guid",
            "author",
            "mesg",
            "attachment",
        );

        parent::__construct($guid);

        try
        {
            $this->expectType("log");
        }
        catch (Exception $e)
        {
            $this->expectType("mesg");
        }
    }

    /*
     * Initialize a new regular message.
     */
    public static function initNew(string $message, user $author, obj $parent) : mesg
    {
        $mesg = new mesg();
        $mesg->setOwner($author);
        $mesg->setParent($parent);
        $mesg->name = "message " . $mesg->guid;
        $mesg->objtype = "mesg";
        $mesg->setAuthor($author);
        $mesg->mesg = $message;
        $mesg->saveObj();
        return $mesg;
    }

    /*
     * Initialize a new pad discussion thread.
     */
    public static function initNewDiscussion(string $name, string $message, user $author,
        pad $parent) : mesg
    {
        $mesg = new mesg();
        $mesg->setOwner($author);
        $mesg->setParent($parent);
        $mesg->name = $name;
        $mesg->objtype = "mesg";
        $mesg->setAuthor($author);
        $mesg->mesg = $message;
        $mesg->saveObj();
        return $mesg;
    }

    /*
     * Initialize a new private message (user-to-user).
     */
    public static function initNewPM(string $name, string $message, user $author,
        user $rcpt) : mesg
    {
        $mesg = new mesg();
        $mesg->setOwner($rcpt);
        $mesg->setParent($rcpt);
        $mesg->name = $name;
        $mesg->objtype = "mesg";
        $mesg->setAuthor($author);
        $mesg->mesg = $message;
        $mesg->saveObj();
        return $mesg;
    }

    /*
     * Initialize a new log message.
     */
    public static function initNewLog(string $message, user $author, obj $parent) : mesg
    {
        $owner = $parent->getOwner();

        if (!$owner)
            $owner = $parent;

        $mesg = new mesg();
        $mesg->setOwner($owner);
        $mesg->setParent($parent);
        $mesg->name = "log " . $mesg->guid;
        $mesg->objtype = "log";
        $mesg->setAuthor($author);
        $mesg->mesg = $message;
        $mesg->saveObj();
        return $mesg;
    }

    /*
     * Initialize a new admin log message.
     */
    public static function initNewAdminLog(string $message, user $author) : mesg
    {
        $mesg = new mesg();
        $mesg->saveObj(); // need to get a guid
        $mesg->name = "admin log " . $mesg->guid;
        $mesg->objtype = "log";
        $mesg->setAuthor($author);
        $mesg->mesg = $message;
        $mesg->saveObj();
        return $mesg;
    }

    /*
     * Get an array of messages in the admin log, between two timestamps.
     * With no arguments, the entire log is returned.  Results are sorted
     * in reverse chronological order.
     */
    public static function getAdminLog_ordByDatetime(?string $after = NULL,
        ?string $before = NULL) : array
    {
        $query = "SELECT guid FROM objects WHERE objtype = 'log' AND " .
            "parent = '' ";

        if ($after)
            $query += "AND created >= '" . database::esc($after) . "' ";

        if ($before)
            $query += "AND created < '" . database::esc($before) . "' ";

        $query += "ORDER BY created DESC";
        $res = database::query($query);

        $log = array();

        foreach ($res as $l)
            $log[] = new mesg($l['guid']);

        return $log;
    }

    /*
     * Get the author of this message.  This user either actually wrote
     * this message, or caused it to be generated.
     */
    public function getAuthor() : user
    {
        if (!isset($this->author) || $this->author == "")
            return NULL;

        return new user($this->author);
    }

    /*
     * Set the author of this message.  This should usually only be done
     * while constructing a new message or to clear out references to
     * a user that got removed.
     */
    public function setAuthor(user $author) : void
    {
        $this->author = $author->guid;
        $this->saveObj();
    }

    /*
     * Check whether this message has been seen by the given user
     */
    public function seenBy(user $viewer) : bool
    {
        $query = "SELECT * FROM views WHERE guid = '" . database::esc($this->guid) . "' " .
            "AND viewer = '" . database::esc($viewer->guid) . "'";
        $res = database::query($query);

        return count($res) > 0;
    }

    /*
     * Mark this message as seen by the given user
     */
    public function markSeen(user $viewer) : void
    {
        if (!$this->seenBy($viewer))
        {
            $query = "INSERT INTO views (guid, viewer) VALUES ('" .
                database::esc($this->guid) . "', '" . database::esc($viewer->guid) . "')";
            database::query($query);
        }
    }

    /*
     * Format message (if auto generated), and insert HTML linebreaks (<br />)
     * at message newlines.
     */
    public function renderMesg() : string
    {
        if ($this->objtype == "log")
            $mesg = sprintf($this->mesg, $this->getAuthor()->getDisplayName());
        else
            $mesg = $this->mesg;

        return nl2br($mesg);
    }

    /*
     * Get the URL to this message's attachment.  If no file is attached,
     * NULL is returned.
     */
    public function getAttachment() : ?string
    {
        if (!is_file("dynmic/attach/" . $this->guid))
            return NULL;

        return ar() . "/df.php?d=attach&f=" . $this->guid;
    }

    /*
     * Set the attached file for this message.  Should typically be done
     * during new message creation and not changed afterward.  Returns
     * false if there is a problem saving the attachment.
     */
    public function setAttachment(array $file) : bool
    {
        $path = "dynmic/attach/" . $this->guid;
        $origName = "";

        $ret = saveFile($file, $path, self::ATTACH_MAXSIZE, NULL, $origName);
        $this->attachment = $origName;
        $this->saveObj();

        return $ret;
    }

    /*
     * Promote a pad discussion thread to an issue.  This message object
     * must be the top-level message (op) of the discussion thread (ie:
     * its parent must be a pad).  All reply messages to this one are
     * retained and will be messages left on the new issue.  A new issue
     * object is created and this message object will be destroyed.  If
     * this is not an eligible message for promotion, NULL is returned.
     */
    public function makeIssue(stage $parent) : ?issue
    {
        if ($this->getParent()->objtype != "pad")
            return NULL;

        $issue = issue::initNew($this->name, $this->getOwner(), $parent);
        $issue->created = $this->created;
        $issue->description = $this->mesg;
        $issue->saveObj();

        foreach ($this->getMesgs_ordByDatetime() as $mesg)
            $mesg->setParent($issue);

        $this->delObj();
        return $issue;
    }

    /*
     * Email this message to parents, owners, members.  In the case that
     * this is an issue message or a reply message, the assignee or original
     * author is also included.  Attachments are included in mailing.  Any
     * duplicates in the rcpt list are removed before sending.  Success
     * or failure is returned.
     */
    public function emailMesg() : bool
    {
        $parent = $this->getParent();

        if (!$parent)
            return true;

        $rcpt = $parent->getMembers();
        $rcpt[] = $parent->getOwner();

        switch ($parent->objtype)
        {
            case "user":
                $rcpt[] = $parent;
                $subj = $this->author . " " . $this->getAuthor()->getDisplayName() . " // " . $this->name;
                break;

            case "issue":
                $rcpt[] = $parent->getAssignee();
                $pad = $parent->getPad();
                $subj = $parent->guid . " " . $pad->name . " [#" . $parent->numb . "] " . $parent->name;
                break;

            case "mesg":
            case "log":
                $rcpt[] = $parent->getAuthor();
                $pad = $parent->getParent();
                $subj = $parent->guid . " " . $pad->name . " // " . $parent->name;
                break;
        }

        $rcpt = obj::arrayUnique($rcpt);
        $author = $this->author;
        $rcpt = array_filter($rcpt, function ($val) use($author) { return $val->guid != $author; });
        $attachPath = ($this->getAttachment() ? "dynmic/attach/" . $this->guid : NULL);
        $mesg = $this->getAuthor()->getDisplayName() . " wrote on " . $this->created . "\n\n";
        $mesg .= $this->renderMesg();

        foreach ($rcpt as $r)
        {
            if (!$r->sendEmail($subj, $mesg, $attachPath, $this->attachment))
                return false;
        }

        return true;
    }
}

?>