Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.86% covered (warning)
89.86%
62 / 69
28.57% covered (danger)
28.57%
2 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
UndoSubmitAction
89.86% covered (warning)
89.86%
62 / 69
28.57% covered (danger)
28.57%
2 / 7
15.23
0.00% covered (danger)
0.00%
0 / 1
 getName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getRestriction
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 show
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
3.01
 checkPermissions
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
4.00
 undo
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
3.10
 storePatchedSchema
88.24% covered (warning)
88.24%
15 / 17
0.00% covered (danger)
0.00%
0 / 1
2.01
 createSummaryCommentForUndoRev
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare( strict_types = 1 );
4
5namespace EntitySchema\MediaWiki\Actions;
6
7use EntitySchema\DataAccess\MediaWikiRevisionEntitySchemaUpdater;
8use EntitySchema\Domain\Model\EntitySchemaId;
9use EntitySchema\Services\Converter\FullArrayEntitySchemaData;
10use MediaWiki\CommentStore\CommentStoreComment;
11use MediaWiki\MediaWikiServices;
12use MediaWiki\Status\Status;
13use PermissionsError;
14use ReadOnlyError;
15use RuntimeException;
16use UserBlockedError;
17
18/**
19 * @license GPL-2.0-or-later
20 */
21class UndoSubmitAction extends AbstractUndoAction {
22
23    public function getName(): string {
24        return 'submit';
25    }
26
27    public function getRestriction(): string {
28        return 'edit';
29    }
30
31    public function show(): void {
32        $permStatus = $this->checkPermissions();
33        if ( !$permStatus->isOK() ) {
34            $this->showUndoErrorPage( $permStatus );
35            return;
36        }
37
38        $undoStatus = $this->undo();
39        if ( !$undoStatus->isOK() ) {
40            $this->showUndoErrorPage( $undoStatus );
41        }
42
43        $this->getOutput()->redirect(
44            $this->getTitle()->getFullURL()
45        );
46    }
47
48    /**
49     * @throws ReadOnlyError
50     * @throws UserBlockedError
51     * @throws PermissionsError
52     */
53    private function checkPermissions(): Status {
54        $method = $this->getContext()->getRequest()->getMethod();
55        if ( $method !== 'POST' ) {
56            return Status::newFatal( 'entityschema-error-not-post' );
57        }
58
59        $services = MediaWikiServices::getInstance();
60        $pm = $services->getPermissionManager();
61
62        $permissionErrors = $pm->getPermissionErrors(
63            $this->getRestriction(),
64            $this->getUser(),
65            $this->getTitle()
66        );
67        if ( $permissionErrors !== [] ) {
68            throw new PermissionsError( $this->getRestriction(), $permissionErrors );
69        }
70
71        if ( $services->getReadOnlyMode()->isReadOnly() ) {
72            throw new ReadOnlyError;
73        }
74
75        return Status::newGood();
76    }
77
78    private function undo(): Status {
79        $req = $this->getContext()->getRequest();
80
81        $diffStatus = $this->getDiffFromRequest( $req );
82        if ( !$diffStatus->isOK() ) {
83            return $diffStatus;
84        }
85
86        $patchStatus = $this->tryPatching( $diffStatus->getValue() );
87        if ( !$patchStatus->isOK() ) {
88            return $patchStatus;
89        }
90
91        [ $patchedSchema, $baseRevId ] = $patchStatus->getValue();
92        return $this->storePatchedSchema( $patchedSchema, $baseRevId );
93    }
94
95    private function storePatchedSchema( FullArrayEntitySchemaData $patchedSchema, int $baseRevId ): Status {
96        $schemaUpdater = MediaWikiRevisionEntitySchemaUpdater::newFromContext( $this->getContext() );
97
98        $summary = $this->createSummaryCommentForUndoRev(
99            $this->getContext()->getRequest()->getText( 'wpSummary' ),
100            $this->getContext()->getRequest()->getInt( 'undo' )
101            );
102
103        try {
104            $schemaUpdater->overwriteWholeSchema(
105                new EntitySchemaId( $this->getTitle()->getTitleValue()->getText() ),
106                $patchedSchema->data['labels'],
107                $patchedSchema->data['descriptions'],
108                $patchedSchema->data['aliases'],
109                $patchedSchema->data['schemaText'],
110                $baseRevId,
111                $summary
112            );
113        } catch ( RuntimeException $e ) {
114            return Status::newFatal( 'entityschema-error-saving-failed', $e->getMessage() );
115        }
116
117        return Status::newGood();
118    }
119
120    private function createSummaryCommentForUndoRev( string $userSummary, int $undoRevId ): CommentStoreComment {
121        $revToBeUndone = MediaWikiServices::getInstance()
122            ->getRevisionStore()
123            ->getRevisionById( $undoRevId );
124        $userName = $revToBeUndone->getUser()->getName();
125        $autoComment = MediaWikiRevisionEntitySchemaUpdater::AUTOCOMMENT_UNDO
126            . ':' . $undoRevId
127            . ':' . $userName;
128        return CommentStoreComment::newUnsavedComment(
129            '/* ' . $autoComment . ' */' . $userSummary,
130            [
131                'key' => MediaWikiRevisionEntitySchemaUpdater::AUTOCOMMENT_UNDO,
132                'summary' => $userSummary,
133                'undoRevId' => $undoRevId,
134                'userName' => $userName,
135            ]
136        );
137    }
138
139}