Compare commits

...

10 Commits

Author SHA1 Message Date
Jayden Bailey c465d89431 Add message about branch no longer being maintained 2021-10-19 14:14:32 +01:00
Jayden Bailey fb7cc8f982 Remove composer.json. I don't use unit tests here. 2021-10-19 14:12:30 +01:00
Jayden Bailey a3edfd227f [backport] Fix bug with preg_replace for username truncating and change truncation to be configurable 2021-05-04 17:31:36 +01:00
Jayden Bailey aae7b02186 Change emojis to be configurable (resolves #25) 2021-05-04 17:30:40 +01:00
Jayden Bailey d9acaa2148 [backport] Sanitise summary/reason text input (closes #13) 2021-05-04 17:30:21 +01:00
Jayden Bailey fb6e0f7755 Update README file 2020-06-12 16:02:35 +01:00
Jayden Bailey 4e17d17de6 Add emojis config option 2020-06-12 16:00:01 +01:00
Jayden Bailey f3b2531380 Support Approved Revs hooks
Closes #24
2020-06-12 15:36:15 +01:00
Jayden Bailey 536a4afe13 Support ArticleMergeComplete hook
Closes #16
2020-06-12 14:22:16 +01:00
Jayden Bailey b3648a462c Use RequestContext instead of wgUser
Closes #9
2019-11-23 11:48:21 +00:00
8 changed files with 303 additions and 61 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018 Jayden Bailey
Copyright (c) 2021 Jayden Bailey
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+12
View File
@@ -1,3 +1,5 @@
> ⚠️ **This branch is no longer maintained.** MediaWiki 1.31 went End-of-Life in September 2021.
# Discord (mw-discord)
MediaWiki extension for sending notifications to a Discord webhook from MediaWiki. When a certain event occurs on your MediaWiki wiki, including new edits, they can be sent as a message to a channel on a Discord server using a webhook.
@@ -48,11 +50,14 @@ This extension can be configured using the `LocalSettings.php` file in your Medi
| `$wgDiscordNoNull` | bool | Do not send notifications for [null edits](https://www.mediawiki.org/wiki/Manual:Purge#Null_edits) | `true`
| `$wgDiscordSuppressPreviews` | bool | Force previews for links in Discord messages to be suppressed | `true`
| `$wgDiscordMaxChars` | int | Maximum amount of characters for user-generated text (e.g summaries, reasons). Set to `null` to disable truncation | `null`
| `$wgDiscordMaxCharsUsernames` | int | Maximum amount of characters for usernames. Set to `null` to disable truncation | `25`
| `$wgDiscordDisabledHooks` | array | List of hooks to disable sending webhooks for (see [below](#hooks-used)) | `[]`
| `$wgDiscordDisabledNS` | array | List of namespaces to disable sending webhooks for | `[]`
| `$wgDiscordDisabledUsers` | array | List of users whose performed actions shouldn't send webhooks | `[]`
| `$wgDiscordPrependTimestamp` | bool | Prepend a timestamp (in UTC) to all sent messages. The format can be changed by editing the MediaWiki message `discord-timestampformat` | `false`
| `$wgDiscordUseFileGetContents` | bool | Use `file_get_contents` instead of cURL. Requires `allow_url_fopen` to be set to true in `php.ini`. Not recommended as cURL makes simultaneous calls instead. | `false`
| `$wgDiscordUseEmojis` | bool | Prepend emojis to different types of messages to help distinguish them | `false`
| `$wgDiscordEmojis` | array | Map of hook names and their associated emojis to prepend to messages if `$wgDiscordUseEmojis` is enabled | See [extension.json](/extension.json)
## Hooks used
- `PageContentSaveComplete` - New edits to pages and page creations
@@ -69,6 +74,13 @@ This extension can be configured using the `LocalSettings.php` file in your Medi
- `FileDeleteComplete` - File revision was deleted
- `FileUndeleteComplete` - File revision was restored
- `AfterImportPage` - Page was imported
- `ArticleMergeComplete` - Article histories was merged
### [Approved Revs](https://www.mediawiki.org/wiki/Extension:Approved_Revs)
- `ApprovedRevsRevisionApproved` - Revision was approved
- `ApprovedRevsRevisionUnapproved` - Revision was unapproved
- `ApprovedRevsFileRevisionApproved` - File revision was approved
- `ApprovedRevsFileRevisionUnapproved` - File revision was unapproved
## Translation
This extension can be translated through the messages in the `ì18n` folder if you're a developer. As a wiki administrator, you may find it a better option to edit the messages on-site in the MediaWiki namespace.
-5
View File
@@ -1,5 +0,0 @@
{
"require": {
"phpunit/phpunit": "4.8.*"
}
}
+31 -3
View File
@@ -4,7 +4,7 @@
"[https://github.com/jaydenkieran Jayden Bailey]"
],
"url": "https://github.com/jaydenkieran/mw-discord",
"version": "1.0.10",
"version": "1.0.12",
"descriptionmsg": "discord-desc",
"license-name": "MIT",
"manifest_version": 1,
@@ -15,11 +15,34 @@
"DiscordNoNull": true,
"DiscordSuppressPreviews": true,
"DiscordMaxChars": null,
"DiscordMaxCharsUsernames": 25,
"DiscordDisabledHooks": [],
"DiscordDisabledNS": [],
"DiscordDisabledUsers": [],
"DiscordPrependTimestamp": false,
"DiscordUseFileGetContents": false
"DiscordUseFileGetContents": false,
"DiscordUseEmojis": false,
"DiscordEmojis": {
"PageContentSaveComplete": ":pencil2:",
"ArticleDeleteComplete": ":wastebasket:",
"ArticleUndelete": ":wastebasket:",
"ArticleRevisionVisibilitySet": ":spy:",
"ArticleProtectComplete": ":lock:",
"TitleMoveComplete": ":truck:",
"LocalUserCreated": ":wave:",
"BlockIpComplete": ":no_entry_sign:",
"UnblockUserComplete": ":no_entry_sign:",
"UserGroupsChanged": ":people_holding_hands:",
"UploadComplete": ":inbox_tray:",
"FileDeleteComplete": ":wastebasket:",
"FileUndeleteComplete": ":wastebasket:",
"AfterImportPage": ":books:",
"ArticleMergeComplete": ":card_box:",
"ApprovedRevsRevisionApproved": ":white_check_mark",
"ApprovedRevsRevisionUnapproved": ":white_check_mark:",
"ApprovedRevsFileRevisionApproved": ":white_check_mark:",
"ApprovedRevsFileRevisionUnapproved": ":white_check_mark:"
}
},
"AutoloadClasses": {
"DiscordHooks": "src/DiscordHooks.php",
@@ -42,6 +65,11 @@
"UploadComplete": "DiscordHooks::onUploadComplete",
"FileDeleteComplete": "DiscordHooks::onFileDeleteComplete",
"FileUndeleteComplete": "DiscordHooks::onFileUndeleteComplete",
"AfterImportPage": "DiscordHooks::onAfterImportPage"
"AfterImportPage": "DiscordHooks::onAfterImportPage",
"ArticleMergeComplete": "DiscordHooks::onArticleMergeComplete",
"ApprovedRevsRevisionApproved": "DiscordHooks::externalonApprovedRevsRevisionApproved",
"ApprovedRevsRevisionUnapproved": "DiscordHooks::externalonApprovedRevsRevisionUnapproved",
"ApprovedRevsFileRevisionApproved": "DiscordHooks::externalonApprovedRevsFileRevisionApproved",
"ApprovedRevsFileRevisionUnapproved": "DiscordHooks::externalonApprovedRevsFileRevisionUnapproved"
}
}
+6 -1
View File
@@ -30,5 +30,10 @@
"discord-filedeletecomplete": "$1 deleted a version of file $2 $3",
"discord-fileundeletecomplete": "$1 restored some versions of file $2 $3",
"discord-afterimportpage": "$1 imported $2 (imported $4/$3 revisions)",
"discord-timestampformat": "**H:i e:**"
"discord-timestampformat": "**H:i e:**",
"discord-articlemergecomplete": "$1 merged revisions from $2 into $3",
"discord-approvedrevsrevisionapproved": "$1 approved a new revision of $2 (revision $3) from user $4",
"discord-approvedrevsrevisionunapproved": "$1 unapproved the approved revision for $2",
"discord-approvedrevsfilerevisionapproved": "$1 approved a new file revision of $2 ($3) from user $4",
"discord-approvedrevsfilerevisionunapproved": "$1 unapproved the approved file revision for $2"
}
+6 -1
View File
@@ -30,5 +30,10 @@
"discord-filedeletecomplete": "Message sent to Discord when a file version is deleted (not an entire file). Parameters:\n$1 - discord-userlinks\n$2 - File link\n$3 - Comment (always surrounded in tildes)",
"discord-fileundeletecomplete": "Message sent to Discord when a file version is restored (not an entire file). Parameters:\n$1 - discord-userlinks\n$2 - File link\n$3 - Comment (always surrounded in tildes)",
"discord-afterimportpage": "Message sent to Discord when a page is imported. Parameters:\n$1 - discord-userlinks\n$2 - Page link\n$3 - Number of revisions in XML file\n$4 - Number of revisions successfully imported",
"discord-timestampformat": "The formatting used in the gmtime() function for displaying the time an event happened in UTC."
"discord-timestampformat": "The formatting used in the gmtime() function for displaying the time an event happened in UTC.",
"discord-articlemergecomplete": "Message sent to Discord when page histories are merged. Parameters:\n$1 - discord-userlinks\n$2 - Target link\n$3 - Destination link",
"discord-approvedrevsrevisionapproved": "Message sent to Discord when a revision is approved (Approved Revs extension). Parameters:\n$1 - discord-userlinks (admin user)\n$2 - Target link\n$3 - Revision link or ID\n$4 - discord-userlinks (revision author) or ID",
"discord-approvedrevsrevisionunapproved": "Message sent to Discord when a revision is unapproved (Approved Revs extension). Parameters:\n$1 - discord-userlinks (admin user)\n$2 - Target link",
"discord-approvedrevsfilerevisionapproved": "Message sent to Discord when a file revision is approved (Approved Revs extension). Parameters:\n$1 - discord-userlinks (admin user)\n$2 - Target link\n$3 - SHA of uploaded file\n$4 - discord-userlinks (revision author)",
"discord-approvedrevsfilerevisionunapproved": "Message sent to Discord when a file revision is unapproved (Approved Revs extension). Parameters:\n$1 - discord-userlinks (admin user)\n$2 - Target link"
}
+219 -47
View File
@@ -12,8 +12,9 @@ class DiscordHooks {
*/
public static function onPageContentSaveComplete( &$wikiPage, &$user, $content, $summary, $isMinor, $isWatch, $section, &$flags, $revision, &$status, $baseRevId, $undidRevId ) {
global $wgDiscordNoBots, $wgDiscordNoMinor, $wgDiscordNoNull;
$hookName = 'PageContentSaveComplete';
if ( DiscordUtils::isDisabled( 'PageContentSaveComplete', $wikiPage->getTitle()->getNamespace(), $user ) ) {
if ( DiscordUtils::isDisabled( $hookName, $wikiPage->getTitle()->getNamespace(), $user ) ) {
return true;
}
@@ -47,8 +48,8 @@ class DiscordHooks {
$msg = wfMessage( $msgKey, DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $wikiPage->getTitle(), $wikiPage->getTitle()->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
DiscordUtils::createRevisionText( $revision ),
( $summary ? ('`' . DiscordUtils::truncateText( $summary ) . '`' ) : '' ) )->plain();
DiscordUtils::handleDiscord($msg);
( $summary ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $summary ) ) . '`' ) : '' ) )->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -58,8 +59,9 @@ class DiscordHooks {
*/
public static function onArticleDeleteComplete( &$article, User &$user, $reason, $id, $content, LogEntry $logEntry, $archivedRevisionCount ) {
global $wgDiscordNoBots;
$hookName = 'ArticleDeleteComplete';
if ( DiscordUtils::isDisabled( 'ArticleDeleteComplete', $article->getTitle()->getNamespace(), $user ) ) {
if ( DiscordUtils::isDisabled( $hookName, $article->getTitle()->getNamespace(), $user ) ) {
return true;
}
@@ -70,9 +72,9 @@ class DiscordHooks {
$msg = wfMessage( 'discord-articledelete', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $article->getTitle(), $article->getTitle()->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ),
( $reason ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $reason ) ) . '`' ) : '' ),
$archivedRevisionCount)->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -81,22 +83,25 @@ class DiscordHooks {
* @see https://www.mediawiki.org/wiki/Manual:Hooks/ArticleUndelete
*/
public static function onArticleUndelete( Title $title, $create, $comment, $oldPageId, $restoredPages ) {
global $wgDiscordNoBots, $wgUser;
global $wgDiscordNoBots;
$hookName = 'ArticleUndelete';
if ( DiscordUtils::isDisabled( 'ArticleUndelete', $title->getNamespace(), $wgUser ) ) {
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( $hookName, $title->getNamespace(), $user ) ) {
return true;
}
if ( $wgDiscordNoBots && $wgUser->isBot() ) {
if ( $wgDiscordNoBots && $user->isBot() ) {
// Don't continue, this is a bot change
return true;
}
$msg = wfMessage( 'discord-articleundelete', DiscordUtils::createUserLinks( $wgUser ),
$msg = wfMessage( 'discord-articleundelete', DiscordUtils::createUserLinks( $user ),
($create ? '' : wfMessage( 'discord-undeleterev' )->text() ),
DiscordUtils::createMarkdownLink( $title, $title->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $comment ? ('`' . DiscordUtils::truncateText( $comment ) . '`' ) : '' ))->plain();
DiscordUtils::handleDiscord($msg);
( $comment ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $comment ) ) . '`' ) : '' ))->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -105,21 +110,24 @@ class DiscordHooks {
* @see https://www.mediawiki.org/wiki/Manual:Hooks/ArticleRevisionVisibilitySet
*/
public static function onArticleRevisionVisibilitySet( &$title, $ids, $visibilityChangeMap ) {
global $wgDiscordNoBots, $wgUser;
global $wgDiscordNoBots;
$hookName = 'ArticleRevisionVisibilitySet';
if ( DiscordUtils::isDisabled( 'ArticleRevisionVisibilitySet', $title->getNamespace(), $wgUser ) ) {
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( $hookName, $title->getNamespace(), $user ) ) {
return true;
}
if ( $wgDiscordNoBots && $wgUser->isBot() ) {
if ( $wgDiscordNoBots && $user->isBot() ) {
// Don't continue, this is a bot change
return true;
}
$msg = wfMessage( 'discord-revvisibility', DiscordUtils::createUserLinks( $wgUser ),
$msg = wfMessage( 'discord-revvisibility', DiscordUtils::createUserLinks( $user ),
count($visibilityChangeMap),
DiscordUtils::createMarkdownLink( $title, $title->getFullUrl( '', '', $proto = PROTO_HTTP ) ) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -129,8 +137,9 @@ class DiscordHooks {
*/
public static function onArticleProtectComplete( &$article, &$user, $protect, $reason ) {
global $wgDiscordNoBots;
$hookName = 'ArticleProtectComplete';
if ( DiscordUtils::isDisabled( 'ArticleProtectComplete', $article->getTitle()->getNamespace(), $user ) ) {
if ( DiscordUtils::isDisabled( $hookName, $article->getTitle()->getNamespace(), $user ) ) {
return true;
}
@@ -141,9 +150,9 @@ class DiscordHooks {
$msg = wfMessage( 'discord-articleprotect', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $article->getTitle(), $article->getTitle()->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ),
( $reason ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $reason ) ) . '`' ) : '' ),
implode(", ", $protect) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -153,8 +162,9 @@ class DiscordHooks {
*/
public static function onTitleMoveComplete( Title &$title, Title &$newTitle, User $user, $oldid, $newid, $reason, Revision $revision ) {
global $wgDiscordNoBots;
$hookName = 'TitleMoveComplete';
if ( DiscordUtils::isDisabled( 'TitleMoveComplete', $title->getNamespace(), $user ) ) {
if ( DiscordUtils::isDisabled( $hookName, $title->getNamespace(), $user ) ) {
return true;
}
@@ -166,9 +176,9 @@ class DiscordHooks {
$msg = wfMessage( 'discord-titlemove', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $title, $title->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
DiscordUtils::createMarkdownLink( $newTitle, $newTitle->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ),
( $reason ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $reason ) ) . '`' ) : '' ),
DiscordUtils::createRevisionText( $revision ) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -177,12 +187,14 @@ class DiscordHooks {
* @see https://www.mediawiki.org/wiki/Manual:Hooks/LocalUserCreated
*/
public static function onLocalUserCreated( $user, $autocreated ) {
if ( DiscordUtils::isDisabled( 'LocalUserCreated', NULL, $user ) ) {
$hookName = 'LocalUserCreated';
if ( DiscordUtils::isDisabled( $hookName, NULL, $user ) ) {
return true;
}
$msg = wfMessage( 'discord-localusercreated', DiscordUtils::createUserLinks( $user ) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -191,7 +203,9 @@ class DiscordHooks {
* @see https://www.mediawiki.org/wiki/Manual:Hooks/BlockIpComplete
*/
public static function onBlockIpComplete( Block $block, User $user ) {
if ( DiscordUtils::isDisabled( 'BlockIpComplete', NULL, $user ) ) {
$hookName = 'BlockIpComplete';
if ( DiscordUtils::isDisabled( $hookName, NULL, $user ) ) {
return true;
}
@@ -203,9 +217,9 @@ class DiscordHooks {
}
$msg = wfMessage( 'discord-blockipcomplete', DiscordUtils::createUserLinks( $user ), DiscordUtils::createUserLinks( $block->getTarget() ),
( $block->mReason ? ('`' . DiscordUtils::truncateText( $block->mReason ) . '`' ) : '' ),
( $block->mReason ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $block->mReason ) ) . '`' ) : '' ),
$expiryMsg )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -214,12 +228,14 @@ class DiscordHooks {
* @see https://www.mediawiki.org/wiki/Manual:Hooks/UnblockUserComplete
*/
public static function onUnblockUserComplete( Block $block, User $user ) {
if ( DiscordUtils::isDisabled( 'UnblockUserComplete', NULL, $user ) ) {
$hookName = 'UnblockUserComplete';
if ( DiscordUtils::isDisabled( $hookName, NULL, $user ) ) {
return true;
}
$msg = wfMessage( 'discord-unblockusercomplete', DiscordUtils::createUserLinks( $user ), DiscordUtils::createUserLinks( $block->getTarget() ) )->text();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -228,7 +244,9 @@ class DiscordHooks {
* @see https://www.mediawiki.org/wiki/Manual:Hooks/UserGroupsChanged
*/
public static function onUserGroupsChanged( User $user, array $added, array $removed, $performer, $reason ) {
if ( DiscordUtils::isDisabled( 'UserGroupsChanged', NULL, $performer ) ) {
$hookName = 'UserGroupsChanged';
if ( DiscordUtils::isDisabled( $hookName, NULL, $performer ) ) {
return true;
}
@@ -239,10 +257,10 @@ class DiscordHooks {
$msg = wfMessage( 'discord-usergroupschanged', DiscordUtils::createUserLinks( $performer ),
DiscordUtils::createUserLinks( $user ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ),
( $reason ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $reason ) ) . '`' ) : '' ),
( ( count($added) > 0 ) ? ( '+ ' . join(', ', $added) ) : ''),
( ( count($removed) > 0 ) ? ( '- ' . join(', ', $removed) ) : '' ) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -252,11 +270,12 @@ class DiscordHooks {
*/
public static function onUploadComplete( &$image ) {
global $wgDiscordNoBots;
$hookName = 'UploadComplete';
$lf = $image->getLocalFile();
$user = $lf->getUser( $type = 'object' ); // only supported in MW 1.31+
if ( DiscordUtils::isDisabled( 'UploadComplete', NS_FILE, $user ) ) {
if ( DiscordUtils::isDisabled( $hookName, NS_FILE, $user ) ) {
return true;
}
@@ -271,12 +290,12 @@ class DiscordHooks {
$msg = wfMessage( 'discord-uploadcomplete', DiscordUtils::createUserLinks( $user ),
( $isNewRevision ? wfMessage( 'discord-uploadnewver' )->text() : '' ),
DiscordUtils::createMarkdownLink( $lf->getName(), $lf->getTitle()->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $comment ? ('`' . DiscordUtils::truncateText( $comment ) . '`' ) : '' ),
( $comment ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $comment ) ) . '`' ) : '' ),
DiscordUtils::formatBytes($lf->getSize()),
$lf->getWidth(),
$lf->getHeight(),
$lf->getMimeType() )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -286,8 +305,9 @@ class DiscordHooks {
*/
public static function onFileDeleteComplete( $file, $oldimage, $article, $user, $reason ) {
global $wgDiscordNoBots;
$hookName = 'FileDeleteComplete';
if ( DiscordUtils::isDisabled( 'FileDeleteComplete', NS_FILE, $user ) ) {
if ( DiscordUtils::isDisabled( $hookName, NS_FILE, $user ) ) {
return true;
}
@@ -303,8 +323,8 @@ class DiscordHooks {
$msg = wfMessage( 'discord-filedeletecomplete', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $file->getName(), $file->getTitle()->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ) )->plain();
DiscordUtils::handleDiscord($msg);
( $reason ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $reason ) ) . '`' ) : '' ) )->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -314,8 +334,9 @@ class DiscordHooks {
*/
public static function onFileUndeleteComplete( $title, $fileVersions, $user, $reason ) {
global $wgDiscordNoBots;
$hookName = 'FileUndeleteComplete';
if ( DiscordUtils::isDisabled( 'FileUndeleteComplete', NS_FILE, $user ) ) {
if ( DiscordUtils::isDisabled( $hookName, NS_FILE, $user ) ) {
return true;
}
@@ -326,8 +347,8 @@ class DiscordHooks {
$msg = wfMessage( 'discord-fileundeletecomplete', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $title, $title->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ) )->plain();
DiscordUtils::handleDiscord($msg);
( $reason ? ('`' . DiscordUtils::sanitiseText( DiscordUtils::truncateText( $reason ) ) . '`' ) : '' ) )->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
@@ -336,21 +357,172 @@ class DiscordHooks {
* @see https://www.mediawiki.org/wiki/Manual:Hooks/AfterImportPage
*/
public static function onAfterImportPage( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) {
global $wgDiscordNoBots, $wgUser;
global $wgDiscordNoBots;
$hookName = 'AfterImportPage';
if ( DiscordUtils::isDisabled( 'AfterImportPage', $title->getNamespace(), $wgUser ) ) {
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( $hookName, $title->getNamespace(), $user ) ) {
return true;
}
if ( $wgDiscordNoBots && $wgUser->isBot() ) {
if ( $wgDiscordNoBots && $user->isBot() ) {
// Don't continue, this is a bot
return true;
}
$msg = wfMessage( 'discord-afterimportpage', DiscordUtils::createUserLinks( $wgUser ),
$msg = wfMessage( 'discord-afterimportpage', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $title, $title->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
$revCount, $sRevCount)->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
public static function onArticleMergeComplete( $targetTitle, $destTitle ) {
global $wgDiscordNoBots;
$hookName = 'ArticleMergeComplete';
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( $hookName, $destTitle->getNamespace(), $user ) ) {
return true;
}
if ( $wgDiscordNoBots && $user->isBot() ) {
// Don't continue, this is a bot
return true;
}
$msg = wfMessage( 'discord-articlemergecomplete', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $targetTitle, $targetTitle->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
DiscordUtils::createMarkdownLink( $destTitle, $destTitle->getFullUrl( '', '', $proto = PROTO_HTTP ) ))->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
/**
* Called when a revision is approved (Approved Revs extension)
* @see https://github.com/wikimedia/mediawiki-extensions-ApprovedRevs/blob/REL1_34/includes/ApprovedRevs_body.php
*/
public static function externalonApprovedRevsRevisionApproved ( $output, $title, $rev_id, $content ) {
global $wgDiscordNoBots;
$hookName = 'ApprovedRevsRevisionApproved';
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( $hookName, $title->getNamespace(), $user ) ) {
return true;
}
if ( $wgDiscordNoBots && $user->isBot() ) {
// Don't continue, this is a bot
return true;
}
// Get the revision being approved here
$rev = Revision::newFromTitle( $title, $rev_id );
$revLink = $title->getFullURL( array( 'oldid' => $rev_id ), '', $proto = PROTO_HTTP );
$revAuthor = $rev->getUser( Revision::RAW );
if ($revAuthor === 0) {
$revAuthor = DiscordUtils::createUserLinks( User::newFromName($rev->getUserText(), false) );
} else if ($revAuthor) {
$revAuthor = DiscordUtils::createUserLinks( User::newFromId($revAuthor) );
}
$msg = wfMessage( 'discord-approvedrevsrevisionapproved', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $title, $title->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
DiscordUtils::createMarkdownLink( $rev_id, $revLink ),
$revAuthor)->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
/**
* Called when a revision is unapproved (Approved Revs extension)
* @see https://github.com/wikimedia/mediawiki-extensions-ApprovedRevs/blob/REL1_34/includes/ApprovedRevs_body.php
*/
public static function externalonApprovedRevsRevisionUnapproved ( $output, $title, $content ) {
global $wgDiscordNoBots;
$hookName = 'ApprovedRevsRevisionUnapproved';
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( $hookName, $title->getNamespace(), $user ) ) {
return true;
}
if ( $wgDiscordNoBots && $user->isBot() ) {
// Don't continue, this is a bot
return true;
}
$msg = wfMessage( 'discord-approvedrevsrevisionunapproved', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $title, $title->getFullUrl( '', '', $proto = PROTO_HTTP ) ))->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
/**
* Called when a file is approved (Approved Revs extension)
* @see https://github.com/wikimedia/mediawiki-extensions-ApprovedRevs/blob/REL1_34/includes/ApprovedRevs_body.php
*/
public static function externalonApprovedRevsFileRevisionApproved ( $parser, $title, $timestamp, $sha1 ) {
global $wgDiscordNoBots;
$hookName = 'ApprovedRevsFileRevisionApproved';
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( $hookName, $title->getNamespace(), $user ) ) {
return true;
}
if ( $wgDiscordNoBots && $user->isBot() ) {
// Don't continue, this is a bot
return true;
}
$imagepage = ImagePage::newFromID( $title->getArticleID() );
$displayedFile = $imagepage->getDisplayedFile();
$displayedFileUrl = $displayedFile->getCanonicalUrl(); // getFullURL doesn't work quite the same on File classes
$uploader = $displayedFile->getUser();
if (is_string($uploader)) {
$uploader = User::newFromName($uploader, false);
} else {
$uploader = User::newFromId($uploader);
}
$msg = wfMessage( 'discord-approvedrevsfilerevisionapproved', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $title, $title->getFullURL('', '', $proto = PROTO_HTTP) ),
DiscordUtils::createMarkdownLink( 'direct', $displayedFileUrl ),
DiscordUtils::createUserLinks( $uploader ) )->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
/**
* Called when a file is unapproved (Approved Revs extension)
* @see https://github.com/wikimedia/mediawiki-extensions-ApprovedRevs/blob/REL1_34/includes/ApprovedRevs_body.php
*/
public static function externalonApprovedRevsFileRevisionUnapproved ( $parser, $title ) {
global $wgDiscordNoBots;
$hookName = 'ApprovedRevsFileRevisionUnapproved';
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( $hookName, $title->getNamespace(), $user ) ) {
return true;
}
if ( $wgDiscordNoBots && $user->isBot() ) {
// Don't continue, this is a bot
return true;
}
$msg = wfMessage( 'discord-approvedrevsfilerevisionunapproved', DiscordUtils::createUserLinks( $user ),
DiscordUtils::createMarkdownLink( $title, $title->getFullUrl( '', '', $proto = PROTO_HTTP ) ))->plain();
DiscordUtils::handleDiscord($hookName, $msg);
return true;
}
}
+28 -3
View File
@@ -45,8 +45,8 @@ class DiscordUtils {
/**
* Handles sending a webhook to Discord using cURL
*/
public static function handleDiscord ($msg) {
global $wgDiscordWebhookURL, $wgDiscordPrependTimestamp, $wgDiscordUseFileGetContents;
public static function handleDiscord ($hookName, $msg) {
global $wgDiscordWebhookURL, $wgDiscordEmojis, $wgDiscordUseEmojis, $wgDiscordPrependTimestamp, $wgDiscordUseFileGetContents;
if ( !$wgDiscordWebhookURL ) {
// There's nothing in here, so we won't do anything
@@ -73,6 +73,12 @@ class DiscordUtils {
$stripped = $dateString . ' ' . $stripped;
}
if ( $wgDiscordUseEmojis ) {
// Add emoji
$emoji = $wgDiscordEmojis[$hookName];
$stripped = $emoji . ' ' . $stripped;
}
DeferredUpdates::addCallableUpdate( function() use ( $stripped, $urls, $wgDiscordUseFileGetContents ) {
$user_agent = 'mw-discord/1.0 (github.com/jaydenkieran)';
$json_data = [ 'content' => "$stripped" ];
@@ -149,11 +155,21 @@ class DiscordUtils {
* Creates links for a specific MediaWiki User object
*/
public static function createUserLinks ($user) {
global $wgDiscordMaxCharsUsernames;
if ( $user instanceof User ) {
$isAnon = $user->isAnon();
$contribs = Title::newFromText("Special:Contributions/" . $user);
$userPage = DiscordUtils::createMarkdownLink( $user, ( $isAnon ? $contribs : $user->getUserPage() )->getFullUrl( '', '', $proto = PROTO_HTTP ) );
if ($wgDiscordMaxCharsUsernames) {
$user_abbr = strval($user);
if (strlen($user_abbr) > $wgDiscordMaxCharsUsernames) {
$user_abbr = substr($user_abbr, 0, $wgDiscordMaxCharsUsernames);
$user_abbr = $user_abbr.'...';
}
}
$userPage = DiscordUtils::createMarkdownLink( $user_abbr, ( $isAnon ? $contribs : $user->getUserPage() )->getFullUrl( '', '', $proto = PROTO_HTTP ) );
$userTalk = DiscordUtils::createMarkdownLink( wfMessage( 'discord-talk' )->text(), $user->getTalkPage()->getFullUrl( '', '', $proto = PROTO_HTTP ) );
$userContribs = DiscordUtils::createMarkdownLink( wfMessage( 'discord-contribs' )->text(), $contribs->getFullURL( '', '', $proto = PROTO_HTTP ) );
$text = wfMessage( 'discord-userlinks', $userPage, $userTalk, $userContribs )->text();
@@ -230,6 +246,15 @@ class DiscordUtils {
}
return $text;
}
/**
* Sanitise text input, including removing the potential for abuse
* of Discord's @everyone and @here pings
*/
public static function sanitiseText($text) {
$text = preg_replace('/(`|@)/', '', $text);
return $text;
}
}
?>