summaryrefslogblamecommitdiffstats
path: root/app/class/issue.class.php
blob: 47adfa16e85cf84a3411d25cd390fb45423b5c6a (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/stage.class.php";
require_once "class/user.class.php";
require_once "class/mesg.class.php";

/*
 * This class models Scrott issues.  Issues represent units of work, track
 * messages, can be assigned to users, and advance through a pipeline.
 */
class issue extends obj
{
    /*
     * Constructor
     */
    public function __construct(?string $guid = NULL)
    {
        $this->fields['issues'] = array(
            "guid",
            "numb",
            "mesg",
            "closer",
            "closed",
            "due",
            "tags",
        );

        parent::__construct($guid);
        $this->expectType("issue");
    }

    /*
     * Initialize a new issue object with the given message, parent,
     * and owner.  The issue's name is taken from the message's name.
     * The given message object is updated to parent the new issue.
     */
    public static function initNew(mesg $mesg, user $owner, stage $parent) : issue
    {
        $pad = $parent->getParent();
        $numb = $pad->issueNumb++;
        $pad->saveObj();

        $issue = new issue();
        $issue->setOwner($owner);
        $issue->setParent($parent);
        $issue->name = $mesg->name;
        $issue->objtype = "issue";
        $issue->numb = $numb;
        $issue->mesg = $mesg->guid;
        $issue->saveObj();

        $mesg->setParent($issue);

        return $issue;
    }

    /*
     * Get all assignees.  Assignees are returned as an array of
     * stdClass instances.  Objects contain data from the 'assignees'
     * database table with no defined operations.  Pointers to users
     * will be followed and an instanciated user object will be
     * in their place.  Limit of zero returns all assignees.
     */
    public function getAssignees(int $limit = 0) : array
    {
        $assign = array();
        $query = "SELECT * FROM assignees WHERE guid = '" .
            database::esc($this->guid) . "'";

        if ($limit != 0)
            $query .= " LIMIT " . database::esc($limit);

        $res = database::query($query);

        foreach ($res as $a)
        {
            $obj = new stdClass();

            foreach ($a as $k => $v)
                $obj->{$k} = $v;

            $obj->assignee = new user($obj->assignee);
            $obj->assigner = new user($obj->assigner);

            if (isset($obj->dismisser) && $obj->dismisser != "")
                $obj->dismisser = new user($obj->dismisser);

            $assign[] = $obj;
        }

        return $assign;
    }

    /*
     * Add an assignee to this issue.  Returns false if user is
     * already assigned, or if another error occurs; true
     * otherwise.
     */
    public function addAssignee(user $assignee, user $assigner) : bool
    {
        if ($assignee->isAssignedTo($this) || !isset($assignee->guid)
            || !isset($assigner->guid))
            return false;

        $query = "INSERT INTO assignees (guid, assignee, assigner, assigned)" .
            " VALUES ('" . database::esc($this->guid) . "', '" .
            database::esc($assignee->guid) . "', '" . database::esc($assigner->guid) .
            "', '" . database::esc(self::getCurrentTimestamp()) . "')";

        database::query($query);
        return true;
    }

    /*
     * Dismiss an assignee, effectively unassigning them.  Returns
     * false if user is not already an active assignee, or if another
     * error occurs; true otherwise.
     */
    public function dismissAssignee(user $assignee, user $dismisser) : bool
    {
        if (!$assignee->isAssignedTo($this) || !isset($assignee->guid)
            || !isset($dismisser->guid))
            return false;

        $query = "UPDATE assignees SET dismisser = '" . database::esc($dismisser->guid) .
            "', dismissed = '" . database::esc(self::getCurrentTimestamp()) .
            "' WHERE guid = '" . database::esc($this->guid) . "' AND assignee = '" .
            database::esc($assignee->guid) . "'";

        database::query($query);
        return true;
    }

    /*
     * Signoff an assignee's portion of this issue.  Returns false
     * if user is not already an active assignee, or if another
     * error occurs; true otherwise.
     */
    public function signoffAssignee(user $assignee) : bool
    {
        if (!$assignee->isAssignedTo($this) || !isset($assignee->guid))
            return false;

        $query = "UPDATE assignees SET signedoff = '" .
            database::esc(self::getCurrentTimestamp()) . "' WHERE guid = '" .
            database::esc($this->guid) . "' AND assignee = '" .
            database::esc($assignee->guid) . "'";

        database::query($query);
        return true;
    }

    /*
     * Get the OP message for this issue.
     */
    public function getOPMesg() : mesg
    {
        return new mesg($this->mesg);
    }

    /*
     * Get all messages on this issue.  The OP message is filtered
     * from results.  Messages are sorted by date created.
     */
    public function getMesgs_ordByDatetime() : array
    {
        $mesgs = parent::getMesgs_ordByDatetime();
        $i = -1;

        foreach ($mesgs as $k => $m)
        {
            if ($m->guid == $this->mesg)
            {
                $i = $k;
                break;
            }
        }

        if ($i != -1)
        {
            unset($mesgs[$i]);
            $mesgs = array_values($mesgs);
        }

        return $mesgs;
    }

    /*
     * Get the user that closed this issue.  If the issue is still
     * open, NULL is returned.
     */
    public function getCloser() : ?user
    {
        if (!isset($this->closer) || $this->closer == "")
            return NULL;

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

    /*
     * Get the pad this issue exists under
     */
    public function getPad() : pad
    {
        $parent = $this->getParent();

        if ($parent->objtype == "pad")
            return $parent;

        return $parent->getParent();
    }

    /*
     * Advance this issue in the pipeline, closing it if already in the
     * last stage.  A closer is needed incase a close takes place.
     */
    public function advance(user $closer) : void
    {
        $stage = $this->getParent();

        if ($stage->objtype != "stage")
            return;

        if (!($next = $stage->getNext()))
            $this->close($closer);
        else
            $this->setParent($next);
    }

    /*
     * Mark this issue as completed and closed.
     */
    public function close(user $closer) : void
    {
        $pad = $this->getParent()->getParent();

        if ($pad)
        {
            $this->closer = $closer->guid;
            $this->closed = self::getCurrentTimestamp();
            $this->setParent($pad);
        }
    }

    /*
     * Check whether issue is currently open or closed.
     */
    public function isOpen() : bool
    {
        return self::typeOf($this->parent) != "pad";
    }
}

?>