Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
DeleteTag
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 2
30
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3/**
4 * Remove a revision tag from edits and log entries it was applied to.
5 * @see bug T75181
6 */
7
8use MediaWiki\Parser\Sanitizer;
9use MediaWiki\Storage\NameTableAccessException;
10
11require_once __DIR__ . '/Maintenance.php';
12
13class DeleteTag extends Maintenance {
14    public function __construct() {
15        parent::__construct();
16        $this->addDescription( 'Deletes a change tag' );
17        $this->addArg( 'tag name', 'Name of the tag to delete' );
18        $this->setBatchSize( 500 );
19    }
20
21    public function execute() {
22        $dbw = $this->getPrimaryDB();
23        $services = $this->getServiceContainer();
24        $defStore = $services->getChangeTagDefStore();
25
26        $tag = $this->getArg( 0 );
27        try {
28            $tagId = $defStore->getId( $tag );
29        } catch ( NameTableAccessException $ex ) {
30            $this->fatalError( "Tag '$tag' not found" );
31        }
32
33        $status = ChangeTags::canDeleteTag( $tag, null, ChangeTags::BYPASS_MAX_USAGE_CHECK );
34        if ( !$status->isOK() ) {
35            $message = $status->getHTML( false, false, 'en' );
36            $this->fatalError( Sanitizer::stripAllTags( $message ) );
37        }
38
39        $this->output( "Deleting tag '$tag'...\n" );
40
41        // Make the tag impossible to add by users while we're deleting it and drop the
42        // usage counter to zero
43        $dbw->newUpdateQueryBuilder()
44            ->update( 'change_tag_def' )
45            ->set( [
46                'ctd_user_defined' => 0,
47                'ctd_count' => 0,
48            ] )
49            ->where( [ 'ctd_id' => $tagId ] )
50            ->caller( __METHOD__ )->execute();
51        ChangeTags::purgeTagCacheAll();
52
53        // Iterate over change_tag, deleting rows in batches
54        $count = 0;
55        do {
56            $ids = $dbw->newSelectQueryBuilder()
57                ->select( 'ct_id' )
58                ->from( 'change_tag' )
59                ->where( [ 'ct_tag_id' => $tagId ] )
60                ->limit( $this->getBatchSize() )
61                ->caller( __METHOD__ )
62                ->fetchFieldValues();
63
64            if ( !$ids ) {
65                break;
66            }
67            $dbw->newDeleteQueryBuilder()
68                ->deleteFrom( 'change_tag' )
69                ->where( [ 'ct_id' => $ids ] )
70                ->caller( __METHOD__ )->execute();
71            $count += $dbw->affectedRows();
72            $this->output( "$count\n" );
73            $this->waitForReplication();
74        } while ( true );
75        $this->output( "The tag has been removed from $count revisions, deleting the tag itself...\n" );
76
77        ChangeTags::deleteTagEverywhere( $tag );
78        $this->output( "Done.\n" );
79    }
80}
81
82$maintClass = DeleteTag::class;
83require_once RUN_MAINTENANCE_IF_MAIN;