Matrix support
This commit is contained in:
+7
-4
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"name": "Matrix",
|
||||
"author": [
|
||||
"[https://github.com/jayktaylor Jayden Bailey]"
|
||||
"[https://github.com/jayktaylor Jayden Bailey]",
|
||||
"[https://git.pvv.ntnu.no/Projects Programvareverkstedet]"
|
||||
],
|
||||
"url": "https://github.com/jayktaylor/mw-matrix",
|
||||
"url": "https://git.pvv.ntnu.no/Projects/mediawiki-matrix-notifs",
|
||||
"version": "1.2",
|
||||
"descriptionmsg": "matrix-desc",
|
||||
"license-name": "MIT",
|
||||
@@ -12,11 +13,13 @@
|
||||
},
|
||||
"manifest_version": 1,
|
||||
"config": {
|
||||
"MatrixWebhookURL": [],
|
||||
"MatrixHomeserverURL": "",
|
||||
"MatrixUser": "",
|
||||
"MatrixPassword": "",
|
||||
"MatrixRooms": [],
|
||||
"MatrixNoBots": true,
|
||||
"MatrixNoMinor": false,
|
||||
"MatrixNoNull": true,
|
||||
"MatrixSuppressPreviews": true,
|
||||
"MatrixMaxChars": null,
|
||||
"MatrixMaxCharsUsernames": 25,
|
||||
"MatrixDisabledHooks": [],
|
||||
|
||||
+20
-20
@@ -111,7 +111,7 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( $msgKey, MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $wikiPage->getTitle(),
|
||||
MatrixUtils::createLink( $wikiPage->getTitle(),
|
||||
$wikiPage->getTitle()->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createRevisionText( $revisionRecord ),
|
||||
( $summary ? ( '`' . MatrixUtils::sanitiseText(
|
||||
@@ -145,7 +145,7 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-page-deleted', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $page->getTitle(),
|
||||
MatrixUtils::createLink( $page->getTitle(),
|
||||
$page->getTitle()->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
( $reason ? ( '`' . MatrixUtils::sanitiseText( MatrixUtils::truncateText( $reason ) ) . '`' ) : '' ),
|
||||
$archivedRevisionCount )->inContentLanguage()->plain();
|
||||
@@ -181,7 +181,7 @@ class MatrixHooks implements
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-page-undeleted', MatrixUtils::createUserLinks( $user ),
|
||||
( $created ? '' : wfMessage( 'matrix-msg-page-undeleted-revs' )->inContentLanguage()->text() ),
|
||||
MatrixUtils::createMarkdownLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
( $reason ? ( '`' . MatrixUtils::sanitiseText(
|
||||
MatrixUtils::truncateText( $reason ) ) . '`' ) : '' ) )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
@@ -210,7 +210,7 @@ class MatrixHooks implements
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-rev-visibility-changed', MatrixUtils::createUserLinks( $user ),
|
||||
count( $visibilityChangeMap ),
|
||||
MatrixUtils::createMarkdownLink( $title,
|
||||
MatrixUtils::createLink( $title,
|
||||
$title->getFullURL( '', false, PROTO_CANONICAL ) ) )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
return true;
|
||||
@@ -237,7 +237,7 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-page-protect', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $wikiPage->getTitle(),
|
||||
MatrixUtils::createLink( $wikiPage->getTitle(),
|
||||
$wikiPage->getTitle()->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
( $reason ? ( '`' . MatrixUtils::sanitiseText( MatrixUtils::truncateText( $reason ) ) . '`' ) : '' ),
|
||||
implode( ", ", $protect ) )->inContentLanguage()->plain();
|
||||
@@ -278,9 +278,9 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-page-moved', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $old,
|
||||
MatrixUtils::createLink( $old,
|
||||
Title::castFromLinkTarget( $old )->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createMarkdownLink( $new,
|
||||
MatrixUtils::createLink( $new,
|
||||
Title::castFromLinkTarget( $new )->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
( $reason ? ( '`' . MatrixUtils::sanitiseText( MatrixUtils::truncateText( $reason ) ) . '`' ) : '' ),
|
||||
MatrixUtils::createRevisionText( $revision ) )->inContentLanguage()->plain();
|
||||
@@ -427,7 +427,7 @@ class MatrixHooks implements
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-file-upload', MatrixUtils::createUserLinks( $user ),
|
||||
( $isNewRevision ? wfMessage( 'matrix-msg-file-upload-new' )->inContentLanguage()->text() : '' ),
|
||||
MatrixUtils::createMarkdownLink( $lf->getName(),
|
||||
MatrixUtils::createLink( $lf->getName(),
|
||||
$lf->getTitle()->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
( $comment ? ( '`' . MatrixUtils::sanitiseText( MatrixUtils::truncateText( $comment ) ) . '`' ) : '' ),
|
||||
MatrixUtils::formatBytes( $lf->getSize() ),
|
||||
@@ -465,7 +465,7 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-file-delete', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $file->getName(),
|
||||
MatrixUtils::createLink( $file->getName(),
|
||||
$file->getTitle()->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
( $reason ? ( '`' . MatrixUtils::sanitiseText(
|
||||
MatrixUtils::truncateText( $reason ) ) . '`' ) : '' ) )->inContentLanguage()->plain();
|
||||
@@ -494,7 +494,7 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-file-undelete', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
( $reason ? ( '`' . MatrixUtils::sanitiseText(
|
||||
MatrixUtils::truncateText( $reason ) ) . '`' ) : '' ) )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
@@ -525,7 +525,7 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-import', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
$revCount, $sRevCount )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
return true;
|
||||
@@ -552,8 +552,8 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-page-merge', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $targetTitle, $targetTitle->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createMarkdownLink( $destTitle,
|
||||
MatrixUtils::createLink( $targetTitle, $targetTitle->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createLink( $destTitle,
|
||||
$destTitle->getFullURL( '', false, PROTO_CANONICAL ) ) )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
return true;
|
||||
@@ -588,8 +588,8 @@ class MatrixHooks implements
|
||||
$revAuthor = MatrixUtils::createUserLinks( $rev->getUser( RevisionRecord::RAW ) );
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-ext-approvedrevs-approved', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createMarkdownLink( $rev_id, $revLink ),
|
||||
MatrixUtils::createLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createLink( $rev_id, $revLink ),
|
||||
$revAuthor )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
return true;
|
||||
@@ -618,7 +618,7 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-ext-approvedrevs-unapproved', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $title,
|
||||
MatrixUtils::createLink( $title,
|
||||
$title->getFullURL( '', false, PROTO_CANONICAL ) ) )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
return true;
|
||||
@@ -655,8 +655,8 @@ class MatrixHooks implements
|
||||
$displayedFile->getUploader() );
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-ext-approvedrevs-approved-file', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createMarkdownLink( 'direct', $displayedFileUrl ),
|
||||
MatrixUtils::createLink( $title, $title->getFullURL( '', false, PROTO_CANONICAL ) ),
|
||||
MatrixUtils::createLink( 'direct', $displayedFileUrl ),
|
||||
MatrixUtils::createUserLinks( $uploader ) )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
return true;
|
||||
@@ -684,7 +684,7 @@ class MatrixHooks implements
|
||||
}
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-ext-approvedrevs-unapproved-file', MatrixUtils::createUserLinks( $user ),
|
||||
MatrixUtils::createMarkdownLink( $title,
|
||||
MatrixUtils::createLink( $title,
|
||||
$title->getFullURL( '', false, PROTO_CANONICAL ) ) )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
return true;
|
||||
@@ -709,7 +709,7 @@ class MatrixHooks implements
|
||||
|
||||
$msg = wfMessage( 'matrix-msg-user-rename', MatrixUtils::createUserLinks( $user ),
|
||||
"*$old*",
|
||||
MatrixUtils::createMarkdownLink( $new,
|
||||
MatrixUtils::createLink( $new,
|
||||
$renamedUserAsTitle->getFullURL( '', false, PROTO_CANONICAL ) ) )->inContentLanguage()->plain();
|
||||
$this->messageSender->sendToMatrix( $hookName, $msg );
|
||||
}
|
||||
|
||||
+209
-43
@@ -8,7 +8,9 @@ use MediaWiki\Http\HttpRequestFactory;
|
||||
use Wikimedia\Http\MultiHttpClient;
|
||||
|
||||
class MatrixMessageSender {
|
||||
public MultiHttpClient $multiHttpClient;
|
||||
private MultiHttpClient $multiHttpClient;
|
||||
private ?string $accessToken = null;
|
||||
private ?string $accessTokenConfigKey = null;
|
||||
|
||||
public function __construct( HttpRequestFactory $httpRequestFactory ) {
|
||||
$this->multiHttpClient = $httpRequestFactory->createMultiClient( [
|
||||
@@ -24,71 +26,235 @@ class MatrixMessageSender {
|
||||
* @return void
|
||||
*/
|
||||
public function sendToMatrix( string $hookName, string $msg ) {
|
||||
global $wgMatrixWebhookURL, $wgMatrixEmojis, $wgMatrixUseEmojis, $wgMatrixPrependTimestamp;
|
||||
global $wgMatrixEmojis, $wgMatrixUseEmojis, $wgMatrixPrependTimestamp;
|
||||
|
||||
if ( !$wgMatrixWebhookURL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$urls = [];
|
||||
|
||||
if ( is_array( $wgMatrixWebhookURL ) ) {
|
||||
$urls = array_merge( $urls, $wgMatrixWebhookURL );
|
||||
} elseif ( is_string( $wgMatrixWebhookURL ) ) {
|
||||
$urls[] = $wgMatrixWebhookURL;
|
||||
} else {
|
||||
wfDebugLog( 'matrix',
|
||||
'The value of $wgMatrixWebhookURL is not valid and therefore no webhooks could be sent.' );
|
||||
$config = $this->getConnectionConfig();
|
||||
if ( $config === null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Strip whitespace to just one space
|
||||
$stripped = preg_replace( '/\s+/', ' ', $msg );
|
||||
$stripped = preg_replace( '/\s+/', ' ', $msg ) ?? $msg;
|
||||
|
||||
if ( $wgMatrixPrependTimestamp ) {
|
||||
$dateString = gmdate( wfMessage( 'matrix-timestampformat' )->inContentLanguage()->text() );
|
||||
$stripped = $dateString . ' ' . $stripped;
|
||||
$dateFormat = str_replace(
|
||||
'**',
|
||||
'',
|
||||
wfMessage( 'matrix-timestampformat' )->inContentLanguage()->text()
|
||||
);
|
||||
$dateString = gmdate( trim( $dateFormat ) );
|
||||
$stripped = trim( $dateString . ' ' . $stripped );
|
||||
}
|
||||
|
||||
if ( $wgMatrixUseEmojis ) {
|
||||
$emoji = $wgMatrixEmojis[$hookName];
|
||||
$stripped = $emoji . ' ' . $stripped;
|
||||
if ( $wgMatrixUseEmojis && isset( $wgMatrixEmojis[$hookName] ) ) {
|
||||
$stripped = $wgMatrixEmojis[$hookName] . ' ' . $stripped;
|
||||
}
|
||||
|
||||
$reqs = [];
|
||||
foreach ( $urls as $url ) {
|
||||
$reqs[] = $this->buildRequest( $url, $stripped );
|
||||
}
|
||||
DeferredUpdates::addCallableUpdate( function () use ( $config, $stripped ) {
|
||||
$accessToken = $this->getAccessToken(
|
||||
$config['homeserverUrl'],
|
||||
$config['user'],
|
||||
$config['password']
|
||||
);
|
||||
|
||||
if ( $accessToken === null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'msgtype' => 'm.text',
|
||||
'body' => MatrixUtils::toPlainText( $stripped ),
|
||||
'format' => 'org.matrix.custom.html',
|
||||
'formatted_body' => MatrixUtils::toMatrixHtml( $stripped ),
|
||||
];
|
||||
|
||||
$reqs = [];
|
||||
foreach ( $config['rooms'] as $room ) {
|
||||
$reqs[] = $this->buildMessageRequest(
|
||||
$config['homeserverUrl'],
|
||||
$room,
|
||||
$accessToken,
|
||||
$payload
|
||||
);
|
||||
}
|
||||
|
||||
DeferredUpdates::addCallableUpdate( function () use ( $reqs ) {
|
||||
try {
|
||||
$this->multiHttpClient->runMulti( $reqs );
|
||||
} catch ( Exception ) {
|
||||
// TODO: better logging
|
||||
$responses = $this->multiHttpClient->runMulti( $reqs );
|
||||
|
||||
foreach ( $responses as $req ) {
|
||||
$response = $req['response'] ?? null;
|
||||
if ( !is_array( $response ) ) {
|
||||
wfDebugLog( 'matrix', 'Matrix send request returned no response.' );
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->logIfRequestFailed(
|
||||
'Failed to send Matrix message to room "' . ( $req['matrixRoom'] ?? 'unknown' ) . '"',
|
||||
$response
|
||||
);
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
wfDebugLog( 'matrix', 'Failed to send Matrix message: ' . $e->getMessage() );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a request for use with MultiHttpClient
|
||||
* @param string $url
|
||||
* @param string $msg
|
||||
* @return array
|
||||
* @return array{homeserverUrl:string,user:string,password:string,rooms:string[]}|null
|
||||
*/
|
||||
private function buildRequest( string $url, string $msg ): array {
|
||||
private function getConnectionConfig(): ?array {
|
||||
global $wgMatrixHomeserverURL, $wgMatrixUser, $wgMatrixPassword, $wgMatrixRooms;
|
||||
|
||||
if ( !is_string( $wgMatrixHomeserverURL ) || trim( $wgMatrixHomeserverURL ) === '' ) {
|
||||
wfDebugLog( 'matrix',
|
||||
'The value of $wgMatrixHomeserverURL is not valid and therefore no messages could be sent.' );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( !is_string( $wgMatrixUser ) || trim( $wgMatrixUser ) === '' ) {
|
||||
wfDebugLog( 'matrix',
|
||||
'The value of $wgMatrixUser is not valid and therefore no messages could be sent.' );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( !is_string( $wgMatrixPassword ) || trim( $wgMatrixPassword ) === '' ) {
|
||||
wfDebugLog( 'matrix',
|
||||
'The value of $wgMatrixPassword is not valid and therefore no messages could be sent.' );
|
||||
return null;
|
||||
}
|
||||
|
||||
$rooms = [];
|
||||
if ( is_array( $wgMatrixRooms ) ) {
|
||||
foreach ( $wgMatrixRooms as $room ) {
|
||||
if ( is_string( $room ) && trim( $room ) !== '' ) {
|
||||
$rooms[] = trim( $room );
|
||||
}
|
||||
}
|
||||
} elseif ( is_string( $wgMatrixRooms ) && trim( $wgMatrixRooms ) !== '' ) {
|
||||
$rooms[] = trim( $wgMatrixRooms );
|
||||
} else {
|
||||
wfDebugLog( 'matrix',
|
||||
'The value of $wgMatrixRooms is not valid and therefore no messages could be sent.' );
|
||||
return null;
|
||||
}
|
||||
|
||||
$rooms = array_values( array_unique( $rooms ) );
|
||||
if ( $rooms === [] ) {
|
||||
wfDebugLog( 'matrix',
|
||||
'The value of $wgMatrixRooms is empty and therefore no messages could be sent.' );
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'homeserverUrl' => rtrim( trim( $wgMatrixHomeserverURL ), '/' ),
|
||||
'user' => trim( $wgMatrixUser ),
|
||||
'password' => $wgMatrixPassword,
|
||||
'rooms' => $rooms,
|
||||
];
|
||||
}
|
||||
|
||||
private function getAccessToken( string $homeserverUrl, string $user, string $password ): ?string {
|
||||
$configKey = md5( $homeserverUrl . "\n" . $user . "\n" . $password );
|
||||
|
||||
if ( $this->accessToken !== null && $this->accessTokenConfigKey === $configKey ) {
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->multiHttpClient->run(
|
||||
$this->buildLoginRequest( $homeserverUrl, $user, $password )
|
||||
);
|
||||
} catch ( Exception $e ) {
|
||||
wfDebugLog( 'matrix', 'Failed to log in to Matrix: ' . $e->getMessage() );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( $this->logIfRequestFailed( 'Failed to log in to Matrix', $response ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$responseBody = $response['body'] ?? '';
|
||||
$data = json_decode( $responseBody, true );
|
||||
|
||||
if ( !is_array( $data ) || !isset( $data['access_token'] ) || !is_string( $data['access_token'] ) ) {
|
||||
wfDebugLog( 'matrix',
|
||||
'Matrix login did not return a valid access_token. Response body: ' . $responseBody );
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->accessToken = $data['access_token'];
|
||||
$this->accessTokenConfigKey = $configKey;
|
||||
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
private function buildLoginRequest( string $homeserverUrl, string $user, string $password ): array {
|
||||
return [
|
||||
'method' => 'POST',
|
||||
'url' => $url,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'mw-matrix/1.2 (github.com/jayktaylor)'
|
||||
],
|
||||
'url' => $homeserverUrl . '/_matrix/client/r0/login',
|
||||
'headers' => $this->getJsonHeaders(),
|
||||
'body' => json_encode( [
|
||||
'content' => $msg,
|
||||
'allowed_mentions' => [
|
||||
'parse' => []
|
||||
]
|
||||
'type' => 'm.login.password',
|
||||
'user' => $user,
|
||||
'password' => $password,
|
||||
] )
|
||||
];
|
||||
}
|
||||
|
||||
private function buildMessageRequest(
|
||||
string $homeserverUrl,
|
||||
string $room,
|
||||
string $accessToken,
|
||||
array $payload
|
||||
): array {
|
||||
return [
|
||||
'method' => 'PUT',
|
||||
'url' => $homeserverUrl . '/_matrix/client/r0/rooms/' .
|
||||
rawurlencode( $room ) . '/send/m.room.message/' . rawurlencode( $this->generateTxnId() ),
|
||||
'query' => [
|
||||
'access_token' => $accessToken,
|
||||
],
|
||||
'headers' => $this->getJsonHeaders(),
|
||||
'body' => json_encode( $payload ),
|
||||
'matrixRoom' => $room,
|
||||
];
|
||||
}
|
||||
|
||||
private function getJsonHeaders(): array {
|
||||
return [
|
||||
'Content-Type' => 'application/json',
|
||||
'User-Agent' => 'mw-matrix (git.pvv.ntnu.no/Projects/mediawiki-matrix-notifs)',
|
||||
];
|
||||
}
|
||||
|
||||
private function generateTxnId(): string {
|
||||
return str_replace( '.', '-', uniqid( 'mw-matrix-', true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context
|
||||
* @param array $response
|
||||
* @return bool True when the request failed
|
||||
*/
|
||||
private function logIfRequestFailed( string $context, array $response ): bool {
|
||||
$code = (int)( $response['code'] ?? 0 );
|
||||
|
||||
if ( $code >= 200 && $code < 300 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$error = $response['error'] ?? '';
|
||||
$reason = $response['reason'] ?? '';
|
||||
$body = $response['body'] ?? '';
|
||||
|
||||
wfDebugLog(
|
||||
'matrix',
|
||||
$context . ': HTTP ' . $code .
|
||||
( $reason !== '' ? ' ' . $reason : '' ) .
|
||||
( $error !== '' ? ' (' . $error . ')' : '' ) .
|
||||
( $body !== '' ? ' ' . $body : '' )
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+72
-11
@@ -64,16 +64,14 @@ class MatrixUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a formatted markdown link based on text and given URL
|
||||
* Creates a formatted link.
|
||||
* @param string $text
|
||||
* @param string $url
|
||||
* @return string
|
||||
*/
|
||||
public static function createMarkdownLink( string $text, string $url ): string {
|
||||
global $wgMatrixSuppressPreviews;
|
||||
|
||||
return "[" . $text . "]" . '(' . ( $wgMatrixSuppressPreviews ? '<' : '' ) .
|
||||
self::encodeURL( $url ) . ( $wgMatrixSuppressPreviews ? '>' : '' ) . ')';
|
||||
public static function createLink( string $text, string $url ): string {
|
||||
return '<a href="' . self::escapeHtml( self::encodeURL( $url ) ) . '">' .
|
||||
self::escapeHtml( $text ) . '</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,16 +99,17 @@ class MatrixUtils {
|
||||
}
|
||||
}
|
||||
|
||||
$userPage = self::createMarkdownLink( $user_abbr, ( $isAnon ? $contribs : $user->getUserPage() )
|
||||
$userPage = self::createLink( $user_abbr, ( $isAnon ? $contribs : $user->getUserPage() )
|
||||
->getFullURL( '', false, PROTO_CANONICAL ) );
|
||||
$userTalk = self::createMarkdownLink( wfMessage( 'matrix-talk' )->inContentLanguage()->text(),
|
||||
$userTalk = self::createLink( wfMessage( 'matrix-talk' )->inContentLanguage()->text(),
|
||||
$user->getTalkPage()->getFullURL( '', false, PROTO_CANONICAL ) );
|
||||
$userContribs = self::createMarkdownLink( wfMessage( 'matrix-contribs' )->inContentLanguage()->text(),
|
||||
$userContribs = self::createLink( wfMessage( 'matrix-contribs' )->inContentLanguage()->text(),
|
||||
$contribs->getFullURL( '', false, PROTO_CANONICAL ) );
|
||||
$text = wfMessage( 'matrix-userlinks', $userPage, $userTalk, $userContribs )->inContentLanguage()->text();
|
||||
} else {
|
||||
// If we were given a string, handle this differently.
|
||||
$text = wfMessage( 'matrix-userlinks', $user, 'n/a', 'n/a' )->inContentLanguage()->text();
|
||||
$text = wfMessage( 'matrix-userlinks', self::escapeHtml( (string)$user ), 'n/a', 'n/a' )
|
||||
->inContentLanguage()->text();
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
@@ -121,7 +120,7 @@ class MatrixUtils {
|
||||
* @return string
|
||||
*/
|
||||
public static function createRevisionText( RevisionRecord $revision ): string {
|
||||
$diff = self::createMarkdownLink( wfMessage( 'matrix-diff' )->inContentLanguage()->text(),
|
||||
$diff = self::createLink( wfMessage( 'matrix-diff' )->inContentLanguage()->text(),
|
||||
Title::newFromLinkTarget( $revision->getPageAsLinkTarget() )->getFullURL(
|
||||
[ 'diff' => 'prev', 'oldid' => $revision->getId() ], false, PROTO_CANONICAL ) );
|
||||
$minor = '';
|
||||
@@ -143,6 +142,60 @@ class MatrixUtils {
|
||||
return wfMessage( 'matrix-revisionlinks', $diff, $minor, $size )->inContentLanguage()->text();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts extension-generated formatting to Matrix HTML.
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public static function toMatrixHtml( string $text ): string {
|
||||
$text = preg_replace_callback(
|
||||
'/\*\*(.+?)\*\*/s',
|
||||
static function ( array $matches ): string {
|
||||
return '<strong>' . self::escapeHtml( $matches[1] ) . '</strong>';
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
$text = preg_replace_callback(
|
||||
'/`([^`]+)`/',
|
||||
static function ( array $matches ): string {
|
||||
return '<code>' . self::escapeHtml( $matches[1] ) . '</code>';
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
$text = preg_replace_callback(
|
||||
'/(?<!\*)\*([^*\n]+)\*(?!\*)/',
|
||||
static function ( array $matches ): string {
|
||||
return '<em>' . self::escapeHtml( $matches[1] ) . '</em>';
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts extension-generated formatting to plain text.
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
public static function toPlainText( string $text ): string {
|
||||
$html = self::toMatrixHtml( $text );
|
||||
$html = preg_replace_callback(
|
||||
'/<a\s+href="([^"]+)">(.+?)<\/a>/s',
|
||||
static function ( array $matches ): string {
|
||||
$label = html_entity_decode( strip_tags( $matches[2] ), ENT_QUOTES | ENT_HTML5, 'UTF-8' );
|
||||
$url = html_entity_decode( $matches[1], ENT_QUOTES | ENT_HTML5, 'UTF-8' );
|
||||
return $label . ': ' . $url;
|
||||
},
|
||||
$html
|
||||
) ?? $html;
|
||||
|
||||
$plain = html_entity_decode( strip_tags( $html ), ENT_QUOTES | ENT_HTML5, 'UTF-8' );
|
||||
return trim( preg_replace( '/\s+/', ' ', $plain ) ?? $plain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip bad characters from a URL
|
||||
* @param string $url
|
||||
@@ -196,4 +249,12 @@ class MatrixUtils {
|
||||
public static function sanitiseText( string $text ): string {
|
||||
return preg_replace( '/([`@])/', '', $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
private static function escapeHtml( string $text ): string {
|
||||
return htmlspecialchars( $text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8' );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user