diff --git a/scripts/slack-backup b/scripts/slack-backup index 3f36c31..0fc17a5 100755 --- a/scripts/slack-backup +++ b/scripts/slack-backup @@ -15,10 +15,11 @@ def main(): parser.add_argument("token", help="Slack token - a string, which can be" " generated/obtained via " "https://api.slack.com/docs/oauth-test-tokens page") - # parser.add_argument("channel", help="Slack channel name") + parser.add_argument('-d', '--database', default='', + help='Path to the database file') args = parser.parse_args() - slack = client.Client(args.token) + slack = client.Client(args.token, args.database) pprint.pprint(slack.get_hisotry(selected_channels=['elysium'])) diff --git a/slack_backup/client.py b/slack_backup/client.py index 6d880c7..89a3e2c 100644 --- a/slack_backup/client.py +++ b/slack_backup/client.py @@ -7,7 +7,7 @@ import logging import slackclient from slack_backup import db -from slack_backup import objects +from slack_backup import objects as o class Client(object): @@ -24,7 +24,7 @@ class Client(object): else: selected_channels = channels - self._get_user_list() + self._update_users() for channel in selected_channels: # history = [] @@ -36,6 +36,8 @@ class Client(object): if not messages: break + self.session.close() + def _get_channel_history(self, channel, latest='now'): result = self.slack.api_call("channels.history", channel=channel._id, count=1000, latest=latest) @@ -51,13 +53,35 @@ class Client(object): logging.error(result['error']) return None - return [objects.Channel(chan) for chan in result['channels']] + return [o.Channel(chan) for chan in result['channels']] - def _get_user_list(self): + def _update_users(self): + """Fetch and update user list with current state in db""" result = self.slack.api_call("users.list", presence=0) + all_users = self.session.query(o.User).all() if not result.get("ok"): logging.error(result['error']) return None - return [objects.User(user) for user in result['members']] + for user_data in result['members']: + slackid = user_data['id'] + del user_data['id'] + idmap = self.session.query(o.IdMap).\ + filter(o.IdMap.classname == 'User').\ + filter(o.IdMap.slackid == slackid).one_or_none() + if idmap: + user = self.session.query(o.User).get(idmap.dbid) + user.update(user_data) + else: + user = o.User(user_data) + self.session.add(user) + self.session.flush() + + idmap = o.IdMap() + idmap.slackid = slackid + idmap.classname = 'User' + idmap.dbid = user.id + self.session.add(idmap) + + self.session.commit() diff --git a/slack_backup/objects.py b/slack_backup/objects.py index 5ca6889..b2a1bc6 100644 --- a/slack_backup/objects.py +++ b/slack_backup/objects.py @@ -4,7 +4,7 @@ Convinient object mapping from slack API reponses from sqlalchemy import Column, Integer, Text, Boolean, ForeignKey from sqlalchemy import DateTime from sqlalchemy import UniqueConstraint -from sqlalchemy.orm import relation +from sqlalchemy.orm import relationship from slack_backup.db import Base @@ -85,6 +85,7 @@ class UserProfile(Base): __tablename__ = "profiles" id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey("users.id"), index=True) + user = relationship("User", back_populates="profile") avatar_hash = Column(Text) first_name = Column(Text) @@ -99,7 +100,9 @@ class UserProfile(Base): real_name_normalized = Column(Text) def __init__(self, data_dict=None): + self.update(data_dict) + def update(self, data_dict): data_dict = data_dict or {} self.avatar_hash = data_dict.get('avatar_hash', '') @@ -122,17 +125,22 @@ class User(Base): name = Column(Text) real_name = Column(Text) - profile = Column(Integer, ForeignKey('profiles.id'), index=True) + profile = relationship("UserProfile", uselist=False, back_populates="user") - def __init__(self, user_id, data_dict=None): + def __init__(self, data_dict=None): + self.update(data_dict) + + def update(self, data_dict=None): data_dict = data_dict or {} - self.id = data_dict.get('id', '') self.deleted = data_dict.get('deleted', False) self.name = data_dict.get("name", '') self.real_name = data_dict.get('real_name', '') - self.profile = UserProfile(data_dict.get('profile')) + if not self.profile: + self.profile = UserProfile(data_dict.get('profile')) + else: + self.profile.update(data_dict.get('profile')) def __repr__(self): return u'<%s %s>' % (str(hex(id(self))), self.__unicode__())