Skip to content

Instantly share code, notes, and snippets.

@mmerickel
Forked from frostbtn/readme.md
Created September 1, 2019 14:12
Show Gist options
  • Save mmerickel/35ed0fea37052a6749689cd7742742fa to your computer and use it in GitHub Desktop.
Save mmerickel/35ed0fea37052a6749689cd7742742fa to your computer and use it in GitHub Desktop.
rocket.chat web-hook to post messages silently

This is a Rocket.Chat incoming web hook. Hook gets an array of "messages" and silently creates chat messages directly in the Rocket's database without disturbing users with notifications or alerts - messages just appear in the channels. Messages appear silently even if the user has the channel openned: no refresh or re-enter is required (this is not this script's feature, it's how Rocket works).

This script can post messages to channels and groups by name (if message destination set to #name), or by api roomId (no prefixes in destination). And it can post DM to a user (if destination is set to @username). Please note, in this case DM between message author and destination user must already be created.

This hook expects request.content: ISilentMessage[];

ISilentMessage {
  // Message body.
  text: string;

  // User to set as message author.
  // No leading @, user must be registered.
  author: string;

  // Channel to post message to.
  // It may be "#channeg_or_group_name", "@username", or "room_id".
  // NOTE: in case of "@username", the DM between this user and message
  // author must exists, this script doesn't create one
  // (greatly complicates everything).
  destination: string;

  // An array of message attachments. Optional, may be omitted.
  attachments: [];
}

Pyhton

with requests.sessions.Session() as session:
  session.post(
    'https://CHAT.URL/hooks/WEBHOOK/TOKEN',
    json=[
      {
        'text': 'Multiline\nmessage\nto #channel_by_name',
        'author': 'admin',
        'destination': '#channel_by_name',
      },
      {
        'text': 'Message to abc123abc123abc123 (roomId)',
        'author': 'admin',
        'destination': 'abc123abc123abc123',
      },
      {
        'text': 'DM to user `user` (by username)',
        'author': 'admin',
        'destination': '@user',
      },
      {
        'text': 'Message with attachments to #channel_by_name',
        'author': 'admin',
        'destination': '#channel_by_name',
        'attachments': [
          {
            "title": "Rocket.Chat",
            "title_link": "https://rocket.chat",
            "text": "Rocket.Chat, the best open source chat",
            "image_url": "/images/integration-attachment-example.png",
            "color": "#764FA5"
          }
        ]
      },
    ])

curl

curl -X POST -H 'Content-Type: application/json' \
     --data '[ { "text": "Multiline\\nmessage\\nto #channel_by_name", "author": "admin", "destination": "#channel_by_name" }, { "text": "Message to abc123abc123abc123 (roomId)", "author": "admin", "destination": "abc123abc123abc123" }, { "text": "DM to user `user` (by username)", "author": "admin", "destination": "@user" }]' \
     https://chat.url/hooks/WEBHOOK/TOKEN
class Script {
knownRoomIds = new Map();
knownUserIds = new Map();
process_incoming_request({request}) {
/*
* This hook expects
* request.content: ISilentMessage[];
* ISilentMessage {
* // Message body.
* text: string;
*
* // User to set as message author.
* // No leading @, user must be registered.
* author: string;
*
* // Channel to post message to.
* // It may be "#channeg_or_group_name", "@username", or "room_id".
* // NOTE: in case of "@username", the DM between this user and message
* // author must exists, this script doesn't create one
* // (greatly complicates everything).
* destination: string;
*
* // An array of message attachments. Optional, may be omitted.
* attachments: [];
* }
* */
for (const message of request.content) {
authorId = this.findUser(message.author)
if (!authorId) {
continue;
}
rid = this.findDestination(message.destination, authorId);
if (!rid) {
continue;
}
this.postMessageSilent(
rid, authorId, message.author,
message.text, message.attachments);
}
return {
content: null,
};
}
findDestination(dest, authorId) {
if (this.knownRoomIds.has(dest)) {
return this.knownRoomIds.get(dest);
}
let rid = null;
if (dest[0] === '#') {
const room = Rooms.findOneByName(dest.slice(1));
if (!room) {
return null;
}
rid = room._id;
} else if (dest[0] === '@') {
userId = this.findUser(dest.slice(1), knownUserIds);
if (!userId) {
return null;
}
rid = [authorId, userId].sort().join('');
const room = Rooms.findOneById(rid);
if (!room) {
return null;
}
rid = room._id;
} else {
rid = dest;
}
this.knownRoomIds.set(dest, rid);
return rid;
}
findUser(username) {
if (this.knownUserIds.has(username)) {
return this.knownUserIds.get(username);
}
const user = Users.findOneByUsername(username);
if (!user) {
return null;
}
this.knownUserIds.set(username, user._id);
return user._id;
}
postMessageSilent(rid, authorId, authorName, text, attachments) {
const record = {
t: 'p',
rid: rid,
ts: new Date(),
msg: text,
u: {
_id: authorId,
username: authorName,
},
groupable: false,
unread: true,
};
if (attachments && attachments.length) {
record.attachments = attachments;
}
Messages.insertOrUpsert(record);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment