1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-19 16:58:48 +02:00

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
This commit is contained in:
Gareth Evans 2013-07-27 18:37:17 -07:00 committed by epriestley
parent 91c08ca629
commit 70a5ec600d
21 changed files with 222 additions and 24 deletions

View file

@ -0,0 +1,5 @@
ALTER TABLE {$NAMESPACE}_ponder.ponder_question
ADD COLUMN `status` INT(10) UNSIGNED NOT NULL AFTER `authorPHID`;
ALTER TABLE {$NAMESPACE}_ponder.ponder_question
ADD INDEX `status` (`status`);

View file

@ -1881,9 +1881,10 @@ phutil_register_library_map(array(
'PonderCommentMail' => 'applications/ponder/mail/PonderCommentMail.php', 'PonderCommentMail' => 'applications/ponder/mail/PonderCommentMail.php',
'PonderCommentQuery' => 'applications/ponder/query/PonderCommentQuery.php', 'PonderCommentQuery' => 'applications/ponder/query/PonderCommentQuery.php',
'PonderCommentSaveController' => 'applications/ponder/controller/PonderCommentSaveController.php', 'PonderCommentSaveController' => 'applications/ponder/controller/PonderCommentSaveController.php',
'PonderConstants' => 'applications/ponder/PonderConstants.php', 'PonderConstants' => 'applications/ponder/constants/PonderConstants.php',
'PonderController' => 'applications/ponder/controller/PonderController.php', 'PonderController' => 'applications/ponder/controller/PonderController.php',
'PonderDAO' => 'applications/ponder/storage/PonderDAO.php', 'PonderDAO' => 'applications/ponder/storage/PonderDAO.php',
'PonderLiterals' => 'applications/ponder/constants/PonderLiterals.php',
'PonderMail' => 'applications/ponder/mail/PonderMail.php', 'PonderMail' => 'applications/ponder/mail/PonderMail.php',
'PonderMentionMail' => 'applications/ponder/mail/PonderMentionMail.php', 'PonderMentionMail' => 'applications/ponder/mail/PonderMentionMail.php',
'PonderPHIDTypeQuestion' => 'applications/ponder/phid/PonderPHIDTypeQuestion.php', 'PonderPHIDTypeQuestion' => 'applications/ponder/phid/PonderPHIDTypeQuestion.php',
@ -1897,6 +1898,8 @@ phutil_register_library_map(array(
'PonderQuestionPreviewController' => 'applications/ponder/controller/PonderQuestionPreviewController.php', 'PonderQuestionPreviewController' => 'applications/ponder/controller/PonderQuestionPreviewController.php',
'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php', 'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php',
'PonderQuestionSearchEngine' => 'applications/ponder/query/PonderQuestionSearchEngine.php', 'PonderQuestionSearchEngine' => 'applications/ponder/query/PonderQuestionSearchEngine.php',
'PonderQuestionStatus' => 'applications/ponder/constants/PonderQuestionStatus.php',
'PonderQuestionStatusController' => 'applications/ponder/controller/PonderQuestionStatusController.php',
'PonderQuestionSummaryView' => 'applications/ponder/view/PonderQuestionSummaryView.php', 'PonderQuestionSummaryView' => 'applications/ponder/view/PonderQuestionSummaryView.php',
'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php',
'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php', 'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php',
@ -1905,6 +1908,7 @@ phutil_register_library_map(array(
'PonderUserProfileView' => 'applications/ponder/view/PonderUserProfileView.php', 'PonderUserProfileView' => 'applications/ponder/view/PonderUserProfileView.php',
'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php', 'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php',
'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php', 'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php',
'PonderVote' => 'applications/ponder/constants/PonderVote.php',
'PonderVoteEditor' => 'applications/ponder/editor/PonderVoteEditor.php', 'PonderVoteEditor' => 'applications/ponder/editor/PonderVoteEditor.php',
'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php', 'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php',
'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php',
@ -3996,6 +4000,7 @@ phutil_register_library_map(array(
'PonderCommentSaveController' => 'PonderController', 'PonderCommentSaveController' => 'PonderController',
'PonderController' => 'PhabricatorController', 'PonderController' => 'PhabricatorController',
'PonderDAO' => 'PhabricatorLiskDAO', 'PonderDAO' => 'PhabricatorLiskDAO',
'PonderLiterals' => 'PonderConstants',
'PonderMail' => 'PhabricatorMail', 'PonderMail' => 'PhabricatorMail',
'PonderMentionMail' => 'PonderMail', 'PonderMentionMail' => 'PonderMail',
'PonderPHIDTypeQuestion' => 'PhabricatorPHIDType', 'PonderPHIDTypeQuestion' => 'PhabricatorPHIDType',
@ -4021,6 +4026,8 @@ phutil_register_library_map(array(
'PonderQuestionPreviewController' => 'PonderController', 'PonderQuestionPreviewController' => 'PonderController',
'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PonderQuestionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PonderQuestionSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PonderQuestionStatus' => 'PonderConstants',
'PonderQuestionStatusController' => 'PonderController',
'PonderQuestionSummaryView' => 'AphrontView', 'PonderQuestionSummaryView' => 'AphrontView',
'PonderQuestionViewController' => 'PonderController', 'PonderQuestionViewController' => 'PonderController',
'PonderRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PonderRemarkupRule' => 'PhabricatorRemarkupRuleObject',
@ -4028,6 +4035,7 @@ phutil_register_library_map(array(
'PonderSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PonderSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
'PonderUserProfileView' => 'AphrontView', 'PonderUserProfileView' => 'AphrontView',
'PonderVotableView' => 'AphrontView', 'PonderVotableView' => 'AphrontView',
'PonderVote' => 'PonderConstants',
'PonderVoteEditor' => 'PhabricatorEditor', 'PonderVoteEditor' => 'PhabricatorEditor',
'PonderVoteSaveController' => 'PonderController', 'PonderVoteSaveController' => 'PonderController',
'ProjectRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'ProjectRemarkupRule' => 'PhabricatorRemarkupRuleObject',

View file

@ -1,10 +0,0 @@
<?php
final class PonderConstants {
const UP_VOTE = 1;
const NONE_VOTE = 0;
const DOWN_VOTE = -1;
const ANSWERED_LITERAL = "answered";
const ASKED_LITERAL = "asked";
}

View file

@ -54,6 +54,8 @@ final class PhabricatorApplicationPonder extends PhabricatorApplication {
'answer/preview/' => 'PonderAnswerPreviewController', 'answer/preview/' => 'PonderAnswerPreviewController',
'question/ask/' => 'PonderQuestionAskController', 'question/ask/' => 'PonderQuestionAskController',
'question/preview/' => 'PonderQuestionPreviewController', 'question/preview/' => 'PonderQuestionPreviewController',
'question/(?P<status>open|close)/(?P<id>[1-9]\d*)/' =>
'PonderQuestionStatusController',
'comment/add/' => 'PonderCommentSaveController', 'comment/add/' => 'PonderCommentSaveController',
'(?P<kind>question)/vote/' => 'PonderVoteSaveController', '(?P<kind>question)/vote/' => 'PonderVoteSaveController',
'(?P<kind>answer)/vote/' => 'PonderVoteSaveController' '(?P<kind>answer)/vote/' => 'PonderVoteSaveController'

View file

@ -0,0 +1,4 @@
<?php
abstract class PonderConstants {
}

View file

@ -0,0 +1,10 @@
<?php
/**
* @group ponder
*/
final class PonderLiterals extends PonderConstants {
const LITERAL_ANSWERED = "answered";
const LITERAL_ASKED = "asked";
}

View file

@ -0,0 +1,34 @@
<?php
/**
* @group ponder
*/
final class PonderQuestionStatus extends PonderConstants {
const STATUS_OPEN = 0;
const STATUS_CLOSED = 1;
public static function getQuestionStatusMap() {
return array(
self::STATUS_OPEN => pht('Open'),
self::STATUS_CLOSED => pht('Closed'),
);
}
public static function getQuestionStatusFullName($status) {
$map = array(
self::STATUS_OPEN => pht('Open'),
self::STATUS_CLOSED => pht('Closed by author'),
);
return idx($map, $status, '???');
}
public static function getQuestionStatusTagColor($status) {
$map = array(
self::STATUS_CLOSED => PhabricatorTagView::COLOR_BLACK,
);
return idx($map, $status);
}
}

View file

@ -0,0 +1,11 @@
<?php
/**
* @group ponder
*/
final class PonderVote extends PonderConstants {
const VOTE_UP = 1;
const VOTE_NONE = 0;
const VOTE_DOWN = -1;
}

View file

@ -29,7 +29,7 @@ final class PonderAnswerPreviewController
->setPreview(true) ->setPreview(true)
->setUser($user) ->setUser($user)
->setHandles($handles) ->setHandles($handles)
->setAction(PonderConstants::ANSWERED_LITERAL); ->setAction(PonderLiterals::LITERAL_ANSWERED);
return id(new AphrontAjaxResponse()) return id(new AphrontAjaxResponse())
->setContent($view->render()); ->setContent($view->render());

View file

@ -17,6 +17,7 @@ final class PonderQuestionAskController extends PonderController {
if ($request->isFormPost()) { if ($request->isFormPost()) {
$question->setTitle($request->getStr('title')); $question->setTitle($request->getStr('title'));
$question->setContent($request->getStr('content')); $question->setContent($request->getStr('content'));
$question->setStatus(PonderQuestionStatus::STATUS_OPEN);
$len = phutil_utf8_strlen($question->getTitle()); $len = phutil_utf8_strlen($question->getTitle());
if ($len < 1) { if ($len < 1) {

View file

@ -45,6 +45,9 @@ final class PonderQuestionListController extends PonderController
$item->setHeader($question->getTitle()); $item->setHeader($question->getTitle());
$item->setHref('/Q'.$question->getID()); $item->setHref('/Q'.$question->getID());
$item->setObject($question); $item->setObject($question);
$item->setBarColor(
PonderQuestionStatus::getQuestionStatusTagColor(
$question->getStatus()));
$created_date = phabricator_date($question->getDateCreated(), $viewer); $created_date = phabricator_date($question->getDateCreated(), $viewer);
$item->addIcon('none', $created_date); $item->addIcon('none', $created_date);

View file

@ -0,0 +1,40 @@
<?php
final class PonderQuestionStatusController
extends PonderController {
private $status;
private $id;
public function willProcessRequest(array $data) {
$this->status = idx($data, 'status');
$this->id = idx($data, 'id');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$question = id(new PonderQuestion())->load($this->id);
if (!$question) {
return new Aphront404Response();
}
switch ($this->status) {
case 'open':
$question->setStatus(PonderQuestionStatus::STATUS_OPEN);
break;
case 'close':
$question->setStatus(PonderQuestionStatus::STATUS_CLOSED);
break;
default:
return new Aphront400Response();
}
$question->save();
return id(new AphrontRedirectResponse())->setURI('/Q'.$question->getID());
}
}

View file

@ -92,10 +92,34 @@ final class PonderQuestionViewController extends PonderController {
private function buildActionListView(PonderQuestion $question) { private function buildActionListView(PonderQuestion $question) {
$request = $this->getRequest(); $request = $this->getRequest();
return id(new PhabricatorActionListView()) $user = $request->getUser();
->setUser($request->getUser())
$action_list = id(new PhabricatorActionListView())
->setUser($user)
->setObject($question) ->setObject($question)
->setObjectURI($request->getRequestURI()); ->setObjectURI($request->getRequestURI());
if ($user->getPhid() === $question->getAuthorPhid()) {
if ($question->getStatus() == PonderQuestionStatus::STATUS_OPEN) {
$name = pht("Close Question");
$icon = "delete";
$href = "close";
} else {
$name = pht("Open Question");
$icon = "enable";
$href = "open";
}
$action_list->addAction(
id(new PhabricatorActionView())
->setName($name)
->setIcon($icon)
->setRenderAsForm(true)
->setHref(
$this->getApplicationURI(
"/question/{$href}/{$this->questionID}/")));
}
return $action_list;
} }
private function buildPropertyListView( private function buildPropertyListView(
@ -105,6 +129,11 @@ final class PonderQuestionViewController extends PonderController {
$view = id(new PhabricatorPropertyListView()) $view = id(new PhabricatorPropertyListView())
->setUser($viewer) ->setUser($viewer)
->setObject($question); ->setObject($question);
$view->addProperty(
pht('Status'),
PonderQuestionStatus::getQuestionStatusFullName($question->getStatus()));
$view->addProperty( $view->addProperty(
pht('Author'), pht('Author'),
$this->getHandle($question->getAuthorPHID())->renderLink()); $this->getHandle($question->getAuthorPHID())->renderLink());

View file

@ -56,7 +56,7 @@ final class PonderVoteEditor extends PhabricatorEditor {
$votable->getVotablePHID()); $votable->getVotablePHID());
if (!$curvote) { if (!$curvote) {
$curvote = PonderConstants::NONE_VOTE; $curvote = PonderVote::VOTE_NONE;
} }
// adjust votable's score by this much // adjust votable's score by this much

View file

@ -12,6 +12,11 @@ final class PonderQuestionQuery
private $answererPHIDs; private $answererPHIDs;
private $order = self::ORDER_CREATED; private $order = self::ORDER_CREATED;
private $status = 'status-any';
const STATUS_ANY = 'status-any';
const STATUS_OPEN = 'status-open';
const STATUS_CLOSED = 'status-closed';
public function withIDs(array $ids) { public function withIDs(array $ids) {
$this->ids = $ids; $this->ids = $ids;
return $this; return $this;
@ -27,6 +32,11 @@ final class PonderQuestionQuery
return $this; return $this;
} }
public function withStatus($status) {
$this->status = $status;
return $this;
}
public function withAnswererPHIDs(array $phids) { public function withAnswererPHIDs(array $phids) {
$this->answererPHIDs = $phids; $this->answererPHIDs = $phids;
return $this; return $this;
@ -83,6 +93,27 @@ final class PonderQuestionQuery
$this->authorPHIDs); $this->authorPHIDs);
} }
if ($this->status) {
switch ($this->status) {
case self::STATUS_ANY:
break;
case self::STATUS_OPEN:
$where[] = qsprintf(
$conn_r,
'q.status = %d',
PonderQuestionStatus::STATUS_OPEN);
break;
case self::STATUS_CLOSED:
$where[] = qsprintf(
$conn_r,
'q.status = %d',
PonderQuestionStatus::STATUS_CLOSED);
break;
default:
throw new Exception("Unknown status query '{$this->status}'!");
}
}
$where[] = $this->buildPagingClause($conn_r); $where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where); return $this->formatWhereClause($where);

View file

@ -14,6 +14,8 @@ final class PonderQuestionSearchEngine
'answererPHIDs', 'answererPHIDs',
array_values($request->getArr('answerers'))); array_values($request->getArr('answerers')));
$saved->setParameter('status', $request->getStr('status'));
return $saved; return $saved;
} }
@ -30,6 +32,18 @@ final class PonderQuestionSearchEngine
$query->withAnswererPHIDs($answerer_phids); $query->withAnswererPHIDs($answerer_phids);
} }
$status = $saved->getParameter('status');
if ($status != null) {
switch ($status) {
case 0:
$query->withStatus(PonderQuestionQuery::STATUS_OPEN);
break;
case 1:
$query->withStatus(PonderQuestionQuery::STATUS_CLOSED);
break;
}
}
return $query; return $query;
} }
@ -39,6 +53,8 @@ final class PonderQuestionSearchEngine
$author_phids = $saved_query->getParameter('authorPHIDs', array()); $author_phids = $saved_query->getParameter('authorPHIDs', array());
$answerer_phids = $saved_query->getParameter('answererPHIDs', array()); $answerer_phids = $saved_query->getParameter('answererPHIDs', array());
$status = $saved_query->getParameter(
'status', PonderQuestionStatus::STATUS_OPEN);
$phids = array_merge($author_phids, $answerer_phids); $phids = array_merge($author_phids, $answerer_phids);
$handles = id(new PhabricatorObjectHandleData($phids)) $handles = id(new PhabricatorObjectHandleData($phids))
@ -61,7 +77,13 @@ final class PonderQuestionSearchEngine
->setDatasource('/typeahead/common/users/') ->setDatasource('/typeahead/common/users/')
->setName('answerers') ->setName('answerers')
->setLabel(pht('Answered By')) ->setLabel(pht('Answered By'))
->setValue($answerer_tokens)); ->setValue($answerer_tokens))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Status'))
->setName('status')
->setValue($status)
->setOptions(PonderQuestionStatus::getQuestionStatusMap()));
} }
protected function getURI($path) { protected function getURI($path) {
@ -70,6 +92,7 @@ final class PonderQuestionSearchEngine
public function getBuiltinQueryNames() { public function getBuiltinQueryNames() {
$names = array( $names = array(
'open' => pht('Open Questions'),
'all' => pht('All Questions'), 'all' => pht('All Questions'),
); );
@ -89,6 +112,8 @@ final class PonderQuestionSearchEngine
switch ($query_key) { switch ($query_key) {
case 'all': case 'all':
return $query; return $query;
case 'open':
return $query->setParameter('status', PonderQuestionQuery::STATUS_OPEN);
case 'authored': case 'authored':
return $query->setParameter( return $query->setParameter(
'authorPHIDs', 'authorPHIDs',

View file

@ -29,7 +29,7 @@ final class PonderAnswer extends PonderDAO
public function setUserVote($vote) { public function setUserVote($vote) {
$this->vote = $vote['data']; $this->vote = $vote['data'];
if (!$this->vote) { if (!$this->vote) {
$this->vote = PonderConstants::NONE_VOTE; $this->vote = PonderVote::VOTE_NONE;
} }
return $this; return $this;
} }

View file

@ -14,6 +14,7 @@ final class PonderQuestion extends PonderDAO
protected $phid; protected $phid;
protected $authorPHID; protected $authorPHID;
protected $status;
protected $content; protected $content;
protected $contentSource; protected $contentSource;
@ -95,7 +96,7 @@ final class PonderQuestion extends PonderDAO
public function setUserVote($vote) { public function setUserVote($vote) {
$this->vote = $vote['data']; $this->vote = $vote['data'];
if (!$this->vote) { if (!$this->vote) {
$this->vote = PonderConstants::NONE_VOTE; $this->vote = PonderVote::VOTE_NONE;
} }
return $this; return $this;
} }

View file

@ -55,7 +55,7 @@ final class PonderAnswerListView extends AphrontView {
$view $view
->setQuestion($question) ->setQuestion($question)
->setTarget($cur_answer) ->setTarget($cur_answer)
->setAction(PonderConstants::ANSWERED_LITERAL) ->setAction(PonderLiterals::LITERAL_ANSWERED)
->setHandles($handles) ->setHandles($handles)
->setUser($user); ->setUser($user);

View file

@ -30,7 +30,7 @@ final class PonderQuestionDetailView extends AphrontView {
->setQuestion($question) ->setQuestion($question)
->setUser($user) ->setUser($user)
->setHandles($handles) ->setHandles($handles)
->setAction(PonderConstants::ASKED_LITERAL); ->setAction(PonderLiterals::LITERAL_ASKED);
$commentview = new PonderCommentListView(); $commentview = new PonderCommentListView();
$commentview $commentview

View file

@ -1471,14 +1471,18 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
'type' => 'php', 'type' => 'php',
'name' => $this->getPatchPath('20130716.archivememberlessprojects.php'), 'name' => $this->getPatchPath('20130716.archivememberlessprojects.php'),
), ),
'20130723.taskstarttime.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130723.taskstarttime.sql'),
),
'20130722.pholioreplace.sql' => array( '20130722.pholioreplace.sql' => array(
'type' => 'sql', 'type' => 'sql',
'name' => $this->getPatchPath('20130722.pholioreplace.sql'), 'name' => $this->getPatchPath('20130722.pholioreplace.sql'),
), ),
'20130723.taskstarttime.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130723.taskstarttime.sql'),
),
'20130727.ponderquestionstatus.sql' => array(
'type' => 'sql',
'name' => $this->getPatchPath('20130727.ponderquestionstatus.sql'),
),
); );
} }
} }