Bsitu has uploaded a new change for review.
https://gerrit.wikimedia.org/r/92159
Change subject: Board History
......................................................................
Board History
Items not completed yet:
1. Add a history link to the board page
2. Code cleanup, testing and documentation
Change-Id: Ie48edfa4b8f85eaffa282b136663e95353c17215
---
M Flow.i18n.php
M Flow.php
M HistoryActions.php
M Hooks.php
M container.php
A db_patches/patch-topic_list_topic_id_idx.sql
M includes/Block/Header.php
M includes/Block/TopicList.php
A includes/Data/BoardHistoryStorage.php
M includes/Data/ObjectManager.php
M includes/Data/RevisionStorage.php
M includes/Model/AbstractRevision.php
A includes/Model/BoardHistoryEntry.php
M includes/Model/TopicListEntry.php
M includes/Repository/TreeRepository.php
M includes/View/History/HistoryRecord.php
M modules/history/styles/history.less
A templates/board-history.html.php
18 files changed, 469 insertions(+), 41 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow
refs/changes/59/92159/1
diff --git a/Flow.i18n.php b/Flow.i18n.php
index bb940da..4f1dd17 100644
--- a/Flow.i18n.php
+++ b/Flow.i18n.php
@@ -89,8 +89,8 @@
'flow-rev-message-new-post' => '[[User:$1|$1]] {{GENDER:$1|created}}
the topic <span class="plainlinks">[$2 $3]</span>.',
'flow-rev-message-hid-post' => '[[User:$1|$1]] {{GENDER:$1|hid}} a
<span class="plainlinks">[$3 comment]</span>.',
'flow-rev-message-edit-title' => '[[User:$1|$1]] {{GENDER:$1|edited}}
the topic title to <span class="plainlinks">[$2 $3]</span>.',
- 'flow-rev-message-create-header' => 'Created header',
- 'flow-rev-message-edit-header' => 'Edited header',
+ 'flow-rev-message-create-header' => "[[User:$1|$1]]
{{GENDER:$1|created}} the header '''$2'''.",
+ 'flow-rev-message-edit-header' => "[[User:$1|$1]] {{GENDER:$1|edited}}
the header '''$2'''.",
'flow-rev-message-restored-post' => '[[User:$1|$1]]
{{GENDER:$1|restored}} a <span class="plainlinks">[$3 comment]</span>.',
'flow-rev-message-deleted-post' => '[[User:$1|$1]]
{{GENDER:$1|deleted}} a <span class="plainlinks">[$3 comment]</span>.',
'flow-rev-message-censored-post' => '[[User:$1|$1]]
{{GENDER:$1|suppressed}} a <span class="plainlinks">[$3 comment]</span>.',
@@ -104,6 +104,8 @@
'flow-history-pages-post' => 'Appears on <span class="plainlinks">[$1
$2]</span>',
'flow-topic-participants' => '{{PLURAL:$1|$3 started this
topic|{{GENDER:$3|$3}}, {{GENDER:$4|$4}} and {{PLURAL:$2|other|others}}|0=No
participation yet|2={{GENDER:$3|$3}} and {{GENDER:$4|$4}}}}',
'flow-topic-comments' => '{{PLURAL:$1|0=Be the first to
comment!|Comment ($1)}}',
+
+ 'flow-board-history' => '"$1" History',
'flow-comment-restored' => 'Restored comment',
'flow-comment-deleted' => 'Deleted comment',
@@ -357,8 +359,16 @@
* $1: Username of the user who edited the title. Can be used for GENDER
* $2: The url of the topic
* $3: The topic title",
- 'flow-rev-message-create-header' => 'Used as revision comment when a
header has been created',
- 'flow-rev-message-edit-header' => 'Used as revision comment when a
header has been edited',
+ 'flow-rev-message-create-header' => 'Used as revision comment when the
header has been created.
+
+Parameters:
+* $1: Username of the user who created the header. Can be used for GENDER
+* $2: The header text',
+ 'flow-rev-message-edit-header' => 'Used as revision comment when the
header has been edited.
+
+Parameters:
+* $1: Username of the user who edited the header. Can be used for GENDER
+* $2: The header text',
'flow-rev-message-restored-post' => 'Used as revision comment when a
post has been restored (un-hidden).
Parameters:
@@ -408,6 +418,10 @@
Parameters:
* $1 - The amount of comments on this topic, can be used for PLURAL',
+ 'flow-board-history' => 'Used as <code><nowiki><h1></nowiki></code>
heading and HTML title in the "Board history" page.
+
+Parameters:
+* $1: The title to which the flow board belongs',
'flow-comment-restored' => 'Used as revision comment when the post has
been restored.
See also:
diff --git a/Flow.php b/Flow.php
index 0afd59c..6ba653b 100755
--- a/Flow.php
+++ b/Flow.php
@@ -103,6 +103,11 @@
$wgAutoloadClasses['Flow\Data\UniqueFeatureIndex'] = $dir .
'includes/Data/ObjectManager.php';
$wgAutoloadClasses['Flow\Data\TopKIndex'] = $dir .
'includes/Data/ObjectManager.php';
$wgAutoloadClasses['Flow\Data\TopicHistoryIndex'] = $dir .
'includes/Data/ObjectManager.php';
+$wgAutoloadClasses['Flow\Data\BoardHistoryStorage'] = $dir .
'includes/Data/BoardHistoryStorage.php';
+$wgAutoloadClasses['Flow\Data\BoardHistoryIndex'] = $dir .
'includes/Data/BoardHistoryStorage.php';
+$wgAutoloadClasses['Flow\Data\BoardHistoryHeaderIndex'] = $dir .
'includes/Data/BoardHistoryStorage.php';
+$wgAutoloadClasses['Flow\Data\BoardHistoryTopicListIndex'] = $dir .
'includes/Data/BoardHistoryStorage.php';
+$wgAutoloadClasses['Flow\Model\BoardHistoryEntry'] = $dir .
'includes/Model/BoardHistoryEntry.php';
$wgAutoloadClasses['Flow\Data\ObjectStorage'] = $dir .
'includes/Data/ObjectManager.php';
$wgAutoloadClasses['Flow\Data\BasicDbStorage'] = $dir .
'includes/Data/ObjectManager.php';
$wgAutoloadClasses['Flow\Data\ObjectMapper'] = $dir .
'includes/Data/ObjectManager.php';
diff --git a/HistoryActions.php b/HistoryActions.php
index 6e6c087..d186218 100644
--- a/HistoryActions.php
+++ b/HistoryActions.php
@@ -2,6 +2,7 @@
use Flow\View\History;
use Flow\Model\PostRevision;
+use Flow\Model\Header;
use Flow\Block\Block;
use Flow\UrlGenerator;
@@ -18,6 +19,31 @@
* the list-item & clicking on it will reveal the individual history entries)
*/
$wgFlowHistoryActions = array(
+ 'flow-edit-header' => array(
+ 'i18n-message' => 'flow-rev-message-edit-header',
+ 'i18n-params' => array(
+ function ( Header $revision, UrlGenerator
$urlGenerator, User $user, Block $block ) {
+ return $revision->getUserText( $user );
+ },
+ function ( Header $revision, UrlGenerator
$urlGenerator, User $user, Block $block ) {
+ return $revision->getContent( $user, 'wikitext'
);
+ },
+ // @todo: find previous revision & return header of
that revision
+ ),
+ 'class' => 'flow-rev-message-edit-header',
+ ),
+ 'flow-create-header' => array(
+ 'i18n-message' => 'flow-rev-message-create-header',
+ 'i18n-params' => array(
+ function ( Header $revision, UrlGenerator
$urlGenerator, User $user, Block $block ) {
+ return $revision->getUserText( $user );
+ },
+ function ( Header $revision, UrlGenerator
$urlGenerator, User $user, Block $block ) {
+ return $revision->getContent( $user, 'wikitext'
);
+ },
+ ),
+ 'class' => 'flow-rev-message-create-header',
+ ),
'flow-rev-message-edit-post' => array(
'i18n-message' => 'flow-rev-message-edit-post',
'i18n-params' => array(
@@ -83,16 +109,6 @@
// @todo: find previous revision & return title of that
revision
),
'class' => 'flow-rev-message-edit-title',
- ),
- 'flow-rev-message-create-header' => array(
- 'i18n-message' => 'flow-rev-message-create-header',
- // @todo: AFAIK, we don't have a board history yet, where this
will be surfaced
- 'class' => 'flow-rev-message-create-header',
- ),
- 'flow-rev-message-edit-header' => array(
- 'i18n-message' => 'flow-rev-message-edit-header',
- // @todo: AFAIK, we don't have a board history yet, where this
will be surfaced
- 'class' => 'flow-rev-message-edit-header',
),
'flow-rev-message-restored-post' => array(
'i18n-message' => 'flow-rev-message-restored-post',
diff --git a/Hooks.php b/Hooks.php
index 513c452..f7f6d11 100644
--- a/Hooks.php
+++ b/Hooks.php
@@ -41,6 +41,7 @@
}
$updater->addExtensionIndex( 'flow_workflow',
'flow_workflow_lookup', "$dir/db_patches/patch-workflow_lookup_idx.sql" );
+ $updater->addExtensionIndex( 'flow_topic_list',
'flow_topic_list_topic_id', "$dir/db_patches/patch-topic_list_topic_id_idx.sql"
);
require_once
__DIR__.'/maintenance/FlowInsertDefaultDefinitions.php';
$updater->addPostDatabaseUpdateMaintenance(
'FlowInsertDefaultDefinitions' );
diff --git a/container.php b/container.php
index 1681fc3..e619441 100644
--- a/container.php
+++ b/container.php
@@ -61,6 +61,10 @@
use Flow\Data\UniqueFeatureIndex;
use Flow\Data\TopKIndex;
use Flow\Data\TopicHistoryIndex;
+use Flow\Data\BoardHistoryStorage;
+use Flow\Data\BoardHistoryTopicListIndex;
+use Flow\Data\BoardHistoryHeaderIndex;
+use Flow\Data\BoardHistoryIndex;
use Flow\Data\ObjectMapper;
use Flow\Data\ObjectManager;
@@ -112,6 +116,24 @@
return new ObjectManager( $mapper, $storage, $indexes, $lifecycle );
} );
+
+$c['storage.board_history'] = $c->share( function( $c ) {
+ $cache = $c['memcache.buffered'];
+ $mapper = BasicObjectMapper::model( 'Flow\\Model\\BoardHistoryEntry' );
+ $storage = new BoardHistoryStorage( $c['db.factory'] );
+
+ $indexes = array(
+ new BoardHistoryIndex( $cache, $storage, $c['repository.tree'],
'flow_revision:topic_list_history',
+ array( 'topic_list_id' ),
+ array(
+ 'limit' => 500,
+ 'sort' => 'rev_id',
+ 'order' => 'DESC'
+ ) ),
+ );
+ return new ObjectManager( $mapper, $storage, $indexes );
+} );
+
// Arbitrary bit of revisioned wiki-text attached to a workflow
$c['storage.header'] = $c->share( function( $c ) {
global $wgFlowExternalStore, $wgContLang;
@@ -144,6 +166,13 @@
'flow_header:latest', array( 'header_workflow_id' ),
array( 'limit' => 1 ) + $workflowIndexOptions
),
+ new BoardHistoryHeaderIndex( $cache, new BoardHistoryStorage(
$c['db.factory'] ), $c['repository.tree'], 'flow_revision:topic_list_history',
+ array( 'topic_list_id' ),
+ array(
+ 'limit' => 500,
+ 'sort' => 'rev_id',
+ 'order' => 'DESC'
+ ) ),
);
$handlers = array(
@@ -232,7 +261,14 @@
return $row['tree_parent_id'] === null
&& $row['rev_parent_id'] ===
null;
},
- ) )
+ ) ),
+ new BoardHistoryTopicListIndex( $cache, new
BoardHistoryStorage( $c['db.factory'] ), $c['repository.tree'],
'flow_revision:topic_list_history',
+ array( 'topic_list_id' ),
+ array(
+ 'limit' => 500,
+ 'sort' => 'rev_id',
+ 'order' => 'DESC'
+ ) ),
);
$handlers = array(
@@ -293,6 +329,9 @@
'Flow\\Model\\Header' => 'storage.header',
'Header' => 'storage.header',
+
+ 'Flow\\Model\\BoardHistoryEntry' =>
'storage.board_history',
+ 'BoardHistoryEntry' => 'storage.board_history',
)
);
} );
diff --git a/db_patches/patch-topic_list_topic_id_idx.sql
b/db_patches/patch-topic_list_topic_id_idx.sql
new file mode 100644
index 0000000..2d0d8df
--- /dev/null
+++ b/db_patches/patch-topic_list_topic_id_idx.sql
@@ -0,0 +1 @@
+CREATE INDEX /*i*/flow_topic_list_topic_id ON /*_*/flow_topic_list (topic_id);
diff --git a/includes/Block/Header.php b/includes/Block/Header.php
index 14f9540..7d35965 100644
--- a/includes/Block/Header.php
+++ b/includes/Block/Header.php
@@ -85,14 +85,17 @@
}
public function render( Templating $templating, array $options ) {
- $templating->getOutput()->addModules( 'ext.flow.header' );
- $templateName = ( $this->action == 'edit-header' ) ?
'edit-header' : 'header';
- $templating->render( "flow:$templateName.html.php", array(
- 'block' => $this,
- 'workflow' => $this->workflow,
- 'header' => $this->header,
- 'user' => $this->user,
- ) );
+ // Don't show header in board history page
+ if ( $this->action !== 'board-history' ) {
+ $templating->getOutput()->addModules( 'ext.flow.header'
);
+ $templateName = ( $this->action == 'edit-header' ) ?
'edit-header' : 'header';
+ $templating->render( "flow:$templateName.html.php",
array(
+ 'block' => $this,
+ 'workflow' => $this->workflow,
+ 'header' => $this->header,
+ 'user' => $this->user,
+ ) );
+ }
}
public function renderAPI( Templating $templating, array $options ) {
diff --git a/includes/Block/TopicList.php b/includes/Block/TopicList.php
index c9bffa1..d7a52a3 100644
--- a/includes/Block/TopicList.php
+++ b/includes/Block/TopicList.php
@@ -2,6 +2,8 @@
namespace Flow\Block;
+use Flow\View\History\History;
+use Flow\View\History\HistoryRenderer;
use Flow\DbFactory;
use Flow\Data\ManagerGroup;
use Flow\Data\ObjectManager;
@@ -62,9 +64,10 @@
$firstPost->setChildren( array() );
$storage->put( $topicWorkflow );
+ $storage->put( $topicListEntry );
$storage->put( $topicPost );
$storage->put( $firstPost );
- $storage->put( $topicListEntry );
+
$this->notificationController->notifyNewTopic( array(
'board-workflow' => $this->workflow,
@@ -101,16 +104,25 @@
'page' => false,
) );
} else {
- $findOptions = $this->getFindOptions( $options );
- $page = $this->getPage( $findOptions );
- $topics = $this->getTopics( $page );
-
- $templating->render( "flow:topiclist.html.php", array(
- 'block' => $this,
- 'topics' => $topics,
- 'user' => $this->user,
- 'page' => $page,
- ) );
+ if ( $this->action == 'board-history' ) {
+ $templating->getOutput()->addModules(
'ext.flow.history' );
+ $templating->render(
"flow:board-history.html.php", array(
+ 'title' => wfMessage(
'flow-board-history', $this->workflow->getArticleTitle() )->escaped(),
+ 'history' => new History(
$this->getTopicListHistory() ),
+ 'historyRenderer' => new
HistoryRenderer( $templating, $this ),
+ ) );
+ } else {
+ $findOptions = $this->getFindOptions( $options
);
+ $page = $this->getPage( $findOptions );
+ $topics = $this->getTopics( $page );
+
+ $templating->render( "flow:topiclist.html.php",
array(
+ 'block' => $this,
+ 'topics' => $topics,
+ 'user' => $this->user,
+ 'page' => $page,
+ ) );
+ }
}
}
@@ -204,5 +216,19 @@
return $topics;
}
+
+ protected function getTopicListHistory() {
+ $found = $this->storage->find(
+ 'BoardHistoryEntry',
+ array( 'topic_list_id' => $this->workflow->getId() ),
+ array( 'sort' => 'rev_id', 'order' => 'DESC', 'limit'
=> 300 )
+ );
+
+ if ( $found === false ) {
+ throw new \MWException( "Unable to load topic list
history for " . $this->workflow->getId()->getHex() );
+ }
+
+ return $found;
+ }
}
diff --git a/includes/Data/BoardHistoryStorage.php
b/includes/Data/BoardHistoryStorage.php
new file mode 100644
index 0000000..32d6b8b
--- /dev/null
+++ b/includes/Data/BoardHistoryStorage.php
@@ -0,0 +1,232 @@
+<?php
+
+namespace Flow\Data;
+
+use Flow\Model\UUID;
+use Flow\Model\PostRevision;
+use Flow\Model\Header;
+use Flow\DbFactory;
+use Flow\Repository\TreeRepository;
+use Flow\Container;
+
+class BoardHistoryStorage implements WritableObjectStorage {
+
+ protected $dbFactory;
+
+ public function __construct( DbFactory $dbFactory ) {
+ $this->dbFactory = $dbFactory;
+ }
+
+ public function getIterator() {
+ throw new \MWException( 'Not Implemented' );
+ }
+
+ function find( array $attributes, array $options = array() ) {
+ $multi = $this->findMulti( $attributes, $options );
+ if ( $multi ) {
+ return reset( $multi );
+ }
+ return null;
+ }
+
+ function findMulti( array $queries, array $options = array() ) {
+ $res = RevisionStorage::mergeExternalContent(
+ array( $this->findHeaderHistory( $queries, $options )
+ $this->findTopicListHistory( $queries, $options ) )
+ );
+
+ return $res;
+ }
+
+ function findHeaderHistory( array $queries, array $options = array() ) {
+ $queries = current( $queries );
+
+ $res = $this->dbFactory->getDB( DB_SLAVE )->select(
+ array( 'flow_header_revision', 'flow_revision' ),
+ array( '*' ),
+ array( 'header_rev_id = rev_id' ) + UUID::convertUUIDs(
array( 'header_workflow_id' => $queries['topic_list_id'] ) ),
+ __METHOD__,
+ $options
+ );
+
+ $retval = array();
+
+ if ( $res ) {
+ foreach ( $res as $row ) {
+ $retval[UUID::create( $row->rev_id )->getHex()]
= (array) $row;
+ }
+ }
+ return $retval;
+ }
+
+ function findTopicListHistory( array $queries, array $options = array()
) {
+ $res = $this->dbFactory->getDB( DB_SLAVE )->select(
+ array( 'flow_topic_list', 'flow_tree_revision',
'flow_revision' ),
+ array( '*' ),
+ array( 'tree_rev_id = rev_id', 'tree_rev_descendant_id
= topic_id' ) + UUID::convertUUIDs( current( $queries ) ),
+ __METHOD__,
+ $options
+ );
+
+ $retval = array();
+
+ if ( $res ) {
+ foreach ( $res as $row ) {
+ $retval[UUID::create( $row->rev_id )->getHex()]
= (array) $row;
+ }
+ }
+ return $retval;
+ }
+
+ public function getPrimaryKeyColumns() {
+ return array( 'topic_list_id' );
+ }
+
+ public function insert( array $row ) {
+ throw new \MWException( __CLASS__ . ' does not support insert
action' );
+ }
+
+ public function update( array $old, array $new ) {
+ throw new \MWException( __CLASS__ . ' does not support update
action' );
+ }
+
+ public function remove( array $row ) {
+ throw new \MWException( __CLASS__ . ' does not support remove
action' );
+ }
+
+}
+
+class BoardHistoryIndex extends topKIndex {
+
+ protected $treeRepository;
+
+ public function __construct( BufferedCache $cache, BoardHistoryStorage
$storage, TreeRepository $treeRepo, $prefix, array $indexed, array $options =
array() ) {
+ if ( $indexed !== array( 'topic_list_id' ) ) {
+ throw new \Exception( __CLASS__ . ' is hardcoded to
only index topic_list_id: ' . print_r( $indexed, true ) );
+ }
+ parent::__construct( $cache, $storage, $prefix, $indexed,
$options );
+ $this->treeRepository = $treeRepo;
+ }
+
+ public function isBuildIndex() {
+ return false;
+ }
+
+ public function backingStoreFindMulti( array $queries, array $idxToKey,
array $retval = array() ) {
+ $res = $this->storage->findMulti( $queries,
$this->queryOptions() );
+ if ( !$res ) {
+ return false;
+ }
+
+ $this->cache->add( current( $idxToKey ),
$this->rowCompactor->compactRows( $res[0] ) );
+ $retval[] = $res[0];
+
+ return $retval;
+ }
+}
+
+class BoardHistoryTopicListIndex extends TopKIndex {
+
+ protected $treeRepository;
+
+ public function __construct( BufferedCache $cache, BoardHistoryStorage
$storage, TreeRepository $treeRepo, $prefix, array $indexed, array $options =
array() ) {
+ if ( $indexed !== array( 'topic_list_id' ) ) {
+ throw new \Exception( __CLASS__ . ' is hardcoded to
only index topic_list_id: ' . print_r( $indexed, true ) );
+ }
+ parent::__construct( $cache, $storage, $prefix, $indexed,
$options );
+ $this->treeRepository = $treeRepo;
+ }
+
+ public function isSearchIndex() {
+ return false;
+ }
+
+ public function onAfterInsert( $object, array $new ) {
+ $post = UUID::create( $new['tree_rev_descendant_id'] );
+ if ( $this->isRootPost( $post ) ) {
+ $topicListId = $this->findTopicListId( $post );
+ if ( $topicListId ) {
+ $new['topic_list_id'] = $topicListId;
+ parent::onAfterInsert( $object, $new );
+ }
+ }
+ }
+
+ public function onAfterUpdate( $object, array $old, array $new ) {
+ $post = UUID::create( $old['tree_rev_descendant_id'] );
+ if ( $this->isRootPost( $post ) ) {
+ $topicListId = $this->findTopicListId( $post );
+ if ( $topicListId ) {
+ $new['topic_list_id'] = $old['topic_list_id'] =
$topicListId;
+ parent::onAfterUpdate( $object, $old, $new );
+ }
+ }
+ }
+
+ public function onAfterRemove( $object, array $old ) {
+ $post = UUID::create( $old['tree_rev_descendant_id'] );
+ if ( $this->isRootPost( $post ) ) {
+ $topicListId = $this->findTopicListId( $post );
+ if ( $topicListId ) {
+ $old['topic_list_id'] = $topicListId;
+ parent::onAfterRemove( $object, $old );
+ }
+ }
+ }
+
+ protected function isRootPost( $postId ) {
+ $parent = $this->treeRepository->findParent( $postId );
+ if ( $parent ) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ protected function findTopicListId( $post ) {
+ $topicListEntry = Container::get( 'storage' )->find(
+ 'TopicListEntry',
+ array( 'topic_id' => $post->getBinary() )
+ );
+
+ if ( $topicListEntry ) {
+ $topicListEntry = current( $topicListEntry );
+ return $topicListEntry->getListId()->getBinary();
+ } else {
+ return false;
+ }
+ }
+
+}
+
+class BoardHistoryHeaderIndex extends TopKIndex {
+
+ protected $treeRepository;
+
+ public function __construct( BufferedCache $cache, BoardHistoryStorage
$storage, TreeRepository $treeRepo, $prefix, array $indexed, array $options =
array() ) {
+ if ( $indexed !== array( 'topic_list_id' ) ) {
+ throw new \Exception( __CLASS__ . ' is hardcoded to
only index topic_list_id: ' . print_r( $indexed, true ) );
+ }
+ parent::__construct( $cache, $storage, $prefix, $indexed,
$options );
+ $this->treeRepository = $treeRepo;
+ }
+
+ public function isSearchIndex() {
+ return false;
+ }
+
+ public function onAfterInsert( $object, array $new ) {
+ $new['topic_list_id'] = $new['header_workflow_id'];
+ parent::onAfterInsert( $object, $new );
+ }
+
+ public function onAfterUpdate( $object, array $old, array $new ) {
+ $new['topic_list_id'] = $old['topic_list_id'] =
$new['header_workflow_id'];
+ parent::onAfterUpdate( $object, $old, $new );
+ }
+
+ public function onAfterRemove( $object, array $old ) {
+ $old['topic_list_id'] = $old['header_workflow_id'];
+ parent::onAfterRemove( $object, $old );
+ }
+
+}
diff --git a/includes/Data/ObjectManager.php b/includes/Data/ObjectManager.php
index e217311..b951da9 100644
--- a/includes/Data/ObjectManager.php
+++ b/includes/Data/ObjectManager.php
@@ -234,6 +234,9 @@
}
$index = $this->getIndexFor( $keys, $options );
+ if ( !$index->isSearchIndex() ) {
+ throw new \MWException( 'Index: ' . get_class( $index )
. ' is not a search index' );
+ }
$res = $index->findMulti( $queries );
if ( $res === null ) {
@@ -766,6 +769,23 @@
}
/**
+ * Return true if this index can be used for data search, false
otherwise
+ * @return boolean
+ */
+ public function isSearchIndex() {
+ return true;
+ }
+
+ /**
+ * Determine if this index can be used for building data cache, false
+ * otherwise
+ * @return boolean
+ */
+ public function isBuildIndex() {
+ return true;
+ }
+
+ /**
* This must be in the provided order so portions of the application can
* array_combine( $index->getPrimaryKeyColumns(), $primaryKeyValues )
*/
@@ -819,6 +839,9 @@
}
public function onAfterInsert( $object, array $new ) {
+ if ( !$this->isBuildIndex() ) {
+ throw new \MWException( 'Index: ' . __CLASS__ . ' is
not a build index' );
+ }
$indexed = ObjectManager::splitFromRow( $new , $this->indexed );
// is un-indexable a bail-worthy occasion? Probably not but
makes debugging easier
if ( !$indexed ) {
@@ -833,6 +856,9 @@
}
public function onAfterUpdate( $object, array $old, array $new ) {
+ if ( !$this->isBuildIndex() ) {
+ throw new \MWException( 'Index: ' . __CLASS__ . ' is
not a build index' );
+ }
$oldIndexed = ObjectManager::splitFromRow( $old, $this->indexed
);
$newIndexed = ObjectManager::splitFromRow( $new, $this->indexed
);
if ( !$oldIndexed ) {
@@ -858,6 +884,9 @@
}
public function onAfterRemove( $object, array $old ) {
+ if ( !$this->isBuildIndex() ) {
+ throw new \MWException( 'Index: ' . __CLASS__ . ' is
not a build index' );
+ }
$indexed = ObjectManager::splitFromRow( $old, $this->indexed );
if ( !$indexed ) {
throw new \MWException( 'Unindexable row: '
.json_encode( $old ) );
diff --git a/includes/Data/RevisionStorage.php
b/includes/Data/RevisionStorage.php
index a13b48a..c8847af 100644
--- a/includes/Data/RevisionStorage.php
+++ b/includes/Data/RevisionStorage.php
@@ -66,7 +66,7 @@
$res = $this->findMultiInternal( $queries, $options );
}
// Fetches content for all revisions flagged 'external'
- return $this->mergeExternalContent( $res );
+ return self::mergeExternalContent( $res );
}
protected function fallbackFindMulti( array $queries, array $options ) {
@@ -181,7 +181,7 @@
* @param array $cacheResult 2d array of rows
* @return array 2d array of rows with content merged and
rev_content_url populated
*/
- protected function mergeExternalContent( array $cacheResult ) {
+ public static function mergeExternalContent( array $cacheResult ) {
foreach ( $cacheResult as &$source ) {
foreach ( $source as &$row ) {
$flags = explode( ',', $row['rev_flags'] );
diff --git a/includes/Model/AbstractRevision.php
b/includes/Model/AbstractRevision.php
index 15d5bcd..eb989ba 100644
--- a/includes/Model/AbstractRevision.php
+++ b/includes/Model/AbstractRevision.php
@@ -121,7 +121,7 @@
$obj->flags = array_filter( explode( ',', $row['rev_flags'] ) );
$obj->content = $row['rev_content'];
// null if external store is not being used
- $obj->contentUrl = $row['rev_content_url'];
+ $obj->contentUrl = isset( $row['rev_content_url'] ) ?
$row['rev_content_url'] : null;
$obj->decompressedContent = null;
$obj->moderationState = $row['rev_mod_state'];
diff --git a/includes/Model/BoardHistoryEntry.php
b/includes/Model/BoardHistoryEntry.php
new file mode 100644
index 0000000..8741df8
--- /dev/null
+++ b/includes/Model/BoardHistoryEntry.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Flow\Model;
+
+/**
+ * This is a virutal model for Board history entry, which is a wrapper for
+ * Header and PostRevision
+ */
+class BoardHistoryEntry {
+
+ /**
+ * The revision for a board history entry
+ * @var Header/PostRevision
+ */
+ protected $revision;
+
+ /**
+ * Wrapper function for Header/PostRevision fromStorageRow method
+ */
+ public static function fromStorageRow( array $row, $obj = null ) {
+ if ( $row['rev_type'] === 'header' ) {
+ return Header::fromStorageRow( $row );
+ } elseif ( $row['rev_type'] === 'post' ) {
+ return PostRevision::fromStorageRow( $row );
+ } else {
+ throw new \MWException( 'Invalid rev_type for board
history entry: ' . $row['rev_type'] );
+ }
+ }
+
+ /**
+ * Wrapper function for toStoragerow method
+ */
+ public static function toStorageRow( $rev ) {
+ return $rev->toStorageRow( $rev );
+ }
+
+}
diff --git a/includes/Model/TopicListEntry.php
b/includes/Model/TopicListEntry.php
index 0521d89..27a9eb3 100644
--- a/includes/Model/TopicListEntry.php
+++ b/includes/Model/TopicListEntry.php
@@ -41,7 +41,7 @@
}
public function getListId() {
- return $this-topicListId;
+ return $this->topicListId;
}
}
diff --git a/includes/Repository/TreeRepository.php
b/includes/Repository/TreeRepository.php
index 2d6e98a..716133e 100644
--- a/includes/Repository/TreeRepository.php
+++ b/includes/Repository/TreeRepository.php
@@ -267,6 +267,12 @@
}
public function fetchParentMapFromDb( array $nodes ) {
+ foreach ( $nodes as $key => $node ) {
+ if ( $node instanceof UUID ) {
+ $node = $node->getBinary();
+ }
+ $nodes[$key] = $node;
+ }
// Find out who the parent is for those nodes
$dbr = $this->dbFactory->getDB( DB_SLAVE );
$res = $dbr->select(
diff --git a/includes/View/History/HistoryRecord.php
b/includes/View/History/HistoryRecord.php
index 3457abe..2f178ed 100644
--- a/includes/View/History/HistoryRecord.php
+++ b/includes/View/History/HistoryRecord.php
@@ -3,6 +3,7 @@
namespace Flow\View\History;
use Flow\Model\PostRevision;
+use Flow\Model\AbstractRevision;
use MWException;
use MWTimestamp;
use Message;
@@ -21,7 +22,7 @@
/**
* @param PostRevision $revision
*/
- public function __construct( PostRevision $revision ) {
+ public function __construct( AbstractRevision $revision ) {
$this->data = $revision;
}
diff --git a/modules/history/styles/history.less
b/modules/history/styles/history.less
index 0917156..bb8f329 100644
--- a/modules/history/styles/history.less
+++ b/modules/history/styles/history.less
@@ -67,7 +67,7 @@
}
}
- &.flow-rev-message-edit-title {
+ &.flow-rev-message-edit-title,
&.flow-rev-message-edit-header {
.background-image-svg('../../base/images/edit_normal.svg',
'../../base/images/edit_normal.png');
}
@@ -75,7 +75,7 @@
.background-image-svg('../../base/images/edit_normal.svg',
'../../base/images/edit_normal.png');
}
- &.flow-rev-message-new-post {
+ &.flow-rev-message-new-post,
&.flow-rev-message-create-header {
.background-image-svg('../../base/images/added_normal.svg',
'../../base/images/added_normal.png');
}
diff --git a/templates/board-history.html.php b/templates/board-history.html.php
new file mode 100644
index 0000000..03a206f
--- /dev/null
+++ b/templates/board-history.html.php
@@ -0,0 +1,18 @@
+<?php
+$this->getOutput()->setHtmlTitle( $title );
+$this->getOutput()->setPageTitle( $title );
+$timespans = $historyRenderer->getTimespans( $history );
+?>
+<div class="flow-history-container">
+ <div class="flow-history-log">
+ <?php
+ foreach ( $timespans as $text => $timespan ) {
+ $timespan = $history->getTimespan(
$timespan['from'], $timespan['to'] );
+ if ( $timespan->numRows() ) {
+ echo "<h2>$text</h2>";
+ echo $historyRenderer->render(
$timespan );
+ }
+ }
+ ?>
+ </div>
+</div>
--
To view, visit https://gerrit.wikimedia.org/r/92159
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie48edfa4b8f85eaffa282b136663e95353c17215
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: Bsitu <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits