mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 22:10:55 +01:00
Allow ponder answers to be edited
Summary: Ref T3373. Use applicationtransactions to edit ponder answers. Also enable tokens and subscriptions. Test Plan: edited an answer Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T3373 Differential Revision: https://secure.phabricator.com/D6607
This commit is contained in:
parent
71841e262a
commit
946a5cd5ce
8 changed files with 199 additions and 98 deletions
|
@ -1870,6 +1870,7 @@ phutil_register_library_map(array(
|
|||
'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php',
|
||||
'PonderAddCommentView' => 'applications/ponder/view/PonderAddCommentView.php',
|
||||
'PonderAnswer' => 'applications/ponder/storage/PonderAnswer.php',
|
||||
'PonderAnswerEditController' => 'applications/ponder/controller/PonderAnswerEditController.php',
|
||||
'PonderAnswerEditor' => 'applications/ponder/editor/PonderAnswerEditor.php',
|
||||
'PonderAnswerListView' => 'applications/ponder/view/PonderAnswerListView.php',
|
||||
'PonderAnswerPreviewController' => 'applications/ponder/controller/PonderAnswerPreviewController.php',
|
||||
|
@ -3990,8 +3991,11 @@ phutil_register_library_map(array(
|
|||
1 => 'PhabricatorMarkupInterface',
|
||||
2 => 'PonderVotableInterface',
|
||||
3 => 'PhabricatorPolicyInterface',
|
||||
4 => 'PhabricatorSubscribableInterface',
|
||||
5 => 'PhabricatorTokenReceiverInterface',
|
||||
),
|
||||
'PonderAnswerEditor' => 'PhabricatorEditor',
|
||||
'PonderAnswerEditController' => 'PonderController',
|
||||
'PonderAnswerEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PonderAnswerListView' => 'AphrontView',
|
||||
'PonderAnswerPreviewController' => 'PonderController',
|
||||
'PonderAnswerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
|
|
|
@ -51,6 +51,7 @@ final class PhabricatorApplicationPonder extends PhabricatorApplication {
|
|||
'/ponder/' => array(
|
||||
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PonderQuestionListController',
|
||||
'answer/add/' => 'PonderAnswerSaveController',
|
||||
'answer/edit/(?P<id>\d+)/' => 'PonderAnswerEditController',
|
||||
'answer/preview/' => 'PonderAnswerPreviewController',
|
||||
'question/edit/(?:(?P<id>\d+)/)?' => 'PonderQuestionEditController',
|
||||
'question/preview/' => 'PonderQuestionPreviewController',
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
final class PonderAnswerEditController extends PonderController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$answer = id(new PonderAnswerQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$answer) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$v_content = $answer->getContent();
|
||||
$e_content = true;
|
||||
|
||||
|
||||
$question = $answer->getQuestion();
|
||||
$qid = $question->getID();
|
||||
$aid = $answer->getID();
|
||||
|
||||
$question_uri = "/Q{$qid}#A{$aid}";
|
||||
|
||||
$errors = array();
|
||||
if ($request->isFormPost()) {
|
||||
$v_content = $request->getStr('content');
|
||||
|
||||
if (!strlen($v_content)) {
|
||||
$errors[] = pht('You must provide some substance in your answer.');
|
||||
$e_content = pht('Required');
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PonderAnswerTransaction())
|
||||
->setTransactionType(PonderAnswerTransaction::TYPE_CONTENT)
|
||||
->setNewValue($v_content);
|
||||
|
||||
$editor = id(new PonderAnswerEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true);
|
||||
|
||||
$editor->applyTransactions($answer, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($question_uri);
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
$errors = id(new AphrontErrorView())->setErrors($errors);
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel(pht('Question'))
|
||||
->setValue($question->getTitle()))
|
||||
->appendChild(
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setLabel(pht('Answer'))
|
||||
->setName('content')
|
||||
->setValue($v_content)
|
||||
->setError($e_content))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Update Answer'))
|
||||
->addCancelButton($question_uri));
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName("Q{$qid}")
|
||||
->setHref($question_uri));
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName(pht('Edit Answer')));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$errors,
|
||||
$form,
|
||||
),
|
||||
array(
|
||||
'title' => pht('Edit Answer'),
|
||||
'dust' => true,
|
||||
'device' => true,
|
||||
));
|
||||
|
||||
}
|
||||
}
|
|
@ -237,6 +237,8 @@ final class PonderQuestionViewController extends PonderController {
|
|||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$id = $answer->getID();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$answer,
|
||||
|
@ -247,10 +249,6 @@ final class PonderQuestionViewController extends PonderController {
|
|||
->setObject($answer)
|
||||
->setObjectURI($request->getRequestURI());
|
||||
|
||||
/*
|
||||
|
||||
TODO
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('edit')
|
||||
|
@ -259,8 +257,6 @@ final class PonderQuestionViewController extends PonderController {
|
|||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
*/
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,99 +1,66 @@
|
|||
<?php
|
||||
|
||||
final class PonderAnswerEditor extends PhabricatorEditor {
|
||||
final class PonderAnswerEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
private $question;
|
||||
private $answer;
|
||||
private $shouldEmail = true;
|
||||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
public function setQuestion($question) {
|
||||
$this->question = $question;
|
||||
return $this;
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
$types[] = PonderAnswerTransaction::TYPE_CONTENT;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
public function setAnswer($answer) {
|
||||
$this->answer = $answer;
|
||||
return $this;
|
||||
}
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
public function saveAnswer() {
|
||||
$actor = $this->requireActor();
|
||||
if (!$this->question) {
|
||||
throw new Exception("Must set question before saving answer");
|
||||
}
|
||||
if (!$this->answer) {
|
||||
throw new Exception("Must set answer before saving it");
|
||||
}
|
||||
|
||||
$question = $this->question;
|
||||
$answer = $this->answer;
|
||||
$conn = $answer->establishConnection('w');
|
||||
$trans = $conn->openTransaction();
|
||||
$trans->beginReadLocking();
|
||||
|
||||
$question->reload();
|
||||
|
||||
queryfx($conn,
|
||||
'UPDATE %T as t
|
||||
SET t.`answerCount` = t.`answerCount` + 1
|
||||
WHERE t.`PHID` = %s',
|
||||
$question->getTableName(),
|
||||
$question->getPHID());
|
||||
|
||||
$answer->setQuestionID($question->getID());
|
||||
$answer->save();
|
||||
|
||||
$trans->endReadLocking();
|
||||
$trans->saveTransaction();
|
||||
|
||||
$question->attachRelated();
|
||||
id(new PhabricatorSearchIndexer())
|
||||
->indexDocumentByPHID($question->getPHID());
|
||||
|
||||
// subscribe author and @mentions
|
||||
$subeditor = id(new PhabricatorSubscriptionsEditor())
|
||||
->setObject($question)
|
||||
->setActor($actor);
|
||||
|
||||
$subeditor->subscribeExplicit(array($answer->getAuthorPHID()));
|
||||
|
||||
$content = $answer->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,
|
||||
$answer,
|
||||
$actor))
|
||||
->setToPHIDs($at_mention_phids)
|
||||
->send();
|
||||
}
|
||||
|
||||
$other_subs =
|
||||
array_diff(
|
||||
$subscribers,
|
||||
$at_mention_phids);
|
||||
|
||||
// 'Answered' emails for subscribers who are not @mentiond (and excluding
|
||||
// author depending on their MetaMTA settings).
|
||||
if ($other_subs) {
|
||||
id(new PonderAnsweredMail(
|
||||
$question,
|
||||
$answer,
|
||||
$actor))
|
||||
->setToPHIDs($other_subs)
|
||||
->send();
|
||||
}
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PonderAnswerTransaction::TYPE_CONTENT:
|
||||
return $object->getContent();
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PonderAnswerTransaction::TYPE_CONTENT:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PonderAnswerTransaction::TYPE_CONTENT:
|
||||
$object->setContent($xaction->getNewValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
protected function mergeTransactions(
|
||||
PhabricatorApplicationTransaction $u,
|
||||
PhabricatorApplicationTransaction $v) {
|
||||
|
||||
$type = $u->getTransactionType();
|
||||
switch ($type) {
|
||||
case PonderAnswerTransaction::TYPE_CONTENT:
|
||||
return $v;
|
||||
}
|
||||
|
||||
return parent::mergeTransactions($u, $v);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ final class PonderAnswer extends PonderDAO
|
|||
implements
|
||||
PhabricatorMarkupInterface,
|
||||
PonderVotableInterface,
|
||||
PhabricatorPolicyInterface {
|
||||
PhabricatorPolicyInterface,
|
||||
PhabricatorSubscribableInterface,
|
||||
PhabricatorTokenReceiverInterface {
|
||||
|
||||
const MARKUP_FIELD_CONTENT = 'markup:content';
|
||||
|
||||
|
@ -145,4 +147,23 @@ final class PonderAnswer extends PonderDAO
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
|
||||
|
||||
|
||||
public function getUsersToNotifyOfTokenGiven() {
|
||||
return array(
|
||||
$this->getAuthorPHID(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
||||
|
||||
|
||||
public function isAutomaticallySubscribed($phid) {
|
||||
return ($phid == $this->getAuthorPHID());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
final class PonderAnswerTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
const TYPE_CONTENT = 'ponder.answer:content';
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'ponder';
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ final class PonderQuestion extends PonderDAO
|
|||
}
|
||||
|
||||
public function isAutomaticallySubscribed($phid) {
|
||||
return false;
|
||||
return ($phid == $this->getAuthorPHID());
|
||||
}
|
||||
|
||||
public function save() {
|
||||
|
@ -198,8 +198,10 @@ final class PonderQuestion extends PonderDAO
|
|||
return ($viewer->getPHID() == $this->getAuthorPHID());
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
|
||||
|
||||
|
||||
public function getUsersToNotifyOfTokenGiven() {
|
||||
return array(
|
||||
$this->getAuthorPHID(),
|
||||
|
|
Loading…
Reference in a new issue