def Authenticate(self): botlog.LogConsoleInfo('Authenticating...') self.SessionToken = callout.GetSessionToken() if self.SessionToken != '': botlog.LogSymphonyInfo('Success! Session token obtained.') self.KeyAuthToken = callout.GetKeyManagerToken() if self.KeyAuthToken != '': botlog.LogSymphonyInfo('Success! Key Manager token obtained.') self.SessionExpirationDate = datetime.date.today() + datetime.timedelta(days=7) # self.RESTHeaders = {"sessionToken": self.SessionToken, "keyManagerToken": self.KeyAuthToken, # "Content-Type": "application/json"} self.RESTHeaders = callout.BuildHeaders(self.SessionToken, self.KeyAuthToken) # Attempting to use requests.Session callout.agentSession.headers.update(self.RESTHeaders) botlog.LogSymphonyInfo('Session expires on ' + str(self.SessionExpirationDate)) self.IsAuthenticated = True else: botlog.LogSystemError("Failed to obtain KM Token") else: botlog.LogSystemError("Failed to obtain Session Token")
def Main(): global loopCount botlog.LogSymphonyInfo('Starting Bot session...') botSession = botbuilder.SymSession() # Bot Loop Begins here loopControl = botSession.StartBot() loopCount = 0 # Pre-load the command definitions cmdloader.LoadAllCommands() while loopControl: messages = datafeed.PollDataFeed(botSession.DataFeedId) if messages is not None: if len(messages) == 0: # botlog.LogConsoleInfo('204 - No Content') pass for msg in messages: if msg.IsValid and msg.Sender.IsValidSender: hub.ProcessCommand(msg) else: botlog.LogSymphonyInfo( 'Error detected reading datafeed. Invalidating session...') botSession.InvalidateSession() loopControl = False loopControl = botSession.StartBot()
def RunSlashCommand(messageDetail): # Check to see if it's a default command command = None if messageDetail.Command.CommandName in cmdloader.DefaultCommands: command = cmdloader.DefaultCommands[messageDetail.Command.CommandName] elif messageDetail.Command.CommandName in cmdloader.PluginCommands: command = cmdloader.PluginCommands[messageDetail.Command.CommandName] if command is not None: if messageDetail.Command.IsHelp: SendHelp(messageDetail, command.HelpText, command.Description) else: mod = importlib.import_module(command.Module) if hasattr(mod, command.Function): func = getattr(mod, command.Function) # Allow for some commands to be processed immediately if command.IsImmediate or not config.UseRedisQueues: func(messageDetail) else: queue.AsyncCommand(func, messageDetail) else: #SendReply(messageDetail, "Apologies - I found a definition for that command, ""but the developer forgot to build the function.") botlog.LogSymphonyInfo( "Apologies - I found a definition for that command, " "but the developer forgot to build the function.") else: #SendReply(messageDetail, "I am sorry but I do not understand that command.") botlog.LogSymphonyInfo( "I am sorry but I do not understand that command.")
def SubmitSFDCFeedbackRequest(messageDetail): ep = util.sfdcBaseURL + '/services/apexrest/symphony/feedback' # etree.findall() hashtags = messageDetail.Command.MessageXML.findall('.//hash') clients = [] for ele in hashtags: if 'client' in ele.attrib['tag'] and ele.tail: clients = [x.strip() for x in ele.tail.split(',')] sfdcBody = { "messageid": messageDetail.MessageId, "streamid": messageDetail.StreamId, "submitteremail": messageDetail.Sender.Email, "hashtags": messageDetail.Command.Hashtags, "mentionedusers": messageDetail.Command.Mentions, "summary": messageDetail.Command.MessageFlattened[:50].replace('"', '\''), "comments": messageDetail.Command.MessageFlattened.replace(r'\"', '\'').replace('"', '\''), "companylist": clients } if messageDetail.Attachments: sfdcBody['attachments'] = messageDetail.Attachments log.LogSymphonyInfo(messageDetail.MessageRaw) return util.SFDC_REST('POST', ep, sfdcBody)
def GetGoogleTranslation(messageDetail): transText = messageDetail.Command.MessageText if transText: botlog.LogSymphonyInfo('Attempting to translate: ' + transText) payload = { "client": "gtx", "sl": "auto", "tl": "en", "dt": "t", "q": transText } transEP = "https://translate.googleapis.com/translate_a/single" response = requests.get(transEP, params=payload).json() translation = response[0][0][0] lang = response[2] msg = 'I think you said: ' + translation + ' (' + lang + ')' else: msg = 'Please include a word or sentence to be translated.' messaging.SendSymphonyMessage(messageDetail.StreamId, msg)
def PollDataFeed(datafeedId): datafeedEP = config.SymphonyBaseURL + '/agent/v2/datafeed/' + datafeedId + '/read' #datafeedEP = config.SymphonyBaseURL + '/agent/v4/datafeed/' + datafeedId + '/read' response = callout.SymphonyGET(datafeedEP) # Messages coming from the API are formatted as an array of JSON objects # Thus, I need to break up the array, parse the individual objects, and pass # the list of python objects back to the engine messageItems = [] if response.Success: for respItem in response.ResponseData: # Hopefully this will try: if respItem.v2messageType and respItem.v2messageType == 'V2Message': detail = msg.MessageDetail(respItem) detail.Sender = user.GetSymphonyUserDetail( detail.FromUserId) detail.ChatRoom = stream.GetStreamInfo(respItem.streamId) botlog.LogSymphonyInfo(detail.GetConsoleLogLine()) if detail.Sender and detail.Sender.IsValidSender: detail.InitiateCommandParsing() messageItems.append(detail) elif respItem.v2messageType != 'V2Message': botlog.LogConsoleInfo('Non-chat Message Type: ' + respItem.v2messageType) else: botlog.LogConsoleInfo('Non-chat Message Type: unknown') except SystemExit: botlog.LogConsoleInfo('Exiting Symphony Zendesk Bot.') #messaging.SendSymphonyMessage(_configDef['BotStreamForPing'], "Exiting Symphony Zendesk Bot.") except Exception as ex: errorStr = "Symphony REST Exception (system): " + str(ex) #messaging.SendSymphonyMessage(_configDef['BotStreamForPing'], "Symphony REST Exception (system): " + str(ex)) # stackTrace = 'Stack Trace: ' + ''.join(traceback.format_stack()) exInfo = sys.exc_info() stackTrace = 'Stack Trace: ' + ''.join( traceback.format_exception(exInfo[0], exInfo[1], exInfo[2])) botlog.LogSystemError(errorStr) botlog.LogSystemError(stackTrace) botlog.LogConsoleInfo(response.ResponseText) #messaging.SendSymphonyMessage(_configDef['BotStreamForPing'], response.ResponseText) elif response.ResponseCode == 204: return [] else: botlog.LogConsoleInfo("datafeed.py error - Response Code: " + str(response.ResponseCode)) botlog.LogConsoleInfo("Response Message: " + response.ResponseText) #messaging.SendSymphonyMessage(_configDef['BotStreamForPing'], "datafeed.py error - Response Code: " + str(response.ResponseCode) + " Response Message: " + response.ResponseText) # if the response is not successful, return None. This way, I can tell the datafeed call was bad # and attempt to reconnect to the server. return None return messageItems
def SendSymphonyMessage(streamId, message: str): if not message.startswith('<messageML>'): message = FormatSymphonyMessage(message) messageEP = config.GetSendMessageEndpoint(streamId, config.MessageMLVersion.v1) bodyJSON = {"message": message, "format": "MESSAGEML"} botlog.LogSymphonyInfo('Sending Symphony Message | StreamId: ' + streamId + ' | Message: ' + message) return callout.SymphonyPOST(messageEP, json.dumps(bodyJSON))
def ConnectDatafeed(self): self.BotUserId = user.GetBotUserId() botlog.LogSymphonyInfo('Bot User Id: ' + str(self.BotUserId)) if self.DataFeedId == '': botlog.LogSymphonyInfo('Creating Datafeed...') self.DataFeedId = datafeed.CreateDataFeed() else: botlog.LogSymphonyInfo('Attempting to Reuse Existing Datafeed in 5 seconds...') for sleepIndex in range(0, 5): botlog.LogConsoleInfo(str(sleepIndex) + '...') time.sleep(1) botlog.LogSymphonyInfo('Reconnecting to Datafeed...') if self.DataFeedId != '': botlog.LogSymphonyInfo('Datafeed Connected! Id: ' + self.DataFeedId) self.IsDatafeedConnected = True else: botlog.LogSymphonyError('Failed to connect to Datafeed.')
def LimitedAuth(self): botlog.LogSymphonyInfo('Authenticating...') for index in range(0, 5): self.Authenticate() if self.IsAuthenticated: return else: botlog.LogSymphonyError('Authentication attmept ' + str(index) + 'failed. Trying again in 5 seconds.') time.sleep(5) botlog.LogSymphonyError('Maximum authentication attempts reached. Halting bot.') exit(1)
def LimitedDatafeedConnect(self): botlog.LogSymphonyInfo('Connecting to the Datafeed...') for index in range(0, 5): self.ConnectDatafeed() if self.IsDatafeedConnected: return else: botlog.LogSymphonyError('Datafeed Connect attmpt ' + str(index) + 'failed. Trying again in 5 seconds.') time.sleep(5) botlog.LogSymphonyError('Maximum datafeed connection attempts reached. Halting bot.') exit(1)
def SendSymphonyMessage(streamId, message: str): if not message.startswith('<messageML>'): message = FormatSymphonyMessage(message) # messageEP = config.SymphonyBaseURL + '/agent/v2/stream/' + streamId + '/message/create' # messageEP = endpointRoom.substitute(host=config.SymphonyBaseURL, roomVersion='v2', streamId=streamId) messageEP = config.GetSendMessageEndpoint(streamId, config.MessageMLVersion.v1) bodyJSON = {"message": message, "format": "MESSAGEML"} botlog.LogSymphonyInfo('Sending Symphony Message | StreamId: ' + streamId + ' | Message: ' + message) return callout.SymphonyPOST(messageEP, json.dumps(bodyJSON))
def SendSymphonyMessageV2(streamId, message: str, data=None): if not message.startswith('<messageML>'): message = FormatSymphonyMessage(message) # messageEP = endpointRoom.substitute(host=config.SymphonyBaseURL, roomVersion='v4', streamId=streamId) messageEP = config.GetSendMessageEndpoint(streamId, config.MessageMLVersion.v2) # The data payload has to be converted to a JSON string - the MultipartEncoder won't # convert a dict automatically if data is not None: data = json.dumps(data) bodyObj = {"message": message, "data": data} botlog.LogSymphonyInfo('Sending Symphony Message Create V4 | StreamId: ' + streamId + ' | Message: ' + message) return callout.SymphonyPOSTV2(messageEP, bodyObj)
def SendSymphonyMessageAttachment(streamId, message: str, attach_data: str): chat = GetStreamInfo(streamId) if chat.CrossPod == True: return if not message.startswith('<messageML>'): message = FormatSymphonyMessage(message) #messageEP = config.SymphonyBaseURL + '/agent/v2/stream/' + streamId + '/message/create' messageEP = config.SymphonyBaseURL + '/agent/v4/stream/' + streamId + '/message/create' #bodyJSON = {"message": message, "format": "MESSAGEML"} botlog.LogSymphonyInfo('Sending Symphony Message | StreamId: ' + streamId + ' | Message: ' + message) #return callout.SymphonyPOST(messageEP, json.dumps(bodyJSON)) return callout.SymphonyPOSTv4(messageEP, message, attach_data)
def RunHashCommand(messageDetail): for command in cmdloader.HashCommands: # Set intersection is a clever way to compare the two lists of hashtags intersection = set(messageDetail.Command.Hashtags).intersection( command.Trigger) if len(intersection) > 0: mod = importlib.import_module(command.Module) if hasattr(mod, command.Function): func = getattr(mod, command.Function) func(messageDetail) else: #SendReply(messageDetail, "Sadly, I found triggers for those hashtags, ""but the related function is incomplete or missing.") botlog.LogSymphonyInfo( "Sadly, I found triggers for those hashtags, " "but the related function is incomplete or missing.") break
def GetSymphonyMessages(endpoint): response = callout.SymphonyGET(endpoint) # Messages coming from the API are formatted as an array of JSON objects # Thus, I need to break up the array, parse the individual objects, and pass # the list of python objects back to the engine messageItems = [] if response.Success: for respItem in response.ResponseData: # Hopefully this will try: if respItem.v2messageType and respItem.v2messageType == 'V2Message': detail = msg.MessageDetail(respItem) detail.Sender = user.GetSymphonyUserDetail( detail.FromUserId) detail.ChatRoom = stream.GetStreamInfo(respItem.streamId) botlog.LogSymphonyInfo(detail.GetConsoleLogLine()) if detail.Sender and detail.Sender.IsValidSender: detail.InitiateCommandParsing() messageItems.append(detail) elif respItem.v2messageType != 'V2Message': botlog.LogConsoleInfo('Non-chat Message Type: ' + respItem.v2messageType) else: botlog.LogConsoleInfo('Non-chat Message Type: unknown') except SystemExit: botlog.LogConsoleInfo('Exiting Ares.') except Exception as ex: errorStr = "Symphony REST Exception (system): " + str(ex) # stackTrace = 'Stack Trace: ' + ''.join(traceback.format_stack()) exInfo = sys.exc_info() stackTrace = 'Stack Trace: ' + ''.join( traceback.format_exception(exInfo[0], exInfo[1], exInfo[2])) botlog.LogSystemError(errorStr) botlog.LogSystemError(stackTrace) botlog.LogConsoleInfo(response.ResponseText) return messageItems
def Main(): global loopCount once = True botlog.LogSymphonyInfo('Starting Symphony Zendesk Bot session...') botSession = botbuilder.SymSession() # Bot Loop Begins here loopControl = botSession.StartBot() loopCount = 0 # Pre-load the command definitions cmdloader.LoadAllCommands() #messaging.SendSymphonyMessage(_configDef['BotStreamForPing'], "Starting Bot session") while loopControl: messages = datafeed.PollDataFeed(botSession.DataFeedId) #print(datetime.datetime.now()) #For Tasker now = datetime.datetime.now() #print("Now: " + str(now)) week = datetime.datetime.today().weekday() if messages is not None: if len(messages) == 0: # botlog.LogConsoleInfo('204 - No Content') # messaging.SendSymphonyMessage(_configDef['BotStreamForPing'], "Just a ping to keep the bot alive") pass for msg in messages: if msg.IsValid and msg.Sender.IsValidSender: hub.ProcessCommand(msg) ################################# now = datetime.datetime.now() #print(str(now)) ## Return the day of the week as an integer, where Monday is 0 and Sunday is 6. #week = datetime.datetime.today().weekday() #print(week) #print("###############################") #print(now.strftime("%Y-%m-%d %H:%M:%S")) #deff.listAllTasksTask() # for deff.task in Tasker: # # tasklist = deff.task + " : " + str(Tasker[deff.task]) # tasklist_split = str(tasklist).split(":") # #print(tasklist_split) # # searchOrgTicketorg = tasklist_split[0] # #print(str(searchOrgTicketorg).strip()) # searchOrgTicketstream_id = tasklist_split[1] # #print(str(searchOrgTicketstream_id).strip()) # searchOrgTicketweekday = tasklist_split[2] # #print(str(searchOrgTicketweekday).strip()) # searchOrgTickethour = tasklist_split[3] # #print(str(searchOrgTickethour).strip()) # searchOrgTicketmin = tasklist_split[4] # #print(str(searchOrgTicketmin).strip()) ## Need to intent if used with tasker to be in side for loop if now.hour == int( _configDef['quoteOfTheDay']['hour']) and now.minute == int( _configDef['quoteOfTheDay']['minute']) and once: once = False deff.QoDTask() # messaging.SendSymphonyMessage(_configDef['quoteofthedayStream'], "Hello, test for QOD") ## TODO Scheduler to continue next stream when executed once # # if week == _configDef['searchOrgTicket']['weekday'] and now.hour == _configDef['searchOrgTicket']['hour'] and now.minute == _configDef['searchOrgTicket']['minute'] and once: # # print("Inside") # # once = False # # comm.searchCompanyTicketsTask((_configDef['searchOrgTicket']['org']),(_configDef['searchOrgTicket']['stream'])) # # if week == int(searchOrgTicketweekday) and now.hour == int(searchOrgTickethour) and now.minute == int(searchOrgTicketmin) and once: # #print("Inside") # #once = False # comm.searchCompanyTicketsTask(str(searchOrgTicketorg),(str(searchOrgTicketstream_id))) if now.hour == 23: once = True ################################# else: botlog.LogSymphonyInfo( 'Error detected reading datafeed. Invalidating session...') #messaging.SendSymphonyMessage(_configDef['BotStreamForPing'], "Error detected reading datafeed. Invalidating session...") botSession.InvalidateSession() loopControl = False loopControl = botSession.StartBot()
def LogSymphonyMessageDebug(messageDetail): botlog.LogSymphonyInfo('Message for Debugging: ' + repr(messageDetail.MessageRaw)) messageDetail.ReplyToChat('Thank you for helping improve my code!')