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.util import _
from loops.browser.common import BaseView from loops.browser.common import BaseView
from loops.browser.concept import ConceptView from loops.browser.concept import ConceptView
from loops.organize.interfaces import IPresence
from loops.organize.tracking import access from loops.organize.tracking import access
from loops.versioning.util import getVersion from loops.versioning.util import getVersion
@ -135,9 +136,21 @@ class NodeView(BaseView):
icon='cybertools.icons/user.png', icon='cybertools.icons/user.png',
url=url, url=url,
priority=10) 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 # force early portlet registrations by target by setting up target view
self.virtualTarget self.virtualTarget
@Lazy
def usersPresent(self):
presence = component.getUtility(IPresence)
presence.update(self.request.principal.id)
data = presence.getPresentUsers()
return data
@Lazy @Lazy
def view(self): def view(self):
name = self.request.get('loops.viewName', '') or self.context.viewName name = self.request.get('loops.viewName', '') or self.context.viewName

View file

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

Binary file not shown.

View file

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

View file

@ -34,6 +34,9 @@ from zope.app.security.interfaces import IAuthentication
from zope import schema from zope import schema
from zope.traversing.api import getParent 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 _ from loops.util import _
@ -98,6 +101,14 @@ class PersonBasedAuthenticator(Persistent, Contained):
return InternalPrincipal(self, login) 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): class InternalPrincipal(object):
def __init__(self, auth, login): def __init__(self, auth, login):

View file

@ -50,6 +50,11 @@
<!-- authentication --> <!-- 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"> <zope:localUtility class="loops.organize.auth.PersonBasedAuthenticator">
<require <require
permission="zope.ManageServices" permission="zope.ManageServices"
@ -72,6 +77,8 @@
<zope:adapter factory="loops.organize.setup.SetupManager" <zope:adapter factory="loops.organize.setup.SetupManager"
name="organize" /> name="organize" />
<zope:utility factory="loops.organize.presence.Presence" />
<!-- include --> <!-- include -->
<include package=".browser" /> <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 # 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 # it under the terms of the GNU General Public License as published by
@ -177,3 +177,34 @@ class IAllocated(IConceptSchema):
)), )),
default='standard', default='standard',
required=True) 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]