Package: tgapp-activitystream
About activitystreamactivitystream is a Pluggable application for TurboGears2 for create a simple activity stream.The activity stream is intended to be used as base layer for anotificationsystemCurrently this pluggable works only withmingfell free to submit a pull request withsqlalchemysupportInstallingactivitystream can be installed both from pypi or from github:pip install activitystreamshould just work for most of the usersPlugging activitystreamIn your applicationconfig/app_cfg.pyimportplug:from tgext.pluggable import plugThen at theend of the filecall plug with activitystream:plug(base_config, 'activitystream')ActionManagerWhen you want to create an activity you should do something like:from activitystream import ActionManager
am = ActionManager()

activity = am.create(
    actor=model.User.query.find().all()[0],
    verb='created',
    target=model.Post.query.find().all()[0],
    recipients=model.User.query.find().all()[1:3],
)Then you may want to notify the activity to the recipients.
It’s up to you to choose how to dispatch them.Fields Explanationactor: reference to who is creating the activityverb: a string describing the action itself, for example ‘created’ or ‘updated’action_obj: reference to … I don’t knowtarget: reference to the subject of the activitytimestamp: datetime of the creation of the activitydescription: string with a description of the activityextra: string that you can use for example to store a json with extra informationsrecipients: list of references to who is expected to receive
a notification from this activity. references can be of different entities.Not Seen (counter of unread notifications)Add in your recipient model (probably your User model):from datetime import datetime
last_activity_seen = FieldProperty(s.DateTime, if_missing=datetime.utcnow())then you can get the latest 10 notifications of a recipient with:recipient = model.User.query.find().all()[1]
actions = am.get_by_recipient(recipient).limit(10).all()
# and if you want a counter of unread notifications call
count = am.count_not_seen_by_recipient(recipient)
# you can check if the recipient have seen a notification with
not_seen = actions[0].timestamp > recipient.last_activity_seen
# don't forget to update your recipient when him reads his notifications
recipient.last_activity_seen = datetime.utcnow()Exposed Controllersif you don’t like your urls to start with activitystream justplugwith a new app_id/activitystream/ajax_update_last_seen_of_a_recipient: call this through ajax with_typeand_idof the recipient to updatelast_activity_seen.
should return a json with the last_activity_seen before the update/activitystream/see: updateslast_activity_seenof the logged in user
and redirects to the giventarget_linkNotifications RenderingThis is up to you. I suggest to usetg.render_templatewithtg_cacheadding inmyproject.lib.helpers:from activitystream import am
from tg import render_template
def notification_cache(n):
    return {
        'cache_key': n._id,  # this is really important
        'cache_expire': 604800,  # a week
        'cache_type': 'memory',
    }and in the template where you want your notifications to being displayed:<py:for each="n in h.am.get_by_recipient(request.identity['user']).limit(10)">
  <li>${h.render_template(
    {'n': n, 'tg_cache': h.notification_cache(n)},
    'kajiki',
    'myproject.templates.notification'
  )}<hr/></li>
</py:for>meanwhile yourmyproject.templates.notificationmay look like:<a href="${h.plug_url('activitystream', '/see', params={'target_link': n.target_link})}">
  <img src="${n.actor.avatar_url}"/>
  <div class="content">
    <b>${n.actor.display_name}</b> ${_(n.verb)} <i>${n.target}</i>
    <div>${n.timestamp_since}</div>
  </div>
</a>if your notification needs to be rendered differently based on the recipient then you have to use
another caching strategy