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 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 SymphonyREST(method, endpoint, body): retVal = SymphonyAgentResponse() # Allowing for reauth from the async process if method != 'AUTH' and 'sessionToken' not in agentSession.headers: SymphonyReAuth() try: if method == 'GET': response = agentSession.get(endpoint) elif method == 'POST': response = agentSession.post(endpoint, data=body) elif method == 'POSTV2': response = PostV2(endpoint, body) elif method == 'POSTV2_1': response = PostV2_1(endpoint, body) elif method == 'AUTH': response = agentSession.post(endpoint) else: raise MethodNotImplementedException(method + ' is not yet implemented.') retVal.ResponseText = response.text retVal.ResponseCode = response.status_code if response.status_code == 200: retVal.Success = True retVal.ParseResponseJSON() elif response.status_code // 100 == 2: # Any other 200 code, not success but don't throw exception retVal.Success = True else: response.raise_for_status() except requests.exceptions.HTTPError as httpex: errorStr = "Symphony REST Exception (http): " + str(httpex) botlog.LogConsoleInfo("Response Code: " + str(response.status_code)) botlog.LogConsoleInfo("Response Message: " + response.text) retVal.ErrorMessage = errorStr stackTrace = 'Stack Trace: ' + ''.join(traceback.format_stack()) botlog.LogSymphonyError(errorStr) botlog.LogSymphonyError(stackTrace) except requests.exceptions.RequestException as connex: errorStr = "Symphony REST Exception (connection - Status Code " + str(response.status_code) + \ "): " + str(connex) retVal.ErrorMessage = errorStr stackTrace = 'Stack Trace: ' + ''.join(traceback.format_stack()) botlog.LogSymphonyError(errorStr) botlog.LogSymphonyError(stackTrace) except Exception as ex: errorStr = "Symphony REST Exception (system): " + str(ex) retVal.ErrorMessage = errorStr stackTrace = 'Stack Trace: ' + ''.join(traceback.format_stack()) botlog.LogSystemError(errorStr) botlog.LogSystemError(stackTrace) finally: return retVal
def GetCommandDefinitions(definitionPath, pluginName, cType: CommandTypes): cmdDefs = [] try: with codecs.open(definitionPath, 'r', 'utf-8-sig') as json_file: defJSON = json.load(json_file) if cType == CommandTypes.Hash: defCol = defJSON['hashcommands'] else: defCol = defJSON['commands'] for cmdDef in defCol: if cType == CommandTypes.Hash: cDef = CommandDefinition() cDef.ModuleName = pluginName cDef.Trigger = cmdDef['triggers'] cDef.Function = cmdDef['function'] if pluginName != 'default': cDef.Module = 'modules.plugins.' + pluginName + '.commands' else: cDef.Module = 'modules.command.defaultcommands' cmdDefs.append(cDef) else: for trigger in cmdDef['triggers']: cDef = CommandDefinition() cDef.ModuleName = pluginName if pluginName != 'default': cDef.Module = 'modules.plugins.' + pluginName + '.commands' else: cDef.Module = 'modules.command.defaultcommands' cDef.Trigger = trigger cDef.Description = cmdDef['description'] cDef.HelpText = cmdDef['helptext'] cDef.Function = cmdDef['function'] cDef.IsImmediate = cmdDef[ 'immediate'] if 'immediate' in cmdDef else False cmdDefs.append(cDef) except Exception as ex: errorStr = "Failed to load plugin: " + pluginName + ' - Error: ' + str( ex) stackTrace = 'Stack Trace: ' + ''.join(traceback.format_stack()) botlog.LogSystemError(errorStr) botlog.LogSystemError(stackTrace) return cmdDefs
def GetGiphyImage(messageDetail): try: giphyAPIKey = botconfig.GetCommandSetting('giphy')['apikey'] giphyText = messageDetail.Command.MessageText paramList = giphyText.split() isRandom = len(paramList) == 0 or paramList[0] == 'random' if isRandom: ep = "http://api.giphy.com/v1/gifs/random" payload = {"apikey": giphyAPIKey} else: ep = "http://api.giphy.com/v1/gifs/translate" payload = {"apikey": giphyAPIKey, "s": giphyText} response = requests.get(ep, params=payload).json() if isRandom: msg = "<a href='" + response['data']['image_original_url'] + "'/>" else: msg = "<a href='" + response['data']['images']['original'][ 'url'] + "'/>" messaging.SendSymphonyMessage(messageDetail.StreamId, msg) except Exception as ex: errorStr = "Symphony REST Exception (system): {}".format(ex) botlog.LogSystemError(errorStr) msg = "Sorry, I could not return a GIF right now." messaging.SendSymphonyMessage(messageDetail.StreamId, msg)
def GetAlphaVantageStockQuote(messageDetail): quoteText = messageDetail.Command.MessageText try: avAPIKey = botconfig.GetCommandSetting('alphavantage')['apikey'] quoteSymbol = quoteText.split()[0] payload = { "function": "TIME_SERIES_DAILY", "apikey": avAPIKey, "symbol": quoteSymbol } avEP = 'https://www.alphavantage.co/query' response = requests.get(avEP, params=payload).json() tsDate = sorted(list(response['Time Series (Daily)'].keys()), reverse=True)[0] tsOpen = response['Time Series (Daily)'][tsDate]['1. open'] tsClose = response['Time Series (Daily)'][tsDate]['4. close'] msg = 'Quote for: ' + quoteText + '<br/>Date: ' + tsDate + '<br/>Open: ' + tsOpen msg += '<br/>Close: ' + tsClose + '' messaging.SendSymphonyMessage(messageDetail.StreamId, msg) except Exception as ex: errorStr = "Symphony REST Exception (system): {}".format(ex) botlog.LogSystemError(errorStr) msg = "Sorry, I could not return a quote." messaging.SendSymphonyMessage(messageDetail.StreamId, msg)
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 SubmitUserFeedbackCollection(messageDetailList): from modules.symphony.tokenizer import CommandTypes submitCount = 0 successCount = 0 if len(messageDetailList) > 0: for messageDetail in messageDetailList: if messageDetail.IsValid and messageDetail.Sender.IsValidSender: if messageDetail.Command.IsCommand and messageDetail.Command.CommandType == CommandTypes.Hash: submitCount += 1 response = SubmitSFDCFeedbackRequest(messageDetail) if response.IsSuccess: successCount += 1 else: log.LogSystemError('Failed to send SFDC message: ' + messageDetail.MessageRaw) if submitCount > 0: messageDetailList[0].ReplyToChat('Resubmitted ' + str(submitCount) + ' messages; ' + str(successCount) + ' succeeded.') else: messageDetailList[0].ReplyToChat('No feedback-messages were found.')
pass for msg in messages: if msg.IsValid and msg.Sender.IsValidSender: hub.ProcessCommand(msg) 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() while loopCount < 10: try: Main() except SystemExit: loopCount = 99 pass except Exception as ex: botlog.LogSystemError('Error: ' + str(ex)) botlog.LogSymphonyError( 'Unhandled error, probably network difficulties at the Agent. Retrying in 5s.' ) #messaging.SendSymphonyMessage(_configDef['BotStreamForPing'],"There seems to be some network difficulties at the Agent. Please try again in 5s.") time.sleep(5) loopCount += 1
def SubmitFeedbackJIRAv2(messageDetail): try: issueFieldsDict = {} watcherList = [] labelSet = set(messageDetail.Command.Hashtags) reporter_field = { "name": util.FindJIRAUserByEmailV2(messageDetail.Sender.Email) } issueFieldsDict['reporter'] = reporter_field project = 'SFDC' type_name = 'Unknown' bodyDetail: str = messageDetail.Command.MessageFlattened # Conduct Epic Search epic_item = fbmatch.MatchEpic(bodyDetail) if epic_item is not None: issueFieldsDict['assignee'] = {"name": epic_item['assignTo']} if epic_item['epic'] != "": issueFieldsDict['customfield_10200'] = epic_item['epic'] # Union (|=) the epic specific labels with the hashtag labels labelSet |= set(epic_item['labels']) watcherList = epic_item['mention'] else: log.LogConsoleInfo('No epic match was returned!') # convert label set to list for JSON serialization issueFieldsDict['labels'] = list(labelSet) # Determine what type the feedback is type_dict = { "bug": "Bug", 'bugs': 'Bug', 'defect': 'Bug', 'defects': 'Bug', 'problem': 'Bug', 'problems': 'Bug', 'feature': 'New Feature', 'features': 'New Feature', 'featurerequest': 'New Feature', 'missing': 'New Feature', 'needed': 'New Feature', 'required': 'New Feature', 'newfeature': 'New Feature', 'newfeaturerequest': 'New Feature', 'usability': 'Usability Issue', 'useability': 'Usability Issue', 'performance': 'Usability Issue', 'unstable': 'Usability Issue', 'awkward': 'Usability Issue' } for tag in messageDetail.Command.Hashtags: if tag.lower() in type_dict: type_name = type_dict[tag.lower()] break # Regex to identify hash tags. regexHashtags = r"(\#[a-zA-Z]+\b)" summary = re.sub(regexHashtags, '', messageDetail.Command.MessageFlattened) # Build dict of UID/Users for uid in messageDetail.Command.Mentions: try: userStr = '_u_' + uid userObj = user.GetSymphonyUserDetail(uid) if userObj.Id != '-1': bodyReplace = userObj.FullName + '(' + userObj.Email + ')' bodyDetail = bodyDetail.replace(userStr, bodyReplace) # no need to include the mentioned users in the Summary summary = summary.replace(userStr, '') jiraUser = util.FindJIRAUserByEmailV2(userObj.Email) if jiraUser is not None: watcherList.append(jiraUser) except Exception as ex: log.LogSystemError(str(ex)) # clean up summary # Regex to replace extra spaces with single space regexSpace = "\s\s+" summary = re.sub(regexSpace, ' ', summary)[:100] if messageDetail.Command.CommandRaw is not None: summary = summary.replace(messageDetail.Command.CommandRaw, '') summary = summary.strip() nosubmit = False debug = False for tag in messageDetail.Command.Hashtags: if tag.lower() == 'nosubmit': nosubmit = True elif tag.lower() == 'debug': debug = True if not nosubmit: new_issue = util.CreateIssueV2(projectKey=project, summary=summary, desc=bodyDetail, issueTypeName=type_name, jiraFields=issueFieldsDict) # add watchers util.AddWatchersV2(new_issue, watcherList) msg = 'JIRA created successfully.<br/>Key: ' + new_issue.key + "<br/>JIRA Link: <a href='" + \ new_issue.permalink() + "'/>" messageDetail.ReplyToSenderv2(msg) else: msg = 'Feedback received but #nosubmit was included. Issue not sent to JIRA.' messageDetail.ReplyToSenderv2(msg) if debug: issueFieldsDict['project'] = project issueFieldsDict['summary'] = summary issueFieldsDict['description'] = bodyDetail issueFieldsDict['issueType'] = type_name from modules.symphony.messaging import FormatDicttoMML2 as json_format json_str = json_format(issueFieldsDict) messageDetail.ReplyToSenderv2(json_str) except Exception as ex: errStr = 'Unable to submit JIRA. Error: ' + str(ex) messageDetail.ReplyToSenderv2(errStr) stackTrace = 'Stack Trace: ' + ''.join(traceback.format_exc()) log.LogSymphonyError(errStr) log.LogSymphonyError(stackTrace)