I’ve been helping my husband with his project lately. I’m building small scripts that collect data, process it and send it to RocketChat as notifications.

We are using self hosted RocketChat, with the help of a good friend.

Short story

My husband has an education project, around how to make informed investments in Bucharest Stocks Market.

Currently there are about 400 users in the community, from which maybe around 20 are actively contributing in the RocketChat group channels.

A while ago we had a discussion and we did a brainstorming of how we could improve collaboration in the community my husband is building.

In order to facilitate and help members to know each other and share ideas we would need an environment for them to socialize.

Inspired by Donut I started to look for something similar for RocketChat. I did not find something similar.

I started to look for how this can be implemented as RocketChat has a powerful API on which I already used successfully for other scripts in combination with GitLab CI/CD

Proposal

Steps for implementing a Coffee Chat Bot:

  • On a weekly base get all members of a given channel.
  • Match the members in pairs.
  • Send each member a private message from the coffee-chat bot to inform about the person to have a chat with the current week.
  • Send a message in the coffee channel to summarize how many coffee chat were set that week.
  • Consider the odd case of number of members, in our case we choose to have a fallback user which will be removed from the list.
  • Remove the coffee-chat bot user from the members list.
  • Set up the CI/CD scheduled job in GitLab.

Using rocketchat-ruby gem

I’ve been already using successfully rocketchat-ruby gem for a couple of small projects, many thanks to the author Andrew Bromwich.

For the Coffee Chat Bot I need the list of members for a given channel. There is no API currently so I had to add my own method.

I opend an issue to contribute to the gem with adding this method. Meanwhile the method lives under the Rocket::Channel class.

module Rocket
  class Channel < RocketChat::Messages::Channel
    def members(offset: nil, count: nil,  sort: nil, fields: nil, query: {})
      response = session.request_json(
        "/api/v1/channels.members",
        body: build_list_body(offset, count, sort, fields, query).merge(coffee_channel_params(query))
      )
 
      response['members'].map { |hash| RocketChat::User.new hash } if response['success']
    end
 
    private
 
    def coffee_channel_params(query)
      room_params(query[:room_id],query[:room_name])
    end
  end
end

Later using the members method we can get the full list of members of a given channel, shuffle and pair it.

# coffee.rb
require 'rocketchat'
require_relative 'lib/rocket/channel' 
 
ROCKET_LOGIN    = ARGV[0]
ROCKET_PASSWORD = ARGV[1]
ROCKET_CHANNEL  = ARGV[2]
ROCKET_URL      = ARGV[3] 
FALLBACK_USER   = ARGV[4] 
 
rocket_server = RocketChat::Server.new(ROCKET_URL)
 
session = rocket_server.login(ROCKET_LOGIN, ROCKET_PASSWORD)
channel = Rocket::Channel.new(session)
 
members = channel.members(offset: offset, count: count, query: { room_name: ROCKET_CHANNEL })
 
# Remove the bot user
members.reject!{ |member| member.username == ROCKET_LOGIN}
 
# Remove the fallback user in case of odd number of members 
# in order to avoid matching with nil
if members.size.odd? 
  members.reject!{ |member| member.username == FALLBACK_USER }
End
 
shuffled = members.shuffle.each_slice(2).to_a
 
shuffled.each do |member1, member2|
  session.chat.post_message(room_id: member1.id, text: "Hello, @#{member1.username}! Your coffee-chat partner for this week is @{member2.username}#")
  session.chat.post_message(room_id: member2.id, text:  "Hello, @#{member2.username}! Your coffee-chat partner for this week is @{member1.username}#")
end
 
# Post summary message in coffee-chat channel 
session.chat.post_message(room_id: ROCKET_CHANNEL, text: "There were #{shuffled.size} coffee-chats set up this week")

Use of this would be

ruby coffee.rb 'coffee.bot.username' 'coffeebotpass' coffee-chat-channel https://your.rocketchat.url/ fallback.username

This will take all members in coffee-chat-channel shuffle them, match them into pairs and remove if necessary the fallback username and the coffee.bot.username

Setting up a scheduled job in GitLab

Add the gitlab-ci.yml file to your repo with job:on-schedule:

default:
  image: ruby:2.7.2
  before_script:
    - apt-get update 
    - ruby -v
    - which ruby
    - gem install bundler --no-document
    - bundle install --jobs $(nproc) "${FLAGS[@]}"
job:on-schedule:
  only:
    - schedules
  script:
  - > 
    ruby coffee.rb $ROCKET_LOGIN $ROCKET_PASSWORD $ROCKET_CHANNEL $ROCKET_URL $FALLBACK_USER;
  artifacts:
    paths:
      - public

From the Menu: CI/CD -> Schedules -> New Schedule create a new schedule

Add the ENV vars $ROCKET_LOGIN $ROCKET_PASSWORD $ROCKET_CHANNEL $ROCKET_URL $FALLBACK_USER;

Good to know

  • coffee.bot.username should be a RocketChat bot user, not special permissions needed.
  • coffee.bot.username should be member of the coffee-chat-channel channel.
  • I have used a public channel as a coffee-chat-channel` channel.
  • You might want to have a test channel to test first if the script is behaving as intended.
  • As I have multiple custom integrations I build for RocketChat I prefer to have separte bot users.

Toughts

Using GitLab for these simple tasks is so easy and free. I have a couple of more examples to share with you in future.

I used ruby as it is the programming language I’m most familiar with and I use it on a daily basis. The same result can be achived in other programming languages or using shell scripting(I might try this too).

Reach out on my email, happy to help setting up your own coffee-chat bot and answer to your questions.

🐞Stay safe and be kind!🐞

💜Alina