3 final class PonderQuestionViewController
extends PonderController
{
5 public function shouldAllowPublic() {
9 public function handleRequest(AphrontRequest
$request) {
10 $viewer = $request->getViewer();
11 $id = $request->getURIData('id');
13 $question = id(new PonderQuestionQuery())
17 ->needProjectPHIDs(true)
20 return new Aphront404Response();
23 $answers = $this->buildAnswers($question);
25 $answer_add_panel = id(new PonderAddAnswerView())
26 ->setQuestion($question)
28 ->setActionURI('/ponder/answer/add/');
30 $header = new PHUIHeaderView();
31 $header->setHeader($question->getTitle());
32 $header->setUser($viewer);
33 $header->setPolicyObject($question);
34 $header->setHeaderIcon('fa-university');
36 if ($question->getStatus() == PonderQuestionStatus
::STATUS_OPEN
) {
37 $header->setStatus('fa-square-o', 'bluegrey', pht('Open'));
39 $text = PonderQuestionStatus
::getQuestionStatusFullName(
40 $question->getStatus());
41 $icon = PonderQuestionStatus
::getQuestionStatusIcon(
42 $question->getStatus());
43 $header->setStatus($icon, 'dark', $text);
46 $curtain = $this->buildCurtain($question);
47 $details = $this->buildPropertySectionView($question);
49 $can_edit = PhabricatorPolicyFilter
::hasCapability(
52 PhabricatorPolicyCapability
::CAN_EDIT
);
54 $content_id = celerity_generate_unique_node_id();
55 $timeline = $this->buildTransactionTimeline(
57 id(new PonderQuestionTransactionQuery())
58 ->withTransactionTypes(array(PhabricatorTransactions
::TYPE_COMMENT
)));
59 $xactions = $timeline->getTransactions();
61 $add_comment = id(new PhabricatorApplicationTransactionCommentView())
63 ->setObjectPHID($question->getPHID())
64 ->setShowPreview(false)
65 ->setAction($this->getApplicationURI("/question/comment/{$id}/"))
66 ->setSubmitButtonName(pht('Comment'));
68 $add_comment = phutil_tag_div(
69 'ponder-question-add-comment-view', $add_comment);
71 $comment_view = phutil_tag(
75 'style' => 'display: none;',
82 $footer = id(new PonderFooterView())
83 ->setContentID($content_id)
84 ->setCount(count($xactions));
86 $crumbs = $this->buildApplicationCrumbs();
87 $crumbs->addTextCrumb('Q'.$id, '/Q'.$id);
88 $crumbs->setBorder(true);
90 $subheader = $this->buildSubheaderView($question);
93 if ($question->getAnswerWiki()) {
94 $wiki = new PHUIRemarkupView($viewer, $question->getAnswerWiki());
95 $answer_wiki = id(new PHUIObjectBoxView())
96 ->setBackground(PHUIObjectBoxView
::BLUE_PROPERTY
)
97 ->setHeaderText(pht('Answer Summary'))
99 ->addClass('ponder-answer-wiki');
102 require_celerity_resource('ponder-view-css');
104 $ponder_content = phutil_tag(
107 'class' => 'ponder-question-content',
117 $ponder_view = id(new PHUITwoColumnView())
119 ->setSubheader($subheader)
120 ->setCurtain($curtain)
121 ->setMainColumn($ponder_content)
122 ->addPropertySection(pht('Details'), $details)
123 ->addClass('ponder-question-view');
125 $page_objects = array_merge(
126 array($question->getPHID()),
127 mpull($question->getAnswers(), 'getPHID'));
129 return $this->newPage()
130 ->setTitle('Q'.$question->getID().' '.$question->getTitle())
132 ->setPageObjectPHIDs($page_objects)
133 ->appendChild($ponder_view);
136 private function buildCurtain(PonderQuestion
$question) {
137 $viewer = $this->getViewer();
138 $id = $question->getID();
140 $can_edit = PhabricatorPolicyFilter
::hasCapability(
143 PhabricatorPolicyCapability
::CAN_EDIT
);
145 $curtain = $this->newCurtainView($question);
147 if ($question->getStatus() == PonderQuestionStatus
::STATUS_OPEN
) {
148 $name = pht('Close Question');
149 $icon = 'fa-check-square-o';
151 $name = pht('Reopen Question');
152 $icon = 'fa-square-o';
156 id(new PhabricatorActionView())
157 ->setIcon('fa-pencil')
158 ->setName(pht('Edit Question'))
159 ->setHref($this->getApplicationURI("/question/edit/{$id}/"))
160 ->setDisabled(!$can_edit)
161 ->setWorkflow(!$can_edit));
164 id(new PhabricatorActionView())
168 ->setDisabled(!$can_edit)
169 ->setHref($this->getApplicationURI("/question/status/{$id}/")));
172 id(new PhabricatorActionView())
174 ->setName(pht('View History'))
175 ->setHref($this->getApplicationURI("/question/history/{$id}/")));
180 private function buildSubheaderView(
181 PonderQuestion
$question) {
182 $viewer = $this->getViewer();
184 $asker = $viewer->renderHandle($question->getAuthorPHID())->render();
185 $date = phabricator_datetime($question->getDateCreated(), $viewer);
186 $asker = phutil_tag('strong', array(), $asker);
188 $author = id(new PhabricatorPeopleQuery())
190 ->withPHIDs(array($question->getAuthorPHID()))
191 ->needProfileImage(true)
194 $image_uri = $author->getProfileImageURI();
195 $image_href = '/p/'.$author->getUsername();
197 $content = pht('Asked by %s on %s.', $asker, $date);
199 return id(new PHUIHeadThingView())
200 ->setImage($image_uri)
201 ->setImageHref($image_href)
202 ->setContent($content);
205 private function buildPropertySectionView(
206 PonderQuestion
$question) {
207 $viewer = $this->getViewer();
209 $question_details = PhabricatorMarkupEngine
::renderOneObject(
211 $question->getMarkupField(),
214 if (!$question_details) {
215 $question_details = phutil_tag(
218 pht('No further details for this question.'));
221 $question_details = phutil_tag_div(
222 'phabricator-remarkup ml', $question_details);
224 return $question_details;
228 * This is fairly non-standard; building N timelines at once (N = number of
229 * answers) is tricky business.
231 * TODO - re-factor this to ajax in one answer panel at a time in a more
232 * standard fashion. This is necessary to scale this application.
234 private function buildAnswers(PonderQuestion
$question) {
235 $viewer = $this->getViewer();
236 $answers = $question->getAnswers();
239 $author_phids = mpull($answers, 'getAuthorPHID');
240 $handles = $this->loadViewerHandles($author_phids);
243 foreach ($answers as $answer) {
244 $id = $answer->getID();
245 $handle = $handles[$answer->getAuthorPHID()];
247 $timeline = $this->buildTransactionTimeline(
249 id(new PonderAnswerTransactionQuery())
250 ->withTransactionTypes(array(PhabricatorTransactions
::TYPE_COMMENT
)));
251 $xactions = $timeline->getTransactions();
253 $view[] = id(new PonderAnswerView())
256 ->setTransactions($xactions)
257 ->setTimeline($timeline)
258 ->setHandle($handle);
262 $header = id(new PHUIHeaderView())
263 ->setHeader('Answers');
266 return id(new PHUIBoxView())
267 ->addClass('ponder-answer-section')
268 ->appendChild($header)
269 ->appendChild($view);