Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 61 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
Hooks | |
0.00% |
0 / 61 |
|
0.00% |
0 / 8 |
380 | |
0.00% |
0 / 1 |
onPageSaveComplete | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
12 | |||
onRollbackComplete | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
30 | |||
onRegisterTags | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
onListDefinedTags | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
onChangeTagsListActive | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
countersOnEditSuccess | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
countersOnUndo | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
30 | |||
getCounters | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
16 | * |
17 | * @file |
18 | */ |
19 | |
20 | namespace MediaWiki\Extension\WikimediaEditorTasks; |
21 | |
22 | use MediaWiki\ChangeTags\Hook\ChangeTagsListActiveHook; |
23 | use MediaWiki\ChangeTags\Hook\ListDefinedTagsHook; |
24 | use MediaWiki\Context\RequestContext; |
25 | use MediaWiki\Deferred\AutoCommitUpdate; |
26 | use MediaWiki\Deferred\DeferredUpdates; |
27 | use MediaWiki\MediaWikiServices; |
28 | use MediaWiki\Page\Hook\RollbackCompleteHook; |
29 | use MediaWiki\Revision\RevisionRecord; |
30 | use MediaWiki\Storage\EditResult; |
31 | use MediaWiki\Storage\Hook\PageSaveCompleteHook; |
32 | use MediaWiki\Title\Title; |
33 | use MediaWiki\User\UserIdentity; |
34 | use Wikimedia\Rdbms\IDBAccessObject; |
35 | use WikiPage; |
36 | |
37 | /** |
38 | * Hooks for WikimediaEditorTasks extension |
39 | */ |
40 | class Hooks implements |
41 | RollbackCompleteHook, |
42 | PageSaveCompleteHook, |
43 | ListDefinedTagsHook, |
44 | ChangeTagsListActiveHook |
45 | { |
46 | |
47 | /** |
48 | * Handler for PageSaveComplete hook |
49 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/PageSaveComplete |
50 | * |
51 | * @param WikiPage $wikiPage |
52 | * @param UserIdentity $userIdentity |
53 | * @param string $summary |
54 | * @param int $flags |
55 | * @param RevisionRecord $revisionRecord |
56 | * @param EditResult $editResult |
57 | */ |
58 | public function onPageSaveComplete( |
59 | $wikiPage, |
60 | $userIdentity, |
61 | $summary, |
62 | $flags, |
63 | $revisionRecord, |
64 | $editResult |
65 | ) { |
66 | $undidRevId = $editResult->getUndidRevId(); |
67 | |
68 | $cb = function () use ( $revisionRecord, $userIdentity, $undidRevId, $wikiPage ) { |
69 | if ( $userIdentity->isRegistered() ) { |
70 | self::countersOnEditSuccess( $userIdentity, $revisionRecord ); |
71 | } |
72 | |
73 | if ( $undidRevId ) { |
74 | self::countersOnUndo( $undidRevId, $wikiPage ); |
75 | } |
76 | }; |
77 | |
78 | $services = MediaWikiServices::getInstance(); |
79 | DeferredUpdates::addUpdate( |
80 | new AutoCommitUpdate( |
81 | Utils::getUserCountsDB( DB_PRIMARY, $services ), |
82 | __METHOD__, |
83 | $cb, |
84 | [ $services->getConnectionProvider()->getPrimaryDatabase() ] |
85 | ), |
86 | DeferredUpdates::POSTSEND |
87 | ); |
88 | } |
89 | |
90 | /** |
91 | * Handler for RollbackComplete hook. |
92 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/RollbackComplete |
93 | * |
94 | * @param WikiPage $wikiPage The article that was edited |
95 | * @param UserIdentity $agent The user who did the rollback |
96 | * @param RevisionRecord $newRev The revision the page was reverted back to |
97 | * @param RevisionRecord $oldRev The revision of the top edit that was reverted |
98 | */ |
99 | public function onRollbackComplete( $wikiPage, $agent, $newRev, $oldRev ) { |
100 | $cb = function () use ( $wikiPage, $oldRev, $newRev ) { |
101 | $victim = $oldRev->getUser(); |
102 | |
103 | // Ignore anonymous users and null rollbacks |
104 | if ( $victim && $victim->isRegistered() && !$oldRev->hasSameContent( $newRev ) ) { |
105 | $victimCentralId = Utils::getCentralId( $victim ); |
106 | $oldId = $oldRev->getId(); |
107 | foreach ( self::getCounters() as $counter ) { |
108 | $counter->onRevert( |
109 | $victimCentralId, |
110 | $oldId, |
111 | $oldRev |
112 | ); |
113 | } |
114 | } |
115 | }; |
116 | |
117 | $services = MediaWikiServices::getInstance(); |
118 | DeferredUpdates::addUpdate( |
119 | new AutoCommitUpdate( |
120 | Utils::getUserCountsDB( DB_PRIMARY, $services ), |
121 | __METHOD__, |
122 | $cb, |
123 | [ $services->getConnectionProvider()->getPrimaryDatabase() ] |
124 | ), |
125 | DeferredUpdates::POSTSEND |
126 | ); |
127 | } |
128 | |
129 | /** |
130 | * @param array &$tags |
131 | */ |
132 | private static function onRegisterTags( array &$tags ) { |
133 | $tags[] = 'apps-suggested-edits'; |
134 | } |
135 | |
136 | /** |
137 | * @param array &$tags |
138 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/ListDefinedTags |
139 | */ |
140 | public function onListDefinedTags( &$tags ) { |
141 | self::onRegisterTags( $tags ); |
142 | } |
143 | |
144 | /** |
145 | * @param array &$tags |
146 | */ |
147 | public function onChangeTagsListActive( &$tags ) { |
148 | self::onRegisterTags( $tags ); |
149 | } |
150 | |
151 | /** |
152 | * @param UserIdentity $user user who succeeded in editing |
153 | * @param RevisionRecord $revision revision representing the successful edit |
154 | */ |
155 | private static function countersOnEditSuccess( UserIdentity $user, RevisionRecord $revision ) { |
156 | $centralId = Utils::getCentralId( $user ); |
157 | |
158 | // We need to check the underlying request headers to determine if this is an app edit |
159 | $request = RequestContext::getMain()->getRequest(); |
160 | |
161 | foreach ( self::getCounters() as $counter ) { |
162 | $counter->onEditSuccess( $centralId, $request, $revision ); |
163 | } |
164 | } |
165 | |
166 | /** |
167 | * @param int $undidRevId revision that was undone |
168 | * @param WikiPage $wikiPage wiki page that was just edited |
169 | */ |
170 | private static function countersOnUndo( $undidRevId, $wikiPage ) { |
171 | $undidRev = MediaWikiServices::getInstance()->getRevisionStore() |
172 | ->getRevisionById( $undidRevId, IDBAccessObject::READ_LATEST_IMMUTABLE ); |
173 | |
174 | if ( !$undidRev ) { |
175 | return; |
176 | } |
177 | |
178 | $undidUserIdentity = $undidRev->getUser( RevisionRecord::FOR_PUBLIC ); |
179 | if ( !$undidUserIdentity ) { |
180 | return; |
181 | } |
182 | |
183 | // Check that this isn't a spoofed revert (T59474) |
184 | $undidTitle = Title::newFromLinkTarget( $undidRev->getPageAsLinkTarget() ); |
185 | if ( !$undidTitle->equals( $wikiPage->getTitle() ) ) { |
186 | return; |
187 | } |
188 | |
189 | $undidUserCentralId = Utils::getCentralId( $undidUserIdentity ); |
190 | foreach ( self::getCounters() as $counter ) { |
191 | $counter->onRevert( $undidUserCentralId, $undidRevId, $undidRev ); |
192 | } |
193 | } |
194 | |
195 | /** |
196 | * @return Counter[] |
197 | */ |
198 | private static function getCounters() { |
199 | $counterFactory = WikimediaEditorTasksServices::getInstance()->getCounterFactory(); |
200 | return $counterFactory->createAll( Utils::getEnabledCounters() ); |
201 | } |
202 | |
203 | } |