40 private $doSubpages =
false;
46 private $permissionManager;
48 private $bundleFactory;
50 private $subpageBuilder;
52 private $jobQueueGroup;
55 private const PAGE_TITLE_MSG = [
56 'messagebundle' =>
'pt-deletepage-mb-title',
57 'translatablepage' =>
'pt-deletepage-tp-title',
58 'translationpage' =>
'pt-deletepage-lang-title'
60 private const WRAPPER_LEGEND_MSG = [
61 'messagebundle' =>
'pt-deletepage-mb-legend',
62 'translatablepage' =>
'pt-deletepage-tp-title',
63 'translationpage' =>
'pt-deletepage-tp-legend'
65 private const LOG_PAGE = [
66 'messagebundle' =>
'Special:Log/messagebundle',
67 'translatablepage' =>
'Special:Log/pagetranslation',
68 'translationpage' =>
'Special:Log/pagetranslation'
71 public function __construct(
73 PermissionManager $permissionManager,
76 JobQueueGroup $jobQueueGroup
78 parent::__construct(
'PageTranslationDeletePage',
'pagetranslation' );
79 $this->mainCache = $mainCache;
80 $this->permissionManager = $permissionManager;
81 $this->bundleFactory = $bundleFactory;
82 $this->subpageBuilder = $subpageBuilder;
83 $this->jobQueueGroup = $jobQueueGroup;
86 public function doesWrites() {
90 public function isListed() {
94 public function execute( $par ) {
95 $this->addhelpLink(
'Help:Deletion_and_undeletion' );
97 $request = $this->getRequest();
102 $this->text = $request->getVal(
'wpTitle', $par );
103 $this->title = Title::newFromText( $this->text );
104 $this->reason = $this->getDeleteReason( $request );
105 $this->doSubpages = $request->getBool(
'subpages' );
107 if ( !$this->doBasicChecks() ) {
111 $out = $this->getOutput();
114 $this->entityType = $this->identifyEntityType();
115 if ( !$this->entityType ) {
116 throw new ErrorPageError(
'pt-deletepage-invalid-title',
'pt-deletepage-invalid-text' );
119 if ( $this->isTranslation() ) {
120 [ , $this->code ] = TranslateUtils::figureMessage( $this->title->getText() );
126 $this->msg( self::PAGE_TITLE_MSG[ $this->entityType ], $this->title->getPrefixedText() )
129 if ( !$this->getUser()->isAllowed(
'pagetranslation' ) ) {
130 throw new PermissionsError(
'pagetranslation' );
134 $subactionText = $request->getText(
'subaction' );
135 switch ( $subactionText ) {
136 case $this->msg(
'pt-deletepage-action-check' )->text():
137 $subaction =
'check';
139 case $this->msg(
'pt-deletepage-action-perform' )->text():
140 $subaction =
'perform';
142 case $this->msg(
'pt-deletepage-action-other' )->text():
149 if ( $subaction ===
'check' && $this->checkToken() && $request->wasPosted() ) {
150 $this->showConfirmation();
151 } elseif ( $subaction ===
'perform' && $this->checkToken() && $request->wasPosted() ) {
152 $this->performAction();
164 private function doBasicChecks():
bool {
166 if ( !$this->userCanExecute( $this->getUser() ) ) {
167 $this->displayRestrictionError();
170 if ( $this->title ===
null ) {
171 throw new ErrorPageError(
'notargettitle',
'notargettext' );
174 if ( !$this->title->exists() ) {
175 throw new ErrorPageError(
'nopagetitle',
'nopagetext' );
178 $permissionErrors = $this->permissionManager->getPermissionErrors(
179 'delete', $this->getUser(), $this->title
181 if ( count( $permissionErrors ) ) {
182 throw new PermissionsError(
'delete', $permissionErrors );
185 # Check for database lock
186 $this->checkReadOnly();
197 private function checkToken():
bool {
198 return $this->getContext()->getCsrfTokenSet()->matchTokenField(
'wpEditToken' );
202 private function showForm():
void {
203 $this->getOutput()->addWikiMsg(
'pt-deletepage-intro', self::LOG_PAGE[ $this->entityType ] );
205 $formDescriptor = $this->getCommonFormFields();
207 HTMLForm::factory(
'ooui', $formDescriptor, $this->getContext() )
208 ->setAction( $this->getPageTitle( $this->text )->getLocalURL() )
209 ->setSubmitName(
'subaction' )
210 ->setSubmitTextMsg(
'pt-deletepage-action-check' )
211 ->setWrapperLegendMsg(
'pt-deletepage-any-legend' )
213 ->displayForm(
false );
220 private function showConfirmation():
void {
221 $out = $this->getOutput();
225 $out->addWikiMsg(
'pt-deletepage-intro', self::LOG_PAGE[ $this->entityType ] );
227 $subpages = $this->getPagesForDeletion();
229 $out->wrapWikiMsg(
'== $1 ==',
'pt-deletepage-list-pages' );
231 if ( !$this->isTranslation() ) {
233 $out->addWikiTextAsInterface(
234 $this->getChangeLine( $this->title )
238 $out->wrapWikiMsg(
'=== $1 ===',
'pt-deletepage-list-translation' );
240 foreach ( $subpages[
'translationPages' ] as $old ) {
242 $lines[] = $this->getChangeLine( $old );
244 $this->listPages( $out, $lines );
246 $out->wrapWikiMsg(
'=== $1 ===',
'pt-deletepage-list-section' );
249 foreach ( $subpages[
'translationUnitPages' ] as $old ) {
251 $lines[] = $this->getChangeLine( $old );
253 $this->listPages( $out, $lines );
255 if ( TranslateUtils::allowsSubpages( $this->title ) ) {
256 $out->wrapWikiMsg(
'=== $1 ===',
'pt-deletepage-list-other' );
257 $subpages = $subpages[
'normalSubpages' ];
259 foreach ( $subpages as $old ) {
261 $lines[] = $this->getChangeLine( $old );
263 $this->listPages( $out, $lines );
266 $totalPageCount = $count + $subpageCount;
268 $out->addWikiTextAsInterface(
"----\n" );
270 'pt-deletepage-list-count',
271 $this->getLanguage()->formatNum( $totalPageCount ),
272 $this->getLanguage()->formatNum( $subpageCount )
275 $formDescriptor = $this->getCommonFormFields();
276 $formDescriptor[
'subpages'] = [
278 'name' =>
'subpages',
279 'id' =>
'mw-subpages',
280 'label' => $this->msg(
'pt-deletepage-subpages' )->text(),
281 'default' => $this->doSubpages,
284 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->getContext() );
286 ->setWrapperLegendMsg(
287 $this->msg( self::WRAPPER_LEGEND_MSG[ $this->entityType ], $this->title->getPrefixedText() )
289 ->setAction( $this->getPageTitle( $this->text )->getLocalURL() )
290 ->setSubmitTextMsg(
'pt-deletepage-action-perform' )
291 ->setSubmitName(
'subaction' )
293 'name' =>
'subaction',
294 'value' => $this->msg(
'pt-deletepage-action-other' )->text(),
297 ->displayForm(
false );
301 private function getChangeLine( Title $title ):
string {
302 return '* ' . $title->getPrefixedText();
305 private function performAction():
void {
307 $target = $this->title;
308 $base = $this->title->getPrefixedText();
309 $isTranslation = $this->isTranslation();
310 $subpageList = $this->getPagesForDeletion();
311 $bundle = $this->getValidBundleFromTitle();
312 $bundleType = get_class( $bundle );
314 $user = $this->getUser();
315 foreach ( $subpageList[
'translationPages' ] as $old ) {
316 $jobs[$old->getPrefixedText()] = DeleteTranslatableBundleJob::newJob(
317 $old, $base, $bundleType, $isTranslation, $user, $this->reason
321 foreach ( $subpageList[
'translationUnitPages' ] as $old ) {
322 $jobs[$old->getPrefixedText()] = DeleteTranslatableBundleJob::newJob(
323 $old, $base, $bundleType, $isTranslation, $user, $this->reason
327 if ( $this->doSubpages ) {
328 foreach ( $subpageList[
'normalSubpages' ] as $old ) {
329 $jobs[$old->getPrefixedText()] = DeleteTranslatableBundleJob::newJob(
330 $old, $base, $bundleType, $isTranslation, $user, $this->reason
335 if ( !$isTranslation ) {
336 $jobs[$this->title->getPrefixedText()] = DeleteTranslatableBundleJob::newJob(
337 $this->title, $base, $bundleType, $isTranslation, $user, $this->reason
341 $this->jobQueueGroup->push( $jobs );
343 $this->mainCache->set(
344 $this->mainCache->makeKey(
'pt-base', $target->getPrefixedText() ),
346 6 * $this->mainCache::TTL_HOUR
349 if ( !$isTranslation ) {
350 $this->bundleFactory->getStore( $bundle )->delete( $this->title );
353 $this->getOutput()->addWikiMsg(
'pt-deletepage-started', self::LOG_PAGE[ $this->entityType ] );
356 private function getCommonFormFields(): array {
357 $dropdownOptions = $this->msg(
'deletereason-dropdown' )->inContentLanguage()->text();
359 $options = Xml::listDropDownOptions(
362 'other' => $this->msg(
'pt-deletepage-reason-other' )->inContentLanguage()->text()
370 'label-message' =>
'pt-deletepage-current',
372 'default' => $this->text,
375 'wpDeleteReasonList' => [
377 'name' =>
'wpDeleteReasonList',
378 'label-message' =>
'pt-deletepage-reason',
379 'options' => $options,
383 'name' =>
'wpReason',
384 'label-message' =>
'pt-deletepage-reason-details',
385 'default' => $this->reason,
390 private function listPages( OutputPage $out, array $lines ):
void {
392 $out->addWikiTextAsInterface( implode(
"\n", $lines ) );
394 $out->addWikiMsg(
'pt-deletepage-list-no-pages' );
398 private function getDeleteReason( WebRequest $request ):
string {
399 $dropdownSelection = $request->getText(
'wpDeleteReasonList',
'other' );
400 $reasonInput = $request->getText(
'wpReason' );
402 if ( $dropdownSelection ===
'other' ) {
404 } elseif ( $reasonInput !==
'' ) {
406 $separator = $this->msg(
'colon-separator' )->inContentLanguage()->text();
407 return "$dropdownSelection$separator$reasonInput";
409 return $dropdownSelection;
413 private function getPagesForDeletion(): array {
414 if ( $this->isTranslation() ) {
415 $resultSet = $this->subpageBuilder->getEmptyResultSet();
417 [ $titleKey, ] = TranslateUtils::figureMessage( $this->title->getPrefixedDBkey() );
420 $resultSet[
'translationPages'] = [ $this->title ];
421 $resultSet[
'translationUnitPages'] = $translatablePage->getTranslationUnitPages( $this->code );
424 $bundle = $this->bundleFactory->getValidBundle( $this->title );
425 return $this->subpageBuilder->getSubpagesPerType( $bundle,
false );
430 $bundleTitle = $this->title;
431 if ( $this->isTranslation() ) {
432 [ $key, ] = TranslateUtils::figureMessage( $this->title->getPrefixedDBkey() );
433 $bundleTitle = Title::newFromText( $key );
436 return $this->bundleFactory->getValidBundle( $bundleTitle );
440 private function identifyEntityType(): ?
string {
441 $bundle = $this->bundleFactory->getBundle( $this->title );
444 return 'messagebundle';
446 return 'translatablepage';
449 return 'translationpage';
455 private function isTranslation():
bool {
456 return $this->entityType ===
'translationpage';