def publish(self, topic, obj, reference_message=None): """ Sends an object out over the pubsub connection, properly formatted, and conforming to the protocol. Handles pickling for the wire, etc. This method should *not* be subclassed. """ logging.debug("Publishing topic (%s): \n%s" % (topic, obj)) e = Event( data=obj, type=topic, ) if hasattr(obj, "sender"): e.sender = obj.sender if reference_message: original_incoming_event_hash = None if hasattr(reference_message, "original_incoming_event_hash"): original_incoming_event_hash = reference_message.original_incoming_event_hash elif hasattr(reference_message, "source") and hasattr( reference_message.source, "hash"): original_incoming_event_hash = reference_message.source.hash elif hasattr(reference_message, "source") and hasattr( reference_message.source, "original_incoming_event_hash"): original_incoming_event_hash = reference_message.source.original_incoming_event_hash elif hasattr(reference_message, "hash"): original_incoming_event_hash = reference_message.hash if original_incoming_event_hash: e.original_incoming_event_hash = original_incoming_event_hash return self.publish_to_backend(self._localize_topic(topic), self.encrypt(e))
def say(self, content, message=None, room=None, channel=None, service=None, package_for_scheduling=False, **kwargs): logging.info("self.say") logging.info(content) if channel: room = channel elif room: channel = room if not "channel" in kwargs and channel: kwargs["channel"] = channel message = self.get_message(message) message = self._trim_for_execution(message) backend = self.get_backend(message, service=service) if backend: e = Event( type="say", content=content, source_message=message, kwargs=kwargs, ) if package_for_scheduling: return "message.outgoing.%s" % backend, e else: logging.info("putting in queue: %s" % content) self.publish("message.outgoing.%s" % backend, e)
def say(self, content, message=None, room=None, channel=None, service=None, package_for_scheduling=False, **kwargs): 'Publish an event to be shipped to one of the IO backends.' if channel: room = channel elif room: channel = room if "channel" not in kwargs and channel: kwargs["channel"] = channel message = self.get_message(message) message = self._trim_for_execution(message) backend = self.get_backend(message, service=service) if backend: e = Event( type="say", content=content, source_message=message, kwargs=kwargs, ) if package_for_scheduling: return "message.outgoing.%s" % backend, e logging.info("putting in queue: %s", content) self.publish("message.outgoing.%s" % backend, e) return None
def _changed_callback(self, collection, _id, fields, cleared): logging.debug('_changed_callback') logging.debug('collection: {}'.format(collection)) logging.debug('id: {}'.format(_id)) logging.debug('fields: {}'.format(self.pp.pformat(fields))) logging.debug('cleared: {}'.format(cleared)) event = Event(type='message', version=1, **fields['args'][0]) self.handle_incoming_event(event)
def not_allowed(self, message, explanation): self.bot.pubsub.publish( "message.outgoing.%s" % message.data.backend, Event( type="reply", content=explanation, source_message=message, ), reference_message=message.data.original_incoming_event)
def execute(self, message, option): if "acl" in option.context: acl = option.context["acl"] if type(acl) == type("test"): acl = [acl] allowed = True if len(acl) > 0: allowed = test_acl(message, acl) if not allowed: acl_list = "" more_than_one_s = "" if len(acl) > 1: more_than_one_s = "s" for i in range(0, len(acl)): if i == 0: acl_list = "%s" % acl[i] elif i == len(acl) - 1: acl_list = "%s or %s" % (acl_list, acl[i]) else: acl_list = "%s, %s" % (acl_list, acl[i]) explanation = "Sorry, but I don't have you listed in the %s group%s, which is required to do what you asked." % ( acl_list, more_than_one_s) self.not_allowed(message, explanation) return if "say_content" in option.context: # We're coming from a generation engine like a chatterbot, which doesn't *do* things. self.bot.pubsub.publish( "message.outgoing.%s" % message.data.backend, Event( type="reply", content=option.context["say_content"], source_message=message, ), reference_message=message.data.original_incoming_event) else: module = imp.load_source(option.context.plugin_info["parent_name"], option.context.plugin_info["parent_path"]) cls = getattr(module, option.context.plugin_info["name"]) instantiated_module = cls(message=message) method = getattr(instantiated_module, option.context.function_name) thread_args = [ message, ] + option.context["args"] self.run_execute(method, *thread_args, **option.context.search_matches)
def set_topic(self, topic, message=None, room=None, channel=None, service=None, **kwargs): if channel: room = channel elif room: channel = room message = self.get_message(message) message = self._trim_for_execution(message) backend = self.get_backend(message, service=service) e = Event( type="topic_change", content=topic, topic="message.outgoing.%s" % backend, source_message=message, kwargs=kwargs, ) self.publish("message.outgoing.%s" % backend, e)
def send_file(self, message, content, filename, text=None, filetype='text', service=None, room=None, channel=None, **kwargs): 'Sometimes you need to upload an image or file' if channel: room = channel elif room: channel = room if "channel" not in kwargs and channel: kwargs["channel"] = channel message = self.get_message(message) message = self._trim_for_execution(message) backend = self.get_backend(message, service=service) if backend: if isinstance(content, str): content = content.encode('utf-8') e = Event( type="file.upload", file=content, filename=FILENAME_CLEANER.sub('_', filename), filetype=filetype, source_message=message, title=text, kwargs=kwargs, ) logging.info("putting in queue: %s", content) self.publish("message.outgoing.%s" % backend, e)
def _event(fields): required_fields = {"type": "TBD", "version": 1} required_fields.update(fields) return Event(**required_fields)
def get_event_data(self, event): "Send a Slack message" data = {} if hasattr(event, "kwargs"): data.update(event.kwargs) # Add slack-specific functionality if "color" in event.kwargs: data.update({ "attachments": json.dumps([{ "fallback": event.content, "color": self._map_color(event.kwargs["color"]), "text": event.content, }]), }) elif "attachments" in event.kwargs: data.update({ "text": event.content, "attachments": json.dumps(event.kwargs["attachments"]), }) else: data.update({ "text": event.content, }) else: data.update({ "text": event.content, }) data = self.set_data_channel_and_thread(event, data=data) # Auto-link mention names if "text" in data: if data["text"].find("<@") != -1: data["text"] = data["text"].replace("<@", "<@") data["text"] = data["text"].replace(">", ">") if len(data['text']) > MAX_MESSAGE_SIZE: new_event = Event( type='file.upload', # Removes "code" markers from around the item and then makes it bytes file=data['text'].strip('```').encode('utf-8'), filename=getattr(event, 'filename', getattr(event, 'title', 'response')), filetype=getattr(event, 'filetype', 'text'), source_message=event.source_message, kwargs=event.kwargs, ) try: self.send_file(new_event) except Exception: logging.exception('Error sending file') return None elif "attachments" in data and "text" in data["attachments"][0]: if data["attachments"][0]["text"].find("<@") != -1: data["attachments"][0]["text"] = data["attachments"][0][ "text"].replace("<@", "<@") data["attachments"][0]["text"] = data["attachments"][0][ "text"].replace(">", ">") data.update({ "token": settings.SLACK_API_TOKEN, "as_user": True, }) if hasattr( event, "kwargs") and "html" in event.kwargs and event.kwargs["html"]: data.update({ "parse": "none", }) return data
def reply(self, event, content=None, message=None, package_for_scheduling=False, **kwargs): message = self.get_message(message) if "channel" in kwargs: logging.error( "I was just asked to talk to %(channel)s, but I can't use channel using .reply() - " "it's just for replying to the person who talked to me. Please use .say() instead." % kwargs) return if "service" in kwargs: logging.error( "I was just asked to talk to %(service)s, but I can't use a service using .reply() - " "it's just for replying to the person who talked to me. Please use .say() instead." % kwargs) return if "room" in kwargs: logging.error( "I was just asked to talk to %(room)s, but I can't use room using .reply() - " "it's just for replying to the person who talked to me. Please use .say() instead." % kwargs) return # Be really smart about what we're getting back. if (((event and hasattr(event, "will_internal_type") and event.will_internal_type == "Message") or (event and hasattr(event, "will_internal_type") and event.will_internal_type == "Event")) and type(content) == type("words")): # "1.x world - user passed a message and a string. Keep rolling." pass elif (((content and hasattr(content, "will_internal_type") and content.will_internal_type == "Message") or (content and hasattr(content, "will_internal_type") and content.will_internal_type == "Event")) and type(event) == type("words")): # "User passed the string and message object backwards, and we're in a 1.x world" temp_content = content content = event event = temp_content del temp_content elif (type(event) == type("words") and not content): # "We're in the Will 2.0 automagic event finding." content = event event = self.message else: # "No magic needed." pass # Be smart about backend. if hasattr(event, "data"): message = event.data elif hasattr(self, "message") and hasattr(self.message, "data"): message = self.message.data backend = self.get_backend(message) if backend: e = Event( type="reply", content=content, topic="message.outgoing.%s" % backend, source_message=message, kwargs=kwargs, ) if package_for_scheduling: return e else: self.publish("message.outgoing.%s" % backend, e)