MediaWiki fundraising/REL1_35
WikiEditorHooks.php
Go to the documentation of this file.
1<?php
10use WikimediaEvents\WikimediaEventsHooks;
11
13 // ID used for grouping entries all of a session's entries together in
14 // EventLogging.
15 private static $statsId = false;
16
17 /* Static Methods */
18
29 public static function doEventLogging( $action, $article, $data = [] ) {
30 global $wgWMESchemaEditAttemptStepSamplingRate;
31 $extensionRegistry = ExtensionRegistry::getInstance();
32 if ( !$extensionRegistry->isLoaded( 'EventLogging' ) ) {
33 return false;
34 }
35 // Sample 6.25%
36 $samplingRate = $wgWMESchemaEditAttemptStepSamplingRate ?? 0.0625;
37 $inSample = EventLogging::sessionInSample(
38 (int)( 1 / $samplingRate ), $data['editing_session_id']
39 );
40 $shouldOversample = $extensionRegistry->isLoaded( 'WikimediaEvents' ) &&
41 WikimediaEventsHooks::shouldSchemaEditAttemptStepOversample( $article->getContext() );
42 if ( !$inSample && !$shouldOversample ) {
43 return false;
44 }
45
46 $user = $article->getContext()->getUser();
47 $page = $article->getPage();
48 $title = $article->getTitle();
49 $revisionRecord = $page->getRevisionRecord();
50
51 $data = [
52 'action' => $action,
53 'version' => 1,
54 'is_oversample' => !$inSample,
55 'editor_interface' => 'wikitext',
56 'platform' => 'desktop', // FIXME
57 'integration' => 'page',
58 'page_id' => $page->getId(),
59 'page_title' => $title->getPrefixedText(),
60 'page_ns' => $title->getNamespace(),
61 'revision_id' => $revisionRecord ? $revisionRecord->getId() : 0,
62 'user_id' => $user->getId(),
63 'user_editcount' => $user->getEditCount() ?: 0,
64 'mw_version' => MW_VERSION,
65 ] + $data;
66
67 if ( $user->isAnon() ) {
68 $data['user_class'] = 'IP';
69 }
70
71 return EventLogging::logEvent( 'EditAttemptStep', 18530416, $data );
72 }
73
82 public static function editPageShowEditFormInitial( EditPage $editPage, OutputPage $outputPage ) {
83 if ( $editPage->contentModel !== CONTENT_MODEL_WIKITEXT ) {
84 return;
85 }
86
87 $article = $editPage->getArticle();
88 $request = $article->getContext()->getRequest();
89
90 // Add modules if enabled
91 $user = $article->getContext()->getUser();
92 if ( $user->getOption( 'usebetatoolbar' ) ) {
93 $outputPage->addModuleStyles( 'ext.wikiEditor.styles' );
94 $outputPage->addModules( 'ext.wikiEditor' );
95 }
96
97 // Don't run this if the request was posted - we don't want to log 'init' when the
98 // user just pressed 'Show preview' or 'Show changes', or switched from VE keeping
99 // changes.
100 if ( ExtensionRegistry::getInstance()->isLoaded( 'EventLogging' ) && !$request->wasPosted() ) {
101 $data = [];
102 $data['editing_session_id'] = self::getEditingStatsId( $request );
103 if ( $request->getVal( 'section' ) ) {
104 $data['init_type'] = 'section';
105 } else {
106 $data['init_type'] = 'page';
107 }
108 if ( $request->getHeader( 'Referer' ) ) {
109 if (
110 $request->getVal( 'section' ) === 'new'
111 || !$article->getPage()->exists()
112 ) {
113 $data['init_mechanism'] = 'new';
114 } else {
115 $data['init_mechanism'] = 'click';
116 }
117 } else {
118 $data['init_mechanism'] = 'url';
119 }
120
121 self::doEventLogging( 'init', $article, $data );
122 }
123 }
124
133 public static function editPageShowEditFormFields( EditPage $editPage, OutputPage $outputPage ) {
134 if ( $editPage->contentModel !== CONTENT_MODEL_WIKITEXT ) {
135 return;
136 }
137
138 $req = $outputPage->getRequest();
139 $editingStatsId = self::getEditingStatsId( $req );
140
141 $shouldOversample = ExtensionRegistry::getInstance()->isLoaded( 'WikimediaEvents' ) &&
142 WikimediaEventsHooks::shouldSchemaEditAttemptStepOversample( $outputPage->getContext() );
143
144 $outputPage->addHTML(
145 Xml::element(
146 'input',
147 [
148 'type' => 'hidden',
149 'name' => 'editingStatsId',
150 'id' => 'editingStatsId',
151 'value' => $editingStatsId
152 ]
153 )
154 );
155
156 if ( $shouldOversample ) {
157 $outputPage->addHTML(
158 Xml::element(
159 'input',
160 [
161 'type' => 'hidden',
162 'name' => 'editingStatsOversample',
163 'id' => 'editingStatsOversample',
164 'value' => 1
165 ]
166 )
167 );
168 }
169 }
170
179 public static function getPreferences( $user, &$defaultPreferences ) {
180 // Ideally this key would be 'wikieditor-toolbar'
181 $defaultPreferences['usebetatoolbar'] = [
182 'type' => 'toggle',
183 'label-message' => 'wikieditor-toolbar-preference',
184 'help-message' => 'wikieditor-toolbar-preference-help',
185 'section' => 'editing/editor',
186 ];
187 }
188
194 public static function getModuleData( ResourceLoaderContext $context, Config $config ) {
195 return [
196 // expose magic words for use by the wikieditor toolbar
197 'magicWords' => self::getMagicWords(),
198 'signature' => self::getSignatureMessage( $context )
199 ];
200 }
201
207 public static function getModuleDataSummary( ResourceLoaderContext $context, Config $config ) {
208 return [
209 'magicWords' => self::getMagicWords(),
210 'signature' => self::getSignatureMessage( $context, true )
211 ];
212 }
213
214 private static function getSignatureMessage( MessageLocalizer $ml, $raw = false ) {
215 $msg = $ml->msg( 'sig-text' )->params( '~~~~' )->inContentLanguage();
216 return $raw ? $msg->plain() : $msg->text();
217 }
218
223 private static function getMagicWords() {
224 $requiredMagicWords = [
225 'redirect',
226 'img_right',
227 'img_left',
228 'img_none',
229 'img_center',
230 'img_thumbnail',
231 'img_framed',
232 'img_frameless',
233 ];
234 $magicWords = [];
235 $factory = MediaWikiServices::getInstance()->getMagicWordFactory();
236 foreach ( $requiredMagicWords as $name ) {
237 $magicWords[$name] = $factory->get( $name )->getSynonym( 0 );
238 }
239 return $magicWords;
240 }
241
247 private static function getEditingStatsId( WebRequest $request ) {
248 $fromRequest = $request->getVal( 'editingStatsId' );
249 if ( $fromRequest ) {
250 return $fromRequest;
251 }
252 if ( !self::$statsId ) {
253 self::$statsId = MWCryptRand::generateHex( 32 );
254 }
255 return self::$statsId;
256 }
257
263 public static function editPageAttemptSave( EditPage $editPage ) {
264 $article = $editPage->getArticle();
265 $request = $article->getContext()->getRequest();
266 if ( $request->getVal( 'editingStatsId' ) ) {
268 'saveAttempt',
269 $article,
270 [ 'editing_session_id' => $request->getVal( 'editingStatsId' ) ]
271 );
272 }
273 }
274
281 public static function editPageAttemptSaveAfter( EditPage $editPage, Status $status ) {
282 $article = $editPage->getArticle();
283 $request = $article->getContext()->getRequest();
284 if ( $request->getVal( 'editingStatsId' ) ) {
285 $data = [];
286 $data['editing_session_id'] = $request->getVal( 'editingStatsId' );
287
288 if ( $status->isOK() ) {
289 $action = 'saveSuccess';
290 } else {
291 $action = 'saveFailure';
292 $errors = $status->getErrorsArray();
293
294 if ( isset( $errors[0][0] ) ) {
295 $data['save_failure_message'] = $errors[0][0];
296 }
297
298 $wikiPage = $editPage->getArticle()->getPage();
299 if ( $status->value === EditPage::AS_CONFLICT_DETECTED ) {
300 $data['save_failure_type'] = 'editConflict';
301 } elseif ( $status->value === EditPage::AS_ARTICLE_WAS_DELETED ) {
302 $data['save_failure_type'] = 'editPageDeleted';
303 } elseif ( isset( $errors[0][0] ) && $errors[0][0] === 'abusefilter-disallowed' ) {
304 $data['save_failure_type'] = 'extensionAbuseFilter';
305 } elseif ( isset( $wikiPage->ConfirmEdit_ActivateCaptcha ) ) {
306 // TODO: :(
307 $data['save_failure_type'] = 'extensionCaptcha';
308 } elseif ( isset( $errors[0][0] ) && $errors[0][0] === 'spam-blacklisted-link' ) {
309 $data['save_failure_type'] = 'extensionSpamBlacklist';
310 } else {
311 // Catch everything else... We don't seem to get userBadToken or
312 // userNewUser through this hook.
313 $data['save_failure_type'] = 'responseUnknown';
314 }
315 }
316 self::doEventLogging( $action, $article, $data );
317 }
318 }
319}
const MW_VERSION
The running version of MediaWiki.
Definition Defines.php:40
getContext()
Get the base IContextSource object.
The edit page/HTML interface (split from Article) The actual database and text munging is still in Ar...
Definition EditPage.php:62
static generateHex( $chars)
Generate a run of cryptographically random data and return it in hexadecimal string format.
MediaWikiServices is the service locator for the application scope of MediaWiki.
This is one of the Core classes and should be read at least once by any new developers.
addModuleStyles( $modules)
Load the styles of one or more style-only ResourceLoader modules on this page.
addHTML( $text)
Append $text to the body HTML.
addModules( $modules)
Load one or more ResourceLoader modules on this page.
Context object that contains information about the state of a specific ResourceLoader web request.
isOK()
Returns whether the operation completed.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:44
getErrorsArray()
Get the list of errors (but not warnings)
Definition Status.php:355
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
getVal( $name, $default=null)
Fetch a scalar from the input or return $default if it's not set.
static editPageShowEditFormInitial(EditPage $editPage, OutputPage $outputPage)
EditPage::showEditForm:initial hook.
static editPageAttemptSave(EditPage $editPage)
This is attached to the MediaWiki 'EditPage::attemptSave' hook.
static getMagicWords()
Expose useful magic words which are used by the wikieditor toolbar.
static getModuleData(ResourceLoaderContext $context, Config $config)
static getEditingStatsId(WebRequest $request)
Gets a 32 character alphanumeric random string to be used for stats.
static getSignatureMessage(MessageLocalizer $ml, $raw=false)
static editPageAttemptSaveAfter(EditPage $editPage, Status $status)
This is attached to the MediaWiki 'EditPage::attemptSave:after' hook.
static getModuleDataSummary(ResourceLoaderContext $context, Config $config)
static getPreferences( $user, &$defaultPreferences)
GetPreferences hook.
static editPageShowEditFormFields(EditPage $editPage, OutputPage $outputPage)
EditPage::showEditForm:fields hook.
static doEventLogging( $action, $article, $data=[])
Log stuff to EventLogging's Schema:EditAttemptStep - see https://meta.wikimedia.org/wiki/Schema:EditA...
const CONTENT_MODEL_WIKITEXT
Definition Defines.php:225
Interface for configuration instances.
Definition Config.php:29
const AS_CONFLICT_DETECTED
Status: (non-resolvable) edit conflict.
const AS_ARTICLE_WAS_DELETED
Status: article was deleted while editing and wpRecreate == false or form was not posted.
Interface for localizing messages in MediaWiki.
msg( $key,... $params)
This is the method for getting translated interface messages.