An open API service indexing awesome lists of open source software.

https://github.com/target/karmabot

A karmabot for Slack
https://github.com/target/karmabot

bot karma retention-exempt slack

Last synced: 1 day ago
JSON representation

A karmabot for Slack

Awesome Lists containing this project

README

        

# Karmabot for Slack

This is an implementation of Karma in Python that should be fairly robust to handle a largerish deployment.

## Features

* Karma rate-limiting: Only 60 Karma operations per hour from any user
* Separation of thing/user/group/channel Karma
* Top and Bottom list for all, things, users, channels
* Karma expiration
* General Karma statistics
* Badges

## What is Karma?

Karma is a quazi-reputation system. You may have used it in other Chat systems. Simply put, you can add a `++` or `--` to the end of subject to add or remove karma.
Anyone (except bots) can give Karma. Karma isn't a perfect system — it can be gamed, but it can be a fun way to show your gratitude when someone helps you out.

## What are badges?

Badges are bit of an experiment right now. When a user's karma is shown (either from normal karma operations or a show command) any badges they have will be displayed with the karma score. Badges can only be created by the Slack admins, and only badge owners can give them to a user. A user may choose to remove any of their own badges, too.

The idea is badges should be special, unique, and convey some meaning. For now, the intent is to have badges be limited to groups of 20 or less people, and have any one person have no more than 5 badges (ideally between 0 and 2 badges). No limits are enforced (yet) as this is an experiment. If you have an idea for how badges could be useful, please let us know!

## Architecture

This implementation uses Flask and MongoDB.

The Flask web service listens for the events from Slack and executes them in a separate thread using `flask-executor`. MongoDB is used to store the Karma operations.

### MongoDB

Karma operations are stored as documents in the collection named after the Workspace ID (aka `team_id`). The documents look like:

```
{
"_id" : ObjectId("5a9c5da940ea97000f9cf8dc"),
"expires" : ISODate("2018-06-02T20:57:13.280Z"),
"date" : ISODate("2018-03-04T20:57:13.280Z"),
"subject" : "foo",
"type" : "thing",
"gifter" : "U12345678,
"quantity" : 1
}
```

For the `type`, it can be one of `thing`, `user`, `channel`, or `group`. Users, Channels, and Groups should be stored by their ID, not the display name, to support name changes without loosing Karma.

The MongoDB service should be set up initially with indexes to improve performance, and expire old Karma.

```
db.WKSPCID.createIndex( { "expires": 1 }, { expireAfterSeconds: 0 } )
```

## Setup

* Set up MongoDB somewhere, should be persistent if you don't want to loose your Karma
* Set up a Metrics service, something that accepts InfluxDB line protocol over a TCP port. See the `docker-compose.yml` for an example of a Telegraph instance that does this.
* Create the app entry in `api.slack.com/apps`.
* Create `/karma` command pointed to the proper HTTP endpoint for commands
* Make sure to select "Escape channels, users, and links"
* Create `/badge` command pointed to the proper HTTP endpoint for commands
* Make sure to select "Escape channels, users, and links"
* Start the Karmabot instance somewhere. Its designed to be a Docker service, and configuration is handled via environment variables.
* Update the app entry in `api.slack.com/apps`:
* Create event subscriptions and point at the proper HTTP endpoint for events. Subscribe to Bot Events:
* `app_mention`
* `message.channels`
* `message.groups`
* Set OAuth permissions to include:
* `bot`
* `commands`
* `channels:write`
* `chat:write:bot`
* `im:write`
* `usergroups:read`
* Invite the Karma bot into channels you wish to track Karma

### Environment Variables

As mentioned, configuration is handled via environment variables. Here is the list of things you can configure:
* `VERIFICATION_TOKEN` The verification from your Slack App config. There is no default, you must set this.
* `MONGODB` The MongoDB URI (including username and password if applicable). Defaults to `mongodb://localhost:27017`
* `SLACK_EVENTS_ENDPOINT` The base URI to accept Slack events on. Defaults to `/slack_events`
* `KARMA_RATE_LIMIT` Number of Karma operations per hour a user can do. Defaults to `60`
* `KARMA_TTL` How quickly Karma expires, in days. Defaults to `90`
* `KARMA_COLOR` The highlight color to use when Karmabot posts messages. Defaults to `#af8b2d`
* `FAKE_SLACK` Only used for testing. When set to `True` it will not actually connect to Slack, and instead mocks out the Slack services.

Since the app may be installed to multiple workspaces, there are two ways to handle the OAuth and Bot access tokens, using Hashicorp Vault or environment variables.

Using Vault requires more infrastructure, but allows for dynamically adding workspaces without needing to restart services. Using environment variables is simpler, but requires restarting the service when adding new workspaces.

To use environment variables, leave `USE_VAULT` unset, or set it to `False`. Then store the tokens like this:

* `ACCESS_{workspace_id}` The OAuth Access Token for workspace `{workspace_id}`
* `BOT_{workspace_id}` The Bot Access Token for workspace `{workspace_id}`

To use Vault, set

* `USE_VAULT` to `True` . Defaults to False.
* `VAULT_URI` to the Vault URI to connect to. Defaults to None.
* `VAULT_TOKEN` to the Vault authentication token. Defaults to None.
* `VAULT_BASE` to the location in Vault where tokens can be found. Defaults to `secrets`

Store the tokens in the `VALUT_BASE` location with the name `access_{workspace_id}.txt` where `{workspace}` is the workspace ID (case sensitive), using the kv1 method. For example:

```
vault write secret/secrets/access_T1234.txt value=xoxa-1234-5678
vault write secret/secrets/bot_T1234.txt value=xoxb-1234-5678
```

## How to contribute

This is intended to be a community driven project. Feel free to submit a PR if you think you can improve it, or just open an issue if you have an idea but can't implement it.

We won't take every feature request, but if its a good idea, we will take it in.

## Contributors

* Jay Kline (@slushpupie)
* Jordan Sussman (@JordanSussman)
* Jim Male (@JMaleTarget)
* Emmanuel Meinen (@meinenec)
* James Bell (@lemoney)
* Thiti Vutisalchavakul (@vutisat)