From bb6a3b3d7bc4918d2b6ed092a1f8c8d65f30323d Mon Sep 17 00:00:00 2001 From: helmutm Date: Fri, 31 Oct 2008 16:51:04 +0000 Subject: [PATCH] add access logging git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2963 fd906abe-77d9-0310-91a1-e0d9ade77398 --- browser/common.py | 9 ++++ browser/node.py | 15 ++++++ browser/resource.py | 5 +- organize/tracking/README.txt | 12 +++-- organize/tracking/access.py | 87 ++++++++++++++++++++++++++++++++ organize/tracking/change.py | 2 +- organize/tracking/configure.zcml | 2 + 7 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 organize/tracking/access.py diff --git a/browser/common.py b/browser/common.py index dde524e..ce37cbb 100644 --- a/browser/common.py +++ b/browser/common.py @@ -58,6 +58,7 @@ from cybertools.typology.interfaces import IType, ITypeManager from loops.common import adapted from loops.i18n.browser import I18NView from loops.interfaces import IResource, IView, INode +from loops.organize.tracking import access from loops.resource import Resource from loops.security.common import canAccessObject, canListObject, canWriteObject from loops.type import ITypeConcept @@ -130,6 +131,14 @@ class BaseView(GenericView, I18NView): def name(self): return getName(self.context) + @Lazy + def principalId(self): + principal = self.request.principal + return principal and principal.id or '' + + def recordAccess(self, viewName, **kw): + access.record(self.request, principal=self.principalId, view=viewName, **kw) + @Lazy def versions(self): return version.versions diff --git a/browser/node.py b/browser/node.py index 2eb669f..43f6c92 100644 --- a/browser/node.py +++ b/browser/node.py @@ -60,6 +60,7 @@ from loops import util from loops.util import _ from loops.browser.common import BaseView from loops.browser.concept import ConceptView +from loops.organize.tracking import access from loops.versioning.util import getVersion @@ -82,6 +83,19 @@ class NodeView(BaseView): def macro(self): return self.template.macros['content'] + def update(self): + result = super(NodeView, self).update() + self.recordAccess() + return result + + def recordAccess(self, viewName=''): + target = self.virtualTargetObject + targetUid = target is not None and util.getUidForObject(target) or '' + access.record(self.request, principal=self.principalId, + node=self.uniqueId, + target=targetUid, + view=viewName) + def setupController(self): cm = self.controller.macros cm.register('css', identifier='loops.css', resourceName='loops.css', @@ -462,6 +476,7 @@ class NodeView(BaseView): if ti is not None: target = ti(target) url = self.virtualTargetUrl + self.recordAccess('external_edit') return ExternalEditorView(target, self.request).load(url=url) diff --git a/browser/resource.py b/browser/resource.py index 25d8ccb..b38876a 100644 --- a/browser/resource.py +++ b/browser/resource.py @@ -146,6 +146,7 @@ class ResourceView(BaseView): def show(self, useAttachment=False): """ show means: "download"...""" context = self.context + self.recordAccess('show', target=self.uniqueId) ti = IType(context).typeInterface if ti is not None: context = ti(context) @@ -289,6 +290,7 @@ class DocumentView(ResourceView): def render(self): """ Return the rendered content (data) of the context object. """ + self.recordAccess('render', target=self.uniqueId) ctx = adapted(self.context) text = ctx.data contentType = ctx.contentType @@ -301,11 +303,12 @@ class DocumentView(ResourceView): and canWrite(self.context, 'data')) -class ExternalEditorView(ExternalEditorView): +class ExternalEditorView(ExternalEditorView, BaseView): def load(self, url=None): #context = removeSecurityProxy(self.context) context = self.context + self.recordAccess('external_edit', target=self.uniqueId) data = adapted(context).data r = [] context = removeSecurityProxy(context) diff --git a/organize/tracking/README.txt b/organize/tracking/README.txt index 21334f1..1b08688 100644 --- a/organize/tracking/README.txt +++ b/organize/tracking/README.txt @@ -24,8 +24,8 @@ ZCML setup): >>> concepts, resources, views = t.setup() -Tracking Changes and Object Access -================================== +Tracking Changes +================ >>> loopsRoot = concepts.getLoopsRoot() >>> records = loopsRoot.getRecordManager() @@ -48,7 +48,7 @@ Recording changes to objects >>> from loops.organize.tracking.change import recordModification >>> component.provideHandler(recordModification) - >>> loopsRoot.options = ['organize.tracking:changes'] + >>> loopsRoot.options = ['organize.tracking.changes'] >>> tTask = concepts['task'] >>> from loops.concept import Concept @@ -71,6 +71,12 @@ Recording assignment changes 2 +Tracking Object Access +====================== + + >>> from loops.organize.tracking.access import record + + Fin de partie ============= diff --git a/organize/tracking/access.py b/organize/tracking/access.py new file mode 100644 index 0000000..6ab816e --- /dev/null +++ b/organize/tracking/access.py @@ -0,0 +1,87 @@ +# +# Copyright (c) 2008 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 +# + +""" +Recording changes to loops objects. + +$Id$ +""" + +import os + +from zope.app.publication.interfaces import IEndRequestEvent +from zope.interface import Interface +from zope.cachedescriptors.property import Lazy +from zope.component import adapter +from zope.security.proxy import removeSecurityProxy + +from cybertools.meta.interfaces import IOptions +from cybertools.tracking.btree import Track, getTimeStamp +from cybertools.tracking.interfaces import ITrack +from cybertools.tracking.logfile import Logger, loggers +from loops.interfaces import ILoopsObject +from loops.organize.party import getPersonForUser +from loops.security.common import getCurrentPrincipal +from loops import util + + +request_key = 'loops.organize.tracking.access' +loggers_key = 'loops.access' + +fields = { + '001': ('principal', 'node', 'target', 'view', 'params'), +} + + +def record(request, **kw): + data = request.annotations.setdefault(request_key, {}) + for k, v in kw.items(): + data[k] = v + + +@adapter(IEndRequestEvent) +def logAccess(event): + object = removeSecurityProxy(event.object) + context = getattr(object, 'context', None) + if context is None: + object = getattr(object, 'im_self', None) + context = getattr(object, 'context', None) + if context is None: + return + if not ILoopsObject.providedBy(context): + return + data = event.request.annotations.get(request_key) + if not data: + return + logger = loggers.get(loggers_key) + if not logger: + options = IOptions(context.getLoopsRoot()) + logfile = options('organize.tracking.logfile') + if not logfile: + return + path = os.path.join(util.getVarDirectory(), logfile[0]) + logger = loggers[loggers_key] = Logger(loggers_key, path) + logger.log(marshall(data)) + + +def marshall(data): + version = '001' + values = [version] + for key in fields[version]: + values.append(data.get(key) or '') + return ';'.join(values) diff --git a/organize/tracking/change.py b/organize/tracking/change.py index 38dcc63..fb9a195 100644 --- a/organize/tracking/change.py +++ b/organize/tracking/change.py @@ -60,7 +60,7 @@ class ChangeManager(object): return (not (self.context is None or self.storage is None or self.personId is None) - and 'changes' in self.options('organize.tracking', ())) + and self.options('organize.tracking.changes')) @Lazy def loopsRoot(self): diff --git a/organize/tracking/configure.zcml b/organize/tracking/configure.zcml index caa49b2..d1b4fea 100644 --- a/organize/tracking/configure.zcml +++ b/organize/tracking/configure.zcml @@ -24,6 +24,8 @@ + +