Файловый менеджер - Редактировать - /var/www/html/Echo.zip
Ðазад
PK ! �V���J �J + maintenance/generateSampleNotifications.phpnu �Iw�� <?php // phpcs:disable Generic.Files.LineLength -- Long html test examples // @phan-file-suppress PhanUndeclaredClassMethod, PhanUndeclaredClassConstant Other extensions used for testing purposes use MediaWiki\Content\WikitextContent; use MediaWiki\Extension\Notifications\Model\Event; use MediaWiki\Maintenance\Maintenance; use MediaWiki\Registration\ExtensionRegistry; use MediaWiki\Revision\RevisionRecord; use MediaWiki\Revision\SlotRecord; use MediaWiki\Title\Title; use MediaWiki\User\User; use Wikimedia\Rdbms\IDBAccessObject; $IP = getenv( 'MW_INSTALL_PATH' ); if ( $IP === false ) { $IP = __DIR__ . '/../../..'; } require_once "$IP/maintenance/Maintenance.php"; /** * A maintenance script that generates sample notifications for testing purposes. */ class GenerateSampleNotifications extends Maintenance { /** @var string[] */ private $supportedNotificationTypes = [ 'welcome', 'edit-user-talk', 'mention', 'page-linked', 'reverted', 'email', 'user-rights', 'cx', 'osm', 'edit-thanks', 'edu', 'page-connection', ]; /** @var int */ private $timestampCounter = 5; public function __construct() { parent::__construct(); $this->addDescription( "Generate sample notifications" ); $this->addOption( 'force', 'Bypass confirmation', false, false, 'f' ); $allTypes = implode( ',', $this->supportedNotificationTypes ); $this->addOption( 'types', "Comma-separated list of notification types to generate ($allTypes)", false, true, 't' ); $this->addOption( 'user', 'Name of the user receiving the notifications', true, true, 'u' ); $this->addOption( 'agent', 'Name of the user creating the notifications', true, true, 'a' ); $this->addOption( 'other', 'Name of another user involved with the notifications', true, true, 'o' ); $this->requireExtension( 'Echo' ); $this->addOption( 'timestamp', 'Add notification timestamps (Epoch time format). All notifications that are not ' . 'related directly to edits will be created with a timestamp starting 5 minutes ' . 'before the given timestamp, and increasing by 1 minute per notification.', false, false, 'k' ); } public function execute() { $user = $this->getOptionUser( 'user' ); $agent = $this->getOptionUser( 'agent' ); $otherUser = $this->getOptionUser( 'other' ); $title = Title::newFromText( 'This is a pretty long page title lets see if it is going to be truncated' ); $types = $this->getOption( 'types' ); if ( $types ) { $types = explode( ',', $types ); } else { $types = $this->supportedNotificationTypes; } $this->confirm(); $this->output( "Started processing...\n" ); if ( $this->shouldGenerate( 'welcome', $types ) ) { $this->generateWelcome( $user ); } if ( $this->shouldGenerate( 'edit-user-talk', $types ) ) { $this->generateEditUserTalk( $user, $agent ); } if ( $this->shouldGenerate( 'mention', $types ) ) { $this->generateMention( $user, $agent, $otherUser, $title ); } if ( $this->shouldGenerate( 'page-linked', $types ) ) { $this->generatePageLink( $user, $agent ); } if ( $this->shouldGenerate( 'reverted', $types ) ) { $this->generateReverted( $user, $agent ); } if ( $this->shouldGenerate( 'email', $types ) ) { $this->generateEmail( $user, $agent ); } if ( $this->shouldGenerate( 'user-rights', $types ) ) { $this->generateUserRights( $user, $agent ); } if ( $this->shouldGenerate( 'cx', $types ) ) { $this->generateContentTranslation( $user ); } if ( $this->shouldGenerate( 'osm', $types ) ) { $this->generateOpenStackManager( $user, $agent ); } if ( $this->shouldGenerate( 'edit-thanks', $types ) ) { $this->generateEditThanks( $user, $agent, $otherUser ); } if ( $this->shouldGenerate( 'edu', $types ) ) { $this->generateEducationProgram( $user, $agent ); } if ( $this->shouldGenerate( 'page-connection', $types ) ) { $this->generateWikibase( $user, $agent ); } $this->output( "Completed \n" ); } /** * Get the set timestamp of the event * * @param bool $getEpoch Get the epoch value * @return int Timestamp for the operation */ private function getTimestamp( $getEpoch = false ) { $startTime = $this->getOption( 'timestamp' ) ?: time(); // Incrementally decrease X minutes from start time $timestamp = strtotime( '-' . $this->timestampCounter++ . ' minute', $startTime ); return $getEpoch ? $timestamp : (int)wfTimestamp( TS_UNIX, $timestamp ); } /** * Add a timestamp string to the output, if a timestamp option was given, * to note the time of the new generated event. * * @param string $output New output message with timestamp * @return string */ private function addTimestampToOutput( $output ) { if ( $this->getOption( 'timestamp' ) ) { $output .= ' (Using timestamp: ' . date( 'Y-m-d H:i:s', $this->getTimestamp( true ) ) . ')'; } return $output; } private function generateEditUserTalk( User $user, User $agent ) { $this->output( "{$agent->getName()} is writing on {$user->getName()}'s user talk page\n" ); $editId = $this->generateRandomString(); $section = "== section $editId ==\n\nthis is the text $editId\n\n~~~~\n\n"; $this->addToUserTalk( $user, $agent, $section ); } private function getOptionUser( $optionName ) { $username = $this->getOption( $optionName ); $user = User::newFromName( $username ); if ( !$user->isRegistered() ) { $this->fatalError( "User $username does not seem to exist in this wiki" ); } return $user; } private function generateRandomString( $length = 10 ) { return substr( str_shuffle( "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ), 0, $length ); } protected function confirm() { if ( $this->getOption( 'force', false ) ) { return; } $this->output( "=== WARNING ===\n" ); $this->output( "This script modifies the content of several pages,\n" ); $this->output( "including user's talk pages.\n" ); $this->output( "ONLY RUN ON TEST WIKIS\n" ); $this->output( "Enter 'yes' if you wish to continue or any other key to exit\n" ); $confirm = $this->readconsole(); if ( $confirm !== 'yes' ) { $this->fatalError( 'Safe decision' ); } } private function addToUserTalk( User $user, User $agent, $contentText ) { $this->addToPageContent( $user->getTalkPage(), $agent, $contentText ); } private function addToPageContent( Title $title, User $agent, $contentText ) { $page = $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( $title ); $previousContent = ""; $page->loadPageData( IDBAccessObject::READ_LATEST ); $revision = $page->getRevisionRecord(); if ( $revision ) { $content = $revision->getContent( SlotRecord::MAIN, RevisionRecord::FOR_PUBLIC ); if ( $content instanceof WikitextContent ) { $previousContent = $content->getText(); } } $status = $page->doUserEditContent( new WikitextContent( $contentText . $previousContent ), $agent, 'generating sample notifications' ); if ( !$status->isGood() ) { $this->error( "Failed to edit {$title->getPrefixedText()}: {$status->getMessage()->text()}" ); } return $status->getValue()['revision-record']; } private function generateMention( User $user, User $agent, User $otherUser, Title $title ) { $mention = "== section {$this->generateRandomString()} ==\nHello [[User:{$user->getName()}]] \n~~~~\n"; // article talk $this->output( "{$agent->getName()} is mentioning {$user->getName()} on {$title->getTalkPage()->getPrefixedText()}\n" ); $this->addToPageContent( $title->getTalkPage(), $agent, $mention ); // agent talk $this->output( "{$agent->getName()} is mentioning {$user->getName()} on {$agent->getTalkPage()->getPrefixedText()}\n" ); $this->addToPageContent( $agent->getTalkPage(), $agent, $mention ); // user talk $this->output( "{$agent->getName()} is mentioning {$user->getName()} on {$otherUser->getTalkPage()->getPrefixedText()}\n" ); $this->addToPageContent( $otherUser->getTalkPage(), $agent, $mention ); // any other page $this->output( "{$agent->getName()} is mentioning {$user->getName()} on {$title->getPrefixedText()}\n" ); $this->addToPageContent( $title, $agent, $mention ); } private function generatePageLink( User $user, User $agent ) { $this->generateOnePageLink( $user, $agent ); $this->generateMultiplePageLinks( $user, $agent ); } private function generateNewPageTitle() { return Title::newFromText( $this->generateRandomString() ); } private function generateReverted( User $user, User $agent ) { $services = $this->getServiceContainer(); $services->getUserGroupManager()->addUserToGroup( $agent, 'sysop' ); // revert (undo) $moai = Title::newFromText( 'Moai' ); $page = $services->getWikiPageFactory()->newFromTitle( $moai ); $this->output( "{$agent->getName()} is reverting {$user->getName()}'s edit on {$moai->getPrefixedText()}\n" ); $this->addToPageContent( $moai, $agent, "\ncreating a good revision here\n" ); $this->addToPageContent( $moai, $user, "\nadding a line here\n" ); $undoRev = $page->getRevisionRecord(); $previous = $services->getRevisionLookup() ->getPreviousRevision( $undoRev ); $handler = $services->getContentHandlerFactory() ->getContentHandler( $undoRev->getSlot( SlotRecord::MAIN, RevisionRecord::RAW ) ->getModel() ); $undoContent = $undoRev->getContent( SlotRecord::MAIN ); $previousContent = $previous->getContent( SlotRecord::MAIN ); if ( !$undoContent ) { $this->error( "Failed to undo {$moai->getPrefixedText()}: undoContent is null." ); return; } if ( !$previousContent ) { $this->error( "Failed to undo {$moai->getPrefixedText()}: previousContent is null." ); return; } $content = $handler->getUndoContent( $undoContent, $undoContent, $previousContent, // undoIsLatest true ); $status = $page->doUserEditContent( $content, $agent, 'undo', // $flags 0, // $originalRevId false, // $tags [], $undoRev->getId() ); if ( !$status->isGood() ) { $this->error( "Failed to undo {$moai->getPrefixedText()}: {$status->getMessage()->text()}" ); } } private function generateWelcome( User $user ) { $this->output( "Welcoming {$user->getName()}\n" ); Event::create( [ 'type' => 'welcome', 'agent' => $user, 'timestamp' => $this->getTimestamp(), ] ); } private function generateEmail( User $user, User $agent ) { $output = $this->addTimestampToOutput( "{$agent->getName()} is emailing {$user->getName()}" ); $this->output( "$output\n" ); Event::create( [ 'type' => 'emailuser', 'extra' => [ 'to-user-id' => $user->getId(), 'subject' => 'Long time no see', ], 'agent' => $agent, 'timestamp' => $this->getTimestamp(), ] ); } private function generateUserRights( User $user, User $agent ) { $output = $this->addTimestampToOutput( "{$agent->getName()} is changing {$user->getName()}'s rights" ); $this->output( "$output\n" ); $this->createUserRightsNotification( $user, $agent, [ 'OnlyAdd-1' ], null ); $this->createUserRightsNotification( $user, $agent, null, [ 'JustRemove-1', 'JustRemove-2' ] ); $this->createUserRightsNotification( $user, $agent, [ 'Add-1', 'Add-2' ], [ 'Remove-1', 'Remove-2' ] ); } private function createUserRightsNotification( User $user, User $agent, $add, $remove ) { Event::create( [ 'type' => 'user-rights', 'extra' => [ 'user' => $user->getId(), 'add' => $add, 'remove' => $remove, 'reason' => 'This is the [[reason]] for changing your user rights.', ], 'agent' => $agent, 'timestamp' => $this->getTimestamp(), ] ); } private function generateContentTranslation( User $user ) { if ( !ExtensionRegistry::getInstance()->isLoaded( 'ContentTranslation' ) ) { return; } $this->output( "Generating CX notifications\n" ); foreach ( [ 'cx-first-translation', 'cx-tenth-translation', 'cx-hundredth-translation' ] as $eventType ) { Event::create( [ 'type' => $eventType, 'extra' => [ 'recipient' => $user->getId(), ], 'timestamp' => $this->getTimestamp(), ] ); } Event::create( [ 'type' => 'cx-suggestions-available', 'extra' => [ 'recipient' => $user->getId(), 'lastTranslationTitle' => 'History of the People\'s Republic of China' ], 'timestamp' => $this->getTimestamp(), ] ); } private function generateOnePageLink( User $user, User $agent ) { $pageBeingLinked = $this->generateNewPageTitle(); $this->addToPageContent( $pageBeingLinked, $user, "this is a new page" ); $pageLinking = $this->generateNewPageTitle(); $content = "checkout [[{$pageBeingLinked->getPrefixedText()}]]!"; $this->output( "{$agent->getName()} is linking to {$pageBeingLinked->getPrefixedText()} from {$pageLinking->getPrefixedText()}\n" ); $this->addToPageContent( $pageLinking, $agent, $content ); } private function generateMultiplePageLinks( User $user, User $agent ) { $pageBeingLinked = $this->generateNewPageTitle(); $this->addToPageContent( $pageBeingLinked, $user, "this is a new page" ); $content = "checkout [[{$pageBeingLinked->getPrefixedText()}]]!"; $this->output( "{$agent->getName()} is linking to {$pageBeingLinked->getPrefixedText()} from multiple pages\n" ); $this->addToPageContent( $this->generateNewPageTitle(), $agent, $content ); // @phan-suppress-next-line PhanPluginDuplicateAdjacentStatement $this->addToPageContent( $this->generateNewPageTitle(), $agent, $content ); // @phan-suppress-next-line PhanPluginDuplicateAdjacentStatement $this->addToPageContent( $this->generateNewPageTitle(), $agent, $content ); } private function generateOpenStackManager( User $user, User $agent ) { if ( !ExtensionRegistry::getInstance()->isLoaded( 'OpenStackManager' ) ) { return; } $this->output( "Generating OpenStackManager notifications\n" ); foreach ( [ 'build-completed', 'reboot-completed', 'deleted' ] as $action ) { Event::create( [ 'type' => "osm-instance-$action", 'title' => Title::newFromText( "Moai" ), 'agent' => $user, 'extra' => [ 'instanceName' => 'instance1', 'projectName' => 'TheProject', 'notifyAgent' => true, ], 'timestamp' => $this->getTimestamp(), ] ); } Event::create( [ 'type' => 'osm-projectmembers-add', 'title' => Title::newFromText( "Moai" ), 'agent' => $agent, 'extra' => [ 'userAdded' => $user->getId() ], 'timestamp' => $this->getTimestamp(), ] ); } private function shouldGenerate( $type, array $types ) { return in_array( $type, $types ); } private function generateEditThanks( User $user, User $agent, User $otherUser ) { $this->generateOneEditThanks( $user, $agent ); $this->generateMultipleEditThanks( $user, $agent, $otherUser ); } private function generateOneEditThanks( User $user, User $agent ) { if ( !ExtensionRegistry::getInstance()->isLoaded( 'Thanks' ) ) { return; } // make an edit, thank it once $title = $this->generateNewPageTitle(); $revisionRecord = $this->addToPageContent( $title, $user, "an awesome edit! ~~~~" ); Event::create( [ 'type' => 'edit-thank', 'title' => $title, 'extra' => [ 'revid' => $revisionRecord->getId(), 'thanked-user-id' => $user->getId(), 'source' => 'generateSampleNotifications.php', ], 'agent' => $agent, 'timestamp' => $this->getTimestamp(), ] ); $output = $this->addTimestampToOutput( "{$agent->getName()} is thanking {$user->getName()} for edit {$revisionRecord->getId()} on {$title->getPrefixedText()}" ); $this->output( "$output\n" ); } private function generateMultipleEditThanks( User $user, User $agent, User $otherUser ) { if ( !ExtensionRegistry::getInstance()->isLoaded( 'Thanks' ) ) { return; } // make an edit, thank it twice $title = $this->generateNewPageTitle(); $revisionRecord = $this->addToPageContent( $title, $user, "an even better edit! ~~~~" ); Event::create( [ 'type' => 'edit-thank', 'title' => $title, 'extra' => [ 'revid' => $revisionRecord->getId(), 'thanked-user-id' => $user->getId(), 'source' => 'generateSampleNotifications.php', ], 'agent' => $agent, 'timestamp' => $this->getTimestamp(), ] ); Event::create( [ 'type' => 'edit-thank', 'title' => $title, 'extra' => [ 'revid' => $revisionRecord->getId(), 'thanked-user-id' => $user->getId(), 'source' => 'generateSampleNotifications.php', ], 'agent' => $otherUser, 'timestamp' => $this->getTimestamp(), ] ); $output = $this->addTimestampToOutput( "{$agent->getName()} and {$otherUser->getName()} are thanking {$user->getName()} for edit {$revisionRecord->getId()} on {$title->getPrefixedText()}" ); $this->output( "$output\n" ); } private function generateEducationProgram( User $user, User $agent ) { if ( !ExtensionRegistry::getInstance()->isLoaded( 'EducationProgram' ) ) { $this->output( "Skipping EducationProgram. Extension not installed.\n" ); return; } $chem101 = Title::newFromText( 'School/Chemistry101' ); if ( !$chem101->exists() ) { $this->addToPageContent( $chem101, $agent, "\nThis is the main page for the Chemistry 101 course\n" ); } $notificationManager = EducationProgram\Extension::globalInstance()->getNotificationsManager(); $output = $this->addTimestampToOutput( "{$agent->getName()} is adding {$user->getName()} to {$chem101->getPrefixedText()} as instructor, student, campus volunteer and online volunteer" ); $this->output( "$output\n" ); $types = [ 'ep-instructor-add-notification', 'ep-online-add-notification', 'ep-campus-add-notification', 'ep-student-add-notification', ]; foreach ( $types as $type ) { $notificationManager->trigger( $type, [ 'role-add-title' => $chem101, 'agent' => $agent, 'users' => [ $user->getId() ], ] ); } // NOTE: Not generating 'ep-course-talk-notification' for now // as it requires a full setup to actually work (institution, course, instructors, students). } private function generateWikibase( User $user, User $agent ) { if ( !ExtensionRegistry::getInstance()->isLoaded( 'WikibaseClient' ) ) { $this->output( "Skipping Wikibase. Extension not installed.\n" ); return; } $title = $this->generateNewPageTitle(); $this->addToPageContent( $title, $user, "this is a new page" ); $helpPage = Title::newFromText( 'Project:Wikidata' ); $this->addToPageContent( $helpPage, $user, "this is the help page" ); $output = $this->addTimestampToOutput( "{$agent->getName()} is connecting {$user->getName()}'s page {$title->getPrefixedText()} to an item" ); $this->output( "$output\n" ); Event::create( [ 'type' => EchoNotificationsHandlers::NOTIFICATION_TYPE, 'title' => $title, 'extra' => [ 'url' => Title::newFromText( 'Item:Q1' )->getFullURL(), 'repoSiteName' => 'Wikidata', 'entity' => 'Q1', ], 'agent' => $agent, 'timestamp' => $this->getTimestamp(), ] ); } } $maintClass = GenerateSampleNotifications::class; require_once RUN_MAINTENANCE_IF_MAIN; PK ! y�� � $ maintenance/removeOrphanedEvents.phpnu �Iw�� <?php /** * Remove rows from echo_event that don't have corresponding rows in echo_notification or echo_email_batch. * * @ingroup Maintenance */ use MediaWiki\Extension\Notifications\DbFactory; use MediaWiki\Maintenance\LoggedUpdateMaintenance; require_once getenv( 'MW_INSTALL_PATH' ) !== false ? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php' : __DIR__ . '/../../../maintenance/Maintenance.php'; /** * Maintenance script that removes orphaned event rows * * @ingroup Maintenance */ class RemoveOrphanedEvents extends LoggedUpdateMaintenance { public function __construct() { parent::__construct(); $this->addDescription( "Remove rows from echo_event and echo_target_page that don't have corresponding " . "rows in echo_notification or echo_email_batch" ); $this->setBatchSize( 500 ); $this->requireExtension( 'Echo' ); } public function getUpdateKey() { return __CLASS__; } public function doDBUpdates() { $startId = 0; $dbFactory = DbFactory::newFromDefault(); $dbr = $dbFactory->getEchoDb( DB_REPLICA ); $maxId = (int)$dbr->newSelectQueryBuilder() ->select( 'MAX(event_id)' ) ->from( 'echo_event' ) ->caller( __METHOD__ ) ->fetchField(); $eventsProcessedTotal = 0; $targetsProcessedTotal = 0; while ( $startId < $maxId ) { $startId += $this->getBatchSize() * 1000; [ $eventsProcessed, $targetsProcessed ] = $this->doMajorBatch( $startId ); $eventsProcessedTotal += $eventsProcessed; $targetsProcessedTotal += $targetsProcessed; } $this->output( "In total, deleted $eventsProcessedTotal orphaned events and " . "$targetsProcessedTotal target_page rows.\n" ); return true; } private function doMajorBatch( $maxId ) { $dbFactory = DbFactory::newFromDefault(); $dbw = $dbFactory->getEchoDb( DB_PRIMARY ); $dbr = $dbFactory->getEchoDb( DB_REPLICA ); $iterator = new BatchRowIterator( $dbr, [ 'echo_event', 'echo_notification', 'echo_email_batch' ], 'event_id', $this->getBatchSize() ); $iterator->addJoinConditions( [ 'echo_notification' => [ 'LEFT JOIN', 'notification_event=event_id' ], 'echo_email_batch' => [ 'LEFT JOIN', 'eeb_event_id=event_id' ], ] ); $iterator->addConditions( [ 'notification_user' => null, 'eeb_user_id' => null, $dbr->expr( 'event_id', '<', $maxId ), ] ); $iterator->setCaller( __METHOD__ ); $this->output( "Removing orphaned echo_event rows with max event_id of $maxId...\n" ); $eventsProcessed = 0; $targetsProcessed = 0; foreach ( $iterator as $batch ) { $ids = []; foreach ( $batch as $row ) { $ids[] = $row->event_id; } $dbw->newDeleteQueryBuilder() ->deleteFrom( 'echo_event' ) ->where( [ 'event_id' => $ids ] ) ->caller( __METHOD__ ) ->execute(); $eventsProcessed += $dbw->affectedRows(); $dbw->newDeleteQueryBuilder() ->deleteFrom( 'echo_target_page' ) ->where( [ 'etp_event' => $ids ] ) ->caller( __METHOD__ ) ->execute(); $targetsProcessed += $dbw->affectedRows(); $this->output( "Deleted $eventsProcessed orphaned events and $targetsProcessed target_page rows.\n" ); $this->waitForReplication(); } $this->output( "Removing any remaining orphaned echo_target_page rows with max etp_event of $maxId...\n" ); $iterator = new BatchRowIterator( $dbr, [ 'echo_target_page', 'echo_event' ], 'etp_event', $this->getBatchSize() ); $iterator->addJoinConditions( [ 'echo_event' => [ 'LEFT JOIN', 'event_id=etp_event' ] ] ); $iterator->addConditions( [ 'event_type' => null, $dbr->expr( 'etp_event', '<', $maxId ), ] ); $iterator->addOptions( [ 'DISTINCT' ] ); $iterator->setCaller( __METHOD__ ); $processed = 0; foreach ( $iterator as $batch ) { $ids = []; foreach ( $batch as $row ) { $ids[] = $row->etp_event; } $dbw->newDeleteQueryBuilder() ->deleteFrom( 'echo_target_page' ) ->where( [ 'etp_event' => $ids ] ) ->caller( __METHOD__ ) ->execute(); $processed += $dbw->affectedRows(); $this->output( "Deleted $processed orphaned target_page rows.\n" ); $this->waitForReplication(); } return [ $eventsProcessed, $targetsProcessed + $processed ]; } } $maintClass = RemoveOrphanedEvents::class; require_once RUN_MAINTENANCE_IF_MAIN; PK ! ��{Ef f ) maintenance/removeInvalidNotification.phpnu �Iw�� <?php /** * Remove invalid events from echo_event and echo_notification * * @ingroup Maintenance */ use MediaWiki\Extension\Notifications\DbFactory; use MediaWiki\Maintenance\Maintenance; require_once getenv( 'MW_INSTALL_PATH' ) !== false ? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php' : __DIR__ . '/../../../maintenance/Maintenance.php'; /** * Maintenance script that removes invalid notifications * * @ingroup Maintenance */ class RemoveInvalidNotification extends Maintenance { /** @var string[] */ protected $invalidEventType = [ 'article-linked' ]; public function __construct() { parent::__construct(); $this->addDescription( "Removes invalid notifications from the database." ); $this->setBatchSize( 500 ); $this->requireExtension( 'Echo' ); } public function execute() { $lbFactory = DbFactory::newFromDefault(); if ( !$this->invalidEventType ) { $this->output( "There is nothing to process\n" ); return; } $dbw = $lbFactory->getEchoDb( DB_PRIMARY ); $dbr = $lbFactory->getEchoDb( DB_REPLICA ); $batchSize = $this->getBatchSize(); $count = $batchSize; while ( $count == $batchSize ) { $res = $dbr->newSelectQueryBuilder() ->select( 'event_id' ) ->from( 'echo_event' ) ->where( [ 'event_type' => $this->invalidEventType, ] ) ->limit( $batchSize ) ->caller( __METHOD__ ) ->fetchResultSet(); $event = []; $count = 0; foreach ( $res as $row ) { // @phan-suppress-next-line PhanPossiblyUndeclaredVariable if ( !in_array( $row->event_id, $event ) ) { $event[] = $row->event_id; } $count++; } if ( $event ) { $this->beginTransaction( $dbw, __METHOD__ ); $dbw->newDeleteQueryBuilder() ->deleteFrom( 'echo_event' ) ->where( [ 'event_id' => $event ] ) ->caller( __METHOD__ ) ->execute(); $dbw->newDeleteQueryBuilder() ->deleteFrom( 'echo_notification' ) ->where( [ 'notification_event' => $event ] ) ->caller( __METHOD__ ) ->execute(); $this->commitTransaction( $dbw, __METHOD__ ); $this->output( "processing " . count( $event ) . " invalid events\n" ); $this->waitForReplication(); } // Cleanup is not necessary for // 1. echo_email_batch, invalid notification is removed during the cron } } } $maintClass = RemoveInvalidNotification::class; require_once RUN_MAINTENANCE_IF_MAIN; PK ! ���) ) % maintenance/processEchoEmailBatch.phpnu �Iw�� <?php use MediaWiki\Extension\Notifications\DbFactory; use MediaWiki\Extension\Notifications\EmailBatch; use MediaWiki\Maintenance\Maintenance; $IP = getenv( 'MW_INSTALL_PATH' ); if ( $IP === false ) { $IP = __DIR__ . '/../../..'; } require_once "$IP/maintenance/Maintenance.php"; /** * A maintenance script that processes email digest */ class ProcessEchoEmailBatch extends Maintenance { public function __construct() { parent::__construct(); $this->addDescription( "Process email digest" ); $this->addOption( "ignoreConfiguredSchedule", "Send all pending notifications immediately even if configured to be weekly or daily.", false, false, "i" ); $this->setBatchSize( 300 ); $this->requireExtension( 'Echo' ); } public function execute() { $lbFactory = DbFactory::newFromDefault(); $ignoreConfiguredSchedule = $this->getOption( "ignoreConfiguredSchedule", 0 ); $this->output( "Started processing... \n" ); $startUserId = 0; $batchSize = $this->getBatchSize(); $count = $batchSize; while ( $count === $batchSize ) { $count = 0; $res = EmailBatch::getUsersToNotify( $startUserId, $batchSize ); $updated = false; foreach ( $res as $row ) { $userId = intval( $row->eeb_user_id ); if ( $userId && $userId > $startUserId ) { $emailBatch = EmailBatch::newFromUserId( $userId, !$ignoreConfiguredSchedule ); if ( $emailBatch ) { $this->output( "processing user_Id " . $userId . " \n" ); $emailBatch->process(); } $startUserId = $userId; $updated = true; } $count++; } $this->waitForReplication(); // double check to make sure that the id is updated if ( !$updated ) { break; } } $this->output( "Completed \n" ); } } $maintClass = ProcessEchoEmailBatch::class; require_once RUN_MAINTENANCE_IF_MAIN; PK ! ��}�� � &