Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 85 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
SpecialUserMerge | |
0.00% |
0 / 85 |
|
0.00% |
0 / 8 |
552 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getFormFields | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
20 | |||
validateOldUser | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
validateNewUser | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
30 | |||
alterForm | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
onSubmit | |
0.00% |
0 / 35 |
|
0.00% |
0 / 1 |
56 | |||
getDisplayFormat | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** \file |
3 | * \brief Contains code for the UserMerge Class (extends SpecialPage). |
4 | */ |
5 | |
6 | /** |
7 | * Special page class for the User Merge and Delete extension |
8 | * allows sysops to merge references from one user to another user. |
9 | * It also supports deleting users following merge. |
10 | * |
11 | * @ingroup Extensions |
12 | * @author Tim Laqua <t.laqua@gmail.com> |
13 | * @author Thomas Gries <mail@tgries.de> |
14 | * @author Matthew April <Matthew.April@tbs-sct.gc.ca> |
15 | * |
16 | */ |
17 | |
18 | use MediaWiki\User\UserGroupManager; |
19 | |
20 | class SpecialUserMerge extends FormSpecialPage { |
21 | |
22 | /** @var UserGroupManager */ |
23 | private $userGroupManager; |
24 | |
25 | /** |
26 | * @param UserGroupManager $userGroupManager |
27 | */ |
28 | public function __construct( |
29 | UserGroupManager $userGroupManager |
30 | ) { |
31 | parent::__construct( 'UserMerge', 'usermerge' ); |
32 | $this->userGroupManager = $userGroupManager; |
33 | } |
34 | |
35 | /** |
36 | * @return array |
37 | */ |
38 | protected function getFormFields() { |
39 | return [ |
40 | 'olduser' => [ |
41 | 'type' => 'user', |
42 | 'exists' => true, |
43 | 'label-message' => 'usermerge-olduser', |
44 | 'required' => true, |
45 | 'validation-callback' => function ( $val ) { |
46 | $key = $this->validateOldUser( $val ); |
47 | if ( is_array( $key ) ) { |
48 | return $this->msg( $key )->escaped(); |
49 | } |
50 | return true; |
51 | }, |
52 | ], |
53 | 'newuser' => [ |
54 | 'type' => 'user', |
55 | 'required' => true, |
56 | 'label-message' => 'usermerge-newuser', |
57 | 'validation-callback' => function ( $val ) { |
58 | // only pass strings to User::newFromName |
59 | if ( !is_string( $val ) ) { |
60 | return true; |
61 | } |
62 | |
63 | $key = $this->validateNewUser( $val ); |
64 | if ( is_string( $key ) ) { |
65 | return $this->msg( $key )->escaped(); |
66 | } |
67 | return true; |
68 | }, |
69 | ], |
70 | 'delete' => [ |
71 | 'type' => 'check', |
72 | 'label-message' => 'usermerge-deleteolduser', |
73 | ], |
74 | ]; |
75 | } |
76 | |
77 | /** |
78 | * @param string $val user's input for username |
79 | * @return true|string[] true if valid, a string[] of the error's message key and params |
80 | * if validation failed |
81 | */ |
82 | public function validateOldUser( $val ) { |
83 | $oldUser = User::newFromName( $val ); |
84 | if ( $this->getUser()->getId() === $oldUser->getId() ) { |
85 | return [ 'usermerge-noselfdelete', $this->getUser()->getName() ]; |
86 | } |
87 | $protectedGroups = $this->getConfig()->get( 'UserMergeProtectedGroups' ); |
88 | if ( array_intersect( $this->userGroupManager->getUserGroups( $oldUser ), $protectedGroups ) !== [] ) { |
89 | return [ 'usermerge-protectedgroup', $oldUser->getName() ]; |
90 | } |
91 | |
92 | return true; |
93 | } |
94 | |
95 | /** |
96 | * @param string $val user's input for username |
97 | * @return true|string true if valid, a string of the error's message key if validation failed |
98 | */ |
99 | public function validateNewUser( $val ) { |
100 | $enableDelete = $this->getConfig()->get( 'UserMergeEnableDelete' ); |
101 | if ( $enableDelete && $val === 'Anonymous' ) { |
102 | // Special case |
103 | return true; |
104 | } |
105 | $newUser = User::newFromName( $val ); |
106 | if ( !$newUser || $newUser->getId() === 0 ) { |
107 | return 'usermerge-badnewuser'; |
108 | } |
109 | |
110 | return true; |
111 | } |
112 | |
113 | /** |
114 | * @param HTMLForm $form |
115 | */ |
116 | protected function alterForm( HTMLForm $form ) { |
117 | $form->setSubmitTextMsg( 'usermerge-submit' ); |
118 | } |
119 | |
120 | /** |
121 | * @param array $data |
122 | * @return Status |
123 | */ |
124 | public function onSubmit( array $data ) { |
125 | $enableDelete = $this->getConfig()->get( 'UserMergeEnableDelete' ); |
126 | // Most of the data has been validated using callbacks |
127 | // still need to check if the users are different |
128 | $newUser = User::newFromName( $data['newuser'] ); |
129 | // Handle "Anonymous" as a special case for user deletion |
130 | if ( $enableDelete && $data['newuser'] === 'Anonymous' ) { |
131 | $newUser->mId = 0; |
132 | } |
133 | |
134 | $oldUser = User::newFromName( $data['olduser'] ); |
135 | if ( $newUser->getName() === $oldUser->getName() ) { |
136 | return Status::newFatal( 'usermerge-same-old-and-new-user' ); |
137 | } |
138 | |
139 | // Validation passed, let's merge the user now. |
140 | $um = new MergeUser( $oldUser, $newUser, new UserMergeLogger() ); |
141 | $um->merge( $this->getUser(), __METHOD__ ); |
142 | |
143 | $out = $this->getOutput(); |
144 | |
145 | $out->addWikiMsg( |
146 | 'usermerge-success', |
147 | $oldUser->getName(), $oldUser->getId(), |
148 | $newUser->getName(), $newUser->getId() |
149 | ); |
150 | |
151 | if ( $data['delete'] ) { |
152 | $failed = $um->delete( $this->getUser(), [ $this, 'msg' ] ); |
153 | $out->addWikiMsg( |
154 | 'usermerge-userdeleted', $oldUser->getName(), $oldUser->getId() |
155 | ); |
156 | |
157 | if ( $failed ) { |
158 | // Output an error message for failed moves |
159 | $out->addHTML( Html::openElement( 'ul' ) ); |
160 | $linkRenderer = $this->getLinkRenderer(); |
161 | foreach ( $failed as $oldTitleText => $newTitle ) { |
162 | $oldTitle = Title::newFromText( $oldTitleText ); |
163 | $out->addHTML( |
164 | Html::rawElement( 'li', [], |
165 | $this->msg( 'usermerge-page-unmoved' )->rawParams( |
166 | $linkRenderer->makeLink( $oldTitle ), |
167 | $linkRenderer->makeLink( $newTitle ) |
168 | )->escaped() |
169 | ) |
170 | ); |
171 | } |
172 | $out->addHTML( Html::closeElement( 'ul' ) ); |
173 | } |
174 | } |
175 | |
176 | return Status::newGood(); |
177 | } |
178 | |
179 | /** |
180 | * @inheritDoc |
181 | */ |
182 | protected function getDisplayFormat() { |
183 | return 'ooui'; |
184 | } |
185 | |
186 | /** |
187 | * @inheritDoc |
188 | */ |
189 | protected function getGroupName() { |
190 | return 'users'; |
191 | } |
192 | } |