Create a Slack Bot to Interact with Your Wiki
Wiki platforms have been the “go to” tool for many teams. They are also used by many an open source projects as a communication and organization medium.
In the last few years Slack has come to the stage of tools used by many companies. It’s key goal being effective communication between the members of a team. Besides chat, Slack also offers apps which let you easily connect to other services, such as Trello, MailChimp, Blue Jeans, etc. But app integration is not the only feature Slack has to offer. Today we will look at something different. Bots in chat applications aren’t a new thing, they date back to the IRC days where we would have bots that took care of different things, like chat misbehavior, weather forecast, games, etc. The same concepts apply in Slack.
In this article we will work on a wiki bot. Your team could use some help from a bot here and there sometimes, right?
The wiki platform that we will use is MediaWiki. Mediawiki is an open source wiki package which originally began on Wikipedia. It is one of the most used wiki systems.
Setup
We are going to use two main Ruby gems in this tutorial: media-wiki-api and slack-ruby-bot. We also want our bot to live somewhere, so let’s use the Sinatra framework and host our bot on Heroku.
Start by creating a directory named slack-wikibot, and inside it create two Ruby files, called slack-wikibot.rb and Gemfile. In the Gemfile, add:
Gemfile:
source 'http://rubygems.org'
gem 'slack-ruby-bot'
gem 'celluloid-io'
gem 'puma'
gem 'sinatra'
gem 'dotenv'
gem 'mediawiki_api'
Let’s run bundle install to have these gems installed:
bundle install
Create another directory with the same name (slack-wikibot) and inside that directory create a Ruby file with the name bot.rb. The bot.rb file looks like:
bot.rb:
module SlackWikibot
class Bot < SlackRubyBot::Bot
end
end
Create a web.rb file that will hold our web application and make it easy for hosting the bot. Platforms like Heroku and OpenShift make it very easy to deploy Sinatra apps.
web.rb:
require 'sinatra/base'
module SlackWikibot
class Web < Sinatra::Base
get '/' do
'Bot is running...'
end
end
end
MediaWiki
To create an article via the API, we need first to point to our MediaWiki API URL:
wiki_connection = MediawikiApi::Client.new "http://MEDIAWIKI-ADDRESS/api.php"
We use the create_page
method to create an article, which requires two parameters: the title and content of the article.
wiki_connection.create_page "SitePoint", "Some basic info about SitePoint"
This created a page, but when this code is run directly from a script, we don’t get anything back. There is an object we can use to have access to a parsed MediaWiki API response.
Input:
response = wiki_connection.create_page "SitePoint", "Some basic info about SitePoint"
If we call the data
method now on response
, we get a nice hash.
{"result"=>"Success", "pageid"=>26, "title"=>"SitePoint", "contentmodel"=>"wikitext", "nochange"=>""}
Now we have access to the pageid
of the new wiki article. We can do a simple query http://MediaWiki-Address/?curid=26
and this will return the article.
Let’s take a look at another method that is used to remove our article. The delete
method requires two arguments: the title of the page and the reason for deleting the article. Since MediaWiki offers revisions and it lets you go back in time, having a reason for deletion is very helpful.
wiki_connection.delete_page "SitePoint", "Reason for deletion"
To use this method, you need to have an account and be logged in. This is very easy:
wiki_connection.log_in "username", "password"
Now everywhere we use the wiki_connection object, we are authenticated. If you still are not authorized to delete articles, that means that you are not in the groups that allow this kind of action. I had this problem even though I was the first user of the MediaWiki install. In this case, you need to head to the Special:UserRights page and add yourself to the bureaucrat and sysop groups.
Now create a directory named commands where we will add the commands that the SlackWikiBot will use. Inside the commands directory, create a new file called wiki.rb. The path of this new file is slack-wikibot/slack-wikibot/commands/wiki.rb.
This is the place where our commands live, it can be structured in many different ways. I suggest you take a look at the documentation of the slack-ruby-bot gem. I am using the match
operator, but there are other ways like command
and scan
. In this case, our bot is watching our chat and, whenever it sees that we have used the !wiki create or !wiki delete keywords, it will perform some action.
wiki.rb:
require 'mediawiki_api'
module SlackWikibot
module Commands
class Wiki < SlackRubyBot::Commands::Base
wiki_connection = MediawikiApi::Client.new "http://MediaWiki-URL/api.php"
wiki_connection.log_in "username", "password"
match(/^!wiki create (?<titlewiki>\w*)\s(?<contentwiki>.*)$/) do |client, data, match |
response = wiki_connection.create_page match[:titlewiki], match[:contentwiki]
pageid = response.data["pageid"]
client.say(channel: data.channel, text: "Your wiki is created http://MediaWiki-URL?curid=#{pageid}")
end
match(/^!wiki delete (?<titlewiki>\w*)\s(?<reason>.*)$/) do |client, data, match |
wiki_connection.delete_page match[:titlewiki], match[:reason]
client.say(channel: data.channel, text: "Article #{match[:titlewiki]} page is deleted. Reason: #{match[:reason]}")
end
end
end
end
Let’s take a look at our project structure:
└── slack-wikibot
├── Gemfile
├── Gemfile.lock
├── slack-wikibot.rb
└── slack-wikibot
├── bot.rb
└── commands
└── wiki.rb
Now edit slack-wikibot.rb, which we created in the root directory, and require the slack-ruby-bot gem. With that, our bot and wiki commands are created.
slack-wikibot.rb:
require 'slack-ruby-bot'
require 'slack-wikibot/bot'
require 'slack-wikibot/commands/wiki'
Create a config.ru file for our Rack application. We’ll create a thread for our bot and run the webserver:
config.ru
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'dotenv'
Dotenv.load
require 'slack-wikibot'
require 'web'
Thread.abort_on_exception = true
Thread.new do
begin
SlackWikibot::Bot.run
rescue Exception => e
STDERR.puts "ERROR: #{e}"
STDERR.puts e.backtrace
raise e
end
end
run SlackWikibot::Web
Let’s use Foreman, as it allows us to easily manage our runtime dependencies. Foreman is also useful when we have environment variables, like in a .env file. Furthermore, Heroku also uses Foreman.
We need an API key from Slack so we can interact with the bot in chat. Visit the bot service page while you are logged in your slack team. The first step is to set a username for our bot:
After clicking the “Add bot integration” button, the next step is to add information regarding our bot. We can set a name, upload an image, and set some other properties. Also, the needed API key is on this page:
Create a .env file in the root directory of our project and add the API key:
SLACK_API_TOKEN=xoxb-68226463922-ceoVi1mZgGIQJxuVD6Gpu2CV
Create a Procfile in the root directory, which Foreman will use when you run the command below:
Procfile:
web: bundle exec puma -p $PORT
Now let’s run our bot:
foreman start
Deploy to Heroku
You will need to have the Heroku tools installed:
gem install heroku
Use the Heroku command to create the application:
heroku create
It will assign a random name and add a git remote repository. Now push your code to the Heroku repository.
Note: You will have to use git for this part, so if you haven’t, make sure to git add
and git commit
your code before pushing.
git push heroku master
Now if you visit your Heroku application URL (Yours will be different):
https://agile-retreat-96798.herokuapp.com/
You should get a page that says Bot is running…
Go back to Slack and use the /invite @YourBotsName
to invite your bot to a channel. Then, try one of the commands we created:
Conclusion
Bots are a very handy tool to automate some of our work. You can find more information on making Slack bots in this post on SitePoint.
Every time you find yourself doing a repetitive work, think if it can be done by a bot. If the answer is “yes”, then there is no time to waste, start creating one. There are many benefits in having bots do our work: They are fast and make fewer to no mistakes, just to name a couple. Now is the time to accept our new Slack-bot based overlords :)