From 767f0b5559472828c09be7de50c80f017cc0540a Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 00:51:21 -0400 Subject: mesg: Add mesg class --- app/class/mesg.class.php | 249 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 app/class/mesg.class.php (limited to 'app') diff --git a/app/class/mesg.class.php b/app/class/mesg.class.php new file mode 100644 index 0000000..f9766ca --- /dev/null +++ b/app/class/mesg.class.php @@ -0,0 +1,249 @@ +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 (
) + * 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; + return saveFile($file, $path, self::ATTACH_MAXSIZE); + } +} + +?> -- cgit v1.2.3 From 5f50dd6b09f8458b62ce00fda83debca66bd8544 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 13:18:56 -0400 Subject: Add directory for message attachments --- app/dynmic/attach/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/dynmic/attach/.gitignore (limited to 'app') 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 -- cgit v1.2.3 From 138348bbd1318a3bc2ee5112eee44d385b21751e Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 14:45:23 -0400 Subject: Update df function serveResource() Added optional parameter for resource's filename. If given, a Content-Disposition header will be delivered to the client. --- app/df.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/df.php b/app/df.php index a425d57..9581cae 100644 --- a/app/df.php +++ b/app/df.php @@ -31,15 +31,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); -- cgit v1.2.3 From f43bd09b8287e3876b5a7396e6bb263c35e3972a Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 14:59:25 -0400 Subject: Update df script to support message attachments Now, if a mesg guid is requested under attach/, the attachment file is served and offers the browser the content-disposition for that file. --- app/df.php | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'app') diff --git a/app/df.php b/app/df.php index 9581cae..92dd9dd 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 @@ -93,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) -- cgit v1.2.3 From 4ba37714838e1f863c264d6bea7c7de75cd62514 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 15:38:22 -0400 Subject: Define maxsize of attachment uploads Value set to 512 megabytes. --- app/class/mesg.class.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'app') diff --git a/app/class/mesg.class.php b/app/class/mesg.class.php index f9766ca..fd541cd 100644 --- a/app/class/mesg.class.php +++ b/app/class/mesg.class.php @@ -22,6 +22,11 @@ require_once "class/pad.class.php"; */ class mesg extends object { + /* + * Constants used for uploading attachments + */ + public const ATTACH_MAXSIZE = 536870912; // 512Mb + /* * Constructor */ -- cgit v1.2.3 From d677fe73839b22fe2065be5a7f6c49a1b11e8c18 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 15:44:13 -0400 Subject: Update mesg function setAttachment() Now saving the original name of the attachment file in the message object. --- app/class/mesg.class.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/class/mesg.class.php b/app/class/mesg.class.php index fd541cd..5d6ba4d 100644 --- a/app/class/mesg.class.php +++ b/app/class/mesg.class.php @@ -247,7 +247,13 @@ class mesg extends object public function setAttachment(array $file) : bool { $path = "dynmic/attach/" . $this->guid; - return saveFile($file, $path, self::ATTACH_MAXSIZE); + $origName = ""; + + $ret = saveFile($file, $path, self::ATTACH_MAXSIZE, NULL, $origName); + $this->attachment = $origName; + $this->saveObj(); + + return $ret; } } -- cgit v1.2.3 From d52b67bbc212f85cc6e80e107029bda4d4445b94 Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 18:03:16 -0400 Subject: Fix bug in function serveResource() It is necessary to use double-quotes in the Content-Disposition header. --- app/df.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/df.php b/app/df.php index 92dd9dd..3f648ad 100644 --- a/app/df.php +++ b/app/df.php @@ -43,7 +43,7 @@ function serveResource(string $uri, ?string $filename = NULL) : void header("Content-Length: " . filesize($uri)); if ($filename) - header("Content-Disposition: attachment; filename='" . $filename . "'"); + header("Content-Disposition: attachment; filename=\"" . $filename . "\""); fpassthru($f); fclose($f); -- cgit v1.2.3 From 8e9beac9888e894c8db46401b0d5b4c4cb18407d Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 20:25:35 -0400 Subject: Add mesg function makeIssue() This feature allows a pad-level discussion to be promoted to an issue. A new object is created, but all content is preserved. However, if the thread OP message had an attachment, that attachment cannot be retained. --- app/class/mesg.class.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'app') diff --git a/app/class/mesg.class.php b/app/class/mesg.class.php index 5d6ba4d..6c84d4f 100644 --- a/app/class/mesg.class.php +++ b/app/class/mesg.class.php @@ -15,6 +15,8 @@ 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, @@ -255,6 +257,31 @@ class mesg extends object 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; + } } ?> -- cgit v1.2.3 From a8e79321426b1436f46ba5b7c5dee390c94bdb8b Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Sun, 4 Jun 2017 20:57:12 -0400 Subject: Move function getMesgs() into object class This function is needed in the scope of issue, mesgs, and pads alike. It would also make sense to use this to retrive users' private messages. For these reasons, this function is now being defined higher up in the object hierarchy. --- app/class/issue.class.php | 18 ------------------ app/class/object.class.php | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'app') 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 @@ -62,24 +62,6 @@ class issue extends object return $issue; } - /* - * 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. */ 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 @@ -162,6 +162,24 @@ class object extends table return true; } + /* + * 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 */ -- cgit v1.2.3