mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-27 07:50:57 +01:00
Add a default moderation policy to Ponder
Summary: This allows installs to essentially set a "moderator" for Ponder, who can clean up answers. Fixes T9098 Test Plan: Edit an answer I don't own. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T9098 Differential Revision: https://secure.phabricator.com/D13818
This commit is contained in:
parent
22de31c56d
commit
f98f5a081e
13 changed files with 137 additions and 78 deletions
2
resources/sql/autopatches/20150806.ponder.answer.1.sql
Normal file
2
resources/sql/autopatches/20150806.ponder.answer.1.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_ponder.ponder_answer
|
||||
DROP COLUMN contentSource;
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_ponder.ponder_question
|
||||
DROP COLUMN editPolicy;
|
|
@ -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',
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?php
|
||||
|
||||
final class PonderQuestionDefaultViewCapability
|
||||
final class PonderDefaultViewCapability
|
||||
extends PhabricatorPolicyCapability {
|
||||
|
||||
const CAPABILITY = 'ponder.question.default.view';
|
||||
const CAPABILITY = 'ponder.default.view';
|
||||
|
||||
public function getCapabilityName() {
|
||||
return pht('Default Question View Policy');
|
||||
return pht('Default View Policy');
|
||||
}
|
||||
|
||||
public function shouldAllowPublicPolicySetting() {
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
final class PonderModerateCapability
|
||||
extends PhabricatorPolicyCapability {
|
||||
|
||||
const CAPABILITY = 'ponder.moderate';
|
||||
|
||||
public function getCapabilityName() {
|
||||
return pht('Moderate Policy');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PonderQuestionDefaultEditCapability
|
||||
extends PhabricatorPolicyCapability {
|
||||
|
||||
const CAPABILITY = 'ponder.question.default.edit';
|
||||
|
||||
public function getCapabilityName() {
|
||||
return pht('Default Question Edit Policy');
|
||||
}
|
||||
|
||||
}
|
|
@ -19,9 +19,9 @@ final class PonderAnswerSaveController extends PonderController {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$answer = $request->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())));
|
||||
}
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue