Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/ponder/controller/PonderQuestionEditController.php b/src/applications/ponder/controller/PonderQuestionEditController.php
index 42cf045718..3d0d5bdde8 100644
--- a/src/applications/ponder/controller/PonderQuestionEditController.php
+++ b/src/applications/ponder/controller/PonderQuestionEditController.php
@@ -1,131 +1,157 @@
<?php
final class PonderQuestionEditController extends PonderController {
private $id;
public function willProcessRequest(array $data) {
$this->id = idx($data, 'id');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
if ($this->id) {
$question = id(new PonderQuestionQuery())
->setViewer($user)
->withIDs(array($this->id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$question) {
return new Aphront404Response();
}
+ $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $question->getPHID(),
+ PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
+ $v_projects = array_reverse($v_projects);
} else {
$question = id(new PonderQuestion())
->setStatus(PonderQuestionStatus::STATUS_OPEN)
->setAuthorPHID($user->getPHID())
->setVoteCount(0)
->setAnswerCount(0)
->setHeat(0.0);
+ $v_projects = array();
}
$v_title = $question->getTitle();
$v_content = $question->getContent();
$errors = array();
$e_title = true;
if ($request->isFormPost()) {
$v_title = $request->getStr('title');
$v_content = $request->getStr('content');
+ $v_projects = $request->getArr('projects');
$len = phutil_utf8_strlen($v_title);
if ($len < 1) {
$errors[] = pht('Title must not be empty.');
$e_title = pht('Required');
} else if ($len > 255) {
$errors[] = pht('Title is too long.');
$e_title = pht('Too Long');
}
if (!$errors) {
$template = id(new PonderQuestionTransaction());
$xactions = array();
$xactions[] = id(clone $template)
->setTransactionType(PonderQuestionTransaction::TYPE_TITLE)
->setNewValue($v_title);
$xactions[] = id(clone $template)
->setTransactionType(PonderQuestionTransaction::TYPE_CONTENT)
->setNewValue($v_content);
+ $proj_edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT;
+ $xactions[] = id(new PonderQuestionTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+ ->setMetadataValue('edge:type', $proj_edge_type)
+ ->setNewValue(array('=' => array_fuse($v_projects)));
+
$editor = id(new PonderQuestionEditor())
->setActor($user)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true);
$editor->applyTransactions($question, $xactions);
return id(new AphrontRedirectResponse())
->setURI('/Q'.$question->getID());
}
}
$form = id(new AphrontFormView())
->setUser($user)
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Question'))
->setName('title')
->setValue($v_title)
->setError($e_title))
->appendChild(
id(new PhabricatorRemarkupControl())
->setName('content')
->setID('content')
->setValue($v_content)
->setLabel(pht('Description'))
- ->setUser($user))
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->addCancelButton($this->getApplicationURI())
- ->setValue(pht('Ask Away!')));
+ ->setUser($user));
+
+ if ($v_projects) {
+ $project_handles = $this->loadViewerHandles($v_projects);
+ } else {
+ $project_handles = array();
+ }
+
+ $form->appendChild(
+ id(new AphrontFormTokenizerControl())
+ ->setLabel(pht('Projects'))
+ ->setName('projects')
+ ->setValue($project_handles)
+ ->setDatasource('/typeahead/common/projects/'));
+
+ $form ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->addCancelButton($this->getApplicationURI())
+ ->setValue(pht('Ask Away!')));
$preview = id(new PHUIRemarkupPreviewPanel())
->setHeader(pht('Question Preview'))
->setControlID('content')
->setPreviewURI($this->getApplicationURI('preview/'));
$form_box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Ask New Question'))
->setFormErrors($errors)
->setForm($form);
$crumbs = $this->buildApplicationCrumbs();
$id = $question->getID();
if ($id) {
$crumbs->addTextCrumb("Q{$id}", "/Q{$id}");
$crumbs->addTextCrumb(pht('Edit'));
} else {
$crumbs->addTextCrumb(pht('Ask Question'));
}
return $this->buildApplicationPage(
array(
$crumbs,
$form_box,
$preview,
),
array(
'title' => pht('Ask New Question'),
'device' => true,
));
}
}
diff --git a/src/applications/ponder/editor/PonderQuestionEditor.php b/src/applications/ponder/editor/PonderQuestionEditor.php
index 653dc2ed75..12c1cb2ab5 100644
--- a/src/applications/ponder/editor/PonderQuestionEditor.php
+++ b/src/applications/ponder/editor/PonderQuestionEditor.php
@@ -1,247 +1,249 @@
<?php
final class PonderQuestionEditor
extends PonderEditor {
private $answer;
/**
* This is used internally on @{method:applyInitialEffects} if a transaction
* of type PonderQuestionTransaction::TYPE_ANSWERS is in the mix. The value
* is set to the //last// answer in the transactions. Practically, one
* answer is given at a time in the application, though theoretically
* this is buggy.
*
* The answer is used in emails to generate proper links.
*/
private function setAnswer(PonderAnswer $answer) {
$this->answer = $answer;
return $this;
}
private function getAnswer() {
return $this->answer;
}
protected function shouldApplyInitialEffects(
PhabricatorLiskDAO $object,
array $xactions) {
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
case PonderQuestionTransaction::TYPE_ANSWERS:
return true;
}
}
return false;
}
protected function applyInitialEffects(
PhabricatorLiskDAO $object,
array $xactions) {
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
case PonderQuestionTransaction::TYPE_ANSWERS:
$new_value = $xaction->getNewValue();
$new = idx($new_value, '+', array());
foreach ($new as $new_answer) {
$answer = idx($new_answer, 'answer');
if (!$answer) {
continue;
}
$answer->save();
$this->setAnswer($answer);
}
break;
}
}
}
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = PhabricatorTransactions::TYPE_COMMENT;
$types[] = PonderQuestionTransaction::TYPE_TITLE;
$types[] = PonderQuestionTransaction::TYPE_CONTENT;
$types[] = PonderQuestionTransaction::TYPE_ANSWERS;
$types[] = PonderQuestionTransaction::TYPE_STATUS;
return $types;
}
protected function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PonderQuestionTransaction::TYPE_TITLE:
return $object->getTitle();
case PonderQuestionTransaction::TYPE_CONTENT:
return $object->getContent();
case PonderQuestionTransaction::TYPE_ANSWERS:
return mpull($object->getAnswers(), 'getPHID');
case PonderQuestionTransaction::TYPE_STATUS:
return $object->getStatus();
}
}
protected function getCustomTransactionNewValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PonderQuestionTransaction::TYPE_TITLE:
case PonderQuestionTransaction::TYPE_CONTENT:
case PonderQuestionTransaction::TYPE_STATUS:
return $xaction->getNewValue();
case PonderQuestionTransaction::TYPE_ANSWERS:
$raw_new_value = $xaction->getNewValue();
$new_value = array();
foreach ($raw_new_value as $key => $answers) {
$phids = array();
foreach ($answers as $answer) {
$obj = idx($answer, 'answer');
if (!$answer) {
continue;
}
$phids[] = $obj->getPHID();
}
$new_value[$key] = $phids;
}
$xaction->setNewValue($new_value);
return $this->getPHIDTransactionNewValue($xaction);
}
}
protected function applyCustomInternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PonderQuestionTransaction::TYPE_TITLE:
$object->setTitle($xaction->getNewValue());
break;
case PonderQuestionTransaction::TYPE_CONTENT:
$object->setContent($xaction->getNewValue());
break;
case PonderQuestionTransaction::TYPE_STATUS:
$object->setStatus($xaction->getNewValue());
break;
case PonderQuestionTransaction::TYPE_ANSWERS:
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
$add = array_diff_key($new, $old);
$rem = array_diff_key($old, $new);
$count = $object->getAnswerCount();
$count += count($add);
$count -= count($rem);
$object->setAnswerCount($count);
break;
+ case PhabricatorTransactions::TYPE_EDGE:
+ return;
}
}
protected function applyCustomExternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
return;
}
protected function mergeTransactions(
PhabricatorApplicationTransaction $u,
PhabricatorApplicationTransaction $v) {
$type = $u->getTransactionType();
switch ($type) {
case PonderQuestionTransaction::TYPE_TITLE:
case PonderQuestionTransaction::TYPE_CONTENT:
case PonderQuestionTransaction::TYPE_STATUS:
return $v;
}
return parent::mergeTransactions($u, $v);
}
protected function supportsSearch() {
return true;
}
protected function getFeedStoryType() {
return 'PonderTransactionFeedStory';
}
protected function getFeedStoryData(
PhabricatorLiskDAO $object,
array $xactions) {
$data = parent::getFeedStoryData($object, $xactions);
$answer = $this->getAnswer();
if ($answer) {
$data['answerPHID'] = $answer->getPHID();
}
return $data;
}
protected function shouldImplyCC(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PonderQuestionTransaction::TYPE_ANSWERS:
return true;
}
return parent::shouldImplyCC($object, $xaction);
}
protected function shouldSendMail(
PhabricatorLiskDAO $object,
array $xactions) {
return true;
}
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
return id(new PonderQuestionReplyHandler())
->setMailReceiver($object);
}
protected function buildMailBody(
PhabricatorLiskDAO $object,
array $xactions) {
$body = parent::buildMailBody($object, $xactions);
$header = pht('QUESTION DETAIL');
$uri = '/Q'.$object->getID();
foreach ($xactions as $xaction) {
$type = $xaction->getTransactionType();
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
// If the user just asked the question, add the question text.
if ($type == PonderQuestionTransaction::TYPE_CONTENT) {
if ($old === null) {
$body->addRawSection($new);
}
}
// If the user gave an answer, add the answer text. Also update
// the header and uri to be more answer-specific.
if ($type == PonderQuestionTransaction::TYPE_ANSWERS) {
$answer = $this->getAnswer();
$body->addRawSection($answer->getContent());
$header = pht('ANSWER DETAIL');
$uri = $answer->getURI();
}
}
$body->addTextSection(
$header,
PhabricatorEnv::getProductionURI($uri));
return $body;
}
}
diff --git a/src/applications/ponder/storage/PonderQuestion.php b/src/applications/ponder/storage/PonderQuestion.php
index 6788f4fa1c..6b7856871e 100644
--- a/src/applications/ponder/storage/PonderQuestion.php
+++ b/src/applications/ponder/storage/PonderQuestion.php
@@ -1,249 +1,250 @@
<?php
final class PonderQuestion extends PonderDAO
implements
PhabricatorMarkupInterface,
PonderVotableInterface,
PhabricatorSubscribableInterface,
PhabricatorFlaggableInterface,
PhabricatorPolicyInterface,
- PhabricatorTokenReceiverInterface {
+ PhabricatorTokenReceiverInterface,
+ PhabricatorProjectInterface {
const MARKUP_FIELD_CONTENT = 'markup:content';
protected $title;
protected $phid;
protected $authorPHID;
protected $status;
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(PonderPHIDTypeQuestion::TYPECONST);
}
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 {
$comments = array();
}
$this->setComments(idx($comments, $this->getPHID(), array()));
foreach ($this->answers as $answer) {
$answer->attachQuestion($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 = PonderVote::VOTE_NONE;
}
return $this;
}
public function attachUserVote($user_phid, $vote) {
$this->vote = $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 attachAnswers(array $answers) {
assert_instances_of($answers, 'PonderAnswer');
$this->answers = $answers;
return $this;
}
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::getEngine();
}
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 save() {
if (!$this->getMailKey()) {
$this->setMailKey(Filesystem::readRandomCharacters(20));
}
return parent::save();
}
public function getOriginalTitle() {
// TODO: Make this actually save/return the original title.
return $this->getTitle();
}
public function getFullTitle() {
$id = $this->getID();
$title = $this->getTitle();
return "Q{$id}: {$title}";
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
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 ($viewer->getPHID() == $this->getAuthorPHID());
}
public function describeAutomaticCapability($capability) {
return pht(
'The user who asked a question can always view and edit it.');
}
/* -( PhabricatorSubscribableInterface )----------------------------------- */
public function isAutomaticallySubscribed($phid) {
return ($phid == $this->getAuthorPHID());
}
public function shouldShowSubscribersProperty() {
return true;
}
public function shouldAllowSubscription($phid) {
return true;
}
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
public function getUsersToNotifyOfTokenGiven() {
return array(
$this->getAuthorPHID(),
);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 10, 2:53 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
140419
Default Alt Text
(19 KB)

Event Timeline