SlackToTeams
Code style: Black
Code linter: Pyflakes
What it does
Migrate Slack messages into Teams. The information that gets retained for each message:
- the (user) sender of the message.
- the timestamp of the message.
- the content of the message.
- if the content includes code blocks, those get special formatting.
- the (user) other tagged users in the message.
What it can't do
- Replies, on either Slack or Teams side.
- Profile pictures (avatars).
- emojis, reactions to messages.
- uploaded images.
- every message MUST be sent as the same "user", i.e. on Teams it will show up as the same 0365 user sending each message.
- we work around this issue by manually adding the true sender (slack sender) into the body of the message as a "From: " field.
This is a clunky workaround, but at the moment the send ChatMessage API endpoint is not supported by "Applications" (its in Beta afterall). Only individual users can make this request. For this reason, if we want to make a writeMessage request, we are limited to "on-behalf-of" user flow, where authentication is made for 1 user who has special permissions to be able to make this request. The Application is then able to make all requests "on-behalf-of" this user.
I have even tried to make ChatMessage requests with a different user "path" - using /users/<userID>/chat/<chatID> path, but that is also un-authorized. MS says that this endpoint is to be used strictly by the api-caller.
In order words, to send a message as another user, you have to authenticate the app on-behalf-of that user. This is obviously impractical if you have hundreds of users, so its best to wait for MS to get this endpoint out of Beta, and allow the normal "App" flow.
The Setup
- Code is built up from Azure Sample - https://github.com/Azure-Samples/ms-identity-python-daemon/tree/master/1-Call-MsGraph-WithSecret.
- I've created objects representing the overall structure of the app. We have two main entities:
- SlackParser: handles file io, message parsing logic involved with the Slack export.
- MSGraphApi: handles auth with MSGrpah, and provides a few MSGraph Api endpoints to query or write data.
test.pyhas rudimentary tests for parsing logic functions, I suggest these are run anytime code is updated.- A user with special permssions setup on the O365 side. Specifically it needs:
- User.Read, User.Read.All, User.ReadWrite, User.ReadWrite.All
- Group.Read.All, Group.ReadWrite.All
Dependencies
- You must have your own
params.jsonfile, and aresourcesdir containing: users.jsonfile.- the slack channel dir from a slack export
resources/devops/that contains all the messages by day as json files. params.jsonfile (explained below).
Running
pip3 install -r requirements.txtpython3 main.py params.jsonto run the apppython3 test.pyto run the tests, though they get run at the start of main.py itself.
params.json explaination
The configuration file would look like this (sans those // comments):
{
"authority": "https://login.microsoftonline.com/Enter_the_Tenant_Name_Here",
"client_id": "your_client_id",
"scope": ["https://graph.microsoft.com/.default"],
// For more information about scopes for an app, refer:
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate"
"secret": "The secret generated by AAD during your confidential app registration",
// For information about generating client secret, refer:
// https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Client-Credentials#registering-client-secrets-using-the-application-registration-portal
"username": "https://graph.microsoft.com/v1.0/users",
// this is required for obo flow
"password": "https://graph.microsoft.com/v1.0/users",
// this is required for obo flow
"teamname": "Engineering",
// the exact name of the team containing your channel",
"channelname": "Acuity Changelog"
// the exact name of the channgel you want to write to.
}
