2012-08-10 10:44:04 -07:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
final class PonderQuestionViewController extends PonderController {
|
|
|
|
|
|
2015-08-21 06:49:49 -07:00
|
|
|
public function shouldAllowPublic() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-22 13:23:11 -07:00
|
|
|
public function handleRequest(AphrontRequest $request) {
|
2015-08-05 09:42:39 -07:00
|
|
|
$viewer = $request->getViewer();
|
2015-07-22 13:23:11 -07:00
|
|
|
$id = $request->getURIData('id');
|
2012-08-10 10:44:04 -07:00
|
|
|
|
2013-07-28 15:38:47 -07:00
|
|
|
$question = id(new PonderQuestionQuery())
|
2015-08-05 09:42:39 -07:00
|
|
|
->setViewer($viewer)
|
2015-07-22 13:23:11 -07:00
|
|
|
->withIDs(array($id))
|
2013-07-28 16:17:51 -07:00
|
|
|
->needAnswers(true)
|
2015-08-10 14:55:43 -07:00
|
|
|
->needProjectPHIDs(true)
|
2013-07-28 15:38:47 -07:00
|
|
|
->executeOne();
|
2012-08-10 10:44:04 -07:00
|
|
|
if (!$question) {
|
|
|
|
|
return new Aphront404Response();
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-29 11:18:22 -07:00
|
|
|
$answers = $this->buildAnswers($question);
|
2012-08-10 10:44:04 -07:00
|
|
|
|
2015-08-12 07:56:31 -07:00
|
|
|
$answer_add_panel = id(new PonderAddAnswerView())
|
|
|
|
|
->setQuestion($question)
|
|
|
|
|
->setUser($viewer)
|
|
|
|
|
->setActionURI('/ponder/answer/add/');
|
2012-08-10 10:44:04 -07:00
|
|
|
|
2015-08-05 09:42:39 -07:00
|
|
|
$header = new PHUIHeaderView();
|
|
|
|
|
$header->setHeader($question->getTitle());
|
|
|
|
|
$header->setUser($viewer);
|
|
|
|
|
$header->setPolicyObject($question);
|
2016-03-03 22:08:00 +00:00
|
|
|
$header->setHeaderIcon('fa-university');
|
2012-10-05 13:12:31 -07:00
|
|
|
|
2015-01-06 11:13:04 -08:00
|
|
|
if ($question->getStatus() == PonderQuestionStatus::STATUS_OPEN) {
|
|
|
|
|
$header->setStatus('fa-square-o', 'bluegrey', pht('Open'));
|
|
|
|
|
} else {
|
2015-08-08 10:23:33 -07:00
|
|
|
$text = PonderQuestionStatus::getQuestionStatusFullName(
|
|
|
|
|
$question->getStatus());
|
|
|
|
|
$icon = PonderQuestionStatus::getQuestionStatusIcon(
|
|
|
|
|
$question->getStatus());
|
|
|
|
|
$header->setStatus($icon, 'dark', $text);
|
2015-01-06 11:13:04 -08:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
$properties = $this->buildPropertyListView($question);
|
2016-02-26 14:34:51 -08:00
|
|
|
$actions = $this->buildActionListView($question);
|
2016-03-01 12:14:28 -08:00
|
|
|
$details = $this->buildPropertySectionView($question);
|
2016-02-23 07:23:58 -08:00
|
|
|
|
|
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
|
|
|
|
$viewer,
|
|
|
|
|
$question,
|
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
|
|
2015-08-11 10:42:40 -07:00
|
|
|
$content_id = celerity_generate_unique_node_id();
|
|
|
|
|
$timeline = $this->buildTransactionTimeline(
|
|
|
|
|
$question,
|
|
|
|
|
id(new PonderQuestionTransactionQuery())
|
|
|
|
|
->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT)));
|
|
|
|
|
$xactions = $timeline->getTransactions();
|
|
|
|
|
|
|
|
|
|
$add_comment = id(new PhabricatorApplicationTransactionCommentView())
|
|
|
|
|
->setUser($viewer)
|
|
|
|
|
->setObjectPHID($question->getPHID())
|
|
|
|
|
->setShowPreview(false)
|
|
|
|
|
->setAction($this->getApplicationURI("/question/comment/{$id}/"))
|
|
|
|
|
->setSubmitButtonName(pht('Comment'));
|
|
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
$add_comment = phutil_tag_div(
|
|
|
|
|
'ponder-question-add-comment-view', $add_comment);
|
|
|
|
|
|
2015-08-11 10:42:40 -07:00
|
|
|
$comment_view = phutil_tag(
|
|
|
|
|
'div',
|
|
|
|
|
array(
|
|
|
|
|
'id' => $content_id,
|
|
|
|
|
'style' => 'display: none;',
|
|
|
|
|
),
|
|
|
|
|
array(
|
|
|
|
|
$timeline,
|
|
|
|
|
$add_comment,
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
$footer = id(new PonderFooterView())
|
|
|
|
|
->setContentID($content_id)
|
|
|
|
|
->setCount(count($xactions));
|
|
|
|
|
|
2013-04-10 13:08:36 -07:00
|
|
|
$crumbs = $this->buildApplicationCrumbs($this->buildSideNavView());
|
2015-07-22 13:23:11 -07:00
|
|
|
$crumbs->addTextCrumb('Q'.$id, '/Q'.$id);
|
2016-02-23 07:23:58 -08:00
|
|
|
$crumbs->setBorder(true);
|
2013-04-10 13:08:36 -07:00
|
|
|
|
2016-02-26 14:34:51 -08:00
|
|
|
$subheader = $this->buildSubheaderView($question);
|
|
|
|
|
|
2015-08-29 13:59:33 -07:00
|
|
|
$answer_wiki = null;
|
|
|
|
|
if ($question->getAnswerWiki()) {
|
2016-02-23 07:23:58 -08:00
|
|
|
$wiki = new PHUIRemarkupView($viewer, $question->getAnswerWiki());
|
2015-08-29 13:59:33 -07:00
|
|
|
$answer_wiki = id(new PHUIObjectBoxView())
|
2016-02-26 14:34:51 -08:00
|
|
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
|
|
|
|
->setHeaderText(pht('ANSWER SUMMARY'))
|
2016-02-23 07:23:58 -08:00
|
|
|
->appendChild($wiki)
|
|
|
|
|
->addClass('ponder-answer-wiki');
|
2015-08-29 13:59:33 -07:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
require_celerity_resource('ponder-view-css');
|
|
|
|
|
|
|
|
|
|
$ponder_content = phutil_tag(
|
|
|
|
|
'div',
|
|
|
|
|
array(
|
|
|
|
|
'class' => 'ponder-question-content',
|
|
|
|
|
),
|
2015-08-05 09:42:39 -07:00
|
|
|
array(
|
2016-02-23 07:23:58 -08:00
|
|
|
$footer,
|
2016-02-19 14:45:05 -08:00
|
|
|
$comment_view,
|
|
|
|
|
$answer_wiki,
|
|
|
|
|
$answers,
|
|
|
|
|
$answer_add_panel,
|
2012-08-10 10:44:04 -07:00
|
|
|
));
|
2016-02-23 07:23:58 -08:00
|
|
|
|
|
|
|
|
$ponder_view = id(new PHUITwoColumnView())
|
|
|
|
|
->setHeader($header)
|
2016-02-26 14:34:51 -08:00
|
|
|
->setSubheader($subheader)
|
2016-02-23 07:23:58 -08:00
|
|
|
->setMainColumn($ponder_content)
|
2016-02-26 14:34:51 -08:00
|
|
|
->setPropertyList($properties)
|
2016-03-01 12:14:28 -08:00
|
|
|
->addPropertySection(pht('DETAILS'), $details)
|
2016-02-26 14:34:51 -08:00
|
|
|
->setActionList($actions)
|
2016-02-23 07:23:58 -08:00
|
|
|
->addClass('ponder-question-view');
|
|
|
|
|
|
|
|
|
|
$page_objects = array_merge(
|
|
|
|
|
array($question->getPHID()),
|
|
|
|
|
mpull($question->getAnswers(), 'getPHID'));
|
|
|
|
|
|
|
|
|
|
return $this->newPage()
|
|
|
|
|
->setTitle('Q'.$question->getID().' '.$question->getTitle())
|
|
|
|
|
->setCrumbs($crumbs)
|
|
|
|
|
->setPageObjectPHIDs($page_objects)
|
|
|
|
|
->appendChild(
|
|
|
|
|
array(
|
|
|
|
|
$ponder_view,
|
|
|
|
|
));
|
2012-08-10 10:44:04 -07:00
|
|
|
}
|
2012-10-05 13:12:31 -07:00
|
|
|
|
|
|
|
|
private function buildActionListView(PonderQuestion $question) {
|
2015-08-05 09:42:39 -07:00
|
|
|
$viewer = $this->getViewer();
|
2013-07-12 11:39:47 -07:00
|
|
|
$request = $this->getRequest();
|
2013-07-28 15:02:18 -07:00
|
|
|
$id = $question->getID();
|
|
|
|
|
|
|
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
|
|
|
|
$viewer,
|
|
|
|
|
$question,
|
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
2015-08-05 09:42:39 -07:00
|
|
|
->setUser($viewer)
|
Remove all setObjectURI() from ActionListViews
Summary:
Ref T10004. After D14804, we get this behavior by default and no longer need to set it explicitly.
(If some endpoint did eventually need to set it explicitly, it could just change what it passes to `setHref()`, but I believe we currently have no such endpoints and do not foresee ever having any.)
Test Plan:
- As a logged out user, clicked various links in Differential, Maniphest, Files, etc., always got redirected to a sensible place after login.
- Grepped for `setObjectURI()`, `getObjectURI()` (there are a few remaining callsites, but to a different method with the same name in Doorkeeper).
Reviewers: chad
Reviewed By: chad
Subscribers: hach-que
Maniphest Tasks: T10004
Differential Revision: https://secure.phabricator.com/D14805
2015-12-17 06:31:33 -08:00
|
|
|
->setObject($question);
|
2013-07-27 18:37:17 -07:00
|
|
|
|
2013-07-28 15:02:18 -07:00
|
|
|
if ($question->getStatus() == PonderQuestionStatus::STATUS_OPEN) {
|
2014-05-12 10:08:32 -07:00
|
|
|
$name = pht('Close Question');
|
2015-01-06 11:13:04 -08:00
|
|
|
$icon = 'fa-check-square-o';
|
2013-07-28 15:02:18 -07:00
|
|
|
} else {
|
2014-05-12 10:08:32 -07:00
|
|
|
$name = pht('Reopen Question');
|
2015-01-06 11:13:04 -08:00
|
|
|
$icon = 'fa-square-o';
|
2013-07-27 18:37:17 -07:00
|
|
|
}
|
|
|
|
|
|
2016-02-26 14:34:51 -08:00
|
|
|
$view->addAction(
|
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
|
->setIcon('fa-pencil')
|
|
|
|
|
->setName(pht('Edit Question'))
|
|
|
|
|
->setHref($this->getApplicationURI("/question/edit/{$id}/"))
|
|
|
|
|
->setDisabled(!$can_edit)
|
|
|
|
|
->setWorkflow(!$can_edit));
|
|
|
|
|
|
2013-07-28 15:02:18 -07:00
|
|
|
$view->addAction(
|
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
|
->setName($name)
|
|
|
|
|
->setIcon($icon)
|
2015-08-08 10:23:33 -07:00
|
|
|
->setWorkflow(true)
|
2013-07-28 15:02:18 -07:00
|
|
|
->setDisabled(!$can_edit)
|
2015-08-08 10:23:33 -07:00
|
|
|
->setHref($this->getApplicationURI("/question/status/{$id}/")));
|
2013-07-28 15:02:18 -07:00
|
|
|
|
2013-07-28 18:32:55 -07:00
|
|
|
$view->addAction(
|
|
|
|
|
id(new PhabricatorActionView())
|
2014-05-12 10:08:32 -07:00
|
|
|
->setIcon('fa-list')
|
2013-07-28 18:32:55 -07:00
|
|
|
->setName(pht('View History'))
|
|
|
|
|
->setHref($this->getApplicationURI("/question/history/{$id}/")));
|
|
|
|
|
|
2013-07-28 15:02:18 -07:00
|
|
|
return $view;
|
2012-10-05 13:12:31 -07:00
|
|
|
}
|
|
|
|
|
|
2012-10-08 14:47:21 -07:00
|
|
|
private function buildPropertyListView(
|
2016-02-23 07:23:58 -08:00
|
|
|
PonderQuestion $question) {
|
2012-10-08 14:47:21 -07:00
|
|
|
|
2015-08-05 09:42:39 -07:00
|
|
|
$viewer = $this->getViewer();
|
2013-10-11 07:53:56 -07:00
|
|
|
$view = id(new PHUIPropertyListView())
|
2013-05-09 14:40:43 -07:00
|
|
|
->setUser($viewer)
|
2016-02-26 14:34:51 -08:00
|
|
|
->setObject($question);
|
2013-07-27 18:37:17 -07:00
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
$view->invokeWillRenderEvent();
|
2012-10-05 13:12:31 -07:00
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
return $view;
|
|
|
|
|
}
|
2013-07-28 15:02:18 -07:00
|
|
|
|
2016-02-26 14:34:51 -08:00
|
|
|
private function buildSubheaderView(
|
2016-02-23 07:23:58 -08:00
|
|
|
PonderQuestion $question) {
|
|
|
|
|
$viewer = $this->getViewer();
|
2015-08-14 09:51:52 -07:00
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
$asker = $viewer->renderHandle($question->getAuthorPHID())->render();
|
|
|
|
|
$date = phabricator_datetime($question->getDateCreated(), $viewer);
|
|
|
|
|
$asker = phutil_tag('strong', array(), $asker);
|
|
|
|
|
|
|
|
|
|
$author = id(new PhabricatorPeopleQuery())
|
|
|
|
|
->setViewer($viewer)
|
|
|
|
|
->withPHIDs(array($question->getAuthorPHID()))
|
|
|
|
|
->needProfileImage(true)
|
|
|
|
|
->executeOne();
|
|
|
|
|
|
|
|
|
|
$image_uri = $author->getProfileImageURI();
|
|
|
|
|
$image_href = '/p/'.$author->getUsername();
|
|
|
|
|
|
2016-02-26 14:34:51 -08:00
|
|
|
$content = pht('Asked by %s on %s.', $asker, $date);
|
2016-02-23 07:23:58 -08:00
|
|
|
|
2016-02-26 14:34:51 -08:00
|
|
|
return id(new PHUIHeadThingView())
|
|
|
|
|
->setImage($image_uri)
|
|
|
|
|
->setImageHref($image_href)
|
|
|
|
|
->setContent($content);
|
|
|
|
|
}
|
2016-02-23 07:23:58 -08:00
|
|
|
|
2016-03-01 12:14:28 -08:00
|
|
|
private function buildPropertySectionView(
|
2016-02-26 14:34:51 -08:00
|
|
|
PonderQuestion $question) {
|
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
|
|
|
|
|
|
$question_details = PhabricatorMarkupEngine::renderOneObject(
|
|
|
|
|
$question,
|
|
|
|
|
$question->getMarkupField(),
|
|
|
|
|
$viewer);
|
|
|
|
|
|
|
|
|
|
if (!$question_details) {
|
|
|
|
|
$question_details = phutil_tag(
|
|
|
|
|
'em',
|
|
|
|
|
array(),
|
|
|
|
|
pht('No further details for this question.'));
|
|
|
|
|
}
|
2016-02-23 07:23:58 -08:00
|
|
|
|
2016-02-26 14:34:51 -08:00
|
|
|
$question_details = phutil_tag_div(
|
|
|
|
|
'phabricator-remarkup ml', $question_details);
|
2016-02-23 07:23:58 -08:00
|
|
|
|
2016-03-01 12:14:28 -08:00
|
|
|
return $question_details;
|
2012-10-05 13:12:31 -07:00
|
|
|
}
|
2013-07-28 15:02:18 -07:00
|
|
|
|
Transactions - deploy buildTransactionTimeline to remaining applications
Summary:
Ref T4712. Specifically...
- Differential
- needed getApplicationTransactionViewObject() implemented
- Audit
- needed getApplicationTransactionViewObject() implemented
- Repository
- one object needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true)
- Ponder
- BONUS BUG FIX - leaving a comment on an answer had a bad redirect URI
- both PonderQuestion and PonderAnswer needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) on both "history" controllers
- left a "TODO" on buildAnswers on the question view controller, which is non-standard and should be re-written eventually
- Phortune
- BONUS BUG FIX - fix new user "createNewAccount" code to not fatal
- PhortuneAccount, PhortuneMerchant, and PhortuneCart needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) on Account view, merchant view, and cart view controller
- Fund
- Legalpad
- Nuance
- NuanceSource needed PhabricatorApplicationTransactionInterface implemented
- Releeph (this product is kind of a mess...)
- HACKQUEST - had to manually create an arcanist project to even be able to make a "product" and get started...!
- BONUS BUG FIX - make sure to "setName" on product edit
- ReleephProject (should be ReleepProduct...?), ReleephBranch, and ReleepRequest needed PhabricatorApplicationTransactionInterface implemented
- Harbormaster
- HarbormasterBuildable, HarbormasterBuild, HarbormasterBuildPlan, and HarbormasterBuildStep all needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) all over the place
Test Plan: foreach application, viewed the timeline(s) and made sure they still rendered
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T4712
Differential Revision: https://secure.phabricator.com/D10925
2014-12-03 15:35:47 -08:00
|
|
|
/**
|
|
|
|
|
* This is fairly non-standard; building N timelines at once (N = number of
|
|
|
|
|
* answers) is tricky business.
|
|
|
|
|
*
|
|
|
|
|
* TODO - re-factor this to ajax in one answer panel at a time in a more
|
|
|
|
|
* standard fashion. This is necessary to scale this application.
|
|
|
|
|
*/
|
2015-08-29 11:18:22 -07:00
|
|
|
private function buildAnswers(PonderQuestion $question) {
|
2015-08-05 09:42:39 -07:00
|
|
|
$viewer = $this->getViewer();
|
2015-08-29 11:18:22 -07:00
|
|
|
$answers = $question->getAnswers();
|
2013-07-28 16:17:51 -07:00
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
if ($answers) {
|
|
|
|
|
$author_phids = mpull($answers, 'getAuthorPHID');
|
|
|
|
|
$handles = $this->loadViewerHandles($author_phids);
|
2013-07-28 16:17:51 -07:00
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
$view = array();
|
|
|
|
|
foreach ($answers as $answer) {
|
|
|
|
|
$id = $answer->getID();
|
|
|
|
|
$handle = $handles[$answer->getAuthorPHID()];
|
2013-07-28 16:17:51 -07:00
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
$timeline = $this->buildTransactionTimeline(
|
|
|
|
|
$answer,
|
|
|
|
|
id(new PonderAnswerTransactionQuery())
|
|
|
|
|
->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT)));
|
|
|
|
|
$xactions = $timeline->getTransactions();
|
2015-08-20 11:23:30 -07:00
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
$view[] = id(new PonderAnswerView())
|
|
|
|
|
->setUser($viewer)
|
|
|
|
|
->setAnswer($answer)
|
|
|
|
|
->setTransactions($xactions)
|
|
|
|
|
->setTimeline($timeline)
|
|
|
|
|
->setHandle($handle);
|
2013-07-28 16:17:51 -07:00
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$header = id(new PHUIHeaderView())
|
|
|
|
|
->setHeader('Answers');
|
2016-02-23 20:30:43 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
return id(new PHUIBoxView())
|
|
|
|
|
->addClass('ponder-answer-section')
|
|
|
|
|
->appendChild($header)
|
|
|
|
|
->appendChild($view);
|
2013-07-28 16:17:51 -07:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 07:23:58 -08:00
|
|
|
return null;
|
|
|
|
|
|
2013-07-28 16:17:51 -07:00
|
|
|
}
|
|
|
|
|
|
2012-08-10 10:44:04 -07:00
|
|
|
}
|