EBernhardson has uploaded a new change for review.
https://gerrit.wikimedia.org/r/115532
Change subject: [WIP] Combined board history
......................................................................
[WIP] Combined board history
Change-Id: I9719b8a911b497ddb59a149d59063f8c1ce6d7e5
---
M Flow.php
M Resources.php
M container.php
M includes/Block/Header.php
M includes/Data/BoardHistoryStorage.php
A includes/Formatter/BoardHistory.php
A includes/Formatter/BoardHistoryQuery.php
A modules/history/styles/board-history.less
M templates/board-history.html.php
9 files changed, 188 insertions(+), 70 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow
refs/changes/32/115532/1
diff --git a/Flow.php b/Flow.php
index d167d42..5234aff 100755
--- a/Flow.php
+++ b/Flow.php
@@ -140,6 +140,8 @@
$wgAutoloadClasses['Flow\Formatter\CheckUser'] = $dir .
'includes/Formatter/CheckUser.php';
$wgAutoloadClasses['Flow\Formatter\ContributionsQuery'] = $dir .
'includes/Formatter/ContributionsQuery.php';
$wgAutoloadClasses['Flow\Formatter\Contributions'] = $dir .
'includes/Formatter/Contributions.php';
+$wgAutoloadClasses['Flow\Formatter\BoardHistory'] = $dir .
'includes/Formatter/BoardHistory.php';
+$wgAutoloadClasses['Flow\Formatter\BoardHistoryQuery'] = $dir .
'includes/Formatter/BoardHistoryQuery.php';
$wgAutoloadClasses['Flow\Formatter\RecentChanges'] = $dir .
'includes/Formatter/RecentChanges.php';
$wgAutoloadClasses['Flow\Data\UserNameListener'] = $dir .
'includes/Data/UserNameBatch.php';
$wgAutoloadClasses['Flow\Data\UserNameBatch'] = $dir .
'includes/Data/UserNameBatch.php';
diff --git a/Resources.php b/Resources.php
index 195fb78..2fdf6f1 100644
--- a/Resources.php
+++ b/Resources.php
@@ -105,6 +105,7 @@
),
'ext.flow.history' => $flowResourceTemplate + array(
'styles' => array(
+ 'history/styles/board-history.less', // @todo should be
independant?
'history/styles/history.less',
'history/styles/diff.less',
),
diff --git a/container.php b/container.php
index daa00ab..3f1d4c4 100644
--- a/container.php
+++ b/container.php
@@ -185,7 +185,8 @@
} );
$c['storage.board_history.index'] = $c->share( function( $c ) {
- return new BoardHistoryIndex( $c['memcache.buffered'],
$c['storage.board_history.backing'], 'flow_revision:topic_list_history',
+ return new BoardHistoryIndex( $c['memcache.buffered'],
$c['storage.board_history.backing'],
+ 'flow_revision:vXxXxX:topic_list_history',
array( 'topic_list_id' ),
array(
'limit' => 500,
@@ -483,7 +484,19 @@
$c['templating']
);
} );
-
+$c['board-history.query'] = $c->share( function( $c ) {
+ return new Flow\Formatter\BoardHistoryQuery(
+ $c['storage'],
+ $c['repository.tree']
+ );
+} );
+$c['board-history.formatter'] = $c->share( function( $c ) {
+ return new Flow\Formatter\BoardHistory(
+ $c['storage'],
+ $c['flow_actions'],
+ $c['templating']
+ );
+} );
$c['logger'] = $c->share( function( $c ) {
return new Flow\Log\Logger(
$c['flow_actions'],
diff --git a/includes/Block/Header.php b/includes/Block/Header.php
index 1f5a364..db15179 100644
--- a/includes/Block/Header.php
+++ b/includes/Block/Header.php
@@ -4,13 +4,9 @@
use Flow\Container;
use Flow\Model\Header;
-use Flow\Model\PostRevision;
use Flow\RevisionActionPermissions;
-use Flow\View\History\History;
-use Flow\View\History\HistoryRenderer;
use Flow\Templating;
use Flow\Exception\InvalidActionException;
-use Flow\Exception\InvalidDataException;
class HeaderBlock extends AbstractBlock {
@@ -142,19 +138,26 @@
if ( $this->action === 'board-history' ) {
$templating->getOutput()->addModuleStyles( array(
'ext.flow.history' ) );
$templating->getOutput()->addModules( array(
'ext.flow.history' ) );
- $tplVars = array(
- 'title' => wfMessage( 'flow-board-history',
$this->workflow->getArticleTitle() )->escaped(),
- 'historyExists' => false,
- );
+ $title = $this->workflow->getArticleTitle();
- $history = $this->loadBoardHistory();
- if ( $history ) {
- $tplVars['historyExists'] = true;
- $tplVars['history'] = new History( $history );
- $tplVars['historyRenderer'] = new
HistoryRenderer( $templating, $this );
+ $lines = array();
+ $history = Container::get( 'board-history.query'
)->getResults( $this->workflow );
+ $renderer = Container::get( 'board-history.formatter' );
+ // @todo is this the right context?
+ $ctx = \RequestContext::getMain();
+ foreach ( $history as $row ) {
+ $res = $renderer->format( $row, $ctx );
+ if ( $res !== false ) {
+ // formatter implementations always
return safe html
+ $lines[] = $res;
+ }
}
- $templating->render( "flow:board-history.html.php",
$tplVars );
+ $templating->render( "flow:board-history.html.php",
array(
+ 'title' => wfMessage( 'flow-board-history',
$title )->escaped(),
+ 'lines' => $lines,
+ 'historyExists' => count( $history ) > 0,
+ ) );
} else {
$templating->getOutput()->addModuleStyles( array(
'ext.flow.header' ) );
$templating->getOutput()->addModules( array(
'ext.flow.header' ) );
@@ -192,30 +195,6 @@
);
return $output;
- }
-
- protected function loadBoardHistory() {
- $history = $this->storage->find(
- 'BoardHistoryEntry',
- array( 'topic_list_id' => $this->workflow->getId() ),
- array( 'sort' => 'rev_id', 'order' => 'DESC', 'limit'
=> 300 )
- );
-
- if ( !$history ) {
- throw new InvalidDataException( 'Unable to load topic
list history for ' . $this->workflow->getId()->getAlphadecimal(),
'fail-load-history' );
- }
-
- // get rid of history entries user doesn't have sufficient
permissions for
- foreach ( $history as $i => $revision ) {
- /** @var PostRevision|Header $revision */
-
- // only check against the specific revision, ignoring
the most recent
- if ( !$this->permissions->isAllowed( $revision,
'post-history' ) ) {
- unset( $history[$i] );
- }
- }
-
- return $history;
}
public function getName() {
diff --git a/includes/Data/BoardHistoryStorage.php
b/includes/Data/BoardHistoryStorage.php
index 828b7ba..d09d8c3 100644
--- a/includes/Data/BoardHistoryStorage.php
+++ b/includes/Data/BoardHistoryStorage.php
@@ -62,9 +62,13 @@
$queries = $this->preprocessSqlArray( reset( $queries ) );
$res = $this->dbFactory->getDB( DB_SLAVE )->select(
- array( 'flow_topic_list', 'flow_tree_revision',
'flow_revision' ),
+ array( 'flow_topic_list', 'flow_tree_node',
'flow_tree_revision', 'flow_revision' ),
array( '*' ),
- array( 'tree_rev_id = rev_id', 'tree_rev_descendant_id
= topic_id' ) + $queries,
+ array(
+ 'topic_id = tree_ancestor_id',
+ 'tree_descendant_id = tree_rev_descendant_id',
+ 'tree_rev_id = rev_id',
+ ) + $queries,
__METHOD__,
$options
);
@@ -134,11 +138,11 @@
* @param string[] $new
*/
public function onAfterInsert( $object, array $new ) {
- if ( $object->getRevisionType() === 'header' ) {
+ if ( $object instanceof Header ) {
$new['topic_list_id'] = $new['header_workflow_id'];
parent::onAfterInsert( $object, $new );
- } elseif ( $object->getRevisionType() === 'post' ) {
- $topicListId = $this->findTopicListIdForRootPost(
$object );
+ } elseif ( $object instanceof PostRevision ) {
+ $topicListId = $this->findTopicListIdForRootPost(
$object->getRootPost() );
if ( $topicListId ) {
$new['topic_list_id'] = $topicListId;
parent::onAfterInsert( $object, $new );
@@ -152,11 +156,11 @@
* @param string[] $new
*/
public function onAfterUpdate( $object, array $old, array $new ) {
- if ( $object->getRevisionType() === 'header' ) {
+ if ( $object instanceof Header ) {
$new['topic_list_id'] = $old['topic_list_id'] =
$new['header_workflow_id'];
parent::onAfterUpdate( $object, $old, $new );
- } elseif ( $object->getRevisionType() === 'post' ) {
- $topicListId = $this->findTopicListIdForRootPost(
$object );
+ } elseif ( $object instanceof PostRevision ) {
+ $topicListId = $this->findTopicListIdForRootPost(
$object->getRootPost() );
if ( $topicListId ) {
$new['topic_list_id'] = $old['topic_list_id'] =
$topicListId;
parent::onAfterUpdate( $object, $old, $new );
@@ -169,11 +173,11 @@
* @param string[] $old
*/
public function onAfterRemove( $object, array $old ) {
- if ( $object->getRevisionType() === 'header' ) {
+ if ( $object instanceof Header ) {
$old['topic_list_id'] = $old['header_workflow_id'];
parent::onAfterRemove( $object, $old );
- } elseif ( $object->getRevisionType() === 'post' ) {
- $topicListId = $this->findTopicListIdForRootPost(
$object );
+ } elseif ( $object instanceof PostRevision ) {
+ $topicListId = $this->findTopicListIdForRootPost(
$object->getRootPost() );
if ( $topicListId ) {
$old['topic_list_id'] = $topicListId;
parent::onAfterRemove( $object, $old );
@@ -187,14 +191,10 @@
* @param PostRevision $object
* @return string|boolean False when object is not root post or topic
is not found
*/
- protected function findTopicListIdForRootPost( $object ) {
- if ( !$object->isTopicTitle() ) {
- return false;
- }
-
+ protected function findTopicListId( PostRevision $object ) {
$topicListEntry = Container::get( 'storage' )->find(
'TopicListEntry',
- array( 'topic_id' => $object->getPostId() )
+ array( 'topic_id' =>
$object->getRootPost()->getPostId() )
);
if ( $topicListEntry ) {
diff --git a/includes/Formatter/BoardHistory.php
b/includes/Formatter/BoardHistory.php
new file mode 100644
index 0000000..823dfe8
--- /dev/null
+++ b/includes/Formatter/BoardHistory.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Flow\Formatter;
+
+use Flow\Exception\FlowException;
+use Flow\Model\Header;
+use Flow\Model\PostRevision;
+use Html;
+use IContextSource;
+
+class BoardHistory extends AbstractFormatter {
+
+ /**
+ * @param \stdClass $row A result row from BoardHistoryQuery
+ * @param IContextSource $ctx
+ * @return string|false HTML string representing $row
+ */
+ public function format( $row, IContextSource $ctx ) {
+ try {
+ return $this->formatReal( $row, $ctx );
+ } catch ( FlowException $e ) {
+ \MWExceptionHandler::logException( $e );
+ return false;
+ }
+ }
+
+ protected function formatReal( $row, IContextSource $ctx ) {
+ $revision = $row->revision;
+ $workflow = $row->workflow;
+ $workflowId = $workflow->getId();
+ $title = $workflow->getArticleTitle();
+
+ $user = $ctx->getUser();
+ $lang = $ctx->getLanguage();
+ $perm = $this->getPermissions( $user );
+
+ if ( !$perm->isAllowed( $revision, 'board-history' ) ) {
+ return false;
+ }
+
+ if ( $revision instanceof PostRevision ) {
+ if ( !$perm->isAllowed( $row->root_post,
'board-history' ) ) {
+ return false;
+ }
+ $blockType = 'header';
+ } elseif ( $revision instanceof Header ) {
+ $blockType = 'topic';
+ } else {
+ throw new \Exception( 'Unknown revision type' );
+ }
+
+ $description = $this->getActionDescription( $workflowId,
$blockType, $revision );
+ $dateFormats = $this->getDateFormats( $revision, $user, $lang );
+
+ list( $href, $msg ) = $this->topicLink( $title, $workflowId );
+
+ $formattedTime = Html::element(
+ 'a',
+ array(
+ 'href' => $href,
+ 'title' => $msg->text(),
+ ),
+ $dateFormats['timeAndDate']
+ );
+
+ $linksContent = ''; // @todo
+ $charDiff = $this->getCharDiff(
+ $row->revision,
+ $row->previous_revision
+ );
+
+
+ return $formattedTime
+ . ' . . '
+ . $description
+ . ( $charDiff ? " . . $charDiff" : '' )
+ . $linksContent;
+ }
+
+}
diff --git a/includes/Formatter/BoardHistoryQuery.php
b/includes/Formatter/BoardHistoryQuery.php
new file mode 100644
index 0000000..39b1606
--- /dev/null
+++ b/includes/Formatter/BoardHistoryQuery.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Flow\Formatter;
+
+use Flow\Model\Workflow;
+use Flow\Exception\FlowException;
+use Flow\Exception\InvalidDataException;
+use MWExceptionHandler;
+
+class BoardHistoryQuery extends AbstractQuery {
+ public function getResults( Workflow $workflow ) {
+ // Load the history
+ $history = $this->storage->find(
+ 'BoardHistoryEntry',
+ array( 'topic_list_id' => $workflow->getId() ),
+ array( 'sort' => 'rev_id', 'order' => 'DESC', 'limit'
=> 300 )
+ );
+
+ if ( !$history ) {
+ throw new InvalidDataException( 'Unable to load topic
list history for ' . $workflow->getId()->getAlphadecimal(), 'fail-load-history'
);
+ }
+
+ $blockType = array(
+ 'Flow\Model\PostRevision' => 'topic',
+ 'Flow\Model\Header' => 'header',
+ );
+
+ // pre-load our workflow
+ $this->workflowCache[$workflow->getId()->getAlphadecimal()] =
$workflow;
+ // fetch any necessary metadata
+ $this->loadMetadataBatch( $history );
+ // build rows with the extra metadata
+ $results = array();
+ foreach ( $history as $revision ) {
+ try {
+ $result = $this->buildResult( $revision,
$blockType[get_class( $revision )], 'rev_id' );
+ } catch ( FlowException $e ) {
+ $result = false;
+ MWExceptionHandler::logException( $e );
+ }
+ if ( $result ) {
+ $results[] = $result;
+ }
+ }
+
+ return $results;
+ }
+}
diff --git a/modules/history/styles/board-history.less
b/modules/history/styles/board-history.less
new file mode 100644
index 0000000..a31f9a6
--- /dev/null
+++ b/modules/history/styles/board-history.less
@@ -0,0 +1,4 @@
+
+.flow-board-history-container {
+ font-size: 14px;
+}
diff --git a/templates/board-history.html.php b/templates/board-history.html.php
index 3f123d7..b66f7b0 100644
--- a/templates/board-history.html.php
+++ b/templates/board-history.html.php
@@ -2,19 +2,10 @@
$this->getOutput()->setHtmlTitle( $title );
$this->getOutput()->setPageTitle( $title );
?>
-<div class="flow-history-container">
+<div class="flow-board-history-container">
<div class="flow-history-log">
- <?php
- if ( $historyExists ) {
- $timespans = $historyRenderer->getTimespans(
$history );
- foreach ( $timespans as $text => $timespan ) {
- $timespan = $history->getTimespan(
$timespan['from'], $timespan['to'] );
- if ( $timespan->numRows() ) {
- echo "<h2>$text</h2>";
- echo $historyRenderer->render(
$timespan );
- }
- }
- }
- ?>
+ <ul>
+ <li><?php echo implode( "</li>\n<li>", $lines ) ?></li>
+ </ul>
</div>
</div>
--
To view, visit https://gerrit.wikimedia.org/r/115532
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9719b8a911b497ddb59a149d59063f8c1ce6d7e5
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: EBernhardson <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits