summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorMalf Furious <m@lfurio.us>2017-06-04 22:28:09 -0400
committerMalf Furious <m@lfurio.us>2017-06-04 22:28:09 -0400
commit2376aabe74528b018189982224d61a643325b114 (patch)
tree3aa16bc3dd40b1a7dd1a1f524d71a6c16055e716 /app
parent6b69e5a8f85ebdf92b84e3330bea306d4a90a115 (diff)
parenta8e79321426b1436f46ba5b7c5dee390c94bdb8b (diff)
downloadscrott-2376aabe74528b018189982224d61a643325b114.tar.gz
scrott-2376aabe74528b018189982224d61a643325b114.zip
Merge branch 'feature/mesgs' into dev
Diffstat (limited to 'app')
-rw-r--r--app/class/issue.class.php18
-rw-r--r--app/class/mesg.class.php287
-rw-r--r--app/class/object.class.php18
-rw-r--r--app/df.php16
-rw-r--r--app/dynmic/attach/.gitignore3
5 files changed, 321 insertions, 21 deletions
diff --git a/app/class/issue.class.php b/app/class/issue.class.php
index 3127a87..6056457 100644
--- a/app/class/issue.class.php
+++ b/app/class/issue.class.php
@@ -63,24 +63,6 @@ class issue extends object
}
/*
- * Get all activity for this issue. Messages are sorted by date
- * created.
- */
- public function getMesgs_ordByDatetime() : array
- {
- $query = "SELECT guid FROM objects WHERE objtype = 'mesg' AND " .
- "parent = '" . database::esc($this->guid) . "' ORDER BY created";
- $res = database::query($query);
-
- $mesgs = array();
-
- foreach ($res as $m)
- $mesgs[] = new mesg($m['guid']);
-
- return $mesgs;
- }
-
- /*
* Reset the seen flag and reassign this issue.
*/
public function assignTo(user $assignee) : void
diff --git a/app/class/mesg.class.php b/app/class/mesg.class.php
new file mode 100644
index 0000000..6c84d4f
--- /dev/null
+++ b/app/class/mesg.class.php
@@ -0,0 +1,287 @@
+<?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/object.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 object
+{
+ /*
+ * 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, object $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, object $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;
+ }
+}
+
+?>
diff --git a/app/class/object.class.php b/app/class/object.class.php
index 7c80b5b..461f1b1 100644
--- a/app/class/object.class.php
+++ b/app/class/object.class.php
@@ -163,6 +163,24 @@ class object extends table
}
/*
+ * Get all messages on this object. Messages are sorted by date
+ * created.
+ */
+ public function getMesgs_ordByDatetime() : array
+ {
+ $query = "SELECT guid FROM objects WHERE objtype = 'mesg' AND " .
+ "parent = '" . database::esc($this->guid) . "' ORDER BY created";
+ $res = database::query($query);
+
+ $mesgs = array();
+
+ foreach ($res as $m)
+ $mesgs[] = new mesg($m['guid']);
+
+ return $mesgs;
+ }
+
+ /*
* Get the URL to the head image resource for this object
*/
public function getHeadImg() : string
diff --git a/app/df.php b/app/df.php
index a425d57..3f648ad 100644
--- a/app/df.php
+++ b/app/df.php
@@ -13,6 +13,7 @@
*/
require_once "class/user.class.php";
+require_once "class/mesg.class.php";
/*
* This file is a proxy script for fetching resources from the /dynmic
@@ -31,15 +32,19 @@ require_once "class/user.class.php";
* request. When finished, this function will exit PHP and terminate
* this script.
*/
-function serveResource(string $uri) : void
+function serveResource(string $uri, ?string $filename = NULL) : void
{
$f = fopen($uri, "rb");
if (!$f)
exit;
- header("Content-type: " . mime_content_type($uri));
- header("Content-length: " . filesize($uri));
+ header("Content-Type: " . mime_content_type($uri));
+ header("Content-Length: " . filesize($uri));
+
+ if ($filename)
+ header("Content-Disposition: attachment; filename=\"" . $filename . "\"");
+
fpassthru($f);
fclose($f);
@@ -89,6 +94,11 @@ function main(string $dir, string $guid) : void
case "bgs":
serveResource("dynmic/bgs/" . $guid);
break;
+
+ case "attach":
+ $mesg = new mesg($guid);
+ serveResource("dynmic/attach/" . $guid, $mesg->attachment);
+ break;
}
}
catch (Exception $e)
diff --git a/app/dynmic/attach/.gitignore b/app/dynmic/attach/.gitignore
new file mode 100644
index 0000000..e38384e
--- /dev/null
+++ b/app/dynmic/attach/.gitignore
@@ -0,0 +1,3 @@
+# Track empty directory
+*
+!.gitignore