Skip to content

Instantly share code, notes, and snippets.

@amrav
Created June 20, 2017 01:56
Show Gist options
  • Save amrav/34fed60a4ff62bd23d12afa8637f00df to your computer and use it in GitHub Desktop.
Save amrav/34fed60a4ff62bd23d12afa8637f00df to your computer and use it in GitHub Desktop.

Revisions

  1. amrav created this gist Jun 20, 2017.
    13 changes: 13 additions & 0 deletions LocalSettings.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    # Slack integration
    require_once "$IP/extensions/Slack/Slack.php";

    # Slack extension configuration options
    $wgSlackWebhookURL = "https://hooks.slack.com/services/some-webhook-url"
    $wgSlackUserName = "batman";
    $wgSlackChannel = "#recent-changes";
    $wgSlackIconURL = "http://i.picresize.com/images/2015/09/20/tdpsU.jpg";
    $wgSlackLinkUsers = true;

    # Redis
    $redis = new Redis();
    $redis->pconnect('127.0.0.1');
    209 changes: 209 additions & 0 deletions Slack.hooks.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,209 @@
    <?php
    /**
    * Mediawiki Slack integration extension.
    * @version 1.0.1
    *
    * Copyright (C) 2014-2015 George Goldberg <[email protected]>
    * @author George Goldberg <[email protected]>
    *
    * @license MIT
    *
    * @file The hooks of the Mediawiki Slack integration extension.
    * For more information on Slack, see http://www.slack.com.
    * @ingroup Extensions
    */

    class SlackHooks {

    public static function isCreate() {
    global $wgSlackIsCreate;

    if ($wgSlackIsCreate === true) {
    return true;
    }

    $wgSlackIsCreate = true;
    return false;
    }

    public static function encodeSlackChars($in) {
    // This function encodes chars that the Slack API expects to be encoded in the JSON values.
    // See https://api.slack.com/docs/formatting for details.
    $o = str_replace("&", "&amp;", $in);
    $o = str_replace("<", "&lt;", $o);
    $o = str_replace(">", "&gt;", $o);
    $o = str_replace('"', "&quot;", $o);

    return $o;
    }

    public static function sendToRedis($payload) {
    /*global $wgSlackWebhookURL;
    wfDebug("Slack URL: ".$wgSlackWebhookURL."\n");
    wfDebug("Slack Payload: ".$payload."\n");
    $post = "payload=".urlencode($payload);
    // POST it to Slack.
    $options = array(
    'http' => array(
    'header' => "Content-type: application/x-www-form-urlencoded\r\n",
    'method' => 'POST',
    'content' => $post,
    'timeout' => 0.5, // don't wait for Slack's response
    ),
    ); */

    try {
    global $redis;
    $redis->lPush('slack:recent-changes', $payload);
    } catch (Exception $e) {
    wfDebug('sendToRedis failed: '.$e->getMessage()."\n");
    }

    /*$context = stream_context_create($options);
    $result = file_get_contents($wgSlackWebhookURL, false, $context);
    if (!$result) {
    wfDebug("API call failed!\n");
    } else {
    wfDebug("Slack Result: ".$result."\n");
    }*/
    }

    public static function buildMessage($wikiPage, $user, $summary, $verb) {
    global $wgSlackLinkUsers;

    // Build the message we're going to post to Slack.
    $message = '*<'.SlackHooks::encodeSlackChars($wikiPage->getTitle()->getFullURL())
    .'|'.SlackHooks::encodeSlackChars($wikiPage->getTitle()).'>* '
    .$verb.' by *';
    if ($wgSlackLinkUsers) {
    $message .= '@';
    }
    $message .= SlackHooks::encodeSlackChars(strtolower($user->getName())).'*';
    if (!empty($summary)) {
    $message .= ': '.$summary;
    }
    $message .= '.';

    return $message;
    }

    public static function buildPayload($message) {
    global $wgSlackChannel, $wgSlackLinkUsers, $wgSlackUserName, $wgSlackIconURL;

    // Build the WebHook Payload.
    // NB: The Slack parser chokes if there is a trailing , at the end of the list of items
    // in the payload. Make sure any optional items are in the middle to avoid this.
    $payload = '{"channel": "'.$wgSlackChannel.'",';
    if ($wgSlackLinkUsers) {
    $payload .= '"link_names": "1",';
    }
    if ($wgSlackIconURL) {
    $payload .= '"icon_url": "'.$wgSlackIconURL.'",';
    }
    $payload .= '"username": "'.$wgSlackUserName.'",'
    .'"text": "'.$message.'"'
    .'}';

    return $payload;
    }

    public static function buildRichPayload($wikiPage, $user, $summary, $diff, $verb) {
    global $wgSlackUserName, $wgSlackIconURL, $wgSlackLinkUsers;
    $attachment = array();
    $attachment['fallback'] = sprintf('%s %s by %s', $wikiPage->getTitle(), $verb, strtolower($user->getName()));
    $attachment['title'] = $wikiPage->getTitle()->getFullText();
    $attachment['title_link'] = $wikiPage->getTitle()->GetFullURL();
    if (!empty($summary)) {
    $attachment['fallback'] .= ': '.SlackHooks::encodeSlackChars($summary);
    }
    $attachment['fallback'] .= '.';
    $attachment['pretext'] = SlackHooks::encodeSlackChars($summary);
    $attachment['text'] = $diff;
    $attachment['author_name'] = strtolower($user->getName());
    $attachment['author_link'] = sprintf('https://wiki.metakgp.org/w/User:%s', $user->getName());
    $attachment['color'] = 'good';
    $payload['attachments'] = array($attachment);
    $payload['username'] = $wgSlackUserName;
    $payload['icon_url'] = $wgSlackIconURL;
    $payload['link_names'] = "1";

    return json_encode($payload, JSON_UNESCAPED_SLASHES|JSON_HEX_APOS|JSON_HEX_QUOTE);

    }

    private static function isBot($user) {
    if (in_array("bot", $user->getGroups())) {
    return true;
    }
    return false;
    }

    public static function onPageContentSaveComplete($wikiPage, $user, $content, $summary, $isMinor,
    $isWatch, $section, $flags, $revision, $status, $baseRevId) {
    global $wgSlackIgnoreMinor;

    // If this is a bot, return now
    if (SlackHooks::isBot($user)) {
    return true;
    }

    // If this is a minor edit and we want to ignore minor edits, return now.
    if ($wgSlackIgnoreMinor && $isMinor) {
    return true;
    }

    // If this is a page creation, don't notify it as being modified too.
    if (true === SlackHooks::isCreate()) {
    return true;
    }


    // Build the Slack Message.
    $message = SlackHooks::buildMessage($wikiPage, $user, $summary, "modified");

    //$oldRevision = $revision->getPrevious();


    // Build the Slack Payload.
    //$payload = SlackHooks::buildPayload($wikiPage, $user, $summary, $content->getNativeData(), "modified");

    $payload = SlackHooks::buildPayload($message);

    // Send the message to Slack.
    SlackHooks::sendToRedis($payload);

    return true;
    }

    public static function onPageContentInsertComplete($wikiPage, $user, $content, $summary, $isMinor, $isWatch, $section, $flags, $revision) {
    global $wgSlackIsCreate, $wgSlackIgnoreMinor;

    // If this is a bot, return now
    if (SlackHooks::isBot($user)) {
    return true;
    }
    // If this is a minor edit and we want to ignore minor edits, return now.
    if ($wgSlackIgnoreMinor && $isMinor) {
    return true;
    }

    // Flag this as a page creation so we don't notify it's been modified as well.
    $wgSlackIsCreate = true;

    // Build the Slack Message.
    $message = SlackHooks::buildMessage($wikiPage, $user, $summary, "created");

    // Build the Slack Payload.
    $payload = SlackHooks::buildPayload($message);

    // Send the message to Slack.
    SlackHooks::sendToRedis($payload);

    return true;
    }

    }