123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- from __future__ import unicode_literals
- import datetime
- import logging
- import emoji
- class Message(object):
- _DEFAULT_USER_ICON_SIZE = 72
- def __init__(self, formatter, message):
- self._formatter = formatter
- self._message = message
- ##############
- # Properties #
- ##############
- @property
- def user_id(self):
- if "user" in self._message:
- return self._message["user"]
- elif "bot_id" in self._message:
- return self._message["bot_id"]
- else:
- logging.error("No user ID on %s", self._message)
- @property
- def user(self):
- return self._formatter.find_user(self._message)
- @property
- def username(self):
- try:
- return self.user.display_name
- except KeyError:
- # In case this is a bot or something, we fallback to "username"
- if "username" in self._message:
- return self._message["username"]
- elif "user" in self._message:
- return self.user_id
- elif "bot_id" in self._message:
- return self._message["bot_id"]
- else:
- return None
- @property
- def time(self):
- # Handle this: "ts": "1456427378.000002"
- tsepoch = float(self._message["ts"].split(".")[0])
- return str(datetime.datetime.fromtimestamp(tsepoch)).split('.')[0]
- @property
- def attachments(self):
- return [ LinkAttachment("ATTACHMENT", entry, self._formatter)
- for entry in self._message.get("attachments", []) ]
- @property
- def files(self):
- if "file" in self._message: # this is probably an outdated case
- allfiles = [self._message["file"]]
- else:
- allfiles = self._message.get("files", [])
- return [ LinkAttachment("FILE", entry, self._formatter) for entry in allfiles ]
- @property
- def msg(self):
- text = self._message.get("text")
- if text:
- text = self._formatter.render_text(text)
- return text
- def user_message(self, user_id):
- return {"user": user_id}
- def usernames(self, reaction):
- return [
- self._formatter.find_user(self.user_message(user_id)).display_name
- for user_id
- in reaction.get("users")
- if self._formatter.find_user(self.user_message(user_id))
- ]
- @property
- def reactions(self):
- reactions = self._message.get("reactions", [])
- return [
- {
- "usernames": self.usernames(reaction),
- "name": emoji.emojize(
- self._formatter.slack_to_accepted_emoji(':{}:'.format(reaction.get("name"))),
- language='alias'
- )
- }
- for reaction in reactions
- ]
- @property
- def img(self):
- try:
- return self.user.image_url(self._DEFAULT_USER_ICON_SIZE)
- except KeyError:
- return ""
- @property
- def id(self):
- return self.time
- @property
- def subtype(self):
- return self._message.get("subtype")
- class LinkAttachment(object):
- """
- Wrapper class for entries in either the "files" or "attachments" arrays.
- """
- _DEFAULT_THUMBNAIL_SIZE = 360
- # Fields that need to be processed for markup (and possibly markdown)
- _TEXT_FIELDS = {"pretext", "text", "footer"}
- def __init__(self, attachment_type, raw, formatter):
- self._type = attachment_type
- self._raw = raw
- self._formatter = formatter
- def __getitem__(self, key):
- content = self._raw[key]
- if content and key in self._TEXT_FIELDS:
- process_markdown = (key in self._raw.get("mrkdwn_in", []))
- content = self._formatter.render_text(content, process_markdown)
- return content
- def thumbnail(self, size=None):
- size = size if size else self._DEFAULT_THUMBNAIL_SIZE
- # ATTACHMENT type
- if "image_url" in self._raw:
- logging.debug("image_url path")
- return {
- "src": self._raw["image_url"],
- "width": self._raw.get("image_width"),
- "height": self._raw.get("image_height"),
- }
- else: # FILE type
- thumb_key = "thumb_{}".format(size)
- logging.debug("thumb path" + thumb_key)
- if thumb_key not in self._raw:
- # let's try some fallback logic
- thumb_key = "thumb_{}".format(self._raw.get("filetype"))
- if thumb_key not in self._raw:
- # pick the first one that shows up in the iterator
- candidates = [k for k in self._raw.keys()
- if k.startswith("thumb_") and not k.endswith(("_w","_h"))]
- if candidates:
- thumb_key = candidates[0]
- logging.info("Fell back to thumbnail key %s for [%s]",
- thumb_key, self._raw.get("title"))
- if thumb_key in self._raw:
- return {
- "src": self._raw[thumb_key],
- "width": self._raw.get(thumb_key + "_w"),
- "height": self._raw.get(thumb_key + "_h"),
- }
- else:
- logging.info("No thumbnail found for [%s]", self._raw.get("title"))
- @property
- def is_image(self):
- return self._raw.get("mimetype", "").startswith("image/")
- @property
- def link(self):
- if "from_url" in self._raw:
- return self._raw["from_url"]
- else:
- return self._raw.get("url_private")
- @property
- def fields(self):
- """
- Fetch the "fields" list, and process the text within each field, including markdown
- processing if the message indicates that the fields contain markdown.
- Only present on attachments, not files--this abstraction isn't 100% awesome.'
- """
- process_markdown = ("fields" in self._raw.get("mrkdwn_in", []))
- fields = self._raw.get("fields", [])
- if fields:
- logging.debug("Rendering with markdown markdown %s for %s", process_markdown, fields)
- return [
- {"title": e["title"], "short": e.get("short", False), "value": self._formatter.render_text(e["value"], process_markdown)}
- for e in fields
- ]
|