@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allowing Closing of questions

Summary:
Fixes T3579

As a basic overview, this enables the author of a question to open/close a question.

Other bits;

- Add "Open" filter to the builtin queries
- Add "Status" to search form
- Refactor ponder constants
- Add coloured bars for different question statuses

Test Plan:
- Open/Close questions
- Search for some bits
- Use filters

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T3579

Differential Revision: https://secure.phabricator.com/D6590

Conflicts:
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php

authored by

Gareth Evans and committed by
epriestley
70a5ec60 91c08ca6

+220 -22
+5
resources/sql/patches/20130727.ponderquestionstatus.sql
··· 1 + ALTER TABLE {$NAMESPACE}_ponder.ponder_question 2 + ADD COLUMN `status` INT(10) UNSIGNED NOT NULL AFTER `authorPHID`; 3 + 4 + ALTER TABLE {$NAMESPACE}_ponder.ponder_question 5 + ADD INDEX `status` (`status`);
+9 -1
src/__phutil_library_map__.php
··· 1881 1881 'PonderCommentMail' => 'applications/ponder/mail/PonderCommentMail.php', 1882 1882 'PonderCommentQuery' => 'applications/ponder/query/PonderCommentQuery.php', 1883 1883 'PonderCommentSaveController' => 'applications/ponder/controller/PonderCommentSaveController.php', 1884 - 'PonderConstants' => 'applications/ponder/PonderConstants.php', 1884 + 'PonderConstants' => 'applications/ponder/constants/PonderConstants.php', 1885 1885 'PonderController' => 'applications/ponder/controller/PonderController.php', 1886 1886 'PonderDAO' => 'applications/ponder/storage/PonderDAO.php', 1887 + 'PonderLiterals' => 'applications/ponder/constants/PonderLiterals.php', 1887 1888 'PonderMail' => 'applications/ponder/mail/PonderMail.php', 1888 1889 'PonderMentionMail' => 'applications/ponder/mail/PonderMentionMail.php', 1889 1890 'PonderPHIDTypeQuestion' => 'applications/ponder/phid/PonderPHIDTypeQuestion.php', ··· 1897 1898 'PonderQuestionPreviewController' => 'applications/ponder/controller/PonderQuestionPreviewController.php', 1898 1899 'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php', 1899 1900 'PonderQuestionSearchEngine' => 'applications/ponder/query/PonderQuestionSearchEngine.php', 1901 + 'PonderQuestionStatus' => 'applications/ponder/constants/PonderQuestionStatus.php', 1902 + 'PonderQuestionStatusController' => 'applications/ponder/controller/PonderQuestionStatusController.php', 1900 1903 'PonderQuestionSummaryView' => 'applications/ponder/view/PonderQuestionSummaryView.php', 1901 1904 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 1902 1905 'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php', ··· 1905 1908 'PonderUserProfileView' => 'applications/ponder/view/PonderUserProfileView.php', 1906 1909 'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php', 1907 1910 'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php', 1911 + 'PonderVote' => 'applications/ponder/constants/PonderVote.php', 1908 1912 'PonderVoteEditor' => 'applications/ponder/editor/PonderVoteEditor.php', 1909 1913 'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php', 1910 1914 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', ··· 3996 4000 'PonderCommentSaveController' => 'PonderController', 3997 4001 'PonderController' => 'PhabricatorController', 3998 4002 'PonderDAO' => 'PhabricatorLiskDAO', 4003 + 'PonderLiterals' => 'PonderConstants', 3999 4004 'PonderMail' => 'PhabricatorMail', 4000 4005 'PonderMentionMail' => 'PonderMail', 4001 4006 'PonderPHIDTypeQuestion' => 'PhabricatorPHIDType', ··· 4021 4026 'PonderQuestionPreviewController' => 'PonderController', 4022 4027 'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4023 4028 'PonderQuestionSearchEngine' => 'PhabricatorApplicationSearchEngine', 4029 + 'PonderQuestionStatus' => 'PonderConstants', 4030 + 'PonderQuestionStatusController' => 'PonderController', 4024 4031 'PonderQuestionSummaryView' => 'AphrontView', 4025 4032 'PonderQuestionViewController' => 'PonderController', 4026 4033 'PonderRemarkupRule' => 'PhabricatorRemarkupRuleObject', ··· 4028 4035 'PonderSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 4029 4036 'PonderUserProfileView' => 'AphrontView', 4030 4037 'PonderVotableView' => 'AphrontView', 4038 + 'PonderVote' => 'PonderConstants', 4031 4039 'PonderVoteEditor' => 'PhabricatorEditor', 4032 4040 'PonderVoteSaveController' => 'PonderController', 4033 4041 'ProjectRemarkupRule' => 'PhabricatorRemarkupRuleObject',
-10
src/applications/ponder/PonderConstants.php
··· 1 - <?php 2 - 3 - final class PonderConstants { 4 - const UP_VOTE = 1; 5 - const NONE_VOTE = 0; 6 - const DOWN_VOTE = -1; 7 - 8 - const ANSWERED_LITERAL = "answered"; 9 - const ASKED_LITERAL = "asked"; 10 - }
+2
src/applications/ponder/application/PhabricatorApplicationPonder.php
··· 54 54 'answer/preview/' => 'PonderAnswerPreviewController', 55 55 'question/ask/' => 'PonderQuestionAskController', 56 56 'question/preview/' => 'PonderQuestionPreviewController', 57 + 'question/(?P<status>open|close)/(?P<id>[1-9]\d*)/' => 58 + 'PonderQuestionStatusController', 57 59 'comment/add/' => 'PonderCommentSaveController', 58 60 '(?P<kind>question)/vote/' => 'PonderVoteSaveController', 59 61 '(?P<kind>answer)/vote/' => 'PonderVoteSaveController'
+4
src/applications/ponder/constants/PonderConstants.php
··· 1 + <?php 2 + 3 + abstract class PonderConstants { 4 + }
+10
src/applications/ponder/constants/PonderLiterals.php
··· 1 + <?php 2 + /** 3 + * @group ponder 4 + */ 5 + final class PonderLiterals extends PonderConstants { 6 + 7 + const LITERAL_ANSWERED = "answered"; 8 + const LITERAL_ASKED = "asked"; 9 + 10 + }
+34
src/applications/ponder/constants/PonderQuestionStatus.php
··· 1 + <?php 2 + 3 + /** 4 + * @group ponder 5 + */ 6 + final class PonderQuestionStatus extends PonderConstants { 7 + 8 + const STATUS_OPEN = 0; 9 + const STATUS_CLOSED = 1; 10 + 11 + public static function getQuestionStatusMap() { 12 + return array( 13 + self::STATUS_OPEN => pht('Open'), 14 + self::STATUS_CLOSED => pht('Closed'), 15 + ); 16 + } 17 + 18 + public static function getQuestionStatusFullName($status) { 19 + $map = array( 20 + self::STATUS_OPEN => pht('Open'), 21 + self::STATUS_CLOSED => pht('Closed by author'), 22 + ); 23 + return idx($map, $status, '???'); 24 + } 25 + 26 + public static function getQuestionStatusTagColor($status) { 27 + $map = array( 28 + self::STATUS_CLOSED => PhabricatorTagView::COLOR_BLACK, 29 + ); 30 + 31 + return idx($map, $status); 32 + } 33 + 34 + }
+11
src/applications/ponder/constants/PonderVote.php
··· 1 + <?php 2 + /** 3 + * @group ponder 4 + */ 5 + final class PonderVote extends PonderConstants { 6 + 7 + const VOTE_UP = 1; 8 + const VOTE_NONE = 0; 9 + const VOTE_DOWN = -1; 10 + 11 + }
+1 -1
src/applications/ponder/controller/PonderAnswerPreviewController.php
··· 29 29 ->setPreview(true) 30 30 ->setUser($user) 31 31 ->setHandles($handles) 32 - ->setAction(PonderConstants::ANSWERED_LITERAL); 32 + ->setAction(PonderLiterals::LITERAL_ANSWERED); 33 33 34 34 return id(new AphrontAjaxResponse()) 35 35 ->setContent($view->render());
+1
src/applications/ponder/controller/PonderQuestionAskController.php
··· 17 17 if ($request->isFormPost()) { 18 18 $question->setTitle($request->getStr('title')); 19 19 $question->setContent($request->getStr('content')); 20 + $question->setStatus(PonderQuestionStatus::STATUS_OPEN); 20 21 21 22 $len = phutil_utf8_strlen($question->getTitle()); 22 23 if ($len < 1) {
+3
src/applications/ponder/controller/PonderQuestionListController.php
··· 45 45 $item->setHeader($question->getTitle()); 46 46 $item->setHref('/Q'.$question->getID()); 47 47 $item->setObject($question); 48 + $item->setBarColor( 49 + PonderQuestionStatus::getQuestionStatusTagColor( 50 + $question->getStatus())); 48 51 49 52 $created_date = phabricator_date($question->getDateCreated(), $viewer); 50 53 $item->addIcon('none', $created_date);
+40
src/applications/ponder/controller/PonderQuestionStatusController.php
··· 1 + <?php 2 + 3 + final class PonderQuestionStatusController 4 + extends PonderController { 5 + 6 + private $status; 7 + private $id; 8 + 9 + public function willProcessRequest(array $data) { 10 + $this->status = idx($data, 'status'); 11 + $this->id = idx($data, 'id'); 12 + } 13 + 14 + public function processRequest() { 15 + 16 + $request = $this->getRequest(); 17 + $user = $request->getUser(); 18 + 19 + $question = id(new PonderQuestion())->load($this->id); 20 + if (!$question) { 21 + return new Aphront404Response(); 22 + } 23 + 24 + switch ($this->status) { 25 + case 'open': 26 + $question->setStatus(PonderQuestionStatus::STATUS_OPEN); 27 + break; 28 + case 'close': 29 + $question->setStatus(PonderQuestionStatus::STATUS_CLOSED); 30 + break; 31 + default: 32 + return new Aphront400Response(); 33 + } 34 + 35 + $question->save(); 36 + 37 + return id(new AphrontRedirectResponse())->setURI('/Q'.$question->getID()); 38 + } 39 + 40 + }
+31 -2
src/applications/ponder/controller/PonderQuestionViewController.php
··· 92 92 93 93 private function buildActionListView(PonderQuestion $question) { 94 94 $request = $this->getRequest(); 95 - return id(new PhabricatorActionListView()) 96 - ->setUser($request->getUser()) 95 + $user = $request->getUser(); 96 + 97 + $action_list = id(new PhabricatorActionListView()) 98 + ->setUser($user) 97 99 ->setObject($question) 98 100 ->setObjectURI($request->getRequestURI()); 101 + 102 + if ($user->getPhid() === $question->getAuthorPhid()) { 103 + if ($question->getStatus() == PonderQuestionStatus::STATUS_OPEN) { 104 + $name = pht("Close Question"); 105 + $icon = "delete"; 106 + $href = "close"; 107 + } else { 108 + $name = pht("Open Question"); 109 + $icon = "enable"; 110 + $href = "open"; 111 + } 112 + $action_list->addAction( 113 + id(new PhabricatorActionView()) 114 + ->setName($name) 115 + ->setIcon($icon) 116 + ->setRenderAsForm(true) 117 + ->setHref( 118 + $this->getApplicationURI( 119 + "/question/{$href}/{$this->questionID}/"))); 120 + } 121 + 122 + return $action_list; 99 123 } 100 124 101 125 private function buildPropertyListView( ··· 105 129 $view = id(new PhabricatorPropertyListView()) 106 130 ->setUser($viewer) 107 131 ->setObject($question); 132 + 133 + $view->addProperty( 134 + pht('Status'), 135 + PonderQuestionStatus::getQuestionStatusFullName($question->getStatus())); 136 + 108 137 $view->addProperty( 109 138 pht('Author'), 110 139 $this->getHandle($question->getAuthorPHID())->renderLink());
+1 -1
src/applications/ponder/editor/PonderVoteEditor.php
··· 56 56 $votable->getVotablePHID()); 57 57 58 58 if (!$curvote) { 59 - $curvote = PonderConstants::NONE_VOTE; 59 + $curvote = PonderVote::VOTE_NONE; 60 60 } 61 61 62 62 // adjust votable's score by this much
+31
src/applications/ponder/query/PonderQuestionQuery.php
··· 12 12 private $answererPHIDs; 13 13 private $order = self::ORDER_CREATED; 14 14 15 + private $status = 'status-any'; 16 + const STATUS_ANY = 'status-any'; 17 + const STATUS_OPEN = 'status-open'; 18 + const STATUS_CLOSED = 'status-closed'; 19 + 15 20 public function withIDs(array $ids) { 16 21 $this->ids = $ids; 17 22 return $this; ··· 24 29 25 30 public function withAuthorPHIDs(array $phids) { 26 31 $this->authorPHIDs = $phids; 32 + return $this; 33 + } 34 + 35 + public function withStatus($status) { 36 + $this->status = $status; 27 37 return $this; 28 38 } 29 39 ··· 81 91 $conn_r, 82 92 'q.authorPHID IN (%Ls)', 83 93 $this->authorPHIDs); 94 + } 95 + 96 + if ($this->status) { 97 + switch ($this->status) { 98 + case self::STATUS_ANY: 99 + break; 100 + case self::STATUS_OPEN: 101 + $where[] = qsprintf( 102 + $conn_r, 103 + 'q.status = %d', 104 + PonderQuestionStatus::STATUS_OPEN); 105 + break; 106 + case self::STATUS_CLOSED: 107 + $where[] = qsprintf( 108 + $conn_r, 109 + 'q.status = %d', 110 + PonderQuestionStatus::STATUS_CLOSED); 111 + break; 112 + default: 113 + throw new Exception("Unknown status query '{$this->status}'!"); 114 + } 84 115 } 85 116 86 117 $where[] = $this->buildPagingClause($conn_r);
+26 -1
src/applications/ponder/query/PonderQuestionSearchEngine.php
··· 14 14 'answererPHIDs', 15 15 array_values($request->getArr('answerers'))); 16 16 17 + $saved->setParameter('status', $request->getStr('status')); 18 + 17 19 return $saved; 18 20 } 19 21 ··· 28 30 $answerer_phids = $saved->getParameter('answererPHIDs'); 29 31 if ($answerer_phids) { 30 32 $query->withAnswererPHIDs($answerer_phids); 33 + } 34 + 35 + $status = $saved->getParameter('status'); 36 + if ($status != null) { 37 + switch ($status) { 38 + case 0: 39 + $query->withStatus(PonderQuestionQuery::STATUS_OPEN); 40 + break; 41 + case 1: 42 + $query->withStatus(PonderQuestionQuery::STATUS_CLOSED); 43 + break; 44 + } 31 45 } 32 46 33 47 return $query; ··· 39 53 40 54 $author_phids = $saved_query->getParameter('authorPHIDs', array()); 41 55 $answerer_phids = $saved_query->getParameter('answererPHIDs', array()); 56 + $status = $saved_query->getParameter( 57 + 'status', PonderQuestionStatus::STATUS_OPEN); 42 58 43 59 $phids = array_merge($author_phids, $answerer_phids); 44 60 $handles = id(new PhabricatorObjectHandleData($phids)) ··· 61 77 ->setDatasource('/typeahead/common/users/') 62 78 ->setName('answerers') 63 79 ->setLabel(pht('Answered By')) 64 - ->setValue($answerer_tokens)); 80 + ->setValue($answerer_tokens)) 81 + ->appendChild( 82 + id(new AphrontFormSelectControl()) 83 + ->setLabel(pht('Status')) 84 + ->setName('status') 85 + ->setValue($status) 86 + ->setOptions(PonderQuestionStatus::getQuestionStatusMap())); 65 87 } 66 88 67 89 protected function getURI($path) { ··· 70 92 71 93 public function getBuiltinQueryNames() { 72 94 $names = array( 95 + 'open' => pht('Open Questions'), 73 96 'all' => pht('All Questions'), 74 97 ); 75 98 ··· 89 112 switch ($query_key) { 90 113 case 'all': 91 114 return $query; 115 + case 'open': 116 + return $query->setParameter('status', PonderQuestionQuery::STATUS_OPEN); 92 117 case 'authored': 93 118 return $query->setParameter( 94 119 'authorPHIDs',
+1 -1
src/applications/ponder/storage/PonderAnswer.php
··· 29 29 public function setUserVote($vote) { 30 30 $this->vote = $vote['data']; 31 31 if (!$this->vote) { 32 - $this->vote = PonderConstants::NONE_VOTE; 32 + $this->vote = PonderVote::VOTE_NONE; 33 33 } 34 34 return $this; 35 35 }
+2 -1
src/applications/ponder/storage/PonderQuestion.php
··· 14 14 protected $phid; 15 15 16 16 protected $authorPHID; 17 + protected $status; 17 18 protected $content; 18 19 protected $contentSource; 19 20 ··· 95 96 public function setUserVote($vote) { 96 97 $this->vote = $vote['data']; 97 98 if (!$this->vote) { 98 - $this->vote = PonderConstants::NONE_VOTE; 99 + $this->vote = PonderVote::VOTE_NONE; 99 100 } 100 101 return $this; 101 102 }
+1 -1
src/applications/ponder/view/PonderAnswerListView.php
··· 55 55 $view 56 56 ->setQuestion($question) 57 57 ->setTarget($cur_answer) 58 - ->setAction(PonderConstants::ANSWERED_LITERAL) 58 + ->setAction(PonderLiterals::LITERAL_ANSWERED) 59 59 ->setHandles($handles) 60 60 ->setUser($user); 61 61
+1 -1
src/applications/ponder/view/PonderQuestionDetailView.php
··· 30 30 ->setQuestion($question) 31 31 ->setUser($user) 32 32 ->setHandles($handles) 33 - ->setAction(PonderConstants::ASKED_LITERAL); 33 + ->setAction(PonderLiterals::LITERAL_ASKED); 34 34 35 35 $commentview = new PonderCommentListView(); 36 36 $commentview
+6 -2
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1471 1471 'type' => 'php', 1472 1472 'name' => $this->getPatchPath('20130716.archivememberlessprojects.php'), 1473 1473 ), 1474 + '20130722.pholioreplace.sql' => array( 1475 + 'type' => 'sql', 1476 + 'name' => $this->getPatchPath('20130722.pholioreplace.sql'), 1477 + ), 1474 1478 '20130723.taskstarttime.sql' => array( 1475 1479 'type' => 'sql', 1476 1480 'name' => $this->getPatchPath('20130723.taskstarttime.sql'), 1477 1481 ), 1478 - '20130722.pholioreplace.sql' => array( 1482 + '20130727.ponderquestionstatus.sql' => array( 1479 1483 'type' => 'sql', 1480 - 'name' => $this->getPatchPath('20130722.pholioreplace.sql'), 1484 + 'name' => $this->getPatchPath('20130727.ponderquestionstatus.sql'), 1481 1485 ), 1482 1486 ); 1483 1487 }