MediaWiki  1.34.0
WikiEditorHooks.php
Go to the documentation of this file.
1 <?php
10 
12  // ID used for grouping entries all of a session's entries together in
13  // EventLogging.
14  private static $statsId = false;
15 
16  /* Static Methods */
17 
28  public static function doEventLogging( $action, $article, $data = [] ) {
29  global $wgVersion, $wgWMESchemaEditAttemptStepSamplingRate;
30  $extensionRegistry = ExtensionRegistry::getInstance();
31  if ( !$extensionRegistry->isLoaded( 'EventLogging' ) ) {
32  return false;
33  }
34  // Sample 6.25%
35  $samplingRate = $wgWMESchemaEditAttemptStepSamplingRate ?? 0.0625;
36  $inSample = EventLogging::sessionInSample( 1 / $samplingRate, $data['editing_session_id'] );
37  $shouldOversample = $extensionRegistry->isLoaded( 'WikimediaEvents' ) &&
38  WikimediaEventsHooks::shouldSchemaEditAttemptStepOversample( $article->getContext() );
39  if ( !$inSample && !$shouldOversample ) {
40  return false;
41  }
42 
43  $user = $article->getContext()->getUser();
44  $page = $article->getPage();
45  $title = $article->getTitle();
46 
47  $data = [
48  'action' => $action,
49  'version' => 1,
50  'is_oversample' => !$inSample,
51  'editor_interface' => 'wikitext',
52  'platform' => 'desktop', // FIXME
53  'integration' => 'page',
54  'page_id' => $page->getId(),
55  'page_title' => $title->getPrefixedText(),
56  'page_ns' => $title->getNamespace(),
57  'revision_id' => $page->getRevision() ? $page->getRevision()->getId() : 0,
58  'user_id' => $user->getId(),
59  'user_editcount' => $user->getEditCount() ?: 0,
60  'mw_version' => $wgVersion,
61  ] + $data;
62 
63  if ( $user->isAnon() ) {
64  $data['user_class'] = 'IP';
65  }
66 
67  return EventLogging::logEvent( 'EditAttemptStep', 18530416, $data );
68  }
69 
78  public static function editPageShowEditFormInitial( EditPage $editPage, OutputPage $outputPage ) {
79  if ( $editPage->contentModel !== CONTENT_MODEL_WIKITEXT ) {
80  return;
81  }
82 
83  $article = $editPage->getArticle();
84  $request = $article->getContext()->getRequest();
85 
86  // Add modules if enabled
87  $user = $article->getContext()->getUser();
88  if ( $user->getOption( 'usebetatoolbar' ) ) {
89  $outputPage->addModuleStyles( 'ext.wikiEditor.styles' );
90  $outputPage->addModules( 'ext.wikiEditor' );
91  }
92 
93  // Don't run this if the request was posted - we don't want to log 'init' when the
94  // user just pressed 'Show preview' or 'Show changes', or switched from VE keeping
95  // changes.
96  if ( ExtensionRegistry::getInstance()->isLoaded( 'EventLogging' ) && !$request->wasPosted() ) {
97  $data = [];
98  $data['editing_session_id'] = self::getEditingStatsId();
99  if ( $request->getVal( 'section' ) ) {
100  $data['init_type'] = 'section';
101  } else {
102  $data['init_type'] = 'page';
103  }
104  if ( $request->getHeader( 'Referer' ) ) {
105  if ( $request->getVal( 'section' ) === 'new' || !$article->exists() ) {
106  $data['init_mechanism'] = 'new';
107  } else {
108  $data['init_mechanism'] = 'click';
109  }
110  } else {
111  $data['init_mechanism'] = 'url';
112  }
113 
114  self::doEventLogging( 'init', $article, $data );
115  }
116  }
117 
126  public static function editPageShowEditFormFields( EditPage $editPage, OutputPage $outputPage ) {
127  if ( $editPage->contentModel !== CONTENT_MODEL_WIKITEXT ) {
128  return;
129  }
130 
131  $req = $outputPage->getRequest();
132  $editingStatsId = $req->getVal( 'editingStatsId' );
133  if ( !$editingStatsId || !$req->wasPosted() ) {
134  $editingStatsId = self::getEditingStatsId();
135  }
136 
137  $outputPage->addHTML(
138  Xml::element(
139  'input',
140  [
141  'type' => 'hidden',
142  'name' => 'editingStatsId',
143  'id' => 'editingStatsId',
144  'value' => $editingStatsId
145  ]
146  )
147  );
148  }
149 
158  public static function EditPageBeforeEditToolbar( &$toolbar ) {
159  global $wgUser;
160  if ( $wgUser->getOption( 'usebetatoolbar' ) ) {
161  $toolbar = '';
162  // Return false to signify that the toolbar has been over-written, so
163  // the old toolbar code shouldn't be added to the page.
164  return false;
165  }
166  return true;
167  }
168 
177  public static function getPreferences( $user, &$defaultPreferences ) {
178  // Ideally this key would be 'wikieditor-toolbar'
179  $defaultPreferences['usebetatoolbar'] = [
180  'type' => 'toggle',
181  'label-message' => 'wikieditor-toolbar-preference',
182  'help-message' => 'wikieditor-toolbar-preference-help',
183  'section' => 'editing/editor',
184  ];
185  }
186 
192  public static function getModuleData( ResourceLoaderContext $context, Config $config ) {
193  return [
194  // expose magic words for use by the wikieditor toolbar
195  'magicWords' => self::getMagicWords(),
196  'signature' => self::getSignatureMessage( $context )
197  ];
198  }
199 
205  public static function getModuleDataSummary( ResourceLoaderContext $context, Config $config ) {
206  return [
207  'magicWords' => self::getMagicWords(),
208  'signature' => self::getSignatureMessage( $context, true )
209  ];
210  }
211 
212  private static function getSignatureMessage( MessageLocalizer $ml, $raw = false ) {
213  $msg = $ml->msg( 'sig-text' )->params( '~~~~' )->inContentLanguage();
214  return $raw ? $msg->plain() : $msg->text();
215  }
216 
220  private static function getMagicWords() {
221  $requiredMagicWords = [
222  'redirect',
223  'img_right',
224  'img_left',
225  'img_none',
226  'img_center',
227  'img_thumbnail',
228  'img_framed',
229  'img_frameless',
230  ];
231  $magicWords = [];
232  if ( class_exists( MagicWordFactory::class ) ) {
233  $factory = MediaWikiServices::getInstance()->getMagicWordFactory();
234  }
235  foreach ( $requiredMagicWords as $name ) {
236  if ( class_exists( MagicWordFactory::class ) ) {
237  $magicWords[$name] = $factory->get( $name )->getSynonym( 0 );
238  } else {
239  $magicWords[$name] = MagicWord::get( $name )->getSynonym( 0 );
240  }
241  }
242  return $magicWords;
243  }
244 
249  private static function getEditingStatsId() {
250  if ( !self::$statsId ) {
251  self::$statsId = MWCryptRand::generateHex( 32 );
252  }
253  return self::$statsId;
254  }
255 
261  public static function editPageAttemptSave( EditPage $editPage ) {
262  $article = $editPage->getArticle();
263  $request = $article->getContext()->getRequest();
264  if ( $request->getVal( 'editingStatsId' ) ) {
266  'saveAttempt',
267  $article,
268  [ 'editing_session_id' => $request->getVal( 'editingStatsId' ) ]
269  );
270  }
271  }
272 
279  public static function editPageAttemptSaveAfter( EditPage $editPage, Status $status ) {
280  $article = $editPage->getArticle();
281  $request = $article->getContext()->getRequest();
282  if ( $request->getVal( 'editingStatsId' ) ) {
283  $data = [];
284  $data['editing_session_id'] = $request->getVal( 'editingStatsId' );
285 
286  if ( $status->isOK() ) {
287  $action = 'saveSuccess';
288  } else {
289  $action = 'saveFailure';
290  $errors = $status->getErrorsArray();
291 
292  if ( isset( $errors[0][0] ) ) {
293  $data['save_failure_message'] = $errors[0][0];
294  }
295 
296  if ( $status->value === EditPage::AS_CONFLICT_DETECTED ) {
297  $data['save_failure_type'] = 'editConflict';
298  } elseif ( $status->value === EditPage::AS_ARTICLE_WAS_DELETED ) {
299  $data['save_failure_type'] = 'editPageDeleted';
300  } elseif ( isset( $errors[0][0] ) && $errors[0][0] === 'abusefilter-disallowed' ) {
301  $data['save_failure_type'] = 'extensionAbuseFilter';
302  } elseif ( isset( $editPage->getArticle()->getPage()->ConfirmEdit_ActivateCaptcha ) ) {
303  // TODO: :(
304  $data['save_failure_type'] = 'extensionCaptcha';
305  } elseif ( isset( $errors[0][0] ) && $errors[0][0] === 'spam-blacklisted-link' ) {
306  $data['save_failure_type'] = 'extensionSpamBlacklist';
307  } else {
308  // Catch everything else... We don't seem to get userBadToken or
309  // userNewUser through this hook.
310  $data['save_failure_type'] = 'responseUnknown';
311  }
312  }
313  self::doEventLogging( $action, $article, $data );
314  }
315  }
316 }
ResourceLoaderContext
Context object that contains information about the state of a specific ResourceLoader web request.
Definition: ResourceLoaderContext.php:33
WikiEditorHooks\editPageAttemptSave
static editPageAttemptSave(EditPage $editPage)
This is attached to the MediaWiki 'EditPage::attemptSave' hook.
Definition: WikiEditorHooks.php:261
$magicWords
$magicWords
English (English)
Definition: CategoryTree.i18n.magic.php:12
MagicWord\get
static get( $id)
Factory: creates an object representing an ID.
Definition: MagicWord.php:123
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:117
WikiEditorHooks
Definition: WikiEditorHooks.php:11
$wgVersion
$wgVersion
MediaWiki version number.
Definition: DefaultSettings.php:75
WikiEditorHooks\doEventLogging
static doEventLogging( $action, $article, $data=[])
Log stuff to EventLogging's Schema:EditAttemptStep - see https://meta.wikimedia.org/wiki/Schema:EditA...
Definition: WikiEditorHooks.php:28
WikiEditorHooks\editPageShowEditFormInitial
static editPageShowEditFormInitial(EditPage $editPage, OutputPage $outputPage)
EditPage::showEditForm:initial hook.
Definition: WikiEditorHooks.php:78
CONTENT_MODEL_WIKITEXT
const CONTENT_MODEL_WIKITEXT
Definition: Defines.php:215
WikiEditorHooks\editPageAttemptSaveAfter
static editPageAttemptSaveAfter(EditPage $editPage, Status $status)
This is attached to the MediaWiki 'EditPage::attemptSave:after' hook.
Definition: WikiEditorHooks.php:279
MessageLocalizer
Interface for localizing messages in MediaWiki.
Definition: MessageLocalizer.php:28
Status
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:40
WikiEditorHooks\editPageShowEditFormFields
static editPageShowEditFormFields(EditPage $editPage, OutputPage $outputPage)
EditPage::showEditForm:fields hook.
Definition: WikiEditorHooks.php:126
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:106
Config
Interface for configuration instances.
Definition: Config.php:28
WikiEditorHooks\getModuleDataSummary
static getModuleDataSummary(ResourceLoaderContext $context, Config $config)
Definition: WikiEditorHooks.php:205
MessageLocalizer\msg
msg( $key,... $params)
This is the method for getting translated interface messages.
WikiEditorHooks\getMagicWords
static getMagicWords()
Expose useful magic words which are used by the wikieditor toolbar.
Definition: WikiEditorHooks.php:220
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:41
WikiEditorHooks\EditPageBeforeEditToolbar
static EditPageBeforeEditToolbar(&$toolbar)
EditPageBeforeEditToolbar hook.
Definition: WikiEditorHooks.php:158
EditPage\getArticle
getArticle()
Definition: EditPage.php:501
$title
$title
Definition: testCompression.php:34
WikiEditorHooks\$statsId
static $statsId
Definition: WikiEditorHooks.php:14
MWCryptRand\generateHex
static generateHex( $chars)
Generate a run of cryptographically random data and return it in hexadecimal string format.
Definition: MWCryptRand.php:36
WikiEditorHooks\getModuleData
static getModuleData(ResourceLoaderContext $context, Config $config)
Definition: WikiEditorHooks.php:192
EditPage
The edit page/HTML interface (split from Article) The actual database and text munging is still in Ar...
Definition: EditPage.php:46
WikiEditorHooks\getEditingStatsId
static getEditingStatsId()
Gets a 32 character alphanumeric random string to be used for stats.
Definition: WikiEditorHooks.php:249
$context
$context
Definition: load.php:45
$status
return $status
Definition: SyntaxHighlight.php:347
WikiEditorHooks\getSignatureMessage
static getSignatureMessage(MessageLocalizer $ml, $raw=false)
Definition: WikiEditorHooks.php:212
EditPage\AS_CONFLICT_DETECTED
const AS_CONFLICT_DETECTED
Status: (non-resolvable) edit conflict.
Definition: EditPage.php:122
WikiEditorHooks\getPreferences
static getPreferences( $user, &$defaultPreferences)
GetPreferences hook.
Definition: WikiEditorHooks.php:177
EditPage\AS_ARTICLE_WAS_DELETED
const AS_ARTICLE_WAS_DELETED
Status: article was deleted while editing and param wpRecreate == false or form was not posted.
Definition: EditPage.php:106