diff options
| author | kd <kdam0@localhost.localdomain> | 2020-06-09 20:26:53 +0000 |
|---|---|---|
| committer | kd <kdam0@localhost.localdomain> | 2020-06-09 20:26:53 +0000 |
| commit | 474fbe0850ba5dc6a7aa8eb06c60d229af674dcb (patch) | |
| tree | a3404048efbbea06f5943999f2cd034c371ccdbf /slack_parser.py | |
initial commit
Diffstat (limited to 'slack_parser.py')
| -rw-r--r-- | slack_parser.py | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/slack_parser.py b/slack_parser.py new file mode 100644 index 0000000..8756992 --- /dev/null +++ b/slack_parser.py @@ -0,0 +1,169 @@ +import os +import json +import re +import time +from jsonpath_ng import jsonpath, parse + + +# jsonpath match will match in order of appearence. +# This mapping defines which position in the RESULT of match to look for which key. +# so. eg. at 0th position (of the match) will be the key "text", etc. +key_orderings = { + "text": 0, + "ts": 1, + "name": 2 +} + +class SlackParser(object): + + """Docstring for SlackParser. """ + + def __init__(self, messagesDir=None, usersFile=None, keys=None): + + self.messagesDir = "" + self.usersFile = "" + self.keys = list() + if messagesDir is not None: + self.messagesDir += messagesDir + if usersFile is not None: + self.usersFile += usersFile + if keys is not None: + self.keys += keys + + self.usersLib = None + + def getSortedMessageFiles(self): + """Docstring for getSortedMessageFiles. + Get the files that contain channel data sorted. + + :returns: a sorted list of json files names for the channel + + """ + files = sorted(os.listdir( self.messagesDir )) + return files + + def getUsers(self): + """Docstring for getUsers + Get the parsed json that contains the raw user info. + + :returns: a dict with all users infos + + """ + path = self.usersFile + # TODO: check for path validity + content = json.load(open(path)) + return content + + + def buildUsersLibrary(self): + """Docstring for buildUsersLibrary + Build a Users dict that keeps only usersid to name mappings. + + :returns: a dict user info + + """ + userLib = {} + for userjson in self.getUsers(): + if "name" in userjson and "id" in userjson: + userLib[userjson["id"]] = userjson["name"] + self.setUsersLib(userLib) + return self + + def setUsersLib(self, usersLib): + """Docstring for buildUsersLibrary + A setter method that sets the object lib to the given lib. + + """ + self.usersLib = usersLib + + def getMessages(self, slackFile): + """Docstring for getMessages. + Given a file, get the messages in that file. + + :slackFile: the json file name containing messages + :returns: a list of all messages in the file + + """ + path = self.messagesDir + "/" + slackFile + # TODO: check for path validity + content = json.load(open(path)) + return content + + def getKeyValues(self, slackMessage): + """Docstring for getKeyValues. + Get the value for each key (defined during init) from the mssg. + + :slackMessage: the parsed json slack message + :returns: on success, a dict with only required keys and values + on failure, None + + """ + data = None + # we also check for "subtype" to filter out mssgs like: + # "s joined the channel", "x left the channel" etc. + if "type" in slackMessage and "subtype" not in slackMessage: + if slackMessage["type"] == "message" and slackMessage["text"] != "": + data = {} + jsonpath_expression = parse("$.." + str(self.keys)) + # search slackMessage for each key, and add all matches (incl. dups.) in-order + match = jsonpath_expression.find(slackMessage) + #print(match[0]) + for key in self.keys: + # TODO: validation for matches possible "index out of range" here. + data[key] = match[key_orderings[key]].value + # get the user id in the text + userIds = self.getUserIdsFromMessage(data["text"]) + if userIds != []: + # find corresponding usernames from library + userNamesinMessageDict = self.getUserNamesFromIds(self.usersLib, userIds) + # inject usernames in the text replace userid + data["text"] = self.replaceMessageUserIdsWithNames(userNamesinMessageDict, data["text"]) + # convert ts to a human readble time + data["ts"] = time.strftime( "%H:%M %b %d, %Y", time.localtime(float(data["ts"])) ) + + return data + + @staticmethod + def getUserIdsFromMessage(text): + """Docstring for getUserIdsFromMessage. + A helper method that searches a text for Slack user ids. It maps: + "<@SLACKID1>adsfasdf <@SLACKID2>" -> ["SLACKID1", "SLACKID2"] + + :text: raw text from Slack message json + :returns: a list of userids strings in the text in order of match + + """ + regex = r"<@(.+?)>" + matches = re.findall(regex, text) + return matches + + @staticmethod + def getUserNamesFromIds(usersDict, userIds): + """Docstring for getUserNamesFromIds. + A helper method to search a dict for a keys, and get the values. + + :usersDict: a dict library of userid and name mappings + :ids: a string list of userids + :returns: dict of each userid and its username + + """ + userMap = {} + for userId in userIds: + if userId in usersDict: + userMap[userId] = usersDict[userId] + return userMap + + @staticmethod + def replaceMessageUserIdsWithNames(messageUsersDict, text): + """Docstring for replaceMessageUserIdsWithNames. + A helper method to replace all Slackuser id tags with their @username. So it maps: + { "USERID1" : "name1" , "USERID2": "name2" },"<@USERID1> blah blah <@USERID2>." -> "@name1 blah blah @name2." + + :messageUsersDict: the dict containing userid to username mappings for this text + :text: the original string contianing Slack userids in it + :returns: a string with each Slack userid replaced with mapping value from dict. + + """ + for userId in messageUsersDict.keys(): + text = re.sub( "<@{}>".format(userId), "<i style='color: #B18904;'>@{}</i>".format(messageUsersDict[userId]), text ) + return text |
