Skip to content

Commit

Permalink
move everything out of the __init__
Browse files Browse the repository at this point in the history
  • Loading branch information
Cadair committed Apr 10, 2018
1 parent 5629017 commit 9b93a89
Show file tree
Hide file tree
Showing 2 changed files with 254 additions and 259 deletions.
260 changes: 1 addition & 259 deletions __init__.py
@@ -1,259 +1 @@
import logging

import slacker

from opsdroid.matchers import match_regex
from opsdroid.matchers import match_crontab
from opsdroid.message import Message

from matrix_client.errors import MatrixRequestError

_LOGGER = logging.getLogger(__name__)


def get_room_members(slack, channel_id):
"""
Get a list of members in a given room
"""
resp = slack.channels.get("conversations.members", params={'channel': channel_id})
return resp.body['members']


def join_bot_to_channel(slack, bot_id, channel_id):
"""
Invite the bot to the channel if the bot is not already in the channel.
"""
members = get_room_members(slack, channel_id)
if bot_id not in members:
# Do an extra guard here just in case
try:
slack.channels.invite(channel_id, bot_id)
except slacker.Error:
_LOGGER.exception("Invite failed")


def get_channel_mapping(slack):

response = slack.channels.list()
channels = response.body['channels']

return {c['id']: c['name'] for c in channels}


def get_new_channels(slack, config, seen_channels):
"""
Get channels in the workspace that are not in seen_channels
"""
# Get channel list
response = slack.channels.list()
channels = response.body['channels']

# Get the new channels we need to process
new_channels = {}
token = config['slack_bot_token']
slack = slacker.Slacker(token)
for channel in channels:
if channel['id'] not in seen_channels.keys():
prefix = config['room_prefix']
channel_name = get_channel_mapping(slack)[channel['id']]
server_name = config['server_name']
alias = f"#{prefix}-{channel_name}:{server_name}"
new_channels[channel['id']] = alias

return new_channels


def get_matrix_connector(opsdroid):
"""
Return the first configured matrix connector.
"""
for conn in opsdroid.connectors:
if conn.name == "ConnectorMatrix":
return conn


async def room_id_if_exists(api, room_alias):
"""
Returns the room id if the room exists or `None` if it doesn't.
"""
if room_alias.startswith('!'):
return room_alias
try:
room_id = await api.get_room_id(room_alias)
return room_id
except MatrixRequestError as e:
if e.code != 404:
raise e
return None


async def joined_rooms(api):
json = await api._send("GET", "/joined_rooms")
return json['joined_rooms']


async def is_in_matrix_room(api, room_id):
rooms = await joined_rooms(api)
return room_id in rooms


async def intent_self_in_room(opsdroid, room):
"""
This function should result in the connector user being in the given room.
Irrespective of if that room existed before.
"""

connector = get_matrix_connector(opsdroid)

room_id = await room_id_if_exists(connector.connection, room)

if room_id is None:
logging.debug(room)
try:
json = await connector.connection.create_room(alias=room.split(':')[0][1:])
room_id = json['room_id']
except MatrixRequestError:
room_id = await connector.connection.get_room_id(room)
json = await connector.connection.join_room(room_id)
else:
is_in_room = is_in_matrix_room(connector.connection, room_id)

if not is_in_room:
json = await connector.connection.join_room(room_id)

return room_id


async def intent_user_in_room(opsdroid, user, room):
"""
Ensure a user is in a room.
If the room doesn't exist or the invite fails, then return None
"""
connector = get_matrix_connector(opsdroid)
room_id = await room_id_if_exists(connector.connection, room)
logging.debug(f"1: {room_id}")

if room_id is not None:
try:
await connector.connection.invite_user(room_id, user)
except MatrixRequestError as e:
logging.debug(f"---- {e}")
if "already in the room" in str(e):
return room_id
room_id = None
# raise

return room_id


async def admin_of_community(opsdroid, community):
"""
Ensure the community exists, and the user is admin otherwise return None.
"""

connector = get_matrix_connector(opsdroid)

# Check the Python SDK speaks communities
if not hasattr(connector.connection, "create_group"):
return None

# Check community exists
try:
profile = await connector.connection.get_group_profile(community)
except MatrixRequestError as e:
if e.code != 404:
raise e
else:
group = await connector.connection.create_group(community.split(':')[0][1:])
return group['group_id']

# Ensure we are admin
if profile:
users = await connector.connection.get_users_in_group(community)
myself = list(filter(lambda key: key['user_id'] == connector.mxid, users['chunk']))
if not myself['is_privileged']:
return None

return community


@match_crontab('* * * * *')
@match_regex('!updatechannels')
async def mirror_slack_channels(opsdroid, config, message):
"""
Check what channels exist in the Slack workspace and list them.
"""

conn = get_matrix_connector(opsdroid)

if not message:
message = Message("",
None,
config.get("room", conn.default_room),
conn)

token = config['slack_bot_token']
u_token = config['slack_user_token']
slack = slacker.Slacker(token)

# Get userid for bot user
bridge_bot_id = config['bridge_bot_name']
bridge_bot_id = slack.users.get_user_id(bridge_bot_id)

# Get the channels we have already processed out of memory
seen_channels = await opsdroid.memory.get("seen_channels")
seen_channels = seen_channels if seen_channels else {}

# Get channels that are now in the workspace that we haven't seen before
new_channels = get_new_channels(slack, config, seen_channels)

# Ensure that the community exists and we are admin
community = admin_of_community(opsdroid, config['community_id'])

# Get a list of rooms currently in the community
if community:
response = await conn.connection.get_rooms_in_group(community)
rooms_in_community = {r['room_id'] for r in response['chunk']}
else:
rooms_in_community = {}

for channel_id, room_alias in new_channels.items():
# Join the slack bot to these new channels
join_bot_to_channel(slack, bridge_bot_id, channel_id)

# Create a new matrix room for this channels
room_id = await intent_self_in_room(opsdroid, room_alias)

# Change the room name to something sane
await conn.connection.set_room_name(room_id, room_alias.split(':')[0][1:])

# Make room publicly joinable
try:
await conn.connection.send_state_event(room_id,
'm.room.join_rules',
content={'join_rule': 'public'})
except Exception:
logging.exception("Could not make room publicly joinable")
message.respond(f"ERROR: Could not make {room_alias} publically joinable.")

# Invite the Appservice matrix user to the room
room_id = await intent_user_in_room(opsdroid, config['as_userid'], room_id)
if room_id is None:
message.respond(f"ERROR: Could not invite appservice bot to {room_alias}, skipping channel.")
continue

# Run link command in the appservice admin room
await message.respond(
f"link --channel_id {channel_id} --room {room_id} --slack_bot_token {token} --slack_user_token {u_token}",
room='bridge')

# Add room to community
if room_id not in rooms_in_community:
await conn.connection.add_room_to_group(community, room_id)

message.respond(f"Finished Adding room {room_alias}")

# update the memory with the channels we just processed
seen_channels.update(new_channels)
await opsdroid.memory.put("seen_channels", seen_channels)
from .picard import mirror_slack_channels

0 comments on commit 9b93a89

Please sign in to comment.