diff --git a/src/applications/ponder/controller/PonderVoteSaveController.php b/src/applications/ponder/controller/PonderVoteSaveController.php index 73bca07bee..5becd6fc56 100644 --- a/src/applications/ponder/controller/PonderVoteSaveController.php +++ b/src/applications/ponder/controller/PonderVoteSaveController.php @@ -1,42 +1,41 @@ <?php final class PonderVoteSaveController extends PonderController { private $kind; public function willProcessRequest(array $data) { $this->kind = $data['kind']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $newvote = $request->getInt("vote"); $phid = $request->getStr("phid"); if (1 < $newvote || $newvote < -1) { return new Aphront400Response(); } $target = null; if ($this->kind == "question") { $target = PonderQuestionQuery::loadSingleByPHID($user, $phid); - } - else if ($this->kind == "answer") { + } else if ($this->kind == "answer") { $target = PonderAnswerQuery::loadSingleByPHID($user, $phid); } if (!$target) { return new Aphront404Response(); } $editor = id(new PonderVoteEditor()) ->setVotable($target) ->setActor($user) ->setVote($newvote) ->saveVote(); return id(new AphrontAjaxResponse())->setContent("."); } } diff --git a/src/applications/ponder/editor/PonderCommentEditor.php b/src/applications/ponder/editor/PonderCommentEditor.php index 1b7ab918ff..5f656b2dfd 100644 --- a/src/applications/ponder/editor/PonderCommentEditor.php +++ b/src/applications/ponder/editor/PonderCommentEditor.php @@ -1,107 +1,106 @@ <?php final class PonderCommentEditor extends PhabricatorEditor { private $question; private $comment; private $targetPHID; private $shouldEmail = true; public function setComment(PonderComment $comment) { $this->comment = $comment; return $this; } public function setQuestion(PonderQuestion $question) { $this->question = $question; return $this; } public function setTargetPHID($target) { $this->targetPHID = $target; return $this; } public function save() { $actor = $this->requireActor(); if (!$this->comment) { throw new Exception("Must set comment before saving it"); } if (!$this->question) { throw new Exception("Must set question before saving comment"); } if (!$this->targetPHID) { throw new Exception("Must set target before saving comment"); } $comment = $this->comment; $question = $this->question; $target = $this->targetPHID; $comment->save(); id(new PhabricatorSearchIndexer()) ->indexDocumentByPHID($question->getPHID()); // subscribe author and @mentions $subeditor = id(new PhabricatorSubscriptionsEditor()) ->setObject($question) ->setActor($actor); $subeditor->subscribeExplicit(array($comment->getAuthorPHID())); $content = $comment->getContent(); $at_mention_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( array($content) ); $subeditor->subscribeImplicit($at_mention_phids); $subeditor->save(); if ($this->shouldEmail) { // now load subscribers, including implicitly-added @mention victims $subscribers = PhabricatorSubscribersQuery ::loadSubscribersForPHID($question->getPHID()); // @mention emails (but not for anyone who has explicitly unsubscribed) if (array_intersect($at_mention_phids, $subscribers)) { id(new PonderMentionMail( $question, $comment, $actor)) ->setToPHIDs($at_mention_phids) ->send(); } if ($target === $question->getPHID()) { $target = $question; - } - else { + } else { $answers_by_phid = mgroup($question->getAnswers(), 'getPHID'); $target = head($answers_by_phid[$target]); } // only send emails to others in the same thread $thread = mpull($target->getComments(), 'getAuthorPHID'); $thread[] = $target->getAuthorPHID(); $thread[] = $question->getAuthorPHID(); $other_subs = array_diff( array_intersect($thread, $subscribers), $at_mention_phids ); // 'Comment' emails for subscribers who are in the same comment thread, // including the author of the parent question and/or answer, excluding // @mentions (and excluding the author, depending on their MetaMTA // settings). if ($other_subs) { id(new PonderCommentMail( $question, $comment, $actor)) ->setToPHIDs($other_subs) ->send(); } } } } diff --git a/src/applications/ponder/mail/PonderMentionMail.php b/src/applications/ponder/mail/PonderMentionMail.php index bbd9a7098a..63cc659f99 100644 --- a/src/applications/ponder/mail/PonderMentionMail.php +++ b/src/applications/ponder/mail/PonderMentionMail.php @@ -1,48 +1,46 @@ <?php final class PonderMentionMail extends PonderMail { public function __construct( PonderQuestion $question, $target, PhabricatorUser $actor) { $this->setQuestion($question); $this->setTarget($target); $this->setActorHandle($actor); } protected function renderVaryPrefix() { return "[Mentioned]"; } protected function renderBody() { $question = $this->getQuestion(); $target = $this->getTarget(); $actor = $this->getActorName(); $name = $question->getTitle(); $targetkind = "somewhere"; if ($target instanceof PonderQuestion) { $targetkind = "in a question"; - } - else if ($target instanceof PonderAnswer) { + } else if ($target instanceof PonderAnswer) { $targetkind = "in an answer"; - } - else if ($target instanceof PonderComment) { + } else if ($target instanceof PonderComment) { $targetkind = "in a comment"; } $body = array(); $body[] = "{$actor} mentioned you {$targetkind}."; $body[] = null; $content = $target->getContent(); if (strlen($content)) { $body[] = $this->formatText($content); $body[] = null; } return implode("\n", $body); } } diff --git a/src/applications/ponder/storage/PonderQuestion.php b/src/applications/ponder/storage/PonderQuestion.php index 078d37f524..9028681059 100644 --- a/src/applications/ponder/storage/PonderQuestion.php +++ b/src/applications/ponder/storage/PonderQuestion.php @@ -1,194 +1,193 @@ <?php final class PonderQuestion extends PonderDAO implements PhabricatorMarkupInterface, PonderVotableInterface, PhabricatorSubscribableInterface, PhabricatorPolicyInterface { const MARKUP_FIELD_CONTENT = 'markup:content'; protected $title; protected $phid; protected $authorPHID; protected $content; protected $contentSource; protected $voteCount; protected $answerCount; protected $heat; protected $mailKey; private $answers; private $vote; private $comments; public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorPHIDConstants::PHID_TYPE_QUES); } public function setContentSource(PhabricatorContentSource $content_source) { $this->contentSource = $content_source->serialize(); return $this; } public function getContentSource() { return PhabricatorContentSource::newFromSerialized($this->contentSource); } public function attachRelated() { $this->answers = $this->loadRelatives(new PonderAnswer(), "questionID"); $qa_phids = mpull($this->answers, 'getPHID') + array($this->getPHID()); if ($qa_phids) { $comments = id(new PonderCommentQuery()) ->withTargetPHIDs($qa_phids) ->execute(); $comments = mgroup($comments, 'getTargetPHID'); - } - else { + } else { $comments = array(); } $this->setComments(idx($comments, $this->getPHID(), array())); foreach ($this->answers as $answer) { $answer->setQuestion($this); $answer->setComments(idx($comments, $answer->getPHID(), array())); } } public function attachVotes($user_phid) { $qa_phids = mpull($this->answers, 'getPHID') + array($this->getPHID()); $edges = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(array($user_phid)) ->withDestinationPHIDs($qa_phids) ->withEdgeTypes( array( PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION, PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_ANSWER )) ->needEdgeData(true) ->execute(); $question_edge = $edges[$user_phid][PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION]; $answer_edges = $edges[$user_phid][PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_ANSWER]; $edges = null; $this->setUserVote(idx($question_edge, $this->getPHID())); foreach ($this->answers as $answer) { $answer->setUserVote(idx($answer_edges, $answer->getPHID())); } } public function setUserVote($vote) { $this->vote = $vote['data']; if (!$this->vote) { $this->vote = PonderConstants::NONE_VOTE; } return $this; } public function getUserVote() { return $this->vote; } public function setComments($comments) { $this->comments = $comments; return $this; } public function getComments() { return $this->comments; } public function getAnswers() { return $this->answers; } public function getMarkupField() { return self::MARKUP_FIELD_CONTENT; } // Markup interface public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); $id = $this->getID(); return "ponder:Q{$id}:{$field}:{$hash}"; } public function getMarkupText($field) { return $this->getContent(); } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newPonderMarkupEngine(); } public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { return (bool)$this->getID(); } // votable interface public function getUserVoteEdgeType() { return PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION; } public function getVotablePHID() { return $this->getPHID(); } public function isAutomaticallySubscribed($phid) { return false; } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { $policy = PhabricatorPolicies::POLICY_NOONE; switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: $policy = PhabricatorPolicies::POLICY_USER; break; } return $policy; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } } diff --git a/src/applications/ponder/view/PonderPostBodyView.php b/src/applications/ponder/view/PonderPostBodyView.php index 1572687c6e..77e72ee33b 100644 --- a/src/applications/ponder/view/PonderPostBodyView.php +++ b/src/applications/ponder/view/PonderPostBodyView.php @@ -1,128 +1,126 @@ <?php final class PonderPostBodyView extends AphrontView { private $target; private $question; private $handles; private $preview; private $anchorName; private $action; public function setQuestion($question) { $this->question = $question; return $this; } public function setTarget($target) { $this->target = $target; return $this; } public function setAction($action) { $this->action = $action; return $this; } public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } public function setPreview($preview) { $this->preview = $preview; return $this; } public function render() { if (!$this->user) { throw new Exception("Call setUser() before rendering!"); } require_celerity_resource('phabricator-remarkup-css'); require_celerity_resource('ponder-post-css'); $user = $this->user; $question = $this->question; $target = $this->target; $content = $target->getContent(); $info = array(); $content = PhabricatorMarkupEngine::renderOneObject( $target, $target->getMarkupField(), $this->user); $content = '<div class="phabricator-remarkup">'. $content. '</div>'; $author = $this->handles[$target->getAuthorPHID()]; $actions = array($author->renderLink().' '.$this->action); $author_link = $author->renderLink(); $xaction_view = id(new PhabricatorTransactionView()) ->setUser($user) ->setImageURI($author->getImageURI()) ->setContentSource($target->getContentSource()) ->setActions($actions); if ($this->target instanceof PonderAnswer) { $xaction_view->addClass("ponder-answer"); - } - else { + } else { $xaction_view->addClass("ponder-question"); } if ($this->preview) { $xaction_view->setIsPreview($this->preview); } else { $xaction_view->setEpoch($target->getDateCreated()); if ($this->target instanceof PonderAnswer) { $anchor_text = 'Q' . $question->getID(). '#A' . $target->getID(); $xaction_view->setAnchor('A'.$target->getID(), $anchor_text); $xaction_view->addClass("ponder-answer"); } } $xaction_view->appendChild( '<div class="ponder-post-core">'. $content. '</div>' ); $outerview = $xaction_view; if (!$this->preview) { $outerview = id(new PonderVotableView()) ->setPHID($target->getPHID()) ->setCount($target->getVoteCount()) ->setVote($target->getUserVote()); if ($this->target instanceof PonderAnswer) { $outerview->setURI('/ponder/answer/vote/'); - } - else { + } else { $outerview->setURI('/ponder/question/vote/'); } $outerview->appendChild($xaction_view); } return $outerview->render(); } private function renderHandleList(array $phids) { $result = array(); foreach ($phids as $phid) { $result[] = $this->handles[$phid]->renderLink(); } return implode(', ', $result); } } diff --git a/src/infrastructure/daemon/irc/handler/PhabricatorIRCWhatsNewHandler.php b/src/infrastructure/daemon/irc/handler/PhabricatorIRCWhatsNewHandler.php index e065099772..d921dca89c 100644 --- a/src/infrastructure/daemon/irc/handler/PhabricatorIRCWhatsNewHandler.php +++ b/src/infrastructure/daemon/irc/handler/PhabricatorIRCWhatsNewHandler.php @@ -1,149 +1,147 @@ <?php /** * Responds to "Whats new?" using the feed. * * @group irc */ final class PhabricatorIRCWhatsNewHandler extends PhabricatorIRCHandler { private $floodblock = 0; public function receiveMessage(PhabricatorIRCMessage $message) { switch ($message->getCommand()) { case 'PRIVMSG': $reply_to = $message->getReplyTo(); if (!$reply_to) { break; } $message = $message->getMessageText(); $prompt = '~what( i|\')?s new\?~i'; if (preg_match($prompt, $message)) { if (time() < $this->floodblock) { return; } $this->floodblock = time() + 60; $this->getLatest($reply_to); } break; } } public function getLatest($reply_to) { $latest = $this->getConduit()->callMethodSynchronous( 'feed.query', array( 'limit'=>5 )); $phids = array(); foreach ($latest as $action) { if (isset($action['data']['actor_phid'])) { $uid = $action['data']['actor_phid']; - } - else { + } else { $uid = $action['authorPHID']; } switch ($action['class']) { case 'PhabricatorFeedStoryDifferential': $phids[] = $action['data']['revision_phid']; break; case 'PhabricatorFeedStoryAudit': $phids[] = $action['data']['commitPHID']; break; case 'PhabricatorFeedStoryManiphest': $phids[] = $action['data']['taskPHID']; break; default: $phids[] = $uid; break; } array_push($phids,$uid); } $infs = $this->getConduit()->callMethodSynchronous( 'phid.query', array( 'phids'=>$phids )); $cphid = 0; foreach ($latest as $action) { if (isset($action['data']['actor_phid'])) { $uid = $action['data']['actor_phid']; - } - else { + } else { $uid = $action['authorPHID']; } switch ($action['class']) { case 'PhabricatorFeedStoryDifferential': $rinf = $infs[$action['data']['revision_phid']]; break; case 'PhabricatorFeedStoryAudit': $rinf = $infs[$action['data']['commitPHID']]; break; case 'PhabricatorFeedStoryManiphest': $rinf = $infs[$action['data']['taskPHID']]; break; default: $rinf = array('name'=>$action['class']); break; } $uinf = $infs[$uid]; $action = $this->getRhetoric($action['data']['action']); $user = $uinf['name']; $title = $rinf['fullName']; $uri = $rinf['uri']; $color = chr(3); $blue = $color.'12'; $gray = $color.'15'; $bold = chr(2); $reset = chr(15); $content = "{$bold}{$user}{$reset} {$gray}{$action} {$blue}{$bold}". "{$title}{$reset} - {$gray}{$uri}{$reset}"; $this->write('PRIVMSG',"{$reply_to} :{$content}"); } return; } public function getRhetoric($input) { switch ($input) { case 'comment': case 'none': return 'commented on'; break; case 'update': return 'updated'; break; case 'commit': return 'closed'; break; case 'create': return 'created'; break; case 'concern': return 'raised concern for'; break; case 'abandon': return 'abandonned'; break; case 'accept': return 'accepted'; break; default: return $input; break; } } }