$out->addHTML( $this->getPageHeader() );
if ( $this->numRows > 0 ) {
$out->addHTML( $this->msg( 'showingresults' )->numParams(
- $this->numRows, $this->offset + 1 )->parseAsBlock() );
+ min( $this->numRows, $this->limit ), # do not show the one extra row, if exist
+ $this->offset + 1 )->parseAsBlock() );
# Disable the "next" link when we reach the end
$paging = $this->getLanguage()->viewPrevNext( $this->getTitle( $par ), $this->offset,
$this->limit, $this->linkParameters(), ( $this->numRows <= $this->limit ) );
$out->addHTML( Xml::closeElement( 'div' ) );
- return $this->numRows;
+ return min( $this->numRows, $this->limit ); # do not return the one extra row, if exist
}
/**
*/
public function __construct( array $config ) {
parent::__construct( $config );
- $namesUsed = array();
+ $this->syncChecks = isset( $config['syncChecks'] )
+ ? $config['syncChecks']
+ : self::CHECK_SIZE;
// Construct backends here rather than via registration
// to keep these backends hidden from outside the proxy.
+ $namesUsed = array();
foreach ( $config['backends'] as $index => $config ) {
if ( isset( $config['template'] ) ) {
// Config is just a modified version of a registered backend's.
if ( $this->masterIndex < 0 ) { // need backends and must have a master
throw new MWException( 'No master backend defined.' );
}
- $this->syncChecks = isset( $config['syncChecks'] )
- ? $config['syncChecks']
- : self::CHECK_SIZE;
}
/**
/**
* Check that a set of files are consistent across all internal backends
*
- * @param $paths Array
+ * @param $paths Array List of storage paths
* @return Status
*/
public function consistencyCheck( array $paths ) {
// Stat the file on the 'master' backend
$mStat = $mBackend->getFileStat( $mParams );
if ( $this->syncChecks & self::CHECK_SHA1 ) {
- $mSha1 = $mBackend->getFileSha1( $mParams );
+ $mSha1 = $mBackend->getFileSha1Base36( $mParams );
} else {
$mSha1 = false;
}
}
}
if ( $this->syncChecks & self::CHECK_SHA1 ) {
- if ( $cBackend->getFileSha1( $cParams ) !== $mSha1 ) { // wrong SHA1
+ if ( $cBackend->getFileSha1Base36( $cParams ) !== $mSha1 ) { // wrong SHA1
$status->fatal( 'backend-fail-synced', $path );
continue;
}
return $status;
}
+ /**
+ * Check that a set of files are consistent across all internal backends
+ * and re-synchronize those files againt the "multi master" if needed.
+ *
+ * @param $paths Array List of storage paths
+ * @return Status
+ */
+ public function resyncFiles( array $paths ) {
+ $status = Status::newGood();
+
+ $mBackend = $this->backends[$this->masterIndex];
+ foreach ( $paths as $path ) {
+ $mPath = $this->substPaths( $path, $mBackend );
+ $mSha1 = $mBackend->getFileSha1Base36( array( 'src' => $mPath ) );
+ $mExist = $mBackend->fileExists( array( 'src' => $mPath ) );
+ // Check of all clone backends agree with the master...
+ foreach ( $this->backends as $index => $cBackend ) {
+ if ( $index === $this->masterIndex ) {
+ continue; // master
+ }
+ $cPath = $this->substPaths( $path, $cBackend );
+ $cSha1 = $cBackend->getFileSha1Base36( array( 'src' => $cPath ) );
+ if ( $mSha1 === $cSha1 ) {
+ // already synced; nothing to do
+ } elseif ( $mSha1 ) { // file is in master
+ $fsFile = $mBackend->getLocalReference( array( 'src' => $mPath ) );
+ $status->merge( $cBackend->quickStore(
+ array( 'src' => $fsFile->getPath(), 'dst' => $cPath )
+ ) );
+ } elseif ( $mExist === false ) { // file is not in master
+ $status->merge( $cBackend->quickDelete( array( 'src' => $cPath ) ) );
+ }
+ }
+ }
+
+ return $status;
+ }
+
/**
* Get a list of file storage paths to read or write for a list of operations
*
'import-interwiki-templates',
'import-interwiki-submit',
'import-interwiki-namespace',
+ 'import-interwiki-rootpage',
'import-upload-filename',
'import-comment',
'importtext',
'import-error-interwiki',
'import-error-special',
'import-error-invalid',
+ 'import-options-wrong',
+ 'import-rootpage-invalid',
+ 'import-rootpage-nosubpage',
),
'importlog' => array(
'importlogpage',
</p>
!! end
+# FIXME: This test (the IDN characters in the text of a link) is an inconsistency.
+# Where an external link could easily circumvent the sanitization of the text of
+# a link like this (where an IDN-ignore character is in the URL somewhere), this
+# test demands a higher standard. That's a bit strange.
+#
+# Example:
+#
+# http://example.com -> [http://example.com|http://example.com]
+# [http://example.com|http://example.com] -> [http://example.com|http://example.com]
+#
+# The first example is sanitized, but the second is not. Any security benefits
+# from this production are trivial to circumvent. Either remove this test and
+# let the parser(s) do their thing unaccosted, or fix the inconsistency and change
+# the test accordingly.
+#
+# All our love,
+# The Parsoid team.
!! test
External links: IDN ignored character reference in hostname; strip it right off
!! input
array( 'Ab cd', false, ' Ideographic space' ),
);
}
+
+ /**
+ * Test, if for all rights a right- message exist,
+ * which is used on Special:ListGroupRights as help text
+ * Extensions and core
+ */
+ public function testAllRightsWithMessage() {
+ //Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
+ $allRights = User::getAllRights();
+ $allMessageKeys = Language::getMessageKeysFor( 'en' );
+
+ $rightsWithMessage = array();
+ foreach ( $allMessageKeys as $message ) {
+ // === 0: must be at beginning of string (position 0)
+ if ( strpos( $message, 'right-' ) === 0 ) {
+ $rightsWithMessage[] = substr( $message, strlen( 'right-' ) );
+ }
+ }
+
+ sort( $allRights );
+ sort( $rightsWithMessage );
+
+ $this->assertEquals(
+ $allRights,
+ $rightsWithMessage,
+ 'Each user rights (core/extensions) has a corresponding right- message.'
+ );
+ }
}