shellbot.spaces.ciscospark module

class shellbot.spaces.ciscospark.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"
}
shellbot.spaces.ciscospark.no_exception(function, return_value=None)[source]

Stops the propagation of exceptions

Parameters:return_value – Returned by the decorated function on exception

This decorator is a convenient approach for silently discarding exceptions.

#wip – this should be moved in a general-purpose module of shellbot

Example:

@no_exception(return_value=[])
def list_items():
    ...  # if an exception is raised here, an empty list is returned
shellbot.spaces.ciscospark.retry(give_up='Unable to request Cisco Spark API', silent=False, delays=(0.1, 1, 5), skipped=(401, 403, 404, 409))[source]

Improves a call to Cisco Spark API

Parameters:
  • give_up (str) – message to log on final failure
  • silent (bool) – if exceptions should be masked as much as possible
  • delays (a list of positive numbers) – time to wait between repetitions
  • skipped (a list of web status codes) – do not retry for these status codes

This decorator compensates for common transient communication issues with the Cisco Spark platform in the cloud.

Example:

@retry(give_up="Unable to get information on this bot")
def api_call():
    return self.api.people.me()

me = api_call()

credit: http://code.activestate.com/recipes/580745-retry-decorator-in-python/