diff options
author | Malf Furious <m@lfurio.us> | 2018-11-10 23:21:39 -0500 |
---|---|---|
committer | Malf Furious <m@lfurio.us> | 2018-11-10 23:21:39 -0500 |
commit | f3165d28fff6468fca44ff2ec3b6cfb3fb82ee90 (patch) | |
tree | a8edb746f0a21d9e7ad134ba79be8278ecce147e | |
parent | 0421aa1b60f4fe6bf140888159c58059c1013588 (diff) | |
parent | 295ba9fce85a959b04db4ac74b4ee378b42e6153 (diff) | |
download | scrott-0.2.tar.gz scrott-0.2.zip |
Merge branch 'rel/v0.2'v0.2
-rw-r--r-- | README.txt | 12 | ||||
-rw-r--r-- | app/class/agent.class.php | 7 | ||||
-rw-r--r-- | app/class/globals.php | 2 | ||||
-rw-r--r-- | app/class/group.class.php | 11 | ||||
-rw-r--r-- | app/class/image.php | 18 | ||||
-rw-r--r-- | app/class/obj.class.php | 3 | ||||
-rw-r--r-- | app/class/pad.class.php | 18 | ||||
-rw-r--r-- | app/class/user.class.php | 9 | ||||
-rw-r--r-- | app/index.php | 6 | ||||
-rw-r--r-- | app/model/issue.php | 66 | ||||
-rw-r--r-- | app/model/pad.php | 2 | ||||
-rw-r--r-- | app/view/datalsts.php | 4 | ||||
-rw-r--r-- | app/view/issue.php | 66 | ||||
-rw-r--r-- | app/view/pad.php | 12 | ||||
-rw-r--r-- | app/view/pad_closed.php | 68 |
15 files changed, 263 insertions, 41 deletions
@@ -3,12 +3,14 @@ SCROTT - The Secure Centralized Robust Online Ticketing Tool This is the alpha version of Scrott, which is currently only a very simplistic and generic issue tracker, supporting multiple users and project boards (called -'pads'). The alpha will constitute the v0.1.x series of releases. Expect some -upcoming quality-of-life changes to the alpha, as well as bug fixes. +'pads'). -The v0.2 series of releases and on are reserved for the beta, which I am -planning a full rewrite for soon. This progress can be tracked on the 'dev' -source branch. +Development on the beta version has begun. I have planned a full rewrite and +will be introducing some design changes to a few core components of Scrott. +Follow development on the 'dev' source branch. + +In the meantime, expect the alpha to receive no more than bug fixes and, perhaps, +only small features as updates. INSTALLATION diff --git a/app/class/agent.class.php b/app/class/agent.class.php index 4c75f0b..4651a10 100644 --- a/app/class/agent.class.php +++ b/app/class/agent.class.php @@ -90,6 +90,13 @@ abstract class agent extends obj } /* + * Get all contained users. For users, this is an array containing + * only $this. For groups, this is an array containing the owner + * and all members. + */ + public abstract function getContainedUsers() : array; + + /* * Send an email message to this agent using stored configuration * parameters. If config is not established, delivery is not * attempted. Return status. diff --git a/app/class/globals.php b/app/class/globals.php index 74635d7..8a6efd7 100644 --- a/app/class/globals.php +++ b/app/class/globals.php @@ -19,7 +19,7 @@ require_once "class/obj.class.php"; * These are utility functions and constants for the Scrott application. */ -define("__VERSION__", "v0.1"); +define("__VERSION__", "v0.2"); /* * These global variables are arrays of strings logged by Scrott business diff --git a/app/class/group.class.php b/app/class/group.class.php index 1191d71..600fb6d 100644 --- a/app/class/group.class.php +++ b/app/class/group.class.php @@ -64,6 +64,17 @@ class group extends agent } /* + * Get all contained users. This is an array of all members and + * the group owner. + */ + public function getContainedUsers() : array + { + $cus = $this->getMembers(); + $cus[] = $this->getOwner(); + return $cus; + } + + /* * Send an email message to this group using stored configuration * parameters. If config is not established, delivery is not * attempted. Return status. If any delivery attempts fail, the diff --git a/app/class/image.php b/app/class/image.php index 6b73cae..62999aa 100644 --- a/app/class/image.php +++ b/app/class/image.php @@ -20,13 +20,19 @@ /* * Mappings from image MIME types to PHP open/write functions */ -$_IMG_OPEN_FUNCS['image/jpeg'] = "imagecreatefromjpeg"; -$_IMG_OPEN_FUNCS['image/jpg'] = "imagecreatefromjpeg"; -$_IMG_OPEN_FUNCS['image/png'] = "imagecreatefrompng"; +$_IMG_OPEN_FUNCS['image/jpeg'] = "imagecreatefromjpeg"; +$_IMG_OPEN_FUNCS['image/jpg'] = "imagecreatefromjpeg"; +$_IMG_OPEN_FUNCS['image/png'] = "imagecreatefrompng"; +$_IMG_OPEN_FUNCS['image/gif'] = "imagecreatefromgif"; +$_IMG_OPEN_FUNCS['image/bmp'] = "imagecreatefrombmp"; +$_IMG_OPEN_FUNCS['image/x-ms-bmp'] = "imagecreatefrombmp"; -$_IMG_WRITE_FUNCS['image/jpeg'] = "imagejpeg"; -$_IMG_WRITE_FUNCS['image/jpg'] = "imagejpeg"; -$_IMG_WRITE_FUNCS['image/png'] = "imagepng"; +$_IMG_WRITE_FUNCS['image/jpeg'] = "imagejpeg"; +$_IMG_WRITE_FUNCS['image/jpg'] = "imagejpeg"; +$_IMG_WRITE_FUNCS['image/png'] = "imagepng"; +$_IMG_WRITE_FUNCS['image/gif'] = "imagegif"; +$_IMG_WRITE_FUNCS['image/bmp'] = "imagebmp"; +$_IMG_WRITE_FUNCS['image/x-ms-bmp'] = "imagebmp"; /* * Open the given image and crop it, such that the result is a square diff --git a/app/class/obj.class.php b/app/class/obj.class.php index 850184c..353d617 100644 --- a/app/class/obj.class.php +++ b/app/class/obj.class.php @@ -30,6 +30,9 @@ class obj extends table "image/jpeg", "image/jpg", "image/png", + "image/gif", + "image/bmp", + "image/x-ms-bmp", ); /* diff --git a/app/class/pad.class.php b/app/class/pad.class.php index dcf2b32..0c69385 100644 --- a/app/class/pad.class.php +++ b/app/class/pad.class.php @@ -108,6 +108,24 @@ class pad extends obj $stage->saveObj(); $this->saveObj(); } + + /* + * Get an array of all closed issues under this pad. Ordered by + * datetime closed. + */ + public function getClosedIssues_ordByClosed() : array + { + $query = "SELECT o.guid FROM objects o JOIN issues i ON o.guid = i.guid " . + "WHERE o.parent = '" . database::esc($this->guid) . "' ORDER BY i.closed DESC"; + $res = database::query($query); + + $issues = array(); + + foreach ($res as $i) + $issues[] = new issue($i['guid']); + + return $issues; + } } ?> diff --git a/app/class/user.class.php b/app/class/user.class.php index 90aac44..231111d 100644 --- a/app/class/user.class.php +++ b/app/class/user.class.php @@ -294,6 +294,15 @@ class user extends agent } /* + * Get all contained users. This is just an array containing + * the user object. + */ + public function getContainedUsers() : array + { + return array($this); + } + + /* * Send an email message to this user using stored configuration * parameters. If config is not established, delivery is not * attempted. Return status. diff --git a/app/index.php b/app/index.php index 21f3036..7f05479 100644 --- a/app/index.php +++ b/app/index.php @@ -111,7 +111,10 @@ function main(array $argv) : void $obj = new pad($argv[0]); setPageObj($obj); setPageName($obj->name); - require "view/pad.php"; + if (isset($argv[1]) && $argv[1] == "closed") + require "view/pad_closed.php"; + else + require "view/pad.php"; break; } } @@ -119,6 +122,7 @@ function main(array $argv) : void /* page not found */ else { + header("HTTP/1.1 404 Not Found"); require "view/404.php"; } } diff --git a/app/model/issue.php b/app/model/issue.php index 4300bbb..7159015 100644 --- a/app/model/issue.php +++ b/app/model/issue.php @@ -23,7 +23,8 @@ if (isAction("iss-mesg-add")) { $form = new form(); $form->text("issue"); - $form->text("mesg"); + $form->text("mesg", false); + $form->text("assignee"); if (!$form->populate(input())) return; @@ -36,22 +37,69 @@ if (isAction("iss-mesg-add")) return; } - if (!$user->canCreateSub($issue)) + if (isset($form->mesg) && $form->mesg != "") { - logError(ERROR, "You do not have permission to post to this issue"); - return; + if (!$user->canCreateSub($issue)) + { + logError(ERROR, "You do not have permission to post to this issue"); + return; + } + + $mesg = mesg::initNew($form->mesg, $user, $issue); + + if ($mesg->setAttachment("attachment")) + logError(NOTICE, "Saved attachment " . $mesg->attachment); + } + + if (isset(input()['advIssue'])) + { + if (!$user->canModify($issue)) + { + logError(ERROR, "You do not have permission to move this issue"); + return; + } + + $issue->advance($user); + + if ($issue->isOpen()) + { + $sgename = $issue->getParent()->name; + $log = mesg::initNewLog("%s advanced issue to '" . $sgename . "'", $user, $issue); + } + else + { + $log = mesg::initNewLog("%s closed issue", $user, $issue); + } } - $mesg = mesg::initNew($form->mesg, $user, $issue); + else if (isset(input()['assIssue'])) + { + if (!$user->canModify($issue)) + { + logError(ERROR, "You do not have permission to assign this issue"); + return; + } + + $assignee = new user($form->assignee); + $stat = $issue->addAssignee($assignee, $user); - if ($mesg->setAttachment("attachment")) - logError(NOTICE, "Saved attachment " . $mesg->attachment); + if (!$stat) + logError(ERROR, "Failed to assign issue"); + else + $log = mesg::initNewLog("%s assigned " . $assignee->getDisplayName(), $user, $issue); + } - if (isset(input()['closeIssue'])) + else if (isset(input()['closeIssue'])) { + if (!$user->canModify($issue)) + { + logError(ERROR, "You do not have permission to close this issue"); + return; + } + $issue->close($user); logError(NOTICE, "Issue #" . $issue->numb . " closed"); - $log = mesg::initNewLog("% closed issue", $user, $issue); + $log = mesg::initNewLog("%s closed issue", $user, $issue); } } diff --git a/app/model/pad.php b/app/model/pad.php index d7cfb23..0090c27 100644 --- a/app/model/pad.php +++ b/app/model/pad.php @@ -26,4 +26,6 @@ foreach ($stages as $s) $issues = array_merge($issues, $i); } +$closed_issues = $pad->getClosedIssues_ordByClosed(); + ?> diff --git a/app/view/datalsts.php b/app/view/datalsts.php index 2bbb44e..ba9021b 100644 --- a/app/view/datalsts.php +++ b/app/view/datalsts.php @@ -118,6 +118,10 @@ require_once "class/issue.class.php"; <div class="panel panel-default"> <h2 class="text-center"><?=$s->name?></h2> + <?php if (count($s->getIssues_ordByDueByNumb()) == 0) { ?> + <h4 class="text-info text-center">No issues</h4> + <?php } ?> + <table class="table table-hover"> <?php foreach ($s->getIssues_ordByDueByNumb() as $i) { ?> <?=issueListItem($i)?> diff --git a/app/view/issue.php b/app/view/issue.php index 2d781ba..01a9f5f 100644 --- a/app/view/issue.php +++ b/app/view/issue.php @@ -109,23 +109,57 @@ require_once "class/issue.class.php"; </div> <?php } ?> - <form method="post" action="<?=ap()?>" enctype="multipart/form-data"> - <?=\formctrl\formname( "iss-mesg-add" )?> - <?=\formctrl\hidden( "issue", $i->guid )?> - <?=\formctrl\textarea( "New message", "mesg", 5 )?> - - <div class="btn-group pull-right"> - <button type="submit" name="input[postMesg]" class="btn btn-primary"> - <span class="glyphicon glyphicon-envelope"></span> Post message - </button> - - <button type="submit" name="input[closeIssue]" class="btn btn-success"> - <span class="glyphicon glyphicon-ok"></span> Close issue - </button> - </div> + <?php if ($i->isOpen()) { ?> + <form method="post" action="<?=ap()?>" enctype="multipart/form-data"> + <?=\formctrl\formname( "iss-mesg-add" )?> + <?=\formctrl\hidden( "issue", $i->guid )?> + <?=\formctrl\textarea( "New message", "mesg", 5 )?> + + <div class="btn-group pull-right"> + <button type="submit" name="input[postMesg]" class="btn btn-primary" title="Post message"> + <span class="glyphicon glyphicon-envelope"></span> + </button> + + <button type="submit" name="input[closeIssue]" class="btn btn-default" title="Close issue"> + <span class="glyphicon glyphicon-ok"></span> + </button> + + <button type="submit" name="input[advIssue]" class="btn btn-default" title="Advance issue"> + <span class="glyphicon glyphicon-chevron-up"></span> + </button> + + <button type="button" class="btn btn-default" data-toggle="collapse" data-target="#assignCollapse-<?=$i->guid?>" title="Assign issue"> + <span class="glyphicon glyphicon-share-alt"></span> + </button> + </div> - <?=\formctrl\file( "Attachment", "attachment" )?> - </form> + <div class="collapse" id="assignCollapse-<?=$i->guid?>"> + <div class="form-group"> + <label>Select assignee</label> + + <select name="input[assignee]" class="form-control selectpicker"> + <?php foreach ($i->getParent()->getParent()->getOwner()->getContainedUsers() as $memb) { ?> + <option data-icon="glyphicon-user" value="<?=$memb->guid?>"> + <?=$memb->getDisplayName()?> + </option> + <?php } ?> + + <?php foreach ($i->getParent()->getParent()->getMembers() as $memb) { ?> + <option data-icon="glyphicon-user" value="<?=$memb->guid?>"> + <?=$memb->getDisplayName()?> + </option> + <?php } ?> + </select> + </div> + + <button type="submit" name="input[assIssue]" class="btn btn-default"> + <span class="glyphicon glyphicon-share-alt"></span> Post and assign issue + </button> + </div> + + <?=\formctrl\file( "Attachment", "attachment" )?> + </form> + <?php } ?> </div> <div class="col-md-4"> diff --git a/app/view/pad.php b/app/view/pad.php index a9c8508..bf626bf 100644 --- a/app/view/pad.php +++ b/app/view/pad.php @@ -42,9 +42,15 @@ require_once "view/issue.php"; <span class="glyphicon glyphicon-edit"></span> <?=$pad->name?> - <button type="button" class="btn btn-success" data-toggle="modal" data-target="#newIssueModal"> - <span class="glyphicon glyphicon-plus"></span> Open Issue - </button> + <div class="btn-group"> + <button type="button" class="btn btn-success" data-toggle="modal" data-target="#newIssueModal"> + <span class="glyphicon glyphicon-plus"></span> Open Issue + </button> + + <a href="<?=ap()?>/closed" class="btn btn-default"> + View closed issues + </a> + </div> </h1> </div> </div> diff --git a/app/view/pad_closed.php b/app/view/pad_closed.php new file mode 100644 index 0000000..e11ca84 --- /dev/null +++ b/app/view/pad_closed.php @@ -0,0 +1,68 @@ +<?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 "model/pad.php"; +require_once "view/stdpage.php"; +require_once "view/datalsts.php"; +require_once "view/issue.php"; + +?> + +<!DOCTYPE html> + +<html lang="en"> + <head> + <?=stdpage\head( getPageName() )?> + </head> + + <body> + <?php foreach ($closed_issues as $i) { ?> + <?=issue_v\issue($i)?> + <?php } ?> + + <?=stdpage\top()?> + <?=stdpage\nav()?> + + <div class="container"> + <div class="well well-lg"> + <div class="row"> + <div class="col-md-12"> + <h1> + <span class="glyphicon glyphicon-edit"></span> + <?=$pad->name?> + + <a href="<?=ar()?>/<?=$pad->guid?>" class="btn btn-default"> + View open issues + </a> + </h1> + </div> + </div> + </div> + + <div class="panel panel-default"> + <?php if (count($closed_issues) == 0) { ?> + <h4 class="text-info text-center">No closed issues</h4> + <?php } ?> + + <table class="table table-hover"> + <?php foreach ($closed_issues as $i) { ?> + <?=datalsts\issueListItem($i)?> + <?php } ?> + </table> + </div> + </div> + + <?=stdpage\foot()?> + </body> +</html> |