Esempio n. 1
0
def listen_slack():
    """
    Listens to the slack callback and if it is a Slack event then processes it and extracts chanel_id,
    slack_user_id, timestamp, message and calls desired method in a thread.
    If it's not a Slack event then method considers the callback as a Slack callback authentication and returns
    the quoted challenge code if exists.
    :rtype: str
    """
    event = request.json.get('event')
    if event:
        current_timestamp = event.get('ts')
        channel_id = request.json.get('event').get('channel')
        slack_user_id = request.json.get('event').get('user')
        message = request.json.get('event').get('text')
        if message and channel_id and slack_user_id:
            logger.info(
                "Message slack:%s, Current_timestamp: %s, Slack User ID: %s" %
                (message, current_timestamp, slack_user_id))
            run_slack_communication_handler.delay(channel_id, message,
                                                  slack_user_id,
                                                  current_timestamp)
            return 'HTTP_200_OK'
    challenge = request.json.get('challenge')
    if challenge:
        if request.json.get('token') == app.config['SLACK_VERIFICATION_TOKEN']:
            return quote(challenge)
    return 'HTTP_200_OK'
Esempio n. 2
0
def receive_mail():
    """
    End point which listens mail gun callbacks
    :rtype: str
    """
    message = request.form.get('stripped-text')
    sender = request.form.get('sender')
    subject = request.form.get('subject')
    if message and sender:
        logger.info('Received email body: ' + message + ', Sender: ' + sender)
        email_bot.handle_communication(sender, subject, message)
    return 'HTTP_200_OK'
Esempio n. 3
0
 def reply(self, chanel_id, msg, slack_client):
     """
     Replies to user on specified slack channel
     :param SlackClient slack_client: Slack Client RTM object
     :param str chanel_id: Slack channel id
     :param str msg: Message received to bot
     :rtype: None
     """
     logger.info('slack reply: %s' % msg)
     slack_client.api_call("chat.postMessage",
                           channel=chanel_id,
                           text=msg,
                           set_active=True)
Esempio n. 4
0
def set_bot_state_active():
    """
    Receives bot_token and perform an activity using that token to let Slack servers know
    that bot is online
    :rtype: json
    """
    bot_token = request.json.get('bot_token')
    if bot_token:
        print bot_token
        slack_client = SlackClient(bot_token)
        slack_client.rtm_connect()
        logger.info('Slack bot status online for token %s' % bot_token)
        return ApiResponse({"response": "OK"})
    raise InvalidUsage("No token found in request body")
Esempio n. 5
0
 def reply(self, response, recipient):
     """
     Replies to the user through sms
     :param str response: Response message from bot
     :param str recipient: User's mobile number
     :rtype: None
     """
     # Twilio sms text doesn't seem to support'[' and ']'
     response = response.replace('[', '(')
     response = response.replace(']', ')')
     if len(response) > self.standard_sms_length:
         tokens = response.split('\n')
         total_segments, dict_of_segments = self.get_total_sms_segments(tokens)
         for segment_indexer in dict_of_segments:
             segment = dict_of_segments.get(segment_indexer) + \
                     "("+str(segment_indexer)+"/"+str(total_segments) + ")"
             message = self.twilio_client.messages.create(to=recipient, from_=self.twilio_number,
                                                          body=segment)
             logger.info('Twilio response status: ' + message.status)
             logger.info('message body:' + segment)
     else:
         message = self.twilio_client.messages.create(to=recipient, from_=self.twilio_number,
                                                      body=response)
         logger.info('SMS Reply: ' + response)
         logger.info('Twilio response status: ' + message.status)
Esempio n. 6
0
 def is_response_time_more_than_usual(self, user_message):
     """
     Checks if handler is going to take long time for processing
     :param string user_message: User message
     :rtype: bool
     """
     if len(user_message.split()) > MIN_WORDS_IN_QUESTION:
         add_candidates_questions = self.list_of_questions[
             ADD_CANDIDATE_FROM_URL:ADD_CANDIDATE_FROM_URL + 2]
         match_ratio = self.match_question(user_message,
                                           add_candidates_questions)
         if match_ratio >= AVERAGE_QUESTION_MATCH_RATIO:
             logger.info("Responding before processing")
             return True
     return False
Esempio n. 7
0
 def get_bot_id(self, slack_client):
     """
     Gets bot Id
     :param SlackClient slack_client: SlackClient object
     :rtype: str|None
     """
     api_call = slack_client.api_call("users.list")
     if api_call.get('ok'):
         # retrieve all users so we can find our bot
         users = api_call.get('members')
         for user in users:
             if 'name' in user and self.bot_name == user.get('name'):
                 logger.info("Bot ID for %s is %s" %
                             (user['name'], user.get('id')))
                 temp_at_bot = '<@%s>' % user.get('id')
                 return temp_at_bot
     raise NotFoundError("could not find bot user with the name %s" %
                         self.bot_name)
Esempio n. 8
0
 def authenticate_user(self, slack_user_id, message, channel_id):
     """
     Authenticates user
     :param str slack_user_id: User's slack Id
     :param str message: User's message
     :param str channel_id: Slack channel Id
     :rtype: tuple (True|False, None|str, None|Slack_client, TalentbotAuth.slack_user_id|None)
     :return: is_authenticated, user message with bot id stripped, slack_client, user_id
     """
     talentbot_auth = TalentbotAuth.get_talentbot_auth(
         slack_user_id=slack_user_id)
     if talentbot_auth:
         slack_user_token = talentbot_auth.bot_token
         user_id = talentbot_auth.user_id
         if slack_user_token and user_id:
             slack_client = SlackClient(slack_user_token)
             user = User.get_by_id(user_id)
             if user.is_disabled:
                 is_authenticated, user_id = True, None
                 return is_authenticated, message, slack_client, user_id
             try:
                 if talentbot_auth.bot_id:
                     at_bot = '<@%s>' % talentbot_auth.bot_id
                     presence = slack_client.api_call('users.getPresence')
                     if not presence.get('online'):
                         self.set_bot_state_active(talentbot_auth.bot_token)
                 else:
                     at_bot = self.get_bot_id(slack_client)
             except NotFoundError as error:
                 logger.error(error.message)
                 is_authenticated, slack_client, user_id = False, None, None
                 return is_authenticated, message, slack_client, user_id
             # Slack channel Id starts with 'C' if it is a channel and
             # Start's with 'D' if it's a private message
             is_channel = channel_id[0] == 'C'
             is_private_message = channel_id[0] == 'D'
             at_bot_colon = '%s:' % at_bot
             if (at_bot in message or at_bot_colon in message and is_channel) \
                     or (is_private_message and slack_user_id != at_bot):
                 return True, message.replace(at_bot,
                                              ''), slack_client, user_id
     logger.info("Not authenticated")
     is_authenticated, slack_client, user_id = False, None, None
     return is_authenticated, message, slack_client, user_id
Esempio n. 9
0
 def match_question(message, questions, partial=True):
     """
     Matches user message with questions and returns max matched ratio
     :param bool partial: Boolean parameter to determine if partial matching is required or not
     :param string message: User message
     :param string|list questions:
     :rtype: positive
     """
     if isinstance(questions, list):
         max_matched_ratio = ZERO
         for question in questions:
             temp_ratio = fuzz.partial_ratio(
                 question, message) if partial else fuzz.ratio(
                     question, message)
             if temp_ratio > max_matched_ratio:
                 max_matched_ratio = temp_ratio
         return max_matched_ratio
     message_lower = message.lower()
     match_ratio = fuzz.partial_ratio(
         questions, message_lower) if partial else fuzz.ratio(
             questions, message_lower)
     logger.info("%s : %d%% matched" % (message, match_ratio))
     return match_ratio
Esempio n. 10
0
 def empty_users_state():
     """
     This method removes saved users' states from redis db to avoid deadlocks
     """
     # Getting registered user phone ids
     user_phone_ids = TalentbotAuth.get_all_user_phone_ids()
     # Getting first entry of tuples
     user_phone_ids = list(*zip(*user_phone_ids))
     # Removing None from list
     user_phone_ids = filter(partial(is_not, None), user_phone_ids)
     """
     If there is no user_phone_id available in table we get [None], that's why I'm
     comparing user_phone_ids[0] instead of user_phone_ids because [None] != []
     """
     if user_phone_ids:
         # Getting user ids against registered users' phone ids
         user_ids = UserPhone.get_user_ids_by_phone_ids(user_phone_ids)
         # Extracting data from tuple
         user_ids = list(*zip(*user_ids))
         for user_id in user_ids:
             redis_store.delete("bot-pg-%d" % user_id)
             redis_store.delete("%dredis_lock" % user_id)
         logger.info("Flushed user states successfully")
Esempio n. 11
0
 def reply(self, recipient, subject, message):
     """
     Sends Email to the recipient via mailgun API
     :param str recipient: Email sender
     :param str subject: Subject of email
     :param str message: Email response message
     :return: response from mailgun API
     :rtype: response
     """
     html = '<html><img src="' + self.bot_image + '" style="width: 9%; display:'\
                                                  ' inline;"><h5 style="display:'\
                                                  ' table-cell; vertical-align:'\
                                                  ' top;margin-left: 1%;">' + message +\
            '</h5></html>'
     response = send_email(
         source=app.config[TalentConfigKeys.BOT_SOURCE_EMAIL],
         subject=subject,
         body=None,
         html_body=html,
         email_format='html',
         to_addresses=[recipient])
     logger.info('Mail reply "%s", to %s' % (message, recipient))
     return response
Esempio n. 12
0
 def set_bot_state_active(self, bot_token):
     """
     Sets Slack bot state active
     :param str bot_token: bot token
     :rtype: None
     """
     token = User.generate_jw_token()
     header = {'Authorization': token, 'Content-Type': 'application/json'}
     job_config = {
         "frequency": 144,
         "task_type": "periodic",
         "start_datetime": datetime.utcnow(),
         "end_datetime": datetime.utcnow() + relativedelta(days=1),
         "url": TalentBotApiUrl.SLACK_BOT_STATUS,
         "task_name": bot_token,
         "post_data": {
             "bot_token": bot_token
         }
     }
     # Getting task by name
     try:
         task = http_request('get',
                             SchedulerApiUrl.TASK_NAME % bot_token,
                             headers=header)
         if task.status_code == 200:
             task_json = json.loads(task.text)
             http_request('delete',
                          SchedulerApiUrl.TASK % task_json['task']['id'],
                          headers=header)
     except Exception as e:
         logger.info(
             "No Scheduler task exists with name %s creating new one" %
             bot_token)
     response = http_request('POST',
                             SchedulerApiUrl.TASKS,
                             headers=header,
                             data=json.dumps(job_config))
Esempio n. 13
0
"""
    Run Celery Worker

For Celery to run from command line, script runs as separate process with celery command

 Usage: open terminal cd to talent-flask-services directory

 Run the following command to start celery worker:

    $ celery -A talentbot_service.celery_app worker --concurrency=4 --loglevel=info
"""

# Service Specific
from talentbot_service.modules.constants import QUEUE_NAME
from talentbot_service.common.talent_celery import CELERY_WORKER_ARGS
from talentbot_service import celery_app, logger, app

logger.info("Starting Celery worker for:%s" % app.name)
celery_app.start(argv=CELERY_WORKER_ARGS + [QUEUE_NAME] +
                 ['-n', 'talentbot_service'])