diff --git a/resources/sql/autopatches/20150806.ponder.answer.1.sql b/resources/sql/autopatches/20150806.ponder.answer.1.sql new file mode 100644 index 0000000000..9c684b4446 --- /dev/null +++ b/resources/sql/autopatches/20150806.ponder.answer.1.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_ponder.ponder_answer + DROP COLUMN contentSource; diff --git a/resources/sql/autopatches/20150806.ponder.editpolicy.2.sql b/resources/sql/autopatches/20150806.ponder.editpolicy.2.sql new file mode 100644 index 0000000000..954f1b450e --- /dev/null +++ b/resources/sql/autopatches/20150806.ponder.editpolicy.2.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_ponder.ponder_question + DROP COLUMN editPolicy; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 43fc9b3b94..d52f761126 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3402,11 +3402,11 @@ phutil_register_library_map(array( 'PonderConstants' => 'applications/ponder/constants/PonderConstants.php', 'PonderController' => 'applications/ponder/controller/PonderController.php', 'PonderDAO' => 'applications/ponder/storage/PonderDAO.php', + 'PonderDefaultViewCapability' => 'applications/ponder/capability/PonderDefaultViewCapability.php', 'PonderEditor' => 'applications/ponder/editor/PonderEditor.php', + 'PonderModerateCapability' => 'applications/ponder/capability/PonderModerateCapability.php', 'PonderQuestion' => 'applications/ponder/storage/PonderQuestion.php', 'PonderQuestionCommentController' => 'applications/ponder/controller/PonderQuestionCommentController.php', - 'PonderQuestionDefaultEditCapability' => 'applications/ponder/capability/PonderQuestionDefaultEditCapability.php', - 'PonderQuestionDefaultViewCapability' => 'applications/ponder/capability/PonderQuestionDefaultViewCapability.php', 'PonderQuestionEditController' => 'applications/ponder/controller/PonderQuestionEditController.php', 'PonderQuestionEditor' => 'applications/ponder/editor/PonderQuestionEditor.php', 'PonderQuestionHasVotingUserEdgeType' => 'applications/ponder/edge/PonderQuestionHasVotingUserEdgeType.php', @@ -7591,7 +7591,9 @@ phutil_register_library_map(array( 'PonderConstants' => 'Phobject', 'PonderController' => 'PhabricatorController', 'PonderDAO' => 'PhabricatorLiskDAO', + 'PonderDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PonderEditor' => 'PhabricatorApplicationTransactionEditor', + 'PonderModerateCapability' => 'PhabricatorPolicyCapability', 'PonderQuestion' => array( 'PonderDAO', 'PhabricatorApplicationTransactionInterface', @@ -7606,8 +7608,6 @@ phutil_register_library_map(array( 'PhabricatorSpacesInterface', ), 'PonderQuestionCommentController' => 'PonderController', - 'PonderQuestionDefaultEditCapability' => 'PhabricatorPolicyCapability', - 'PonderQuestionDefaultViewCapability' => 'PhabricatorPolicyCapability', 'PonderQuestionEditController' => 'PonderController', 'PonderQuestionEditor' => 'PonderEditor', 'PonderQuestionHasVotingUserEdgeType' => 'PhabricatorEdgeType', diff --git a/src/applications/ponder/application/PhabricatorPonderApplication.php b/src/applications/ponder/application/PhabricatorPonderApplication.php index 6ba5e3ca4f..fe1073b85a 100644 --- a/src/applications/ponder/application/PhabricatorPonderApplication.php +++ b/src/applications/ponder/application/PhabricatorPonderApplication.php @@ -93,11 +93,12 @@ final class PhabricatorPonderApplication extends PhabricatorApplication { protected function getCustomCapabilities() { return array( - PonderQuestionDefaultViewCapability::CAPABILITY => array( + PonderDefaultViewCapability::CAPABILITY => array( 'template' => PonderQuestionPHIDType::TYPECONST, 'capability' => PhabricatorPolicyCapability::CAN_VIEW, ), - PonderQuestionDefaultEditCapability::CAPABILITY => array( + PonderModerateCapability::CAPABILITY => array( + 'default' => PhabricatorPolicies::POLICY_ADMIN, 'template' => PonderQuestionPHIDType::TYPECONST, 'capability' => PhabricatorPolicyCapability::CAN_EDIT, ), diff --git a/src/applications/ponder/capability/PonderQuestionDefaultViewCapability.php b/src/applications/ponder/capability/PonderDefaultViewCapability.php similarity index 53% rename from src/applications/ponder/capability/PonderQuestionDefaultViewCapability.php rename to src/applications/ponder/capability/PonderDefaultViewCapability.php index 593ea1321e..0019714727 100644 --- a/src/applications/ponder/capability/PonderQuestionDefaultViewCapability.php +++ b/src/applications/ponder/capability/PonderDefaultViewCapability.php @@ -1,12 +1,12 @@ getStr('answer'); + $content = $request->getStr('answer'); - if (!strlen(trim($answer))) { + if (!strlen(trim($content))) { $dialog = id(new AphrontDialogView()) ->setUser($viewer) ->setTitle(pht('Empty Answer')) @@ -32,18 +32,9 @@ final class PonderAnswerSaveController extends PonderController { return id(new AphrontDialogResponse())->setDialog($dialog); } - $content_source = PhabricatorContentSource::newForSource( - PhabricatorContentSource::SOURCE_WEB, - array( - 'ip' => $request->getRemoteAddr(), - )); + $answer = PonderAnswer::initializeNewAnswer($viewer); - $res = id(new PonderAnswer()) - ->setAuthorPHID($viewer->getPHID()) - ->setQuestionID($question->getID()) - ->setContent($answer) - ->setVoteCount(0) - ->setContentSource($content_source); + // Question Editor $xactions = array(); $xactions[] = id(new PonderQuestionTransaction()) @@ -51,7 +42,7 @@ final class PonderAnswerSaveController extends PonderController { ->setNewValue( array( '+' => array( - array('answer' => $res), + array('answer' => $answer), ), )); @@ -61,6 +52,27 @@ final class PonderAnswerSaveController extends PonderController { $editor->applyTransactions($question, $xactions); + // Answer Editor + + $template = id(new PonderAnswerTransaction()); + $xactions = array(); + + $xactions[] = id(clone $template) + ->setTransactionType(PonderAnswerTransaction::TYPE_QUESTION_ID) + ->setNewValue($question->getID()); + + $xactions[] = id(clone $template) + ->setTransactionType(PonderAnswerTransaction::TYPE_CONTENT) + ->setNewValue($content); + + $editor = id(new PonderAnswerEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($answer, $xactions); + + return id(new AphrontRedirectResponse())->setURI( id(new PhutilURI('/Q'.$question->getID()))); } diff --git a/src/applications/ponder/controller/PonderQuestionEditController.php b/src/applications/ponder/controller/PonderQuestionEditController.php index d1a8d48f59..293bbe3c79 100644 --- a/src/applications/ponder/controller/PonderQuestionEditController.php +++ b/src/applications/ponder/controller/PonderQuestionEditController.php @@ -31,7 +31,6 @@ final class PonderQuestionEditController extends PonderController { $v_title = $question->getTitle(); $v_content = $question->getContent(); $v_view = $question->getViewPolicy(); - $v_edit = $question->getEditPolicy(); $v_space = $question->getSpacePHID(); $v_status = $question->getStatus(); @@ -43,7 +42,6 @@ final class PonderQuestionEditController extends PonderController { $v_content = $request->getStr('content'); $v_projects = $request->getArr('projects'); $v_view = $request->getStr('viewPolicy'); - $v_edit = $request->getStr('editPolicy'); $v_space = $request->getStr('spacePHID'); $v_status = $request->getStr('status'); @@ -76,10 +74,6 @@ final class PonderQuestionEditController extends PonderController { ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setNewValue($v_view); - $xactions[] = id(clone $template) - ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) - ->setNewValue($v_edit); - $xactions[] = id(clone $template) ->setTransactionType(PhabricatorTransactions::TYPE_SPACE) ->setNewValue($v_space); @@ -131,13 +125,6 @@ final class PonderQuestionEditController extends PonderController { ->setPolicies($policies) ->setValue($v_view) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)) - ->appendControl( - id(new AphrontFormPolicyControl()) - ->setName('editPolicy') - ->setPolicyObject($question) - ->setPolicies($policies) - ->setValue($v_edit) - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Status')) diff --git a/src/applications/ponder/editor/PonderAnswerEditor.php b/src/applications/ponder/editor/PonderAnswerEditor.php index 69ee10f270..9eea95c511 100644 --- a/src/applications/ponder/editor/PonderAnswerEditor.php +++ b/src/applications/ponder/editor/PonderAnswerEditor.php @@ -10,7 +10,9 @@ final class PonderAnswerEditor extends PonderEditor { $types = parent::getTransactionTypes(); $types[] = PhabricatorTransactions::TYPE_COMMENT; + $types[] = PonderAnswerTransaction::TYPE_CONTENT; + $types[] = PonderAnswerTransaction::TYPE_QUESTION_ID; return $types; } @@ -22,6 +24,8 @@ final class PonderAnswerEditor extends PonderEditor { switch ($xaction->getTransactionType()) { case PonderAnswerTransaction::TYPE_CONTENT: return $object->getContent(); + case PonderAnswerTransaction::TYPE_QUESTION_ID: + return $object->getQuestionID(); } } @@ -31,6 +35,7 @@ final class PonderAnswerEditor extends PonderEditor { switch ($xaction->getTransactionType()) { case PonderAnswerTransaction::TYPE_CONTENT: + case PonderAnswerTransaction::TYPE_QUESTION_ID: return $xaction->getNewValue(); } } @@ -43,6 +48,9 @@ final class PonderAnswerEditor extends PonderEditor { case PonderAnswerTransaction::TYPE_CONTENT: $object->setContent($xaction->getNewValue()); break; + case PonderAnswerTransaction::TYPE_QUESTION_ID: + $object->setQuestionID($xaction->getNewValue()); + break; } } diff --git a/src/applications/ponder/storage/PonderAnswer.php b/src/applications/ponder/storage/PonderAnswer.php index 10ada70c5e..937ae75411 100644 --- a/src/applications/ponder/storage/PonderAnswer.php +++ b/src/applications/ponder/storage/PonderAnswer.php @@ -17,7 +17,6 @@ final class PonderAnswer extends PonderDAO protected $questionID; protected $content; - protected $contentSource; protected $mailKey; protected $voteCount; @@ -27,6 +26,20 @@ final class PonderAnswer extends PonderDAO private $userVotes = array(); + public static function initializeNewAnswer(PhabricatorUser $actor) { + $app = id(new PhabricatorApplicationQuery()) + ->setViewer($actor) + ->withClasses(array('PhabricatorPonderApplication')) + ->executeOne(); + + return id(new PonderAnswer()) + ->setQuestionID(0) + ->setContent('') + ->setAuthorPHID($actor->getPHID()) + ->setVoteCount(0); + + } + public function attachQuestion(PonderQuestion $question = null) { $this->question = $question; return $this; @@ -73,10 +86,6 @@ final class PonderAnswer extends PonderDAO 'voteCount' => 'sint32', 'content' => 'text', 'mailKey' => 'bytes20', - - // T6203/NULLABILITY - // This should always exist. - 'contentSource' => 'text?', ), self::CONFIG_KEY_SCHEMA => array( 'key_phid' => null, @@ -102,15 +111,6 @@ final class PonderAnswer extends PonderDAO return PhabricatorPHID::generateNewPHID(PonderAnswerPHIDType::TYPECONST); } - public function setContentSource(PhabricatorContentSource $content_source) { - $this->contentSource = $content_source->serialize(); - return $this; - } - - public function getContentSource() { - return PhabricatorContentSource::newFromSerialized($this->contentSource); - } - public function getMarkupField() { return self::MARKUP_FIELD_CONTENT; } @@ -198,7 +198,9 @@ final class PonderAnswer extends PonderDAO case PhabricatorPolicyCapability::CAN_VIEW: return $this->getQuestion()->getPolicy($capability); case PhabricatorPolicyCapability::CAN_EDIT: - return PhabricatorPolicies::POLICY_NOONE; + $app = PhabricatorApplication::getByClass( + 'PhabricatorPonderApplication'); + return $app->getPolicy(PonderModerateCapability::CAPABILITY); } } @@ -224,6 +226,8 @@ final class PonderAnswer extends PonderDAO case PhabricatorPolicyCapability::CAN_VIEW: $out[] = pht( 'The user who asks a question can always view the answers.'); + $out[] = pht( + 'A moderator can always view the answers.'); break; } return $out; diff --git a/src/applications/ponder/storage/PonderAnswerTransaction.php b/src/applications/ponder/storage/PonderAnswerTransaction.php index 08af2470ad..07b9768c82 100644 --- a/src/applications/ponder/storage/PonderAnswerTransaction.php +++ b/src/applications/ponder/storage/PonderAnswerTransaction.php @@ -4,6 +4,7 @@ final class PonderAnswerTransaction extends PhabricatorApplicationTransaction { const TYPE_CONTENT = 'ponder.answer:content'; + const TYPE_QUESTION_ID = 'ponder.answer:question-id'; public function getApplicationName() { return 'ponder'; @@ -45,16 +46,35 @@ final class PonderAnswerTransaction return $blocks; } + public function shouldHide() { + switch ($this->getTransactionType()) { + case self::TYPE_QUESTION_ID: + return true; + } + return parent::shouldHide(); + } + public function getTitle() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); + $old = $this->getOldValue(); + $new = $this->getNewValue(); + switch ($this->getTransactionType()) { case self::TYPE_CONTENT: - return pht( - '%s edited %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); + if ($old === '') { + return pht( + '%s added %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } else { + return pht( + '%s edited %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } + break; } return parent::getTitle(); @@ -64,12 +84,23 @@ final class PonderAnswerTransaction $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); + $old = $this->getOldValue(); + $new = $this->getNewValue(); + switch ($this->getTransactionType()) { case self::TYPE_CONTENT: - return pht( - '%s updated %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); + if ($old === '') { + return pht( + '%s added %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } else { + return pht( + '%s updated %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } + break; } return parent::getTitleForFeed(); diff --git a/src/applications/ponder/storage/PonderQuestion.php b/src/applications/ponder/storage/PonderQuestion.php index 0e1ea0226b..14fafcecbf 100644 --- a/src/applications/ponder/storage/PonderQuestion.php +++ b/src/applications/ponder/storage/PonderQuestion.php @@ -23,7 +23,6 @@ final class PonderQuestion extends PonderDAO protected $content; protected $contentSource; protected $viewPolicy; - protected $editPolicy; protected $spacePHID; protected $voteCount; @@ -44,14 +43,11 @@ final class PonderQuestion extends PonderDAO ->executeOne(); $view_policy = $app->getPolicy( - PonderQuestionDefaultViewCapability::CAPABILITY); - $edit_policy = $app->getPolicy( - PonderQuestionDefaultEditCapability::CAPABILITY); + PonderDefaultViewCapability::CAPABILITY); return id(new PonderQuestion()) ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy) - ->setEditPolicy($edit_policy) ->setStatus(PonderQuestionStatus::STATUS_OPEN) ->setVoteCount(0) ->setAnswerCount(0) @@ -275,17 +271,33 @@ final class PonderQuestion extends PonderDAO case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: - return $this->getEditPolicy(); + $app = PhabricatorApplication::getByClass( + 'PhabricatorPonderApplication'); + return $app->getPolicy(PonderModerateCapability::CAPABILITY); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + if ($capability == PhabricatorPolicyCapability::CAN_VIEW) { + if (PhabricatorPolicyFilter::hasCapability( + $viewer, $this, PhabricatorPolicyCapability::CAN_EDIT)) { + return true; + } + } return ($viewer->getPHID() == $this->getAuthorPHID()); } public function describeAutomaticCapability($capability) { - return pht('The user who asked a question can always view and edit it.'); + $out = array(); + $out[] = pht('The user who asked a question can always view and edit it.'); + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + $out[] = pht( + 'A moderator can always view the question.'); + break; + } + return $out; }