Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.62% covered (success)
90.62%
58 / 64
50.00% covered (danger)
50.00%
4 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
UndoSubmitAction
90.62% covered (success)
90.62%
58 / 64
50.00% covered (danger)
50.00%
4 / 8
15.19
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
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
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
3.10
 checkPermissions
92.31% covered (success)
92.31%
12 / 13
0.00% covered (danger)
0.00%
0 / 1
4.01
 undo
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
3.10
 storePatchedSchema
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 createSummaryCommentForUndoRev
100.00% covered (success)
100.00%
14 / 14
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\EntitySchemaStatus;
8use EntitySchema\DataAccess\MediaWikiRevisionEntitySchemaUpdater;
9use EntitySchema\Domain\Model\EntitySchemaId;
10use EntitySchema\MediaWiki\EntitySchemaRedirectTrait;
11use EntitySchema\Services\Converter\FullArrayEntitySchemaData;
12use MediaWiki\CommentStore\CommentStoreComment;
13use MediaWiki\Context\IContextSource;
14use MediaWiki\Exception\PermissionsError;
15use MediaWiki\Exception\ReadOnlyError;
16use MediaWiki\Exception\UserBlockedError;
17use MediaWiki\Page\Article;
18use MediaWiki\Permissions\PermissionManager;
19use MediaWiki\Revision\RevisionStore;
20use MediaWiki\Status\Status;
21use Wikimedia\Rdbms\ReadOnlyMode;
22
23/**
24 * @license GPL-2.0-or-later
25 */
26class UndoSubmitAction extends AbstractUndoAction {
27
28    use EntitySchemaRedirectTrait;
29
30    private PermissionManager $permissionManager;
31    private ReadOnlyMode $readOnlyMode;
32
33    public function __construct(
34        Article $article,
35        IContextSource $context,
36        ReadOnlyMode $readOnlyMode,
37        PermissionManager $permissionManager,
38        RevisionStore $revisionStore
39    ) {
40        parent::__construct( $article, $context, $revisionStore );
41        $this->permissionManager = $permissionManager;
42        $this->readOnlyMode = $readOnlyMode;
43    }
44
45    public function getName(): string {
46        return 'submit';
47    }
48
49    public function getRestriction(): string {
50        return 'edit';
51    }
52
53    public function show(): void {
54        $permStatus = $this->checkPermissions();
55        if ( !$permStatus->isOK() ) {
56            $this->showUndoErrorPage( $permStatus );
57            return;
58        }
59
60        $undoStatus = $this->undo();
61        if ( !$undoStatus->isOK() ) {
62            $this->showUndoErrorPage( $undoStatus );
63            return;
64        }
65
66        $this->redirectToEntitySchema( $undoStatus );
67    }
68
69    /**
70     * @throws ReadOnlyError
71     * @throws UserBlockedError
72     * @throws PermissionsError
73     */
74    private function checkPermissions(): Status {
75        $method = $this->getContext()->getRequest()->getMethod();
76        if ( $method !== 'POST' ) {
77            return Status::newFatal( 'entityschema-error-not-post' );
78        }
79
80        $permissionErrors = $this->permissionManager->getPermissionErrors(
81            $this->getRestriction(),
82            $this->getUser(),
83            $this->getTitle()
84        );
85        if ( $permissionErrors !== [] ) {
86            throw new PermissionsError( $this->getRestriction(), $permissionErrors );
87        }
88
89        if ( $this->readOnlyMode->isReadOnly() ) {
90            throw new ReadOnlyError;
91        }
92
93        return Status::newGood();
94    }
95
96    private function undo(): EntitySchemaStatus {
97        $req = $this->getContext()->getRequest();
98
99        $diffStatus = $this->getDiffFromRequest( $req );
100        if ( !$diffStatus->isOK() ) {
101            return EntitySchemaStatus::wrap( $diffStatus );
102        }
103
104        $patchStatus = $this->tryPatching( $diffStatus->getValue() );
105        if ( !$patchStatus->isOK() ) {
106            return EntitySchemaStatus::wrap( $patchStatus );
107        }
108
109        [ $patchedSchema, $baseRevId ] = $patchStatus->getValue();
110        return $this->storePatchedSchema( $patchedSchema, $baseRevId );
111    }
112
113    private function storePatchedSchema(
114        FullArrayEntitySchemaData $patchedSchema,
115        int $baseRevId
116    ): EntitySchemaStatus {
117        $schemaUpdater = MediaWikiRevisionEntitySchemaUpdater::newFromContext( $this->getContext() );
118
119        $summary = $this->createSummaryCommentForUndoRev(
120            $this->getContext()->getRequest()->getText( 'wpSummary' ),
121            $this->getContext()->getRequest()->getInt( 'undo' )
122            );
123
124        return $schemaUpdater->overwriteWholeSchema(
125            new EntitySchemaId( $this->getTitle()->getTitleValue()->getText() ),
126            $patchedSchema->data['labels'],
127            $patchedSchema->data['descriptions'],
128            $patchedSchema->data['aliases'],
129            $patchedSchema->data['schemaText'],
130            $baseRevId,
131            $summary
132        );
133    }
134
135    private function createSummaryCommentForUndoRev( string $userSummary, int $undoRevId ): CommentStoreComment {
136        $revToBeUndone = $this->revisionStore->getRevisionById( $undoRevId );
137        $userName = $revToBeUndone->getUser()->getName();
138        $autoComment = MediaWikiRevisionEntitySchemaUpdater::AUTOCOMMENT_UNDO
139            . ':' . $undoRevId
140            . ':' . $userName;
141        return CommentStoreComment::newUnsavedComment(
142            '/* ' . $autoComment . ' */' . $userSummary,
143            [
144                'key' => MediaWikiRevisionEntitySchemaUpdater::AUTOCOMMENT_UNDO,
145                'summary' => $userSummary,
146                'undoRevId' => $undoRevId,
147                'userName' => $userName,
148            ]
149        );
150    }
151
152}