Compare commits

..

5 Commits

Author SHA1 Message Date
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
6 changed files with 211 additions and 33 deletions
+8
View File
@@ -53,6 +53,7 @@ This extension can be configured using the `LocalSettings.php` file in your Medi
| `$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`
## Hooks used
- `PageContentSaveComplete` - New edits to pages and page creations
@@ -69,6 +70,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.
+9 -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,
@@ -19,7 +19,8 @@
"DiscordDisabledNS": [],
"DiscordDisabledUsers": [],
"DiscordPrependTimestamp": false,
"DiscordUseFileGetContents": false
"DiscordUseFileGetContents": false,
"DiscordUseEmojis": false
},
"AutoloadClasses": {
"DiscordHooks": "src/DiscordHooks.php",
@@ -42,6 +43,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"
}
+175 -26
View File
@@ -48,7 +48,7 @@ class DiscordHooks {
DiscordUtils::createMarkdownLink( $wikiPage->getTitle(), $wikiPage->getTitle()->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
DiscordUtils::createRevisionText( $revision ),
( $summary ? ('`' . DiscordUtils::truncateText( $summary ) . '`' ) : '' ) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':pencil2:', $msg);
return true;
}
@@ -72,7 +72,7 @@ class DiscordHooks {
DiscordUtils::createMarkdownLink( $article->getTitle(), $article->getTitle()->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ),
$archivedRevisionCount)->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':wastebasket:', $msg);
return true;
}
@@ -81,22 +81,24 @@ 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;
if ( DiscordUtils::isDisabled( 'ArticleUndelete', $title->getNamespace(), $wgUser ) ) {
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( 'ArticleUndelete', $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);
DiscordUtils::handleDiscord(':wastebasket:', $msg);
return true;
}
@@ -105,21 +107,23 @@ class DiscordHooks {
* @see https://www.mediawiki.org/wiki/Manual:Hooks/ArticleRevisionVisibilitySet
*/
public static function onArticleRevisionVisibilitySet( &$title, $ids, $visibilityChangeMap ) {
global $wgDiscordNoBots, $wgUser;
global $wgDiscordNoBots;
if ( DiscordUtils::isDisabled( 'ArticleRevisionVisibilitySet', $title->getNamespace(), $wgUser ) ) {
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( 'ArticleRevisionVisibilitySet', $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(':spy:', $msg);
return true;
}
@@ -143,7 +147,7 @@ class DiscordHooks {
DiscordUtils::createMarkdownLink( $article->getTitle(), $article->getTitle()->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ),
implode(", ", $protect) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':lock:', $msg);
return true;
}
@@ -168,7 +172,7 @@ class DiscordHooks {
DiscordUtils::createMarkdownLink( $newTitle, $newTitle->getFullUrl( '', '', $proto = PROTO_HTTP ) ),
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ),
DiscordUtils::createRevisionText( $revision ) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':truck:', $msg);
return true;
}
@@ -182,7 +186,7 @@ class DiscordHooks {
}
$msg = wfMessage( 'discord-localusercreated', DiscordUtils::createUserLinks( $user ) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':wave:', $msg);
return true;
}
@@ -205,7 +209,7 @@ class DiscordHooks {
$msg = wfMessage( 'discord-blockipcomplete', DiscordUtils::createUserLinks( $user ), DiscordUtils::createUserLinks( $block->getTarget() ),
( $block->mReason ? ('`' . DiscordUtils::truncateText( $block->mReason ) . '`' ) : '' ),
$expiryMsg )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':no_entry_sign:', $msg);
return true;
}
@@ -219,7 +223,7 @@ class DiscordHooks {
}
$msg = wfMessage( 'discord-unblockusercomplete', DiscordUtils::createUserLinks( $user ), DiscordUtils::createUserLinks( $block->getTarget() ) )->text();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':no_entry_sign:', $msg);
return true;
}
@@ -242,7 +246,7 @@ class DiscordHooks {
( $reason ? ('`' . DiscordUtils::truncateText( $reason ) . '`' ) : '' ),
( ( count($added) > 0 ) ? ( '+ ' . join(', ', $added) ) : ''),
( ( count($removed) > 0 ) ? ( '- ' . join(', ', $removed) ) : '' ) )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':people_holding_hands:', $msg);
return true;
}
@@ -276,7 +280,7 @@ class DiscordHooks {
$lf->getWidth(),
$lf->getHeight(),
$lf->getMimeType() )->plain();
DiscordUtils::handleDiscord($msg);
DiscordUtils::handleDiscord(':inbox_tray:', $msg);
return true;
}
@@ -304,7 +308,7 @@ 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);
DiscordUtils::handleDiscord(':wastebasket:', $msg);
return true;
}
@@ -327,7 +331,7 @@ 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);
DiscordUtils::handleDiscord(':wastebasket:', $msg);
return true;
}
@@ -336,21 +340,166 @@ 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;
if ( DiscordUtils::isDisabled( 'AfterImportPage', $title->getNamespace(), $wgUser ) ) {
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( 'AfterImportPage', $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(':books:', $msg);
return true;
}
public static function onArticleMergeComplete( $targetTitle, $destTitle ) {
global $wgDiscordNoBots;
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( 'ArticleMergeComplete', $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(':card_box:', $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;
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( 'ApprovedRevsRevisionApproved', $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(':white_check_mark:', $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;
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( 'ApprovedRevsRevisionUnapproved', $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(':white_check_mark:', $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;
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( 'ApprovedRevsFileRevisionApproved', $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(':white_check_mark:', $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;
$user = RequestContext::getMain()->getUser();
if ( DiscordUtils::isDisabled( 'ApprovedRevsFileRevisionUnapproved', $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(':white_check_mark:', $msg);
return true;
}
}
+7 -2
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 ($emoji, $msg) {
global $wgDiscordWebhookURL, $wgDiscordUseEmojis, $wgDiscordPrependTimestamp, $wgDiscordUseFileGetContents;
if ( !$wgDiscordWebhookURL ) {
// There's nothing in here, so we won't do anything
@@ -73,6 +73,11 @@ class DiscordUtils {
$stripped = $dateString . ' ' . $stripped;
}
if ( $wgDiscordUseEmojis ) {
// Add emoji
$stripped = $emoji . ' ' . $stripped;
}
DeferredUpdates::addCallableUpdate( function() use ( $stripped, $urls, $wgDiscordUseFileGetContents ) {
$user_agent = 'mw-discord/1.0 (github.com/jaydenkieran)';
$json_data = [ 'content' => "$stripped" ];