%PDF- %PDF-
| Direktori : /www/varak.net/wiki.varak.net/extensions/Translate/specials/ |
| Current File : /www/varak.net/wiki.varak.net/extensions/Translate/specials/SpecialManageTranslatorSandbox.php |
<?php
/**
* Contains logic for Special:ManageTranslatorSandbox
*
* @file
* @author Niklas Laxström
* @author Amir E. Aharoni
* @license GPL-2.0-or-later
*/
/**
* Special page for managing sandboxed users.
*
* @ingroup SpecialPage TranslateSpecialPage
*/
class SpecialManageTranslatorSandbox extends SpecialPage {
/** @var TranslationStashStorage */
protected $stash;
public function __construct() {
global $wgTranslateUseSandbox;
parent::__construct(
'ManageTranslatorSandbox',
'translate-sandboxmanage',
$wgTranslateUseSandbox
);
}
public function doesWrites() {
return true;
}
protected function getGroupName() {
return 'users';
}
public function execute( $params ) {
$this->setHeaders();
$this->checkPermissions();
$out = $this->getOutput();
$out->addModuleStyles( [
'ext.translate.special.managetranslatorsandbox.styles',
'mediawiki.ui.button',
'jquery.uls.grid'
] );
$out->addModules( 'ext.translate.special.managetranslatorsandbox' );
$this->stash = new TranslationStashStorage( wfGetDB( DB_MASTER ) );
$this->prepareForTests();
$this->showPage();
}
/**
* Deletes a user page if it exists.
* This is needed especially when deleting sandbox users
* that were created as part of the integration tests.
* @param User $user
*/
protected function deleteUserPage( $user ) {
$userpage = WikiPage::factory( $user->getUserPage() );
if ( $userpage->exists() ) {
$dummyError = '';
$userpage->doDeleteArticleReal(
wfMessage( 'tsb-delete-userpage-summary' )->inContentLanguage()->text(),
false,
0,
true,
$dummyError,
$this->getUser()
);
}
}
/**
* Add users to the sandbox or delete them to facilitate browsers tests.
* Use with caution!
*/
public function prepareForTests() {
global $wgTranslateTestUsers;
$user = $this->getUser();
$request = $this->getRequest();
if ( !in_array( $user->getName(), $wgTranslateTestUsers, true ) ) {
return;
}
if ( $request->getVal( 'integrationtesting' ) === 'populate' ) {
// Empty all the users, even if they were created manually
// to ensure the number of users is what the tests expect
$this->emptySandbox();
$textUsernamePrefixes = [ 'Pupu', 'Orava' ];
$testLanguages = [ 'fi', 'uk', 'nl', 'he', 'bn' ];
$testLanguagesCount = count( $testLanguages );
foreach ( $textUsernamePrefixes as $prefix ) {
for ( $i = 0; $i < $testLanguagesCount; $i++ ) {
$name = "$prefix$i";
// Get rid of users, even if promoted during tests
$userToDelete = User::newFromName( $name, false );
$this->deleteUserPage( $userToDelete );
TranslateSandbox::deleteUser( $userToDelete, 'force' );
$user = TranslateSandbox::addUser( $name, "$name@blackhole.io", 'porkkana' );
$user->setOption(
'translate-sandbox',
FormatJson::encode( [
'languages' => [ $testLanguages[$i] ],
'comment' => '',
] )
);
$reminders = [];
for ( $reminderIndex = 0; $reminderIndex < $i; $reminderIndex++ ) {
$reminders[] = wfTimestamp() - $reminderIndex * $i * 10000;
}
$user->setOption(
'translate-sandbox-reminders',
implode( '|', $reminders )
);
$user->saveSettings();
for ( $j = 0; $j < $i; $j++ ) {
$title = Title::makeTitle(
NS_MEDIAWIKI,
wfRandomString( 24 ) . '/' . $testLanguages[$i]
);
$translation = 'plop';
$stashedTranslation = new StashedTranslation( $user, $title, $translation );
$this->stash->addTranslation( $stashedTranslation );
}
}
}
// Another account for testing a translator to multiple languages
$oldPolyglotUser = User::newFromName( 'Kissa', false );
$this->deleteUserPage( $oldPolyglotUser );
TranslateSandbox::deleteUser( $oldPolyglotUser, 'force' );
$polyglotUser = TranslateSandbox::addUser( 'Kissa', 'kissa@blackhole.io', 'porkkana' );
$polyglotUser->setOption(
'translate-sandbox',
FormatJson::encode( [
'languages' => $testLanguages,
'comment' => "I know some languages, and I'm a developer.",
] )
);
$polyglotUser->saveSettings();
for ( $polyglotLang = 0; $polyglotLang < $testLanguagesCount; $polyglotLang++ ) {
$title = Title::makeTitle(
NS_MEDIAWIKI,
wfRandomString( 24 ) . '/' . $testLanguages[$polyglotLang]
);
$translation = "plop in $testLanguages[$polyglotLang]";
$stashedTranslation = new StashedTranslation( $polyglotUser, $title, $translation );
$this->stash->addTranslation( $stashedTranslation );
}
} elseif ( $request->getVal( 'integrationtesting' ) === 'empty' ) {
$this->emptySandbox();
}
}
/**
* Delete all the users in the sandbox.
* Use with caution!
* To facilitate browsers tests.
*/
protected function emptySandbox() {
$users = TranslateSandbox::getUsers();
foreach ( $users as $user ) {
TranslateSandbox::deleteUser( $user );
}
}
/**
* Generates the whole page html and appends it to output
*/
protected function showPage() {
$out = $this->getOutput();
$nojs = Html::element(
'div',
[ 'class' => 'tux-nojs errorbox' ],
$this->msg( 'tux-nojs' )->plain()
);
$out->addHTML( $nojs );
$out->addHTML( <<<HTML
<div class="grid">
<div class="row">
<div class="nine columns pane filter">{$this->makeFilter()}</div>
<div class="three columns pane search">{$this->makeSearchBox()}</div>
</div>
<div class="row tsb-body">
<div class="four columns pane requests">
{$this->makeList()}
<div class="request-footer">
<span class="selected-counter">
{$this->msg( 'tsb-selected-count' )->numParams( 0 )->escaped()}
</span>
<a href="#" class="older-requests-indicator"></a>
</div>
</div>
<div class="eight columns pane details"></div>
</div>
</div>
HTML
);
}
protected function makeFilter() {
return $this->msg( 'tsb-filter-pending' )->escaped();
}
protected function makeSearchBox() {
return <<<HTML
<input class="request-filter-box right"
placeholder="{$this->msg( 'tsb-search-requests' )->escaped()}" type="search">
</input>
HTML;
}
protected function makeList() {
$items = [];
$requests = [];
$users = TranslateSandbox::getUsers();
/** @var User $user */
foreach ( $users as $user ) {
$reminders = $user->getOption( 'translate-sandbox-reminders' );
$reminders = $reminders ? explode( '|', $reminders ) : [];
$remindersCount = count( $reminders );
if ( $remindersCount ) {
$lastReminderTimestamp = new MWTimestamp( end( $reminders ) );
$lastReminderAgo = htmlspecialchars(
$lastReminderTimestamp->getHumanTimestamp()
);
} else {
$lastReminderAgo = '';
}
$requests[] = [
'username' => $user->getName(),
'email' => $user->getEmail(),
'gender' => $user->getOption( 'gender' ),
'registrationdate' => $user->getRegistration(),
'translations' => count( $this->stash->getTranslations( $user ) ),
'languagepreferences' => FormatJson::decode( $user->getOption( 'translate-sandbox' ) ),
'userid' => $user->getId(),
'reminderscount' => $remindersCount,
'lastreminder' => $lastReminderAgo,
];
}
// Sort the requests based on translations and registration date
usort( $requests, [ __CLASS__, 'translatorRequestSort' ] );
foreach ( $requests as $request ) {
$items[] = $this->makeRequestItem( $request );
}
$requestsList = implode( "\n", $items );
return <<<HTML
<div class="row request-header">
<div class="four columns">
<button class="language-selector unselected">
{$this->msg( 'tsb-all-languages-button-label' )->escaped()}
</button>
</div>
<div class="five columns request-count"></div>
<div class="three columns center">
<input class="request-selector-all" name="request" type="checkbox" />
</div>
</div>
<div class="requests-list">
{$requestsList}
</div>
HTML;
}
protected function makeRequestItem( $request ) {
$requestdataEnc = htmlspecialchars( FormatJson::encode( $request ) );
$nameEnc = htmlspecialchars( $request['username'] );
$nameEncForId = htmlspecialchars( Sanitizer::escapeId( $request['username'], 'noninitial' ) );
$emailEnc = htmlspecialchars( $request['email'] );
$countEnc = htmlspecialchars( $request['translations'] );
$timestamp = new MWTimestamp( $request['registrationdate'] );
$agoEnc = htmlspecialchars( $timestamp->getHumanTimestamp() );
return <<<HTML
<div class="row request" data-data="$requestdataEnc" id="tsb-request-$nameEncForId">
<div class="two columns amount">
<div class="translation-count">$countEnc</div>
</div>
<div class="seven columns request-info">
<div class="row username">$nameEnc</div>
<div class="row email">$emailEnc</div>
</div>
<div class="three columns approval center">
<input class="row request-selector" name="request" type="checkbox" />
<div class="row signup-age">$agoEnc</div>
</div>
</div>
HTML;
}
/**
* Sorts groups by descending order of number of translations,
* registration date and username
*
* @since 2013.12
* @param array $a Translation request
* @param array $b Translation request
* @return int comparison result
*/
public static function translatorRequestSort( $a, $b ) {
$translationCountDiff = $b['translations'] - $a['translations'];
if ( $translationCountDiff !== 0 ) {
return $translationCountDiff;
}
$registrationDateDiff = $b['registrationdate'] - $a['registrationdate'];
if ( $registrationDateDiff !== 0 ) {
return $registrationDateDiff;
}
return strcmp( $a['username'], $b['username'] );
}
}