From 69445222f7d9461518e0f295ad05cfa5631b9a48 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 22 Aug 2011 10:25:45 -0700 Subject: [PATCH] Track content sources (email, web, conduit, mobile) for replies Summary: When an object is updated, record the content source for the update. This mostly isn't terribly useful but one concrete thing I want to do with it is let admins audit via-email replies more easily since there are a bunch of options which let you do hyjinx if you intentionally configure them insecurely. I think having a little more auditability around this feature is generally good. At some point I'm going to turn this into a link admins can click to see details. It also allows us to see how frequently different mechanisms are used, and lets you see if someone is at their desk or on a mobile or whatever, at least indirectly. The "tablet" and "mobile" sources are currently unused but I figured I'd throw them in anyway. SMS support should definitely happen at some point. Not 100% sure about the design for this, I might change it to plain text at some point. Test Plan: Updated objects and saw update sources rendered. Reviewers: jungejason, tuomaspelkonen, aran Reviewed By: jungejason CC: aran, epriestley, jungejason Differential Revision: 844 --- resources/sql/patches/071.contentsource.sql | 5 ++ src/__celerity_resource_map__.php | 31 +++++--- src/__phutil_library_map__.php | 3 + src/aphront/request/AphrontRequest.php | 4 + ...API_differential_updaterevision_Method.php | 5 ++ .../differential/updaterevision/__init__.php | 1 + ...ConduitAPI_maniphest_createtask_Method.php | 5 ++ .../method/maniphest/createtask/__init__.php | 1 + .../DifferentialCommentSaveController.php | 7 ++ .../controller/commentsave/__init__.php | 1 + .../comment/DifferentialCommentEditor.php | 15 +++- .../revision/DifferentialRevisionEditor.php | 11 +++ .../replyhandler/DifferentialReplyHandler.php | 6 ++ .../differential/replyhandler/__init__.php | 1 + .../storage/comment/DifferentialComment.php | 10 +++ .../differential/storage/comment/__init__.php | 1 + .../DifferentialRevisionCommentView.php | 12 ++- .../view/revisioncomment/__init__.php | 1 + .../taskedit/ManiphestTaskEditController.php | 7 ++ .../controller/taskedit/__init__.php | 1 + .../ManiphestTransactionSaveController.php | 10 +++ .../controller/transactionsave/__init__.php | 1 + .../replyhandler/ManiphestReplyHandler.php | 7 ++ .../maniphest/replyhandler/__init__.php | 1 + .../transaction/ManiphestTransaction.php | 9 +++ .../storage/transaction/__init__.php | 1 + .../ManiphestTransactionDetailView.php | 10 ++- .../view/transactiondetail/__init__.php | 1 + .../source/PhabricatorContentSource.php | 75 ++++++++++++++++++ .../metamta/contentsource/source/__init__.php | 12 +++ .../view/PhabricatorContentSourceView.php | 64 +++++++++++++++ .../metamta/contentsource/view/__init__.php | 17 ++++ .../contentsource/content-source-view.css | 32 ++++++++ webroot/rsrc/image/icon/fatcow/README | 8 +- .../rsrc/image/icon/fatcow/source/conduit.png | Bin 0 -> 770 bytes .../rsrc/image/icon/fatcow/source/email.png | Bin 0 -> 505 bytes .../rsrc/image/icon/fatcow/source/mobile.png | Bin 0 -> 527 bytes .../rsrc/image/icon/fatcow/source/tablet.png | Bin 0 -> 523 bytes webroot/rsrc/image/icon/fatcow/source/web.png | Bin 0 -> 822 bytes 39 files changed, 358 insertions(+), 18 deletions(-) create mode 100644 resources/sql/patches/071.contentsource.sql create mode 100644 src/applications/metamta/contentsource/source/PhabricatorContentSource.php create mode 100644 src/applications/metamta/contentsource/source/__init__.php create mode 100644 src/applications/metamta/contentsource/view/PhabricatorContentSourceView.php create mode 100644 src/applications/metamta/contentsource/view/__init__.php create mode 100644 webroot/rsrc/css/application/contentsource/content-source-view.css create mode 100644 webroot/rsrc/image/icon/fatcow/source/conduit.png create mode 100644 webroot/rsrc/image/icon/fatcow/source/email.png create mode 100644 webroot/rsrc/image/icon/fatcow/source/mobile.png create mode 100644 webroot/rsrc/image/icon/fatcow/source/tablet.png create mode 100644 webroot/rsrc/image/icon/fatcow/source/web.png diff --git a/resources/sql/patches/071.contentsource.sql b/resources/sql/patches/071.contentsource.sql new file mode 100644 index 0000000000..eae1b7a608 --- /dev/null +++ b/resources/sql/patches/071.contentsource.sql @@ -0,0 +1,5 @@ +ALTER TABLE phabricator_differential.differential_comment + ADD contentSource VARCHAR(255); + +ALTER TABLE phabricator_maniphest.maniphest_transaction + ADD contentSource VARCHAR(255); diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 7ea524bddd..2d93ef3825 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -643,6 +643,17 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/maniphest/behavior-transaction-preview.js', ), + 0 => + array( + 'uri' => '/res/1da00bfe/rsrc/js/javelin/lib/__tests__/URI.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-uri', + 1 => 'javelin-php-serializer', + ), + 'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js', + ), 'javelin-behavior-owners-path-editor' => array( 'uri' => '/res/9cf78ffc/rsrc/js/application/owners/owners-path-editor.js', @@ -725,17 +736,6 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/projects/projects-resource-editor.js', ), - 0 => - array( - 'uri' => '/res/1da00bfe/rsrc/js/javelin/lib/__tests__/URI.js', - 'type' => 'js', - 'requires' => - array( - 0 => 'javelin-uri', - 1 => 'javelin-php-serializer', - ), - 'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js', - ), 'javelin-behavior-refresh-csrf' => array( 'uri' => '/res/88beba4c/rsrc/js/application/core/behavior-refresh-csrf.js', @@ -1169,6 +1169,15 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/herald/PathTypeahead.js', ), + 'phabricator-content-source-view-css' => + array( + 'uri' => '/res/7147f14c/rsrc/css/application/contentsource/content-source-view.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/contentsource/content-source-view.css', + ), 'phabricator-core-buttons-css' => array( 'uri' => '/res/3059cf79/rsrc/css/core/buttons.css', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e30db127a6..ed33b347be 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -344,6 +344,8 @@ phutil_register_library_map(array( 'PhabricatorConduitLogController' => 'applications/conduit/controller/log', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog', 'PhabricatorConduitTokenController' => 'applications/conduit/controller/token', + 'PhabricatorContentSource' => 'applications/metamta/contentsource/source', + 'PhabricatorContentSourceView' => 'applications/metamta/contentsource/view', 'PhabricatorController' => 'applications/base/controller/base', 'PhabricatorCountdownController' => 'applications/countdown/controller/base', 'PhabricatorCountdownDAO' => 'applications/countdown/storage/base', @@ -951,6 +953,7 @@ phutil_register_library_map(array( 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitTokenController' => 'PhabricatorConduitController', + 'PhabricatorContentSourceView' => 'AphrontView', 'PhabricatorController' => 'AphrontController', 'PhabricatorCountdownController' => 'PhabricatorController', 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', diff --git a/src/aphront/request/AphrontRequest.php b/src/aphront/request/AphrontRequest.php index 09250a4875..25eb1fb677 100644 --- a/src/aphront/request/AphrontRequest.php +++ b/src/aphront/request/AphrontRequest.php @@ -252,4 +252,8 @@ class AphrontRequest { return $this->isFormPost() && $this->getStr('__dialog__'); } + final public function getRemoteAddr() { + return $_SERVER['REMOTE_ADDR']; + } + } diff --git a/src/applications/conduit/method/differential/updaterevision/ConduitAPI_differential_updaterevision_Method.php b/src/applications/conduit/method/differential/updaterevision/ConduitAPI_differential_updaterevision_Method.php index 428d5ee97b..f123ed3146 100644 --- a/src/applications/conduit/method/differential/updaterevision/ConduitAPI_differential_updaterevision_Method.php +++ b/src/applications/conduit/method/differential/updaterevision/ConduitAPI_differential_updaterevision_Method.php @@ -66,9 +66,14 @@ class ConduitAPI_differential_updaterevision_Method extends ConduitAPIMethod { throw new ConduitException('ERR_COMMITTED'); } + $content_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_CONDUIT, + array()); + $editor = new DifferentialRevisionEditor( $revision, $revision->getAuthorPHID()); + $editor->setContentSource($content_source); $fields = $request->getValue('fields'); $editor->copyFieldsFromConduit($fields); diff --git a/src/applications/conduit/method/differential/updaterevision/__init__.php b/src/applications/conduit/method/differential/updaterevision/__init__.php index 96f0fe8ce3..e139660974 100644 --- a/src/applications/conduit/method/differential/updaterevision/__init__.php +++ b/src/applications/conduit/method/differential/updaterevision/__init__.php @@ -12,6 +12,7 @@ phutil_require_module('phabricator', 'applications/differential/constants/revisi phutil_require_module('phabricator', 'applications/differential/editor/revision'); phutil_require_module('phabricator', 'applications/differential/storage/diff'); phutil_require_module('phabricator', 'applications/differential/storage/revision'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_module('phabricator', 'infrastructure/env'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/conduit/method/maniphest/createtask/ConduitAPI_maniphest_createtask_Method.php b/src/applications/conduit/method/maniphest/createtask/ConduitAPI_maniphest_createtask_Method.php index 567b16692c..985eccd0a5 100644 --- a/src/applications/conduit/method/maniphest/createtask/ConduitAPI_maniphest_createtask_Method.php +++ b/src/applications/conduit/method/maniphest/createtask/ConduitAPI_maniphest_createtask_Method.php @@ -87,7 +87,12 @@ final class ConduitAPI_maniphest_createtask_Method ); } + $content_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_CONDUIT, + array()); + $template = new ManiphestTransaction(); + $template->setContentSource($content_source); $template->setAuthorPHID($request->getUser()->getPHID()); $transactions = array(); diff --git a/src/applications/conduit/method/maniphest/createtask/__init__.php b/src/applications/conduit/method/maniphest/createtask/__init__.php index 26dcd306c8..06390dfb64 100644 --- a/src/applications/conduit/method/maniphest/createtask/__init__.php +++ b/src/applications/conduit/method/maniphest/createtask/__init__.php @@ -13,6 +13,7 @@ phutil_require_module('phabricator', 'applications/maniphest/constants/transacti phutil_require_module('phabricator', 'applications/maniphest/editor/transaction'); phutil_require_module('phabricator', 'applications/maniphest/storage/task'); phutil_require_module('phabricator', 'applications/maniphest/storage/transaction'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_module('phabricator', 'applications/phid/constants'); diff --git a/src/applications/differential/controller/commentsave/DifferentialCommentSaveController.php b/src/applications/differential/controller/commentsave/DifferentialCommentSaveController.php index 6355d44240..9f589951c9 100644 --- a/src/applications/differential/controller/commentsave/DifferentialCommentSaveController.php +++ b/src/applications/differential/controller/commentsave/DifferentialCommentSaveController.php @@ -40,8 +40,15 @@ class DifferentialCommentSaveController extends DifferentialController { $request->getUser()->getPHID(), $action); + $content_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_WEB, + array( + 'ip' => $request->getRemoteAddr(), + )); + $editor ->setMessage($comment) + ->setContentSource($content_source) ->setAttachInlineComments(true) ->setAddCC($action != DifferentialAction::ACTION_RESIGN) ->setAddedReviewers($reviewers) diff --git a/src/applications/differential/controller/commentsave/__init__.php b/src/applications/differential/controller/commentsave/__init__.php index 20dddcc7dc..7392c007a0 100644 --- a/src/applications/differential/controller/commentsave/__init__.php +++ b/src/applications/differential/controller/commentsave/__init__.php @@ -13,6 +13,7 @@ phutil_require_module('phabricator', 'applications/differential/controller/base' phutil_require_module('phabricator', 'applications/differential/editor/comment'); phutil_require_module('phabricator', 'applications/differential/storage/revision'); phutil_require_module('phabricator', 'applications/draft/storage/draft'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/differential/editor/comment/DifferentialCommentEditor.php b/src/applications/differential/editor/comment/DifferentialCommentEditor.php index 362b3567cb..61e7ca55b5 100644 --- a/src/applications/differential/editor/comment/DifferentialCommentEditor.php +++ b/src/applications/differential/editor/comment/DifferentialCommentEditor.php @@ -30,6 +30,7 @@ class DifferentialCommentEditor { private $addedCCs = array(); private $parentMessageID; + private $contentSource; public function __construct( DifferentialRevision $revision, @@ -88,6 +89,11 @@ class DifferentialCommentEditor { return $this->addedCCs; } + public function setContentSource(PhabricatorContentSource $content_source) { + $this->contentSource = $content_source; + return $this; + } + public function save() { $revision = $this->revision; $action = $this->action; @@ -320,8 +326,13 @@ class DifferentialCommentEditor { ->setRevisionID($revision->getID()) ->setAction($action) ->setContent((string)$this->message) - ->setMetadata($metadata) - ->save(); + ->setMetadata($metadata); + + if ($this->contentSource) { + $comment->setContentSource($this->contentSource); + } + + $comment->save(); $changesets = array(); if ($inline_comments) { diff --git a/src/applications/differential/editor/revision/DifferentialRevisionEditor.php b/src/applications/differential/editor/revision/DifferentialRevisionEditor.php index e570881dc8..20a3fab1f9 100644 --- a/src/applications/differential/editor/revision/DifferentialRevisionEditor.php +++ b/src/applications/differential/editor/revision/DifferentialRevisionEditor.php @@ -33,6 +33,7 @@ class DifferentialRevisionEditor { protected $silentUpdate; private $auxiliaryFields = array(); + private $contentSource; public function __construct(DifferentialRevision $revision, $actor_phid) { $this->revision = $revision; @@ -108,6 +109,11 @@ class DifferentialRevisionEditor { return $this; } + public function setContentSource(PhabricatorContentSource $content_source) { + $this->contentSource = $content_source; + return $this; + } + public function addDiff(DifferentialDiff $diff, $comments) { if ($diff->getRevisionID() && $diff->getRevisionID() != $this->getRevision()->getID()) { @@ -652,6 +658,11 @@ class DifferentialRevisionEditor { ->setRevisionID($revision_id) ->setContent($this->getComments()) ->setAction('update'); + + if ($this->contentSource) { + $comment->setContentSource($this->contentSource); + } + $comment->save(); return $comment; diff --git a/src/applications/differential/replyhandler/DifferentialReplyHandler.php b/src/applications/differential/replyhandler/DifferentialReplyHandler.php index 516ebd453c..a23b28f50e 100644 --- a/src/applications/differential/replyhandler/DifferentialReplyHandler.php +++ b/src/applications/differential/replyhandler/DifferentialReplyHandler.php @@ -139,6 +139,12 @@ class DifferentialReplyHandler extends PhabricatorMailReplyHandler { // implementation jumps straight into handleAction() and will not have // a PhabricatorMetaMTAReceivedMail object. if ($this->receivedMail) { + $content_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_EMAIL, + array( + 'id' => $this->receivedMail->getID(), + )); + $editor->setContentSource($content_source); $editor->setParentMessageID($this->receivedMail->getMessageID()); } $editor->setMessage($body); diff --git a/src/applications/differential/replyhandler/__init__.php b/src/applications/differential/replyhandler/__init__.php index c857d47389..dcf9ca1d33 100644 --- a/src/applications/differential/replyhandler/__init__.php +++ b/src/applications/differential/replyhandler/__init__.php @@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'applications/differential/constants/action phutil_require_module('phabricator', 'applications/differential/editor/comment'); phutil_require_module('phabricator', 'applications/differential/editor/revision'); phutil_require_module('phabricator', 'applications/differential/mail/exception'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_module('phabricator', 'applications/metamta/replyhandler/base'); phutil_require_module('phabricator', 'infrastructure/env'); diff --git a/src/applications/differential/storage/comment/DifferentialComment.php b/src/applications/differential/storage/comment/DifferentialComment.php index 674ea034f3..bb814240a5 100644 --- a/src/applications/differential/storage/comment/DifferentialComment.php +++ b/src/applications/differential/storage/comment/DifferentialComment.php @@ -27,6 +27,7 @@ class DifferentialComment extends DifferentialDAO { protected $content; protected $cache; protected $metadata = array(); + protected $contentSource; public function getConfiguration() { return array( @@ -36,4 +37,13 @@ class DifferentialComment extends DifferentialDAO { ) + parent::getConfiguration(); } + public function setContentSource(PhabricatorContentSource $content_source) { + $this->contentSource = $content_source->serialize(); + return $this; + } + + public function getContentSource() { + return PhabricatorContentSource::newFromSerialized($this->contentSource); + } + } diff --git a/src/applications/differential/storage/comment/__init__.php b/src/applications/differential/storage/comment/__init__.php index 8f477dca99..dbdbe480a5 100644 --- a/src/applications/differential/storage/comment/__init__.php +++ b/src/applications/differential/storage/comment/__init__.php @@ -7,6 +7,7 @@ phutil_require_module('phabricator', 'applications/differential/storage/base'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_source('DifferentialComment.php'); diff --git a/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php b/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php index 74c7a853c6..64fb56ee0d 100644 --- a/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php +++ b/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php @@ -94,7 +94,14 @@ final class DifferentialRevisionCommentView extends AphrontView { $date = phabricator_datetime($comment->getDateCreated(), $this->user); } - $info = array($date); + $info = array(); + + $content_source = new PhabricatorContentSourceView(); + $content_source->setContentSource($comment->getContentSource()); + $content_source->setUser($this->user); + $info[] = $content_source->render(); + + $info[] = $date; $comment_anchor = null; $num = $this->commentNumber; @@ -110,7 +117,7 @@ final class DifferentialRevisionCommentView extends AphrontView { $comment_anchor = 'anchor-comment-'.$num; } - $info = implode(' · ', $info); + $info = implode(' · ', array_filter($info)); $author = $this->handles[$comment->getAuthorPHID()]; $author_link = $author->renderLink(); @@ -278,6 +285,7 @@ final class DifferentialRevisionCommentView extends AphrontView { ''. $inline_render. ''. + $content_source->render(). ''); } diff --git a/src/applications/differential/view/revisioncomment/__init__.php b/src/applications/differential/view/revisioncomment/__init__.php index 8dee4bedd6..c09a1245b9 100644 --- a/src/applications/differential/view/revisioncomment/__init__.php +++ b/src/applications/differential/view/revisioncomment/__init__.php @@ -9,6 +9,7 @@ phutil_require_module('phabricator', 'aphront/writeguard'); phutil_require_module('phabricator', 'applications/differential/constants/action'); phutil_require_module('phabricator', 'applications/differential/storage/comment'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/view'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); phutil_require_module('phabricator', 'infrastructure/javelin/api'); phutil_require_module('phabricator', 'view/base'); diff --git a/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php b/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php index c181e71998..9181ca03c2 100644 --- a/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php +++ b/src/applications/maniphest/controller/taskedit/ManiphestTaskEditController.php @@ -182,8 +182,15 @@ class ManiphestTaskEditController extends ManiphestController { ); } + $content_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_WEB, + array( + 'ip' => $request->getRemoteAddr(), + )); + $template = new ManiphestTransaction(); $template->setAuthorPHID($user->getPHID()); + $template->setContentSource($content_source); $transactions = array(); foreach ($changes as $type => $value) { diff --git a/src/applications/maniphest/controller/taskedit/__init__.php b/src/applications/maniphest/controller/taskedit/__init__.php index 83478c7560..79f39fff09 100644 --- a/src/applications/maniphest/controller/taskedit/__init__.php +++ b/src/applications/maniphest/controller/taskedit/__init__.php @@ -17,6 +17,7 @@ phutil_require_module('phabricator', 'applications/maniphest/editor/transaction' phutil_require_module('phabricator', 'applications/maniphest/extensions/base'); phutil_require_module('phabricator', 'applications/maniphest/storage/task'); phutil_require_module('phabricator', 'applications/maniphest/storage/transaction'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_module('phabricator', 'applications/phid/constants'); phutil_require_module('phabricator', 'applications/phid/handle/data'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); diff --git a/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php b/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php index 0e5aae986e..7d130c5d06 100644 --- a/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php +++ b/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php @@ -219,6 +219,16 @@ class ManiphestTransactionSaveController extends ManiphestController { $transactions[] = $cc_transaction; } + $content_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_WEB, + array( + 'ip' => $request->getRemoteAddr(), + )); + + foreach ($transactions as $transaction) { + $transaction->setContentSource($content_source); + } + $editor = new ManiphestTransactionEditor(); $editor->applyTransactions($task, $transactions); diff --git a/src/applications/maniphest/controller/transactionsave/__init__.php b/src/applications/maniphest/controller/transactionsave/__init__.php index 2967a0a491..43e8b529a3 100644 --- a/src/applications/maniphest/controller/transactionsave/__init__.php +++ b/src/applications/maniphest/controller/transactionsave/__init__.php @@ -17,6 +17,7 @@ phutil_require_module('phabricator', 'applications/maniphest/editor/transaction' phutil_require_module('phabricator', 'applications/maniphest/storage/task'); phutil_require_module('phabricator', 'applications/maniphest/storage/transaction'); phutil_require_module('phabricator', 'applications/markup/engine'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_module('phabricator', 'applications/phid/constants'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/maniphest/replyhandler/ManiphestReplyHandler.php b/src/applications/maniphest/replyhandler/ManiphestReplyHandler.php index 374da6c953..6bb47a8f8e 100644 --- a/src/applications/maniphest/replyhandler/ManiphestReplyHandler.php +++ b/src/applications/maniphest/replyhandler/ManiphestReplyHandler.php @@ -66,7 +66,14 @@ class ManiphestReplyHandler extends PhabricatorMailReplyHandler { $xactions = array(); + $content_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_EMAIL, + array( + 'id' => $mail->getID(), + )); + $template = new ManiphestTransaction(); + $template->setContentSource($content_source); $template->setAuthorPHID($user->getPHID()); if ($is_new_task) { diff --git a/src/applications/maniphest/replyhandler/__init__.php b/src/applications/maniphest/replyhandler/__init__.php index 376777c40f..0f8e28bc54 100644 --- a/src/applications/maniphest/replyhandler/__init__.php +++ b/src/applications/maniphest/replyhandler/__init__.php @@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'applications/maniphest/constants/status'); phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype'); phutil_require_module('phabricator', 'applications/maniphest/editor/transaction'); phutil_require_module('phabricator', 'applications/maniphest/storage/transaction'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_module('phabricator', 'applications/metamta/replyhandler/base'); phutil_require_module('phabricator', 'applications/phid/constants'); phutil_require_module('phabricator', 'infrastructure/env'); diff --git a/src/applications/maniphest/storage/transaction/ManiphestTransaction.php b/src/applications/maniphest/storage/transaction/ManiphestTransaction.php index 153e46f375..fbe5ded867 100644 --- a/src/applications/maniphest/storage/transaction/ManiphestTransaction.php +++ b/src/applications/maniphest/storage/transaction/ManiphestTransaction.php @@ -29,6 +29,7 @@ class ManiphestTransaction extends ManiphestDAO { protected $comments; protected $cache; protected $metadata = array(); + protected $contentSource; public function getConfiguration() { return array( @@ -104,5 +105,13 @@ class ManiphestTransaction extends ManiphestDAO { return (bool)strlen(trim($this->getComments())); } + public function setContentSource(PhabricatorContentSource $content_source) { + $this->contentSource = $content_source->serialize(); + return $this; + } + + public function getContentSource() { + return PhabricatorContentSource::newFromSerialized($this->contentSource); + } } diff --git a/src/applications/maniphest/storage/transaction/__init__.php b/src/applications/maniphest/storage/transaction/__init__.php index c4e475868c..f095c1223e 100644 --- a/src/applications/maniphest/storage/transaction/__init__.php +++ b/src/applications/maniphest/storage/transaction/__init__.php @@ -8,6 +8,7 @@ phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype'); phutil_require_module('phabricator', 'applications/maniphest/storage/base'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/source'); phutil_require_source('ManiphestTransaction.php'); diff --git a/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php b/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php index e11852f786..61145b902f 100644 --- a/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php +++ b/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php @@ -202,6 +202,13 @@ class ManiphestTransactionDetailView extends ManiphestView { } $info = array(); + + $source_transaction = nonempty($comment_transaction, $any_transaction); + $content_source = new PhabricatorContentSourceView(); + $content_source->setContentSource($source_transaction->getContentSource()); + $content_source->setUser($this->user); + $info[] = $content_source->render(); + $info[] = $timestamp; $comment_anchor = null; @@ -218,7 +225,8 @@ class ManiphestTransactionDetailView extends ManiphestView { $comment_anchor = 'anchor-comment-'.$num; } - $info = implode(' · ', $info); + + $info = implode(' · ', array_filter($info)); return phutil_render_tag( 'div', diff --git a/src/applications/maniphest/view/transactiondetail/__init__.php b/src/applications/maniphest/view/transactiondetail/__init__.php index b1c34a4630..e47dde0c10 100644 --- a/src/applications/maniphest/view/transactiondetail/__init__.php +++ b/src/applications/maniphest/view/transactiondetail/__init__.php @@ -11,6 +11,7 @@ phutil_require_module('phabricator', 'applications/maniphest/constants/priority' phutil_require_module('phabricator', 'applications/maniphest/constants/status'); phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype'); phutil_require_module('phabricator', 'applications/maniphest/view/base'); +phutil_require_module('phabricator', 'applications/metamta/contentsource/view'); phutil_require_module('phabricator', 'applications/phid/constants'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); phutil_require_module('phabricator', 'infrastructure/env'); diff --git a/src/applications/metamta/contentsource/source/PhabricatorContentSource.php b/src/applications/metamta/contentsource/source/PhabricatorContentSource.php new file mode 100644 index 0000000000..e058dfdb1d --- /dev/null +++ b/src/applications/metamta/contentsource/source/PhabricatorContentSource.php @@ -0,0 +1,75 @@ + + } + + public static function newForSource($source, array $params) { + $obj = new PhabricatorContentSource(); + $obj->source = $source; + $obj->params = $params; + + return $obj; + } + + public static function newFromSerialized($serialized) { + $dict = json_decode($serialized, true); + if (!is_array($dict)) { + $dict = array(); + } + + $obj = new PhabricatorContentSource(); + $obj->source = idx($dict, 'source', self::SOURCE_UNKNOWN); + $obj->params = idx($dict, 'params', array()); + + return $obj; + } + + public function serialize() { + return json_encode(array( + 'source' => $this->getSource(), + 'params' => $this->getParams(), + )); + } + + public function getSource() { + return $this->source; + } + + public function getParams() { + return $this->params; + } + + public function getParam($key, $default = null) { + return idx($this->params, $key, $default); + } + +} diff --git a/src/applications/metamta/contentsource/source/__init__.php b/src/applications/metamta/contentsource/source/__init__.php new file mode 100644 index 0000000000..96cacc81bc --- /dev/null +++ b/src/applications/metamta/contentsource/source/__init__.php @@ -0,0 +1,12 @@ +contentSource = $content_source; + return $this; + } + + public function setUser(PhabricatorUser $user) { + $this->user = $user; + return $this; + } + + + public function render() { + require_celerity_resource('phabricator-content-source-view-css'); + + $type = null; + $map = array( + PhabricatorContentSource::SOURCE_WEB => 'web', + PhabricatorContentSource::SOURCE_CONDUIT => 'conduit', + PhabricatorContentSource::SOURCE_EMAIL => 'email', + PhabricatorContentSource::SOURCE_MOBILE => 'mobile', + PhabricatorContentSource::SOURCE_TABLET => 'tablet', + ); + + $source = $this->contentSource->getSource(); + $type = idx($map, $source, null); + + if (!$type) { + return; + } + + $type_class = 'phabricator-content-source-'.$type; + + return phutil_render_tag( + 'span', + array( + 'class' => "phabricator-content-source-view {$type_class}", + ), + 'Via'); + } + +} diff --git a/src/applications/metamta/contentsource/view/__init__.php b/src/applications/metamta/contentsource/view/__init__.php new file mode 100644 index 0000000000..fbbe1f68c5 --- /dev/null +++ b/src/applications/metamta/contentsource/view/__init__.php @@ -0,0 +1,17 @@ +@;NroXm^5ezn$R|(v8}Y* zQg(s1yRGwHDHbnIGI?*`oB7PVnOR4(*~He?RujO+($dmnbVxiNe?s@KXd7X6jYb2s z)*KGU{Nm!``|a&*IM~JJ=B7c18tuQ4iey-&@0+xG+c0J~Jv|Lw*O5-A8EkZ9WaJA6 z&?XX%MxRQOBvvYw&y$mrYlDMBI4l%UE+4_N>Nq>Aa>tpOM>r~%kxHdLjg5^x5Y7W6 zTrQVM+BY@zaP3<7I+Cdr86L6NkYovh;D9Je*xUPoP$&e-@IG^t+9}Gie5b#^|DI`@ z$l5tjHvE>on-~y95μY}@WE6NFAcBoaX`mxt<9p(qMFgRHcaf!uDb1!lxfKr9xU zqX^o`=_x!O52ap$s)Fbz~l8m(=-ZTV}F02JLht_`0noR&&~`i)*h!*p(x-+;cyt4g9CV}sO3@# z$z+lj^Z5Aq;|d8&`eF_eiA0pT@P)n_kAkQ|tI z=gpiscV_O$TCIjoR2&?gTv(R1;W&>nO4 zn!NeTvQWIKAiFS!r{|X@$SW>+d~g7__f@Pe=fGS^CynvsC`#oDk|V?L`+V@3rarwk zW5f{49Ev7j`GJ5R<6}u&m&!;c6p7!bdNj1srjIdVh_$^0ERRD8hkFr;gmHd(g+x52 zZ>G|wk1=A1bz5o@a41ssol|oN2D@;k64)=5HhqlA#sGg2K-q?2All!D(|iF_=}GP0 z+1=Ahp^q_Qh(+VUOg(Wa5DxVqUnnA^PD*xZUaR*NLJiFN+KQTi{X@W>st=FIq$Uti zJvx8v1D|y!lfvuUyT;B=r|SePM}4%z?W@&7ktC*OG8Bu}=ce+6+NKZn({0!mLSY~=79W)6HkW>mEn?etE|p3lole7XoZPyf z`75Z^YGv1TkNf~}2^3&78ll(gfph+p$z;wvzv2hekR+4I1s6QH0{I6-3mc6F>h-#8 zB`Mi-M!rB2r_-rftyVL>*;vVJnkFpEGXEVWG0yv9+1oOp-(sBm-sVq$0RSH!@m~Rf R+8h7?002ovPDHLkV1kC8;UNG3 literal 0 HcmV?d00001 diff --git a/webroot/rsrc/image/icon/fatcow/source/tablet.png b/webroot/rsrc/image/icon/fatcow/source/tablet.png new file mode 100644 index 0000000000000000000000000000000000000000..f6772c900cf79d5f06790cc323114d946760bff1 GIT binary patch literal 523 zcmV+m0`&cfP)#K@Xjt;GclX@~MBfo5YR-;10+mvrwd$Uoc8+bHyH2aM4)MW0EzE)@_Ixn_EXOae zZ!j2qbwmMrguUG@xVXH5l|}?n6oR#uJ_7+&V>DP}q#CVBq=NS04t#tL3JV@RWLXZ4 zD1v6Q0bv*lSV)YKe@)VufZ?nv%X2`)l7J@CGzA-22!cSW0L#iCnVh?Qs};yJ|%Xd`hJW8Oz3Ga-(X6awwR zPK^VrL*>1bL1>~cI zF9oB9Xd+w$@!%bln;JDHoa81P^>6SWkgJy-OduwlAoW5#m?*?pLgK-M5DZc%w6x29 z%+7v{?=H5flgzx?%{;&NooC)*b8~ZO9g`29E=3YArIfm+Y4Cjkg()16@3+>M7h3n` z^LeO^kGl__Ob0XrrJL+Ad$tEt%+uYho7b8Y!kL#JM3eLNjX zS-5v+45Nc7M3TV^yWn^M42$Em@&&4Q2wl(N_@uWmHT$dyQQ{>G!@|V)ZH!+Zfn+*~ zk%(QYz&1Za%?u%(y@8ZGMQ_gmDN==I1rsxmmU6jXj9wX_l3iGK8TIoLJUY9}ZGuH` zoNf5ZBs^iDJ-vfAqmHTB=S!qtP@+iA=W^X-6oUu=rjEdNP1sJ25_Q0J&ydO9LP~9e zlD-6itK?6KJZ1Aq1&lE*tLw12fFFjGIRy7iiavb121c6#{u4o{Lq;krzaKr?K4pTI z05na9<#?#u4x$Kfy$Xpr`67|1Dd^do;EsVP-~bx}QiHLt5*D=N`fjVlf?u zmWW^k5DCEd+||-a3SN+d5ZPw_@coQJV$jbR3tnfYzjk-9ffCYPKQx6aXjGUJ!lCIH6zt4{UESj}y0`dHy z3GzIbTA9317#)ehmpN3=I#D^?UyOClR^Bac=Hu8iIQ&k{(CwsDNb-mt6+sOcnQoNI zDw*1a>e1ffZt+{b(TU2xXvUDO^^cRTdA1U`mWZeerEtNhBah16LU3hebM3?A?vJmr z*!=G?H6S#<7dO^lQ+(S3k4Jpzl}6dE