Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 109
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
NewUserMessage
0.00% covered (danger)
0.00%
0 / 109
0.00% covered (danger)
0.00%
0 / 13
1640
0.00% covered (danger)
0.00%
0 / 1
 fetchEditor
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 fetchSignature
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 fetchTemplateIfExists
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
 fetchSubject
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 fetchText
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 fetchFlags
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 substString
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 createNewUserMessage
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 onLocalUserCreated
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
30
 onUserGetReservedNames
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 leaveUserMessage
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 formatUserMessage
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 getMsg
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/** Extension:NewUserMessage
4 *
5 * @file
6 * @ingroup Extensions
7 *
8 * @author [http://www.organicdesign.co.nz/nad User:Nad]
9 * @license GPL-2.0-or-later
10 * @copyright 2007-10-15 [http://www.organicdesign.co.nz/nad User:Nad]
11 * @copyright 2009 Siebrand Mazeland
12 */
13
14namespace MediaWiki\Extension\NewUserMessage;
15
16use ContentHandler;
17use MediaWiki\Auth\Hook\LocalUserCreatedHook;
18use MediaWiki\Deferred\DeferredUpdates;
19use MediaWiki\MediaWikiServices;
20use MediaWiki\Revision\RevisionRecord;
21use MediaWiki\Title\Title;
22use MediaWiki\User\Hook\UserGetReservedNamesHook;
23use MediaWiki\User\User;
24use Message;
25use ParserOptions;
26use WikiPage;
27
28class NewUserMessage implements
29    LocalUserCreatedHook,
30    UserGetReservedNamesHook
31{
32    /**
33     * Produce the editor for new user messages.
34     * @return User|bool
35     */
36    private static function fetchEditor() {
37        // Create a user object for the editing user and add it to the
38        // database if it is not there already
39        $editor = User::newFromName( self::getMsg( 'newusermessage-editor' )->text() );
40
41        if ( !$editor ) {
42            return false; // Invalid username
43        }
44
45        if ( !$editor->isRegistered() ) {
46            $editor->addToDatabase();
47        }
48
49        return $editor;
50    }
51
52    /**
53     * Produce a (possibly random) signature.
54     * @return string
55     */
56    private static function fetchSignature() {
57        $signatures = self::getMsg( 'newusermessage-signatures' )->text();
58        $signature = '';
59
60        if ( !self::getMsg( 'newusermessage-signatures' )->isDisabled() ) {
61            $pattern = '/^\* ?(.*?)$/m';
62            $signatureList = [];
63            preg_match_all( $pattern, $signatures, $signatureList, PREG_SET_ORDER );
64            if ( count( $signatureList ) > 0 ) {
65                $rand = rand( 0, count( $signatureList ) - 1 );
66                $signature = $signatureList[$rand][1];
67            }
68        }
69
70        return $signature;
71    }
72
73    /**
74     * Return the template name if it exists, or '' otherwise.
75     * @param string $template string with page name of user message template
76     * @return string
77     */
78    private static function fetchTemplateIfExists( $template ) {
79        $text = Title::newFromText( $template );
80
81        if ( !$text ) {
82            wfDebug( __METHOD__ . ": '$template' is not a valid title.\n" );
83            return '';
84        } elseif ( $text->getNamespace() !== NS_TEMPLATE ) {
85            wfDebug( __METHOD__ . ": '$template' is not a valid Template.\n" );
86            return '';
87        } elseif ( !$text->exists() ) {
88            return '';
89        }
90
91        return $text->getText();
92    }
93
94    /**
95     * Produce a subject for the message.
96     * @return string
97     */
98    private static function fetchSubject() {
99        return self::fetchTemplateIfExists(
100            self::getMsg( 'newusermessage-template-subject' )->text()
101        );
102    }
103
104    /**
105     * Produce the template that contains the text of the message.
106     * @return string
107     */
108    private static function fetchText() {
109        $template = self::getMsg( 'newusermessage-template-body' )->text();
110
111        $title = Title::newFromText( $template );
112        if ( $title && $title->exists() && $title->getLength() ) {
113            return $template;
114        }
115
116        // Fall back if necessary to the old template
117        return self::getMsg( 'newusermessage-template' )->text();
118    }
119
120    /**
121     * Produce the flags to set on WikiPage::doUserEditContent
122     * @return int
123     */
124    private static function fetchFlags() {
125        global $wgNewUserMinorEdit, $wgNewUserSuppressRC;
126
127        $flags = EDIT_NEW;
128        if ( $wgNewUserMinorEdit ) {
129            $flags |= EDIT_MINOR;
130        }
131        if ( $wgNewUserSuppressRC ) {
132            $flags |= EDIT_SUPPRESS_RC;
133        }
134
135        return $flags;
136    }
137
138    /**
139     * Take care of substition on the string in a uniform manner
140     * @param string $str
141     * @param User $user
142     * @param User $editor
143     * @param Title $talk
144     * @param string|null $preparse If provided, then preparse the string using a Parser
145     * @return string
146     */
147    private static function substString( $str, $user, $editor, $talk, $preparse = null ) {
148        $realName = $user->getRealName();
149        $name = $user->getName();
150
151        // Add (any) content to [[MediaWiki:Newusermessage-substitute]] to substitute the
152        // welcome template.
153        $substDisabled = self::getMsg( 'newusermessage-substitute' )->isDisabled();
154
155        if ( $substDisabled ) {
156            $str = '{{' . "$str|realName=$realName|name=$name}}";
157        } else {
158            $str = '{{subst:' . "$str|realName=$realName|name=$name}}";
159        }
160
161        if ( $preparse ) {
162            $str = MediaWikiServices::getInstance()->getParser()->preSaveTransform(
163                $str,
164                $talk,
165                $editor,
166                new ParserOptions( $user )
167            );
168        }
169
170        return $str;
171    }
172
173    /**
174     * Add the message if the users talk page does not already exist
175     * @param User $user User object
176     * @return bool
177     */
178    public static function createNewUserMessage( $user ) {
179        $talk = $user->getTalkPage();
180
181        // Only leave message if user doesn't have a talk page yet
182        if ( !$talk->exists() ) {
183            $wikiPage = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $talk );
184            $subject = self::fetchSubject();
185            $text = self::fetchText();
186            $signature = self::fetchSignature();
187            $editSummary = self::getMsg( 'newuseredit-summary' )->text();
188            $editor = self::fetchEditor();
189            $flags = self::fetchFlags();
190
191            # Do not add a message if the username is invalid or if the account that adds it,
192            # is blocked
193            if ( !$editor || $editor->getBlock() ) {
194                return true;
195            }
196
197            if ( $subject ) {
198                $subject = self::substString( $subject, $user, $editor, $talk, "preparse" );
199            }
200            if ( $text ) {
201                $text = self::substString( $text, $user, $editor, $talk );
202            }
203
204            self::leaveUserMessage( $user, $wikiPage, $subject, $text,
205                $signature, $editSummary, $editor, $flags );
206        }
207        return true;
208    }
209
210    /**
211     * Hook function to create new user pages when an account is created or autocreated
212     * @param User $user object of the user
213     * @param bool $autocreated
214     */
215    public function onLocalUserCreated( $user, $autocreated ) {
216        global $wgNewUserMessageOnAutoCreate;
217
218        if ( $user->isTemp() ) {
219            return; // not a new registered user
220        }
221
222        if ( !$autocreated ) {
223            DeferredUpdates::addCallableUpdate(
224                static function () use ( $user ) {
225                    if ( $user->isBot() ) {
226                        return; // not a human
227                    }
228
229                    NewUserMessage::createNewUserMessage( $user );
230                },
231                DeferredUpdates::PRESEND
232            );
233        } elseif ( $wgNewUserMessageOnAutoCreate ) {
234            MediaWikiServices::getInstance()->getJobQueueGroup()->lazyPush(
235                new NewUserMessageJob( [ 'userId' => $user->getId() ] ) );
236        }
237    }
238
239    /**
240     * Hook function to provide a reserved name
241     * @param array &$names
242     */
243    public function onUserGetReservedNames( &$names ) {
244        $names[] = 'msg:newusermessage-editor';
245    }
246
247    /**
248     * Leave a user a message
249     * @param User $user User to message
250     * @param WikiPage $wikiPage user talk page
251     * @param string $subject string with the subject of the message
252     * @param string $text string with the message to leave
253     * @param string $signature string to leave in the signature
254     * @param string $summary string with the summary for this change, defaults to
255     *                        "Leave system message."
256     * @param User $editor User leaving the message, defaults to
257     *                        "{{MediaWiki:usermessage-editor}}"
258     * @param int $flags default edit flags
259     *
260     * @return bool true if it was successful
261     */
262    public static function leaveUserMessage( $user, $wikiPage, $subject, $text, $signature,
263            $summary, $editor, $flags
264    ) {
265        $text = self::formatUserMessage( $subject, $text, $signature );
266        $flags = $wikiPage->checkFlags( $flags );
267
268        if ( $flags & EDIT_UPDATE ) {
269            $content = $wikiPage->getContent( RevisionRecord::RAW );
270            if ( $content !== null ) {
271                $text = $content->getNativeData() . "\n" . $text;
272            }
273        }
274
275        $status = $wikiPage->doUserEditContent(
276            ContentHandler::makeContent( $text, $wikiPage->getTitle() ),
277            $editor,
278            $summary,
279            $flags
280        );
281        return $status->isGood();
282    }
283
284    /**
285     * Format the user message using a hook, a template, or, failing these, a static format.
286     * @param string $subject the subject of the message
287     * @param string $text the content of the message
288     * @param string $signature the signature, if provided.
289     * @return string in wiki text with complete user message
290     */
291    protected static function formatUserMessage( $subject, $text, $signature ) {
292        $contents = "";
293        $signature = $signature === '' ? "~~~~" : "{$signature} ~~~~~";
294
295        if ( $subject ) {
296            $contents .= "== $subject ==\n\n";
297        }
298        $contents .= "$text\n\n-- $signature\n";
299
300        return $contents;
301    }
302
303    /**
304     * @param string $name
305     * @return Message
306     */
307    protected static function getMsg( $name ) {
308        return wfMessage( $name )->inContentLanguage();
309    }
310}