Beispiel #1
0
    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))
Beispiel #2
0
    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)
Beispiel #3
0
    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
Beispiel #4
0
 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)
Beispiel #5
0
    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)
Beispiel #6
0
    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)
Beispiel #7
0
    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)
Beispiel #8
0
    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)
Beispiel #9
0
    def _event(fields):
        required_fields = {"type": "TBD", "version": 1}
        required_fields.update(fields)

        return Event(**required_fields)
Beispiel #10
0
    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("&lt;@", "<@")
                data["text"] = data["text"].replace("&gt;", ">")
            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("&lt;@") != -1:
                data["attachments"][0]["text"] = data["attachments"][0][
                    "text"].replace("&lt;@", "<@")
                data["attachments"][0]["text"] = data["attachments"][0][
                    "text"].replace("&gt;", ">")

        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
Beispiel #11
0
    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)