add a portlet showing the presence of other users; may be activated by the global option 'organize.showPresence'

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3466 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2009-07-20 14:56:04 +00:00
parent c54b0e283c
commit 48701178bd
9 changed files with 149 additions and 2 deletions

View file

@ -59,6 +59,7 @@ from loops import util
from loops.util import _
from loops.browser.common import BaseView
from loops.browser.concept import ConceptView
from loops.organize.interfaces import IPresence
from loops.organize.tracking import access
from loops.versioning.util import getVersion
@ -135,9 +136,21 @@ class NodeView(BaseView):
icon='cybertools.icons/user.png',
url=url,
priority=10)
if self.globalOptions('organize.showPresence'):
cm.register('portlet_right', 'presence', title=_(u'Presence'),
subMacro=node_macros.macros['presence'],
icon='cybertools.icons/group.png',
priority=11)
# force early portlet registrations by target by setting up target view
self.virtualTarget
@Lazy
def usersPresent(self):
presence = component.getUtility(IPresence)
presence.update(self.request.principal.id)
data = presence.getPresentUsers()
return data
@Lazy
def view(self):
name = self.request.get('loops.viewName', '') or self.context.viewName

View file

@ -236,6 +236,13 @@
</metal:actions>
<metal:actions define-macro="presence">
<tal:user repeat="user view/usersPresent">
<div tal:content="user" />
</tal:user>
</metal:actions>
<!-- inner HTML macros -->
<div metal:define-macro="inline_edit"

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: $Id$\n"
"POT-Creation-Date: 2007-05-22 12:00 CET\n"
"PO-Revision-Date: 2009-07-13 12:00 CET\n"
"PO-Revision-Date: 2009-07-20 12:00 CET\n"
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
"Language-Team: loops developers <helmutm@cy55.de>\n"
"MIME-Version: 1.0\n"
@ -158,6 +158,9 @@ msgstr "Aktuelles Objekt zu Lesezeichen hinzufügen"
msgid "Remove from favorites"
msgstr "Aus Lesezeichen entfernen"
msgid "Presence"
msgstr "Anwesenheit"
msgid "Actions"
msgstr "Aktionen"

View file

@ -415,6 +415,13 @@ Send Email to Members
u'\n\nEvent #1\nhttp://127.0.0.1/loops/views/menu/.97\n\n'
Show Presence of Other Users
============================
>>> from loops.organize.presence import Presence
>>> component.provideUtility(Presence())
Fin de partie
=============

View file

@ -34,6 +34,9 @@ from zope.app.security.interfaces import IAuthentication
from zope import schema
from zope.traversing.api import getParent
from cybertools.browser.loops.auth import LoopsSessionCredentialsPlugin \
as BaseSessionCredentialsPlugin
from loops.organize.interfaces import IPresence
from loops.util import _
@ -98,6 +101,14 @@ class PersonBasedAuthenticator(Persistent, Contained):
return InternalPrincipal(self, login)
class LoopsSessionCredentialsPlugin(BaseSessionCredentialsPlugin):
def logout(self, request):
presence = component.getUtility(IPresence)
presence.removePresentUser(request.principal.id)
super(LoopsSessionCredentialsPlugin, self).logout(request)
class InternalPrincipal(object):
def __init__(self, auth, login):

View file

@ -50,6 +50,11 @@
<!-- authentication -->
<zope:utility
name="loops Session Credentials"
provides="zope.app.authentication.interfaces.ICredentialsPlugin"
factory="loops.organize.auth.LoopsSessionCredentialsPlugin" />
<zope:localUtility class="loops.organize.auth.PersonBasedAuthenticator">
<require
permission="zope.ManageServices"
@ -72,6 +77,8 @@
<zope:adapter factory="loops.organize.setup.SetupManager"
name="organize" />
<zope:utility factory="loops.organize.presence.Presence" />
<!-- include -->
<include package=".browser" />

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -177,3 +177,34 @@ class IAllocated(IConceptSchema):
)),
default='standard',
required=True)
# presence
class IPresence(Interface):
""" Utility for getting information about active principals,
mapping principal.id to timestamp of last activity.
"""
def update(self, principalId):
""" Update Dictionary of active users, by calling addPresentUser();
automaticly check for inactive users by calling
removeInactiveUsers().
"""
def addPresentUser(self, principalId):
"""Add a user to dictionary of active users.
"""
def removeInactiveUsers(self):
""" Remove a user from dictionary of active users if user
didn't interact for last min_until_logout minutes.
"""
def getPresentUsers(self):
""" Return list of titles of active users.
"""
def removePresentUser(self, principalId):
""" Remove user from dictionary of active users, e.g. when user logs out.
"""

68
organize/presence.py Normal file
View file

@ -0,0 +1,68 @@
#
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Utility for collecting information about logged-in/active users.
Author: Hannes Plattner.
$Id$
"""
from zope.interface import implements
from zope.cachedescriptors.property import Lazy
from cybertools.meta.interfaces import IOptions
from cybertools.util.date import getTimeStamp
from loops.organize.interfaces import IPresence
from loops.organize import util
class Presence(object):
implements(IPresence)
def __init__(self, min_until_logout=10, presentUsers=None):
self.min_until_logout = min_until_logout
self.presentUsers = presentUsers or {}
def update(self, principalId):
self.addPresentUser(principalId)
self.removeInactiveUsers()
def addPresentUser(self, principalId):
self.presentUsers[principalId] = getTimeStamp()
def removeInactiveUsers(self):
toDelete = []
for id, timeStamp in self.presentUsers.iteritems():
if (getTimeStamp() - timeStamp) > (self.min_until_logout*60):
toDelete.append(id)
for id in toDelete:
if id in self.presentUsers:
del self.presentUsers[id]
def getPresentUsers(self):
ret = []
for id, timeStamp in self.presentUsers.iteritems():
ret.append(util.getPrincipalForUserId(id).title)
return ret
def removePresentUser(self, principalId):
if principalId in self.presentUsers:
del self.presentUsers[principalId]