Пример #1
0
class Bot(object):
    """Slack bot class.
    Handle all basic greeting to member rolling standup, including
    timeframe of each standup.
    """
    """Attributes."""
    token = None
    channels = []
    reports = []
    client = None
    login_data = None
    end_time = None

    def __init__(self, token, timeout, secret=""):
        """Initialize bot instance.
        token: slack bot authorization token
        """
        self.headers = {
            "secret": secret,
            "Content-Type": "application/json",
            "Accept": "application/json"
        }
        self.timeout = timeout
        self.token = token

    def start(self):
        """Boot up slack bot."""
        self.client = SlackClient(self.token)
        if self.client.rtm_connect():
            self.login_data = self.client.get_login_data()
            logging.info("bot running")
            for channel in self.get_all_channels():
                if channel['name'] in self.channels:
                    self.reports.append(self.standup_start(channel))
        return self.reports

    def set_channels(self, channels):
        """Pass list of channel to execute standup.
        :channels array of channels
        """
        self.channels = channels
        return self

    def greet(self, channel):
        """Initial greeting.
        channel: target channel name
        """
        self.client.rtm_send_message(
            channel, "Hello, We'll start the stand up \
soon.")

    def farewell(self, channel):
        """Sum up the standups.
        channel: target channel name
        """
        self.client.rtm_send_message(
            channel, "Looks like that's it for today \
Thanks for your effort today")

    def is_bot(self, member):
        """Check if member is current bot.
        member: specified member id
        """
        return self.login_data['id'] == member

    def extract_slack_message(self, message):
        """Extract slack message body.
        message: response from slack
        """
        text, user, channel = message.get('text'), message.get(
            'user'), message.get('channel')
        if not text or not user or not channel or user == self.login_data['id']:
            return None
        return {'user': user, 'text': text, 'channel': channel}

    def fetch_user_data(self, member):
        """Fetch user data from userid.
        member: userid on slack
        """
        response = self.client.api_call("users.info", user=member)
        result = {
            'email': response['user']['profile']['email'],
            'username': response['user']['name'],
            'real_name': response['user']['real_name']
        }
        return result

    def exec_member(self, member, channel):
        """Loop through every questions, and pass to user.
        member: interacted member.
        """
        ongoing = True
        count = -1
        data = {}
        response = {}
        data['user'] = self.fetch_user_data(member)
        # bot start
        self.client.rtm_send_message(
            channel, """
Hello <@{}> type anything to begin,\
or `skip` if you want to skip for \
today.
            """.format(member))
        member_time_out = datetime.now() + timedelta(seconds=int(self.timeout))
        while ongoing:
            if datetime.now() > member_time_out:
                response['message'] = "timeout"
                self.client.rtm_send_message(
                    channel, "<@{}> is not available \
Let's move to another member.".format(member))
                break
            for slack_message in self.client.rtm_read():
                # Start listening for message
                message = self.extract_slack_message(slack_message)
                if message is None:
                    continue
                if message['channel'] != channel or message['user'] != member:
                    continue
                if message['text'].lower() == 'skip':
                    response['message'] = "skipped"
                    self.client.rtm_send_message(message['channel'], 'okay')
                    ongoing = False
                    break
                elif count < 0 and message['text'].lower(
                ) not in constants.POSITIVE:
                    continue
                if count >= 0:
                    response[self.questions[count]] = message['text']
                else:
                    response['init'] = message['text']
                count += 1
                if count >= len(self.questions):
                    ongoing = False
                    break
                # reset timeout variables after each answer
                member_time_out = datetime.now() + timedelta(
                    seconds=int(self.timeout))
                self.client.rtm_send_message(message['channel'],
                                             self.questions[count])
            data['response'] = response
        self.client.rtm_send_message(channel, "Thanks <@{}>.".format(member))
        return data

    def standup_start(self, channel):
        """Start stand up on channel.
        channel: respective channel
        """
        report = {}
        report['channel'] = channel['name']
        report['members'] = []
        self.greet(channel['id'])
        members = self.get_members(channel['id'])
        for member in members:
            if self.is_bot(member):
                continue
            member_report = self.exec_member(member, channel['id'])
            report['members'].append(member_report)
        self.farewell(channel['id'])
        return report

    def get_all_channels(self):
        """Get all channel associated with current bot."""
        response = self.client.api_call("channels.list")
        return response['channels']

    def get_members(self, channel):
        """Get members of channel.
        channel: channel name
        """
        response = self.client.api_call("channels.info", channel=channel)
        return response['channel']['members']

    def set_questions(self, questions):
        """Set question to be asked.
        questions: array of questions
        """
        self.questions = questions
        return self

    def push_question(self, question):
        """Push question to queue.
        question: Question object to be pushed.
        """
        self.questions.append(question)
        return self

    def send_report(self, hook):
        """Send report to hook.
        hook: endpoint to receive the report
        """
        payload = json.dumps(self.reports)
        try:
            response = requests.post(hook, headers=self.headers, data=payload)
            return response
        except requests.exceptions.RequestException as e:
            logging.warning(e)
            return payload