1
0
Fork 0
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:
Chad Little 2015-08-08 12:20:01 -07:00
parent 22de31c56d
commit f98f5a081e
13 changed files with 137 additions and 78 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_ponder.ponder_answer
DROP COLUMN contentSource;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_ponder.ponder_question
DROP COLUMN editPolicy;

View file

@ -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',

View file

@ -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,
),

View file

@ -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() {

View file

@ -0,0 +1,12 @@
<?php
final class PonderModerateCapability
extends PhabricatorPolicyCapability {
const CAPABILITY = 'ponder.moderate';
public function getCapabilityName() {
return pht('Moderate Policy');
}
}

View file

@ -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');
}
}

View file

@ -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())));
}

View file

@ -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'))

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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();

View file

@ -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;
}