def accept_request(body, num_tries=1) -> bool: if body['type'] == 'message': uid = body['from']['id'] chat_id = body['conversation']['id'] get_redis().set('chat_message_id:{}'.format(chat_id), body['id']) # TODO MicrosoftInterface.set_base_url(chat_id, body['serviceUrl']) MicrosoftInterface.set_bot_id(chat_id, body['recipient']['id']) accept_user_message.delay(MicrosoftInterface.name, uid, body, chat_id=chat_id) return True return False
def _retrieve_attachment(self, url): """Retrieves an attachment ID from FB servers.""" from botshot.core.persistence import get_redis redis = get_redis() att_id = redis.get("FB_ATTACHMENT_FOR_{url}".format(url=url)) return att_id.decode("utf8") if att_id else None
def get_set_task_flag(task_id): """Prevents duplicate scheduled tasks.""" from botshot.core.persistence import get_redis redis = get_redis() key = "botshot_task_flag_{}".format(task_id) is_done = redis.exists(key) # remove the flag 3600 sec. after executing for the first time redis.set(name=key, value=1, ex=3600) return is_done
def _upload_attachment(self, meta, url, type, allow_cache): """Uploads an attachment to FB servers.""" from botshot.core.persistence import get_redis att_id = self.interface.upload_attachment(meta, url, type, allow_cache) redis = get_redis() if att_id is not None and redis is not None: expiry = 60 * 60 * 24 # a day redis.set("FB_ATTACHMENT_FOR_{url}".format(url=url), att_id, ex=expiry) return att_id
def get_bot_id(chat_id): if chat_id is None: raise Exception('Chat id must not be null') redis = get_redis() bot_id = redis.get('ms_reply_botid_' + str(chat_id)) if bot_id is None: raise Exception('Bot ID not found for chat {}'.format( str(chat_id))) return bot_id.decode()
def _run_test_module(name, benchmark=False): path = settings.BOT_CONFIG.get("TEST_MODULE", 'tests') module = importlib.import_module("." + name, package=path) importlib.reload(module) result = _run_test_actions(name, module.actions, benchmark=benchmark) test = {'name': name, 'result': result} db = get_redis() db.hset('test_results', name, json.dumps(test)) return test
def accept_request(body): uid = body['user']['userId'] chat_id = body['conversation']['conversationId'] meta = {"uid": uid, "chat_id": chat_id} profile = Profile(uid, None, None) session = ChatSession(GoogleActionsInterface, chat_id, meta, profile) accept_user_message.delay(session, body).get() # responses = GoogleActionsInterface.response_cache.get(session.chat_id) responses = get_redis().get( "response_for_{id}".format(id=session.chat_id)) # TODO return GoogleActionsInterface.convert_responses( session, responses.decode('utf8'))
def set_bot_id(chat_id, bot_id): """ Because the microsoft bot api doesn't send the requests to recipient "BOT_ID", but to recipient "BOT_ID@nnnn" instead and this ID is required to reply, it is saved in redis. When MS updates their documentation about IDs this will hopefully be removed. :param chat_id: :param bot_id: :return: """ if chat_id is None or bot_id is None: raise Exception('Chat id and bot id must not be null') redis = get_redis() redis.set('ms_reply_botid_' + str(chat_id), str(bot_id))
def _upload_attachment(self, conversation, url, type, allow_cache): """Uploads an attachment to FB servers.""" from botshot.core.persistence import get_redis from botshot.core.interfaces.facebook import FacebookInterface redis = get_redis() att_id = FacebookInterface.upload_attachment(conversation, url, type, allow_cache) if att_id is not None: expiry = 60 * 60 * 24 # a day redis.set("FB_ATTACHMENT_FOR_{url}".format(url=url), att_id, ex=expiry)
def _persist_callback(cls, payload) -> str: """ Persists payload to be used with Telegram callbacks (which can be max. 64B) and returns a string that can be used to retrieve the payload from redis. The payload will be persisted for a week. :param payload Payload to be persisted in Redis. :return Unique string associated with the payload, which can be sent to Telegram. """ redis = get_redis() key = ''.join(random.choice(string.hexdigits) for i in range(63)) while redis.exists(key): key = ''.join(random.choice(string.hexdigits) for i in range(63)) redis.set(key, payload, ex=3600 * 24 * 7) return key
def post_message(uid, chat_id, response): if uid and not chat_id: # TODO initiate conversation return message_id = get_redis().get('chat_message_id:{}'.format(chat_id)) if message_id: message_id = message_id.decode() bot_id = MicrosoftInterface.get_bot_id(chat_id) payload = { "type": "message", "from": { "id": bot_id }, "conversation": { "id": chat_id }, "recipient": { "id": uid }, "replyToId": message_id } payload.update(MicrosoftAdapter(chat_id).to_response(response)) url = MicrosoftInterface.get_base_url( chat_id) + 'conversations/' + chat_id + '/activities' if message_id and False: # replying to message TODO get and clear atomically or set timeout or something url += '/' + message_id headers = { "Authorization": "Bearer " + MicrosoftInterface.get_auth_token(), "Content-Type": "application/json" } logging.warning(url) logging.warning(payload) response = requests.post(url, data=json.dumps(payload), headers=headers) if response.status_code != 200: logging.warning(str(payload)) logging.warning(response) logging.warning(response.text) response.raise_for_status()
def get_base_url(chat_id) -> Optional[str]: """ Loads the correct endpoint url for a chat from redis. :param chat_id: Id of the chat. :return: url, throws Exception if chat_id not valid or url not found """ if not chat_id: raise Exception('Chat id must not be null') redis = get_redis() url = redis.get('ms_service_url_' + str(chat_id)) if url is None: raise Exception('Service url not found for chat id ' + str(chat_id)) url = url.decode() if not url.endswith('/'): url += '/' url += 'v3/' return url
def test(request): # TODO use SQL database db = get_redis() results = db.hgetall('test_results') results = [ json.loads(results[k].decode('utf-8')) for k in sorted(list(results)) ] if results else [] updated_time = db.get('test_time') updated_time = db.get('test_time').decode( 'utf-8') if updated_time else None updated_time = datetime.strptime( updated_time, "%Y-%m-%d %H:%M:%S.%f") if updated_time else None # updated_time = naturaltime(updated_time) if updated_time else None status = 'passed' avg = {'duration': 0, 'total': 0, 'init': 0, 'parsing': 0, 'processing': 0} passed = 0 for test in results: result = test['result'] if result['status'] == 'passed': passed += 1 avg['duration'] += result['duration'] avg['total'] += result['report']['avg']['total'] avg['init'] += result['report']['avg']['init'] avg['parsing'] += result['report']['avg']['parsing'] avg['processing'] += result['report']['avg']['processing'] elif status != 'exception': status = result['status'] if passed > 0: for key in avg: avg[key] = avg[key] / passed context = { 'tests': results, 'avg': avg, 'status': status, 'updated_time': updated_time } template = loader.get_template('botshot/test.html') return HttpResponse(template.render(context, request))
def get_auth_token(): """ :returns: Auth token for Microsoft Bot API. """ redis = get_redis() if redis.exists('ms_token'): return redis.get('ms_token').decode() else: url = 'https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token' headers = {"Content-Type": "application/x-www-form-urlencoded"} payload = ('grant_type=client_credentials' + '&client_id=' + settings.BOT_CONFIG.get('MS_BOT_ID') + '&client_secret=' + settings.BOT_CONFIG.get('MS_BOT_TOKEN') + '&scope=' + 'https://api.botframework.com/.default') response = requests.post(url, data=payload, headers=headers) if response.status_code != 200: logging.error(response.text) response.raise_for_status() auth_data = response.json() token = auth_data['access_token'] ex = auth_data['expires_in'] redis.set('ms_token', str(token), ex=ex) return token
def post_message(session, response): GoogleActionsInterface.messages.append(response) get_redis().set("response_for_{id}".format(id=session.chat_id), str(response)) # TODO
def set_base_url(chat_id, url): if not chat_id or not url: raise Exception('Chat id and url must not be null') redis = get_redis() redis.set('ms_service_url_' + str(chat_id), str(url))
def _record(self, type, value): action = RecordedAction(type=type, value=value) get_redis().rpush(DB_KEY, pickle.dumps(action))
def get_actions(): raw_actions = get_redis().lrange(DB_KEY, 0, -1) return [pickle.loads(raw) for raw in raw_actions]
def restart(): get_redis().delete(DB_KEY)
def _retrieve_callback(cls, key) -> Optional[str]: redis = get_redis() if redis.exists(key): return redis.get(key).decode('utf8') return None