shellbot.spaces package

Module contents

class shellbot.spaces.SpaceFactory[source]

Bases: object

Builds a space from configuration

Example:

my_context = Context(settings={
    'space': {
        'type': "spark",
        'room': 'My preferred room',
        'participants':
            ['alan.droit@azerty.org', 'bob.nard@support.tv'],
        'team': 'Anchor team',
        'token': 'hkNWEtMJNkODk3ZDZLOGQ0OVGlZWU1NmYtyY',
        'fuzzy_token': '$MY_FUZZY_SPARK_TOKEN',
    }
})

space = SpaceFactory.build(context=my_context)
classmethod build(context, **kwargs)[source]

Builds an instance based on provided configuration

Parameters:context (Context) – configuration to be used
Returns:a ready-to-use space
Return type:Space

This function “senses” for a type in the context itself, then provides with an instantiated object of this type.

A ValueError is raised when no type can be identified.

classmethod get(type, **kwargs)[source]

Loads a space by type

Parameters:type (str) – the required space
Returns:a space instance

This function seeks for a suitable space class in the library, and returns an instance of it.

Example:

space = SpaceFactory.get('spark', ex_token='123')

A ValueError is raised if the type is unknown.

classmethod sense(context)[source]

Detects type from configuration

Parameters:context (Context) – configuration to be analyzed
Returns:a guessed type
Return type:str

Example:

type = SpaceFactory.sense(context)

A ValueError is raised if no type could be identified.

types = {'spark': <class 'shellbot.spaces.ciscospark.SparkSpace'>, 'local': <class 'shellbot.spaces.local.LocalSpace'>, 'space': <class 'shellbot.spaces.base.Space'>}
class shellbot.spaces.Space(context=None, ears=None, fan=None, **kwargs)[source]

Bases: object

Handles a collaborative space

A collaborative space supports multiple channels for interactions between persons and bots.

The life cycle of a space can be described as follows:

  1. A space instance is created and configured:

    >>>my_context = Context(...)
    >>>space = Space(context=my_context)
    
  2. The space is connected to some back-end API:

    space.connect()
    
  3. Multiple channels can be handled by a single space:

    channel = space.create(title)
    
    channel = space.get_by_title(title)
    channel = space.get_by_id(id)
    channel = space.get_by_person(label)
    
    channel.title = 'A new title'
    space.update(channel)
    
    space.delete(id)
    

    Channels feature common attributes, yet can be extended to convey specificities of some platforms.

  4. Messages can be posted:

    space.post_message(id, 'Hello, World!')  # for group channels
    space.post_message(person, 'Hello, World!')  # for direct messages
    
  5. You can add and remove participants to channels:

    persons = space.list_participant(id)
    space.add_participants(id, persons)
    space.add_participant(id, person)
    space.remove_participants(id, persons)
    space.remove_participant(id, person)
    

Multiple modes can be considered for the handling of inbound events from the cloud.

  • Asynchronous reception - the back-end API sends updates over a web hook to this object, and messages are pushed to the listening queue.

    Example:

    # link local web server to this space
    server.add_route('/hook', space.webhook)
    
    # link cloud service to this local server
    space.register('http://my.server/hook')
    
  • Background loop - this object pulls the API in a loop, and new messages are pushed to the listening queue.

    Example:

    space.run()
    
DEFAULT_SETTINGS = {'server': {'url': '$SERVER_URL', 'hook': '/hook', 'binding': None, 'port': 8080}, 'space': {'type': 'local', 'title': '$CHAT_ROOM_TITLE'}}
DEFAULT_SPACE_TITLE = u'Collaboration space'
PULL_INTERVAL = 0.05
add_participant(id, person, is_moderator=False)[source]

Adds one participant

Parameters:
  • id (str) – the unique id of an existing channel
  • person (str) – e-mail address of the person to add
  • is_moderator (True or False) – if this person has special powers on this channel

The underlying platform may, or not, take the optional parameter is_moderator into account. The default bahaviour is to discard it, as if the parameter had the value False.

This function should be implemented in sub-class. It should not raise exceptions, since this would kill list_participants().

Example:

@no_exception
def add_participant(self, id, person):
    self.api.memberships.create(id=id, person=person)
add_participants(id, persons=[])[source]

Adds multiple participants

Parameters:
  • id (str) – the unique id of an existing channel
  • persons (list of str) – e-mail addresses of persons to add
check()[source]

Checks settings

This function should be expanded in sub-class, where necessary.

Example:

def check(self):
    self.engine.context.check('space.title',
                              is_mandatory=True)
configure(settings={})[source]

Changes settings of the space

Parameters:settings (dict) – a dictionary with some statements for this instance

After a call to this function, bond() has to be invoked to return to normal mode of operation.

configured_title()[source]

Returns the title of the space as set in configuration

Returns:the configured title, or Collaboration space
Return type:str

This function should be rewritten in sub-classes if space title does not come from space.title parameter.

connect(**kwargs)[source]

Connects to the back-end API

This function should be expanded in sub-class, where required.

Example:

def connect(self, **kwargs):
    self.api = ApiFactory(self.token)
create(title, **kwargs)[source]

Creates a channel

Parameters:title (str) – title of a new channel
Returns:Channel

This function returns a representation of the new channel on success, else it should raise an exception.

This function should be implemented in sub-class.

Example:

def create(self, title=None, **kwargs):
    handle = self.api.rooms.create(title=title)
    return Channel(handle.attributes)
delete(id, **kwargs)[source]

Deletes a channel

Parameters:id (str) – the unique id of an existing channel

After a call to this function the related channel does not appear anymore in the list of available resources in the chat space. This can be implemented in the back-end either by actual deletion of resources, or by archiving the channel. In the second scenario, the channel could be restored at a later stage if needed.

This function should be implemented in sub-class.

Example:

def delete(self, id=id, **kwargs):
    self.api.rooms.delete(id)
deregister()[source]

Stops updates from the cloud back-end

This function should be implemented in sub-class.

get_by_id(id, **kwargs)[source]

Looks for an existing channel by id

Parameters:id (str) – id of the target channel
Returns:Channel instance or None

If a channel already exists with this id, a representation of it is returned. Else the value ``None``is returned.

This function should be implemented in sub-class.

Example:

def get_by_id(self, id, **kwargs):
    handle = self.api.rooms.lookup(id=id)
    if handle:
        return Channel(handle.attributes)
get_by_person(label, **kwargs)[source]

Looks for an existing private channel with a person

Parameters:label (str) – the display name of the person’s account
Returns:Channel instance or None

If a channel already exists for this person, a representation of it is returned. Else the value ``None``is returned.

This function should be implemented in sub-class.

Example:

def get_by_id(self, id, **kwargs):
    handle = self.api.rooms.lookup(id=id)
    if handle:
        return Channel(handle.attributes)
get_by_title(title=None, **kwargs)[source]

Looks for an existing space by title

Parameters:title (str) – title of the target channel
Returns:Channel instance or None

If a channel already exists with this id, a representation of it is returned. Else the value ``None``is returned.

This function should be implemented in sub-class.

Example:

def get_by_title(self, title, **kwargs):
    for handle in self.api.rooms.list()
    if handle.title == title:
        return Channel(handle.attributes)
list_group_channels(**kwargs)[source]

Lists available channels

Returns:list of Channel

This function should be implemented in sub-class.

Example:

def list_group_channels(self, **kwargs):
    for handle in self.api.rooms.list(type='group'):
        yield Channel(handle.attributes)
list_messages(id=None, quantity=10, stop_id=None, up_to=None, with_attachment=False, **kwargs)[source]

List messages

Parameters:
  • id (str) – the unique id of an existing channel
  • quantity (positive integer) – maximum number of returned messages
  • stop_id (str) – stop on this message id, and do not include it
  • up_to (str of ISO date and time) – stop on this date and time
  • with_attachment (True or False) – to get only messages with some attachments
Returns:

a list of Message objects

This function fetches messages from one channel, from newest to the oldest. Compared to the bare walk_messages function, it brings additional capabilities listed below:

  • quantity - limit the maximum number of messages provided
  • stop_id - get new messages since the latest we got
  • up_to - get messages up a given date and time
  • with_attachments - filter messages to retrieve attachments

Example:

for message in space.list_messages(id=channel_id):

    do_something_with_message(message)

    if message.url:
        do_something_with_attachment(message.url)
list_participants(id)[source]

Lists participants to a channel

Parameters:id (str) – the unique id of an existing channel
Returns:a list of persons
Return type:list of str

Note: this function returns all participants, except the bot itself.

on_init(**kwargs)[source]

Handles extended initialisation parameters

This function should be expanded in sub-class, where necessary.

Example:

def on_init(self, ex_parameter='extra', **kwargs):
    ...
on_start()[source]

Reacts when engine is started

This function should be expanded in sub-class, where necessary.

Example:

def on_start(self):
    self.load_cache_from_db()
on_stop()[source]

reacts when engine is stopped

This function attempts to deregister webhooks, if any. This behaviour can be expanded in sub-class, where necessary.

post_message(id=None, text=None, content=None, file=None, person=None, **kwargs)[source]

Posts a message

Parameters:
  • id (str) – the unique id of an existing channel
  • person (str) – address for a direct message
  • text (str) – message in plain text
  • content (str) – rich format, such as Markdown or HTML
  • file (str) – URL or local path for an attachment

Example message out of plain text:

space.post_message(id=id, text='hello world')

Example message with Markdown:

space.post_message(id, content='this is a **bold** statement')

Example file upload:

space.post_message(id, file='./my_file.pdf')

Of course, you can combine text with the upload of a file:

text = 'This is the presentation that was used for our meeting'
space.post_message(id=id,
                   text=text,
                   file='./my_file.pdf')

For direct messages, provide who you want to reach instead of a channel id, like this:

space.post_message(person='foo.bar@acme.com', text='hello guy')

This function should be implemented in sub-class.

Example:

def post_message(self, id, text=None, **kwargs):
    self.api.messages.create(id=id, text=text)
pull()[source]

Fetches updates

This function senses most recent items, and pushes them to the listening queue.

This function should be implemented in sub-class.

Example:

def pull(self):
    for message in self.api.list_message():
        self.ears.put(message)
register(hook_url)[source]

Registers to the cloud API for the reception of updates

Parameters:hook_url (str) – web address to be used by cloud service

This function should be implemented in sub-class.

Example:

def register(self, hook_url):
    self.api.register(hook_url)
remove_participant(id, person)[source]

Removes one participant

Parameters:
  • id (str) – the unique id of an existing channel
  • person (str) – e-mail address of the person to delete

This function should be implemented in sub-class. It should not raise exceptions, since this would kill remove_participants().

Example:

@no_exception
def remove_participant(self, id, person):
    self.api.memberships.delete(id=id, person=person)
remove_participants(id, persons=[])[source]

Removes multiple participants

Parameters:
  • id (str) – the unique id of an existing channel
  • persons (list of str) – e-mail addresses of persons to delete
run()[source]

Continuously fetches updates

This function senses new items at regular intervals, and pushes them to the listening queue.

Processing is handled in a separate background process, like in the following example:

# gets updates in the background
process = space.start()

...

# wait for the end of the process
process.join()

The recommended way for stopping the process is to change the parameter general.switch in the context. For example:

engine.set('general.switch', 'off')

Note: this function should not be invoked if a webhok has been configured.

start(hook_url=None)[source]

Starts the update process

Parameters:hook_url (str) – web address to be used by cloud service (optional)
Returns:either the process that has been started, or None

If an URL is provided, it is communicated to the back-end API for asynchronous updates.

Else this function starts a separate daemonic process to pull updates in the background.

update(channel, **kwargs)[source]

Updates an existing channel

Parameters:channel (Channel) – a representation of the updated channel

This function should raise an exception when the update is not successful.

This function should be implemented in sub-class.

Example:

def update(self, channel):
    self.api.rooms.update(channel.attributes)
walk_messages(id=None, **kwargs)[source]

Walk messages

Parameters:id (str) – the unique id of an existing channel
Returns:a iterator of Message objects

This function returns messages from a channel, from the newest to the oldest.

This function should be implemented in sub-class

webhook()[source]

Handles updates sent over the internet

This function should use the request object to retrieve details of the web transaction.

This function should be implemented in sub-class.

Example:

def webhook(self):

    message_id = request.json['data']['id']
    item = self.api.messages.get(messageId=message_id)
    self.ears.put(item._json)
    return "OK"
class shellbot.spaces.LocalSpace(context=None, ears=None, fan=None, **kwargs)[source]

Bases: shellbot.spaces.base.Space

Handles chat locally

This class allows developers to test their commands interface locally, without the need for a real API back-end.

If a list of commands is provided as input, then the space will consume all of them and then it will stop. All kinds of automated tests and scenarios can be build with this approach.

Example of automated interaction with some commands:

engine = Engine(command=Hello(), type='local')
engine.space.push(['help', 'hello', 'help help'])

engine.configure()
engine.run()

If no input is provided, then the space provides a command-line interface so that you can play interactively with your bot. This setup is handy since it does not require access to a real chat back-end.

DEFAULT_PROMPT = u'> '
add_participant(id, person, is_moderator=False)[source]

Adds one participant

Parameters:
  • id (str) – the unique id of an existing channel
  • person (str) – e-mail address of the person to add
  • is_moderator (True or False) – if this person has special powers on this channel
check()[source]

Check settings

This function reads key local and below, and update the context accordingly.

This function also selects the right input for this local space. If some content has been provided during initialisation, it is used to simulate user input. Else stdin is read one line at a time.

create(title, **kwargs)[source]

Creates a channel

Parameters:title (str) – title of a new channel
Returns:Channel

This function returns a representation of the local channel.

delete(id, **kwargs)[source]

Deletes a channel

Parameters:id (str) – the unique id of an existing channel
get_by_id(id, **kwargs)[source]

Looks for an existing channel by id

Parameters:id (str) – identifier of the target channel
Returns:Channel instance or None
get_by_title(title, **kwargs)[source]

Looks for an existing channel by title

Parameters:title (str) – title of the target channel
Returns:Channel instance or None
list_group_channels(**kwargs)[source]

Lists available channels

Returns:list of Channel
list_participants(id)[source]

Lists participants to a channel

Parameters:id (str) – the unique id of an existing channel
Returns:a list of persons
Return type:list of str

Note: this function returns all participants, except the bot itself.

on_init(input=None, **kwargs)[source]

Handles extended initialisation parameters

Parameters:input (str or list of str) – Lines of text to be submitted to the chat

Example:

space = LocalSpace(input='hello world')

Here we create a new local space, and simulate a user typing ‘hello world’ in the chat space.

on_message(item, queue)[source]

Normalizes message for the listener

Parameters:
  • item (dict) – attributes of the inbound message
  • queue (Queue) – the processing queue

This function prepares a Message and push it to the provided queue.

on_start()[source]

Adds processing on engine start

post_message(id=None, text=None, content=None, file=None, person=None, **kwargs)[source]

Posts a message

Parameters:
  • id (str) – the unique id of an existing channel
  • person (str) – address for a direct message
  • text (str) – message in plain text
  • content (str) – rich format, such as MArkdown or HTML
  • file (str) – URL or local path for an attachment
pull()[source]

Fetches updates

This function senses most recent item, and pushes it to the listening queue.

push(input)[source]

Adds more input to this space

Parameters:input (str or list of str) – Simulated user input

This function is used to simulate input user to the bot.

remove_participant(id, person)[source]

Removes one participant

Parameters:
  • id (str) – the unique id of an existing channel
  • person (str) – e-mail address of the person to remove
update(channel, **kwargs)[source]

Updates an existing channel

Parameters:channel (Channel) – a representation of the updated channel
walk_messages(id=None, **kwargs)[source]

Walk messages

Parameters:id (str) – the unique id of an existing channel
Returns:a iterator of Message objects

This function returns messages from a channel, from the newest to the oldest.

class shellbot.spaces.SparkSpace(context=None, ears=None, fan=None, **kwargs)[source]

Bases: shellbot.spaces.base.Space

Handles a Cisco Spark room

This is a representation of a chat space hosted at Cisco Spark.

DEFAULT_SETTINGS = {'server': {'url': '$SERVER_URL', 'hook': '/hook', 'binding': '0.0.0.0', 'port': 8080}, 'space': {'room': '$CHAT_ROOM_TITLE'}}
add_participant(*args, **kwargs)[source]
check()[source]

Checks settings of the space

This function reads key space and below, and update the context accordingly:

space.configure({'space': {
    'type': 'spark',
    'room': 'My preferred room',
    'participants':
       ['alan.droit@azerty.org', 'bob.nard@support.tv'],
    'team': 'Anchor team',
    'token': '$MY_BOT_TOKEN',
    }})

This can also be written in a more compact form:

space.configure({'space.room': 'My preferred room',
    'space.token': '$MY_BOT_TOKEN',
    })

This function handles following parameters:

  • space.room - title of the associated Cisco Spark room. This can refer to an environment variable if it starts with $, e.g., $ROOM_TITLE.
  • space.participants - list of initial participants. This can be taken from $CHANNEL_DEFAULT_PARTICIPANTS from the environment.
  • space.team - title of a team associated with this room
  • space.token - private token of the bot, given by Cisco Spark. Instead of putting the real value of the token you are encouraged to use an environment variable instead, e.g., $MY_BOT_TOKEN. If space.token is not provided, then the function looks for an environment variable CISCO_SPARK_BOT_TOKEN.
  • space.audit_token - token to be used for the audit of chat events. It is recommended that a token of a person is used, so that the visibility is maximised for the proper audit of events. Instead of putting the real value of the token you are encouraged to use an environment variable instead, e.g., $MY_AUDIT_TOKEN. If space.audit_token is not provided, then the function looks for an environment variable CISCO_SPARK_AUDIT_TOKEN.

If a single value is provided for participants then it is turned automatically to a list.

Example:

>>>space.configure({'space.participants': 'bobby@jah.com'})
>>>space.context.get('space.participants')
['bobby@jah.com']
configured_title()[source]

Returns the title of the space as set in configuration

Returns:the configured title, or Collaboration space
Return type:str

This function should be rewritten in sub-classes if space title does not come from space.room parameter.

connect(factory=None, **kwargs)[source]

Connects to the back-end API

Parameters:factory – an API factory, for test purpose
Type:object

If a factory is provided, it is used to get API instances. Else the regular CiscoSparkAPI is invoked instead.

This function loads two instances of Cisco Spark API, one using the bot token, and one using the audit token, if this is available.

create(title, ex_team=None, **kwargs)[source]

Creates a room

Parameters:
  • title (str) – title of a new channel
  • ex_team (str or object) – the team attached to this room (optional)

If the parameter ex_team is provided, then it can be either a simple name, or a team object featuring an id.

Returns:Channel or None

This function returns a representation of the local channel.

delete(id, **kwargs)[source]

Deletes a room

Parameters:id (str) – the unique id of an existing room
deregister()[source]

Stops inbound flow from Cisco Spark

This function deregisters hooks that it may have created.

Previous webhooks registered with the bot token are all removed before registration. This means that only the most recent instance of the bot will be notified of new invitations.

This function also removes webhooks created with the audit token, if any. So after deregister the audit of individual rooms just stops.

download_attachment(url, token=None)[source]

Copies a shared document locally

get_attachment(url, token=None, response=None)[source]

Retrieves a document attached to a room

Returns:a stream of BytesIO
Return type:BytesIO

#TODO: stream from requests response = requests.get(url, stream=True) response.decode_content = True shutil.copyfileobj(response.raw, target)

get_by_id(id, **kwargs)[source]

Looks for an existing room by id

Parameters:id (str) – identifier of the target room
Returns:Channel instance or None
get_by_person(label, **kwargs)[source]

Looks for an existing private room with a person

Parameters:label (str) – the display name of the person’s account
Returns:Channel instance or None

If a channel already exists for this person, a representation of it is returned. Else the value ``None``is returned.

get_by_title(title, **kwargs)[source]

Looks for an existing room by name

Parameters:title (str) – title of the target room
Returns:Channel instance or None

Note: This function looks only into group rooms. To get a direct room use get_by_person() instead.

get_team(name)[source]

Gets a team by name

Parameters:name (str) – name of the target team
Returns:attributes of the team
Return type:Team or None

>>>print(space.get_team(“Hello World”)) Team({

“id” : “Y2lzY29zcGFyazovL3VzL1RFQU0Yy0xMWU2LWE5ZDgtMjExYTBkYzc5NzY5”, “name” : “Hello World”, “created” : “2015-10-18T14:26:16+00:00”

})

list_group_channels(quantity=10, **kwargs)[source]

Lists available channels

Parameters:quantity (positive integer) – maximum quantity of channels to return
Returns:list of Channel
list_participants(id)[source]

Lists participants to a channel

Parameters:id (str) – the unique id of an existing channel
Returns:a list of persons
Return type:list of str

Note: this function returns all participants, except the bot itself.

name_attachment(url, token=None, response=None)[source]

Retrieves a document attached to a room

on_connect()[source]

Retrieves attributes of this bot

This function queries the Cisco Spark API to remember the id of this bot. This is used afterwards to filter inbound messages to the shell.

on_init(token=None, **kwargs)[source]

Handles extended initialisation parameters

Parameters:token (str) – bot authentication token for the Cisco Spark API

Example:

space = SparkSpace(context=context)
on_join(item, queue=None)[source]

Normalizes message for the listener

Parameters:
  • item (dict) – attributes of the inbound message
  • queue (Queue) – the processing queue (optional)

Example item received on memberships:create:

{
    'isMonitor': False,
    'created': '2017-05-31T21:25:30.424Z',
    'personId': 'Y2lzY29zcGFyazovL3VRiMTAtODZkYy02YzU0Yjg5ODA5N2U',
    'isModerator': False,
    'personOrgId': 'Y2lzY29zcGFyazovL3V0FOSVpBVElPTi9jb25zdW1lcg',
    'personDisplayName': 'foo.bar@acme.com',
    'personEmail': 'foo.bar@acme.com',
    'roomId': 'Y2lzY29zcGFyazovL3VzL1JP3LTk5MDAtMDU5MDI2YjBiNDUz',
    'id': 'Y2lzY29zcGFyazovL3VzDctMTFlNy05OTAwLTA1OTAyNmIwYjQ1Mw'
}

This function prepares a Join and push it to the provided queue.

  • type is set to join
  • actor_id is a copy of personId
  • actor_address is a copy of personEmail
  • actor_label is a copy of personDisplayName
  • stamp is a copy of created
on_leave(item, queue=None)[source]

Normalizes message for the listener

Parameters:
  • item (dict) – attributes of the inbound message
  • queue (Queue) – the processing queue (optional)

Example item received on memberships:delete:

{
    'isMonitor': False,
    'created': '2017-05-31T21:25:30.424Z',
    'personId': 'Y2lzY29zcGFyazovL3VRiMTAtODZkYy02YzU0Yjg5ODA5N2U',
    'isModerator': False,
    'personOrgId': 'Y2lzY29zcGFyazovL3V0FOSVpBVElPTi9jb25zdW1lcg',
    'personDisplayName': 'foo.bar@acme.com',
    'personEmail': 'foo.bar@acme.com',
    'roomId': 'Y2lzY29zcGFyazovL3VzL1JP3LTk5MDAtMDU5MDI2YjBiNDUz',
    'id': 'Y2lzY29zcGFyazovL3VzDctMTFlNy05OTAwLTA1OTAyNmIwYjQ1Mw'
}

This function prepares a Leave and push it to the provided queue.

  • type is set to leave
  • actor_id is a copy of personId
  • actor_address is a copy of personEmail
  • actor_label is a copy of personDisplayName
  • stamp is a copy of created
on_message(item, queue=None)[source]

Normalizes message for the listener

Parameters:
  • item (dict) – attributes of the inbound message
  • queue (Queue) – the processing queue (optional)
Returns:

a Message

This function prepares a Message and push it to the provided queue.

This function adds following keys to messages so that a neutral format can be used with the listener:

  • type is set to message
  • content is a copy of html
  • from_id is a copy of personId
  • from_label is a copy of personEmail
  • is_direct if the message is coming from 1:1 room
  • mentioned_ids is a copy of mentionedPeople
  • channel_id is a copy of roomId
  • stamp is a copy of created
post_message(id=None, text=None, content=None, file=None, person=None, **kwargs)[source]

Posts a message to a Cisco Spark room

Parameters:
  • id (str) – the unique id of an existing room
  • person (str) – address for a direct message
  • text (str) – message in plain text
  • content (str) – rich format, such as Markdown or HTML
  • file (str) – URL or local path for an attachment

Example message out of plain text:

space.post_message(id=id, text='hello world')

Example message with Markdown:

space.post_message(id, content='this is a **bold** statement')

Example file upload:

space.post_message(id, file='./my_file.pdf')

Of course, you can combine text with the upload of a file:

text = 'This is the presentation that was used for our meeting'
space.post_message(id=id,
                   text=text,
                   file='./my_file.pdf')

For direct messages, provide who you want to reach instead of a channel id, like this:

space.post_message(person='foo.bar@acme.com', text='hello guy')
pull()[source]

Fetches events from Cisco Spark

This function senses most recent items, and pushes them to a processing queue.

register(hook_url)[source]

Connects in the background to Cisco Spark inbound events

Parameters:webhook (str) – web address to be used by Cisco Spark service

This function registers the provided hook multiple times, so as to receive mutiple kind of updates:

  • The bot is invited to a room, or kicked out of it. People are joining or leaving: webhook name = shellbot-memberships resource = memberships, event = all, registered with bot token
  • Messages are sent, maybe with some files: webhook name = shellbot-messages resource = messages, event = created, registered with bot token
  • Messages sent, maybe with some files, for audit purpose: webhook name = shellbot-audit resource = messages, event = created, registered with audit token

Previous webhooks registered with the bot token are all removed before registration. This means that only the most recent instance of the bot will be notified of new invitations.

remove_participant(*args, **kwargs)[source]
update(channel, **kwargs)[source]

Updates an existing room

Parameters:channel (Channel) – a representation of the updated room

This function can change the title of a room.

For example, change the title from a bot instance:

bot.channel.title = "A new title"
bot.space.update(bot.channel)
walk_messages(id=None, **kwargs)[source]

Walk messages from a Cisco Spark room

Parameters:id (str) – the unique id of an existing room
Returns:an iterator of Message objects
webhook(item=None)[source]

Processes the flow of events from Cisco Spark

Parameters:item (dict) – if provided, do not invoke the request object

This function is called from far far away, over the Internet, most of the time. Or it is called locally, from test environment, when an item is provided.

The structure of the provided item should be identical to those of updates sent by Cisco Spark.

Example event on message creation:

{
    "resource": "messages",
    "event": "created",
    "data": { "id": "...." },
    "name": "shellbot-audit"
}