[PYTHON] A story of trial and error trying to create a dynamic user group in Slack

This article is from JSL \ (Japan System Giken ) Advent Calendar 2019 -Qiita on December 6th. Last year's calendar is here! !!

TL;DR

Preface

Although we have a long history, we are a company that sells free working styles that "recommend full flex & remote work without core time". All the time to go to work is different, and about 30% are remote workers. Therefore, it is rare for everyone who has an office to come to work.

However, when the way of working changes, there are ** good and bad things to discuss and problems to be solved **. This article is about trying to solve the problem of remote work.

Challenges of chat operation during remote work

Recently, I see that the topic of Slack operation of each company, such as @ here, @ channel prohibition, has become a topic. Notifications are useful, but they can also distract programmers.

Meanwhile, there was such a @ here mention on our Slack (my post ...)

スクリーンショット 2019-12-05 18.48.56.png

How about that? As for the situation, "a little hurry" and "I want to notify only active users", so I think it is a general usage of @ here.

But what about remote workers? For remote workers, it should not be a problem if the usage status of the meeting room and reception room of the company building is not shared.

So remote workers don't need this notification.

Of course, you may feel sorry for not only the person being notified but also the person notifying by @ here to skip the notification to the remoteworker.

If it's a company that "recommends remote work ... but I'll give you a lot of unrelated notifications !!", it's not a comfortable environment for programmers ...?

As you can see, as the number of remote workers increases, it becomes important to design a ** notification destination for chat **.

Dynamic mention

So I thought about ** dynamic mention **. I thought that this problem could be solved if there was a mention that was notified only to users who met certain conditions.

In this example, it would be ** "mentions that are notified only to those who are at work today" **.

By the way, @ here is also a dynamic mention in the sense that it only notifies active users in the channel.

Consideration of implementation

We have an in-house destination board and its REST API. If you use this, you can get a list of people who are in the office. So it would be nice if I could somehow mention on Slack toward the list of people who are in the office.

When I was looking for a nice API on Slack, I found an API called ʻusergroups.users.update`.

usergroups.users.update method | Slack

You can update users in a user group by passing an array of user IDs to usergroup and user IDs to users.

So

  1. Get a list of people who are in the office from the API of the destination board
  2. Convert list to Slack user ID
  3. Execute ʻusergroups.users.update` for the user groups created in advance to update the users.
  4. Do this on a regular basis

It seems that we should be able to realize!

Technology used

So I decided to use ʻAWS Lambda`.

With Lambda, even if it works like a minute on weekdays (20 days) + 1 hour before and after (10 hours) 20 * 10 * 60 = 12,000 So I can afford to fit in the free quota of 1,000,000 requests every month,

I also used chalice to deploy Lambda

aws/chalice: Python Serverless Microframework for AWS

chalice is a framework that allows you to write Lambda based on a Flask-like decorator and even create (delete) peripheral services. If you want to receive Http (s), Lambda is troublesome because it needs to cooperate with ʻAPIGateway`, but it takes care of that area.

For example, the regular execution, which is the requirement this time, can also be written in the syntax of chalice.

Example of regular execution every 5 minutes


from chalice import Chalice, Rate

app = Chalice(app_name="helloworld")

# Automatically runs every 5 minutes
@app.schedule(Rate(5, unit=Rate.MINUTES))
def periodic_task(event):
    return {"hello": "world"}

The final code is as follows (the part that uses the company's API is omitted)

src/update_usergroup.py


@app.schedule(Cron('0', '23-9', '?', '*', 'SUN-THU', '*'))
def update_in_office_usergroup(event):
    OAUTH_TOKEN = 'token_xxxx_xxxx'
    #Pre-created user group UID
    in_office_usergroup_uid = 'some_usergorup_uid'

    #~abridgement~

    #List of Slack IDs of users who are in the office obtained from the API
    office_user_slack_ids = ['some', 'user', 'uids']

    try:
        data = urllib.parse.urlencode(
            (
                ("token", OAUTH_TOKEN),
                ("usergroup", in_office_usergroup_uid),
                ("users", ','.join(office_user_slack_ids)),

            )
        )
        data = data.encode("ascii")
        request = urllib.request.Request(
            "https://slack.com/api/usergroups.users.update",
            data=data,
            method="POST"
        )
        request.add_header(
            "Content-Type",
            "application/x-www-form-urlencoded"
        )

        with urllib.request.urlopen(request) as r:
            resp = json.loads(r.read())
        logger.info(resp)
        return {'ok': True}
    except Exception as e:
        logger.error(e)
        return {'ok': False}

Since I use Lambda, I use ʻurllib` without external packages.

In addition, the cron formula is shifted by 9 hours by adjusting UTC so that it is Sunday-Thursday 23-9 o'clock (Monday-Friday 9-18 o'clock in Japan time). (Isn't this a good way?)

It was completed, but ...

I named it @in_office and released it with a doy face.

スクリーンショット 2019-12-06 10.18.37.png

However, there are reports that such notifications come frequently. ..

スクリーンショット 2019-12-06 10.20.00.png

Apparently, when I add / remove user groups, notifications fly from Slackbot. I made it for the purpose of reducing unnecessary notifications, but on the contrary, the number of notifications has increased. This is useless ...

I thought, "Is there an option to turn off notifications via API?", So I looked it up, but it didn't seem to be there.

I got stuck here, and although it was a function I made, I stopped using it. This is the original tree Ami.

Looking back

The main reason is the lack of technical verification.

I started running when I got "I have an API! I have an idea! I think I can do it!" And didn't even try it with a small code. Can the selected technology solve the problem? Is it a suitable way to solve the problem? It is important to consider.

On the other hand, I feel that the idea of designing chat notifications was good.

Well, it's a personal development, so it's a catch that I failed, and this is also part of the technical verification!

Dynamic Mention I think it's a pretty good idea. .. If anyone who has read this article realizes it, please let me know.

bonus

When I made an official inquiry in poor English, I received a polite answer. The current usergroup API (October 2019 at the time of inquiry) cannot turn off notifications, but he wants to inform the feedback team so that he can do it in the future.

I would like to challenge again once it is implemented!

Recommended Posts

A story of trial and error trying to create a dynamic user group in Slack
How to mention a user group in slack notification, how to check the id of the user group
A story of trying out pyenv, virtualenv and virtualenvwrapper
A story about trying to introduce Linter in the middle of a Python (Flask) project
How to create and use static / dynamic libraries in C
A story about trying to implement a private variable in Python.
Now in Singapore The story of creating a LineBot and wanting to do a memorable job
A story about trying to use cron on a Raspberry Pi and getting stuck in space
Overview of how to create a server socket and how to establish a client socket
How to create a large amount of test data in MySQL? ??
I want to create a pipfile and reflect it in docker
Create a function to get the contents of the database in Go
[Google Photo & Slack Photo Bot] A story about making a bot that acquires photos in Google Photos and sends them to Slack.
A story about trying to improve the testing process of a system written in C language for 20 years
Create a bot that posts the number of people positive for the new coronavirus in Tokyo to Slack
A story about trying to run JavaScripthon on Windows and giving up.
A story of a deep learning beginner trying to classify guitars on CNN
A story about trying to connect to MySQL using Heroku and giving up
[Python] [Word] [python-docx] Try to create a template of a word sentence in Python using python-docx
The story of trying to reconnect the client
The story of an error in PyOCR
A story connecting Slack and google spreadsheets
pix2 pix tensorflow2 Record of trial and error
The story of trying deep3d and losing
The story of creating Botonyan that returns the contents of Google Docs in response to a specific keyword on Slack
I made a tool to notify Slack of Connpass events and made it Terraform
How to count the number of elements in Django and output to a template
[Azure] I tried to create a Linux virtual machine in Azure of Microsoft Learn
Japanese translation of self-study "A Beginner's Guide to Getting User Input in Python"
Error of tf.function-decorated function tried to create variables on non-first call. In tensorflow.keras
Create a setting in terraform to send a message from AWS Lambda Python3.8 to Slack
A story of a high school graduate technician trying to predict the survival of the Titanic
I want to create a window in Python
How to create a JSON file in Python
Story of trying to use tensorboard with pytorch
How to create a Rest Api in Django
Error when trying to install psycopg2 in Python
[GCF + Python] How to upload Excel to GCS and create a new table in BigQuery
Use slackbot as a relay and return from bottle to slack in json format.
The story of trying to contribute to COVID-19 analysis with AWS free tier and failing
Create a dataset of images to use for learning
Trial and error to speed up heat map generation
Trial and error to speed up Android screen captures
About import error of numpy and scipy in anaconda
Fatal error in launcher: Unable to create process using'"'
Create a plugin to run Python Doctest in Vim (2)
[Go] How to create a custom error for Sentry
Create a plugin to run Python Doctest in Vim (1)
Note: CGI (during trial and error) in Vagrant environment
Fatal error in launcher: Unable to create process using'"'
Create a batch of images and inflate with ImageDataGenerator
A story about reflecting Discord activity in Slack Status
Group by consecutive elements of a list in Python
Output a binary dump in binary and revert to a binary file
Get a participant's username and screen name in Slack
[Golang] Command to check the supported GOOS and GOARCH in a list (Check the supported platforms of the build)
Error and solution when trying to run a classifier made with Labellio with my own ubuntu
How to create an instance of a particular class from dict using __new__ () in python
[Python] How to delete rows and columns in a table (list of drop method options)
[Note] A story about trying to override a class method with two underscores in Python 3 series.
A story that contributes to new corona analysis using a free trial of Google Cloud Platform