Werdna has uploaded a new change for review.
https://gerrit.wikimedia.org/r/95985
Change subject: [SCHEMA CHANGE] Refactor of moderation logging.
......................................................................
[SCHEMA CHANGE] Refactor of moderation logging.
* Store moderation reason in object.
* Use a LifecycleHandler to do logging rather than doing it directly.
* Includes permalink handling for the logging class. Unfortunately not
backwards compatible.
Change-Id: Idd5a6570268e480c9cbe2c9620dfbb587db71ee4
---
M Flow.php
M Hooks.php
M container.php
A db_patches/patch-moderation_reason.sql
M flow.sql
M includes/Block/Topic.php
M includes/Data/RevisionStorage.php
M includes/Log/Formatter.php
A includes/Log/PostModerationLogger.php
M includes/Model/AbstractRevision.php
10 files changed, 119 insertions(+), 19 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow
refs/changes/85/95985/1
diff --git a/Flow.php b/Flow.php
index a9607de..b8e5879 100755
--- a/Flow.php
+++ b/Flow.php
@@ -121,6 +121,7 @@
$wgAutoloadClasses['Flow\RecentChanges\Formatter'] = $dir .
'includes/RecentChanges/Formatter.php';
$wgAutoloadClasses['Flow\Log\Logger'] = $dir . 'includes/Log/Logger.php';
$wgAutoloadClasses['Flow\Log\Formatter'] = $dir . 'includes/Log/Formatter.php';
+$wgAutoloadClasses['Flow\Log\PostModerationLogger'] = $dir .
'includes/Log/PostModerationLogger.php';
// database interaction for singular models
$wgAutoloadClasses['Flow\Data\RevisionStorage'] = $dir .
'includes/Data/RevisionStorage.php';
diff --git a/Hooks.php b/Hooks.php
index 1f04ab9..d0b6f96 100644
--- a/Hooks.php
+++ b/Hooks.php
@@ -27,6 +27,7 @@
$baseSQLFile = "$dir/flow.sql";
$updater->addExtensionTable( 'flow_revision', $baseSQLFile );
$updater->addExtensionField( 'flow_revision',
'rev_last_edit_id', "$dir/db_patches/patch-revision_last_editor.sql" );
+ $updater->addExtensionField( 'flow_revision', 'rev_mod_reason',
"$dir/db_patches/patch-moderation_reason.sql" );
if ( $updater->getDB()->getType() === 'sqlite' ) {
$updater->modifyExtensionField(
'flow_summary_revision', 'summary_workflow_id',
"$dir/db_patches/patch-summary2header.sqlite.sql" );
$updater->modifyExtensionField( 'flow_revision',
'rev_comment', "$dir/db_patches/patch-rev_change_type.sqlite.sql" );
diff --git a/container.php b/container.php
index c7372b1..0a590f1 100644
--- a/container.php
+++ b/container.php
@@ -287,6 +287,7 @@
);
$handlers = array(
+ new Flow\Log\PostModerationLogger( $c['storage'],
$c['repository.tree'], $c['logger'] ),
new Flow\Data\PostRevisionRecentChanges( $c['storage'],
$c['repository.tree'], $wgContLang ),
$c['storage.board_history.index'],
);
diff --git a/db_patches/patch-moderation_reason.sql
b/db_patches/patch-moderation_reason.sql
new file mode 100644
index 0000000..8bf2a24
--- /dev/null
+++ b/db_patches/patch-moderation_reason.sql
@@ -0,0 +1,3 @@
+-- Patch to add the "moderated reason" field to revision table
+
+ALTER TABLE /*_*/flow_revision ADD COLUMN rev_mod_reason varchar(255) binary;
\ No newline at end of file
diff --git a/flow.sql b/flow.sql
index b0c7ac7..e54f618 100644
--- a/flow.sql
+++ b/flow.sql
@@ -122,6 +122,8 @@
rev_mod_user_id bigint unsigned,
rev_mod_user_text varchar(255) binary,
rev_mod_timestamp varchar(14) binary,
+ -- moderated why? (coming soon: how?, where? and what?)
+ rev_mod_reason varchar(255) binary,
-- track who made the most recent content edit
rev_last_edit_id binary(16) null,
diff --git a/includes/Block/Topic.php b/includes/Block/Topic.php
index 4dccd4b..c5b1946 100644
--- a/includes/Block/Topic.php
+++ b/includes/Block/Topic.php
@@ -228,27 +228,16 @@
$this->errors['moderate'] = wfMessage(
'flow-error-invalid-moderation-reason' );
return;
}
+
+ $reason = $this->submitted['reason'];
+
if ( $post->needsModerateHistorical( $newState ) ) {
$this->relatedRevisions = $this->loadHistorical( $post
);
}
- $this->newRevision = $post->moderate( $this->user, $newState,
$action, $this->relatedRevisions );
+ $this->newRevision = $post->moderate( $this->user, $newState,
$action, $reason, $this->relatedRevisions );
if ( !$this->newRevision ) {
$this->errors['moderate'] = wfMessage(
'flow-error-not-allowed' );
- } else {
- // @todo: would be nice to get this logging into a
LifecycleHandler
- $logger = Container::get( 'logger' );
- if ( $logger->canLog( $post, $action ) ) {
- $logger->log(
- $post,
- $action,
- $this->submitted['reason'],
- $this->getWorkflow(),
- array(
- $this->getName() . '[postId]'
=> $post->getPostId()->getHex(),
- )
- );
- }
}
}
@@ -412,6 +401,13 @@
return $prefix . $templating->render(
'flow:error-permissions.html.php' );
}
+ if ( isset( $options['postId'] ) ) {
+ // Most compatible way of doing this
+ $postId = $options['postId'];
+ $script = "<script
type='text/javascript'>window.location.hash = '#flow-post-{$postId}';</script>";
+ $templating->getOutput()->addHeadItem(
'flow-post-hash', $script );
+ }
+
return $prefix . $templating->renderTopic(
$root,
$this,
diff --git a/includes/Data/RevisionStorage.php
b/includes/Data/RevisionStorage.php
index b8b0547..5d6c202 100644
--- a/includes/Data/RevisionStorage.php
+++ b/includes/Data/RevisionStorage.php
@@ -11,7 +11,11 @@
abstract class RevisionStorage implements WritableObjectStorage {
static protected $allowedUpdateColumns = array(
- 'rev_mod_state', 'rev_mod_user_id', 'rev_mod_user_text',
'rev_mod_timestamp',
+ 'rev_mod_state',
+ 'rev_mod_user_id',
+ 'rev_mod_user_text',
+ 'rev_mod_timestamp',
+ 'rev_mod_reason',
);
protected $dbFactory;
protected $externalStores;
diff --git a/includes/Log/Formatter.php b/includes/Log/Formatter.php
index 659cf28..1f1d107 100644
--- a/includes/Log/Formatter.php
+++ b/includes/Log/Formatter.php
@@ -15,9 +15,15 @@
$type = $this->entry->getType();
$action = $this->entry->getSubtype();
- $title = $this->entry->getTarget();
+ $linkTitle = $title = $this->entry->getTarget();
$skin = $this->plaintext ? null : $this->context->getSkin();
$params = $this->entry->getParameters();
+
+ if ( isset( $params['postId'] ) ) {
+ $linkTitle = clone $title;
+ $linkTitle->setFragment( '#flow-post-' .
$params['postId'] );
+ unset( $params['postId'] );
+ }
// Give grep a chance to find the usages:
// logentry-delete-flow-delete-post,
logentry-delete-flow-restore-post,
@@ -28,7 +34,7 @@
Message::rawParam( $this->getPerformerElement()
),
$this->entry->getPerformer()->getId(),
$title,
- $title->getFullUrl( $params ),
+ $linkTitle->getFullUrl( $params ),
) )
->inLanguage( $language )
->parse();
diff --git a/includes/Log/PostModerationLogger.php
b/includes/Log/PostModerationLogger.php
new file mode 100644
index 0000000..b833463
--- /dev/null
+++ b/includes/Log/PostModerationLogger.php
@@ -0,0 +1,75 @@
+<?php
+
+namespace Flow\Log;
+
+use Flow\Data\LifecycleHandler;
+use Flow\Data\ManagerGroup;
+use Flow\Log\Logger;
+use Flow\Model\AbstractRevision;
+use Flow\Repository\TreeRepository;
+
+class PostModerationLogger implements LifecycleHandler {
+ function __construct( ManagerGroup $storage, TreeRepository $treeRepo,
Logger $logger ) {
+ $this->storage = $storage;
+ $this->treeRepo = $treeRepo;
+ $this->logger = $logger;
+ }
+
+ function onAfterInsert( $object, array $row ) {
+ $moderationChangeTypes = self::getModerationChangeTypes();
+ if ( ! in_array( $object->getChangeType(),
$moderationChangeTypes ) ) {
+ // Do nothing for non-moderation actions
+ return;
+ }
+
+ $lastRevId = $object->getPrevRevisionId();
+ $lastRevision = $this->storage->get( 'PostRevision', $lastRevId
);
+
+ if ( $this->logger->canLog( $lastRevision,
$object->getChangeType() ) ) {
+ // This is awful but it's all I can think of
+ $rootPost = $this->treeRepo->findRoot(
$lastRevision->getPostId() );
+ $workflow = $this->storage->get( 'Workflow', $rootPost
);
+
+ $this->logger->log(
+ $lastRevision,
+ $object->getChangeType(),
+ $object->getModeratedReason(),
+ $workflow,
+ array(
+ 'postId' =>
$object->getPostId()->getHex(),
+ )
+ );
+ }
+ }
+
+ function onAfterLoad( $object, array $old ) {
+ // You don't need to see my identification
+ }
+
+ function onAfterUpdate( $object, array $old, array $new ) {
+ // These aren't the droids you're looking for
+ }
+
+ function onAfterRemove( $object, array $old ) {
+ // Move along
+ }
+
+ protected static function getModerationChangeTypes() {
+ static $changeTypes = false;
+
+ if ( ! $changeTypes ) {
+ $changeTypes = array();
+ foreach( AbstractRevision::$perms as $perm => $info ) {
+ if ( $perm != '' ) {
+ $changeTypes[] = "{$perm}-topic";
+ $changeTypes[] = "{$perm}-post";
+ }
+ }
+
+ $changeTypes[] = 'restore-topic';
+ $changeTypes[] = 'restore-post';
+ }
+
+ return $changeTypes;
+ }
+}
\ No newline at end of file
diff --git a/includes/Model/AbstractRevision.php
b/includes/Model/AbstractRevision.php
index c8f4268..475a432 100644
--- a/includes/Model/AbstractRevision.php
+++ b/includes/Model/AbstractRevision.php
@@ -77,6 +77,7 @@
protected $moderationTimestamp;
protected $moderatedByUserId;
protected $moderatedByUserText;
+ protected $moderatedReason;
protected $lastEditId;
protected $lastEditUserId;
@@ -103,6 +104,7 @@
$obj->moderatedByUserId = $row['rev_mod_user_id'];
$obj->moderatedByUserText = $row['rev_mod_user_text'];
$obj->moderationTimestamp = $row['rev_mod_timestamp'];
+ $obj->moderatedReason = isset( $row['rev_mod_reason'] ) ?
$row['rev_mod_reason'] : null;
// isset required because there is a possible db migration,
cached data will not have it
$obj->lastEditId = isset( $row['rev_last_edit_id'] ) ?
UUID::create( $row['rev_last_edit_id'] ) : null;
@@ -129,6 +131,7 @@
'rev_mod_user_id' => $obj->moderatedByUserId,
'rev_mod_user_text' => $obj->moderatedByUserText,
'rev_mod_timestamp' => $obj->moderationTimestamp,
+ 'rev_mod_reason' => $obj->moderatedReason,
'rev_last_edit_id' => $obj->lastEditId ?
$obj->lastEditId->getBinary() : null,
'rev_edit_user_id' => $obj->lastEditUserId,
@@ -180,7 +183,7 @@
* $historical revisions must be provided when
self::needsModerateHistorical
* returns true.
*/
- public function moderate( User $user, $state, $changeType, array
$historical = array() ) {
+ public function moderate( User $user, $state, $changeType, $reason,
array $historical = array() ) {
if ( ! $this->isValidModerationState( $state ) ) {
wfWarn( __METHOD__ . ': Provided moderation state does
not exist : ' . $state );
return null;
@@ -209,10 +212,14 @@
$rev->moderatedByUserId = null;
$rev->moderatedByUserText = null;
$rev->moderationTimestamp = null;
+ // This is a bit hacky, but we store the
restore reason
+ // in the "moderated reason" field. Hmmph.
+ $rev->moderatedReason = $reason;
} else {
$rev->moderatedByUserId = $user->getId();
$rev->moderatedByUserText = $user->getName();
$rev->moderationTimestamp = $timestamp;
+ $rev->moderatedReason = $reason;
}
}
@@ -396,6 +403,10 @@
return $this->moderationState;
}
+ public function getModeratedReason() {
+ return $this->moderatedReason;
+ }
+
public function isModerated() {
return $this->moderationState !== self::MODERATED_NONE;
}
--
To view, visit https://gerrit.wikimedia.org/r/95985
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Idd5a6570268e480c9cbe2c9620dfbb587db71ee4
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: Werdna <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits