Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 55
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
DeleteTranslatableBundleJob
0.00% covered (danger)
0.00%
0 / 55
0.00% covered (danger)
0.00%
0 / 9
210
0.00% covered (danger)
0.00%
0 / 1
 newJob
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 run
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
30
 getSummary
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 getReason
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isTranslation
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPerformer
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getBase
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getBundleType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\MessageGroupProcessing;
5
6use Job;
7use MediaWiki\Extension\Translate\PageTranslation\Hooks;
8use MediaWiki\Extension\Translate\PageTranslation\TranslatablePage;
9use MediaWiki\Extension\Translate\Services;
10use MediaWiki\Extension\Translate\SystemUsers\FuzzyBot;
11use MediaWiki\MediaWikiServices;
12use MediaWiki\Title\Title;
13use MediaWiki\User\UserIdentity;
14use User;
15
16/**
17 * Job for deleting translatable bundles and translation pages.
18 * @author Niklas Laxström
19 * @license GPL-2.0-or-later
20 * @ingroup PageTranslation JobQueue
21 */
22class DeleteTranslatableBundleJob extends Job {
23    public static function newJob(
24        Title $target,
25        string $base,
26        string $bundleType,
27        bool $isTranslationPage,
28        UserIdentity $performer,
29        string $reason
30    ): self {
31        $params = [
32            'translation' => $isTranslationPage,
33            'base' => $base,
34            'bundleType' => $bundleType,
35            'performer' => $performer->getName(),
36            'reason' => $reason
37        ];
38
39        return new self( $target, $params );
40    }
41
42    public function __construct( Title $title, array $params = [] ) {
43        parent::__construct( 'DeleteTranslatableBundleJob', $title, $params );
44    }
45
46    public function run() {
47        $title = $this->title;
48        $fuzzyBot = FuzzyBot::getUser();
49        $summary = $this->getSummary();
50        $base = $this->getBase();
51        $performer = $this->getPerformer();
52        $reason = $this->getReason();
53        $mwInstance = MediaWikiServices::getInstance();
54
55        // Allows regular user to delete pages that are normally protected from direct editing
56        Hooks::$allowTargetEdit = true;
57        // Skip hook that handles deletion of translation units to avoid recreating translation
58        // pages in middle of a delete.
59        Hooks::$isDeleteTranslatableBundleJobRunning = true;
60
61        $wikipage = $mwInstance->getWikiPageFactory()->newFromTitle( $title );
62        $deletePage = $mwInstance->getDeletePageFactory()->newDeletePage( $wikipage, $fuzzyBot );
63        $status = $deletePage->setSuppress( false )
64            ->forceImmediate( true )
65            ->deleteUnsafe( "$summary$reason" );
66
67        $bundleFactory = Services::getInstance()->getTranslatableBundleFactory();
68        // Since the page has been removed from cache, create a bundle from the class name.
69        $bundle = $bundleFactory->getBundleFromClass( Title::newFromText( $base ), $this->getBundleType() );
70        $logger = $bundleFactory->getPageDeleteLogger( $bundle );
71
72        if ( !$status->isGood() ) {
73            if ( $this->isTranslation() ) {
74                $logger->logPageError( $performer, $reason, $status );
75            } else {
76                $logger->logBundleError( $performer, $reason, $status );
77            }
78        }
79
80        Hooks::$allowTargetEdit = false;
81        Hooks::$isDeleteTranslatableBundleJobRunning = false;
82
83        $cache = $mwInstance->getMainObjectStash();
84        $pageKey = $cache->makeKey( 'pt-base', $base );
85        $pages = (array)$cache->get( $pageKey );
86        $lastitem = array_pop( $pages );
87        if ( $title->getPrefixedText() === $lastitem ) {
88            $cache->delete( $pageKey );
89
90            if ( $this->isTranslation() ) {
91                $logger->logPageSuccess( $performer, $reason );
92            } else {
93                $logger->logBundleSuccess( $performer, $reason );
94            }
95
96            $title->invalidateCache();
97        }
98
99        return true;
100    }
101
102    public function getSummary(): string {
103        $base = $this->getBase();
104        if ( $this->isTranslation() ) {
105            $msg = wfMessage( 'pt-deletepage-lang-logreason', $base )->inContentLanguage()->text();
106        } else {
107            $msg = wfMessage( 'pt-deletepage-full-logreason', $base )->inContentLanguage()->text();
108        }
109
110        return $msg;
111    }
112
113    public function getReason(): string {
114        return $this->params['reason'];
115    }
116
117    private function isTranslation(): bool {
118        return $this->params['translation'];
119    }
120
121    public function getPerformer(): User {
122        $userFactory = MediaWikiServices::getInstance()->getUserFactory();
123        return $userFactory->newFromName( $this->params['performer'] );
124    }
125
126    public function getBase(): string {
127        return $this->params['base'];
128    }
129
130    private function getBundleType(): string {
131        // Default to TranslatablePage if param is not present
132        return $this->params['bundleType'] ?? TranslatablePage::class;
133    }
134}