work in progress: personal filters
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@4034 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
0bbea0f45b
commit
64db0029e6
11 changed files with 298 additions and 11 deletions
|
@ -12,9 +12,9 @@
|
|||
<h1><a tal:omit-tag="python: level > 1"
|
||||
tal:attributes="href request/URL"
|
||||
tal:content="item/title">Title</a></h1>
|
||||
<p tal:define="description description|item/description"
|
||||
<p tal:define="description description|item/renderedDescription"
|
||||
tal:condition="description">
|
||||
<i tal:content="description">Description</i></p>
|
||||
<i tal:content="structure description">Description</i></p>
|
||||
<metal:fields define-slot="fields" />
|
||||
<div class="content-1" id="1.body"
|
||||
tal:attributes="id id;"
|
||||
|
|
|
@ -74,7 +74,8 @@ textarea {
|
|||
|
||||
table.listing {
|
||||
margin: 1px;
|
||||
margin-top: 6px;
|
||||
/*margin-top: 0.5em; */
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
table.listing th {
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
<ul>
|
||||
<li><a href="change_password.html"
|
||||
i18n:translate="">Change Password</a></li>
|
||||
<li><a href="change_password.html"
|
||||
tal:condition="python:item.globalOptions('organize.useFilters')"
|
||||
i18n:translate="">Edit Filters</a></li>
|
||||
</ul>
|
||||
</metal:block>
|
||||
</metal:block>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2010 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
|
||||
|
@ -29,6 +29,7 @@ from zope.cachedescriptors.property import Lazy
|
|||
from zope.traversing.browser.absoluteurl import absoluteURL
|
||||
|
||||
from cybertools.browser.configurator import ViewConfigurator, MacroViewProperty
|
||||
from cybertools.meta.interfaces import IOptions
|
||||
from loops.organize.party import getPersonForUser
|
||||
from loops.util import _
|
||||
|
||||
|
@ -44,17 +45,32 @@ class PortletConfigurator(ViewConfigurator):
|
|||
self.context = context
|
||||
self.request = request
|
||||
|
||||
@property
|
||||
def viewProperties(self):
|
||||
return self.favorites + self.filters
|
||||
|
||||
@Lazy
|
||||
def records(self):
|
||||
return self.context.getLoopsRoot().getRecordManager()
|
||||
|
||||
@Lazy
|
||||
def person(self):
|
||||
return getPersonForUser(self.context, self.request)
|
||||
|
||||
def hasFavorites(self):
|
||||
records = self.context.getLoopsRoot().getRecordManager()
|
||||
if records is not None:
|
||||
return 'favorites' in records
|
||||
if self.records is not None:
|
||||
return 'favorites' in self.records
|
||||
return False
|
||||
|
||||
def hasFilters(self):
|
||||
if (IOptions(self.context.getLoopsRoot()).organize.useFilters and
|
||||
self.records is not None):
|
||||
return 'filters' in self.records
|
||||
return False
|
||||
|
||||
@property
|
||||
def viewProperties(self):
|
||||
if (not self.hasFavorites()
|
||||
or getPersonForUser(self.context, self.request) is None):
|
||||
#if IUnauthenticatedPrincipal.providedBy(self.request.principal):
|
||||
def favorites(self):
|
||||
if (not self.hasFavorites() or self.person is None):
|
||||
return []
|
||||
favorites = MacroViewProperty(self.context, self.request)
|
||||
favorites.setParams(dict(
|
||||
|
@ -67,3 +83,17 @@ class PortletConfigurator(ViewConfigurator):
|
|||
))
|
||||
return [favorites]
|
||||
|
||||
@property
|
||||
def filters(self):
|
||||
if (not self.hasFilters() or self.person is None):
|
||||
return []
|
||||
filters = MacroViewProperty(self.context, self.request)
|
||||
filters.setParams(dict(
|
||||
slot='portlet_right',
|
||||
identifier='loops.organize.filters',
|
||||
title=_(u'Filters'),
|
||||
subMacro=personal_macros.macros['filters_portlet'],
|
||||
priority=195,
|
||||
url=absoluteURL(self.context, self.request) + '/@@filters.html',
|
||||
))
|
||||
return [filters]
|
||||
|
|
|
@ -20,4 +20,13 @@
|
|||
<page name="removeFavorite.html" attribute="remove" />
|
||||
</browser:pages>
|
||||
|
||||
<browser:pages
|
||||
class="loops.organize.personal.browser.filter.FilterView"
|
||||
for="loops.interfaces.INode"
|
||||
permission="zope.View">
|
||||
<page name="filters_view" />
|
||||
<page name="addFilter.html" attribute="add" />
|
||||
<page name="deactivateFilter.html" attribute="deactivate" />
|
||||
</browser:pages>
|
||||
|
||||
</configure>
|
||||
|
|
87
organize/personal/browser/filter.py
Normal file
87
organize/personal/browser/filter.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
#
|
||||
# Copyright (c) 2010 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
|
||||
#
|
||||
|
||||
"""
|
||||
A view (to be used by listings, portlets, ...) for filters.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope import component
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
from cybertools.browser.configurator import ViewConfigurator, MacroViewProperty
|
||||
from loops.browser.node import NodeView
|
||||
from loops.organize.party import getPersonForUser
|
||||
from loops.organize.personal.interfaces import IFilters
|
||||
from loops import util
|
||||
|
||||
|
||||
personal_macros = ViewPageTemplateFile('personal_macros.pt')
|
||||
|
||||
|
||||
class FilterView(NodeView):
|
||||
|
||||
@Lazy
|
||||
def item(self):
|
||||
return self
|
||||
|
||||
@Lazy
|
||||
def person(self):
|
||||
return getPersonForUser(self.context, self.request)
|
||||
|
||||
@Lazy
|
||||
def filters(self):
|
||||
records = self.loopsRoot.getRecordManager()
|
||||
if records is not None:
|
||||
storage = records.get('filters')
|
||||
if storage is not None:
|
||||
return IFilters(storage)
|
||||
return None
|
||||
|
||||
def listFilters(self):
|
||||
if self.filters is None:
|
||||
return
|
||||
for uid in self.filters.list(self.person):
|
||||
obj = util.getObjectForUid(uid)
|
||||
if obj is not None:
|
||||
yield dict(url=self.getUrlForTarget(obj),
|
||||
uid=uid,
|
||||
title=obj.title,
|
||||
description=obj.description,
|
||||
object=obj)
|
||||
|
||||
def add(self):
|
||||
if self.filters is None:
|
||||
return
|
||||
uid = self.request.get('id')
|
||||
if not uid:
|
||||
return
|
||||
obj = util.getObjectForUid(uid)
|
||||
self.filters.add(obj, self.person)
|
||||
self.request.response.redirect(self.virtualTargetUrl)
|
||||
|
||||
def deactivate(self):
|
||||
if self.filters is None:
|
||||
return
|
||||
id = self.request.get('id')
|
||||
if not id:
|
||||
return
|
||||
self.filters.deactivate(id)
|
||||
self.request.response.redirect(self.virtualTargetUrl)
|
|
@ -22,3 +22,29 @@
|
|||
i18n:attributes="title">Add to Favorites</a>
|
||||
</div>
|
||||
</metal:actions>
|
||||
|
||||
|
||||
<metal:actions define-macro="filters_portlet"
|
||||
tal:define="view nocall:context/@@filters_view;
|
||||
targetUid view/targetUid">
|
||||
<div tal:repeat="item view/listFilters">
|
||||
<span style="float:right" class="delete-item"> <a href="removeFilter.html"
|
||||
tal:attributes="href
|
||||
string:${view/url}/deactivateFilter.html?id=${item/uid};
|
||||
title string:Deactivate filter"
|
||||
i18n:attributes="title">X</a> </span>
|
||||
<a href=""
|
||||
tal:attributes="href item/url;
|
||||
title item/description"
|
||||
tal:content="item/title">Some object</a>
|
||||
</div>
|
||||
<div id="addFilter" class="action"
|
||||
tal:condition="targetUid">
|
||||
<a href="addFilter.html"
|
||||
i18n:translate=""
|
||||
tal:attributes="href
|
||||
string:${view/virtualTargetUrl}/addFilter.html?id=$targetUid;
|
||||
title string:Use current object as filter"
|
||||
i18n:attributes="title">Add Filter</a>
|
||||
</div>
|
||||
</metal:actions>
|
||||
|
|
|
@ -17,6 +17,19 @@
|
|||
interface="loops.organize.personal.interfaces.IFavorites" />
|
||||
</class>
|
||||
|
||||
<class class="loops.organize.personal.filter.Filter">
|
||||
<require permission="zope.View"
|
||||
interface="loops.organize.personal.interfaces.IFilter" />
|
||||
<require permission="zope.ManageContent"
|
||||
set_schema="loops.organize.personal.interfaces.IFilter" />
|
||||
</class>
|
||||
|
||||
<adapter factory="loops.organize.personal.filter.Filters" trusted="True" />
|
||||
<class class="loops.organize.personal.filter.Filters">
|
||||
<require permission="zope.View"
|
||||
interface="loops.organize.personal.interfaces.IFilters" />
|
||||
</class>
|
||||
|
||||
<adapter factory="loops.organize.personal.setup.SetupManager"
|
||||
name="organize.personal" />
|
||||
|
||||
|
|
79
organize/personal/filter.py
Normal file
79
organize/personal/filter.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
#
|
||||
# Copyright (c) 2010 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
|
||||
#
|
||||
|
||||
"""
|
||||
Base classes for filters.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.component import adapts
|
||||
from zope.interface import implements
|
||||
|
||||
from cybertools.tracking.btree import Track
|
||||
from cybertools.tracking.interfaces import ITrackingStorage
|
||||
from loops.organize.personal.interfaces import IFilters, IFilter
|
||||
from loops import util
|
||||
|
||||
|
||||
class Filters(object):
|
||||
|
||||
implements(IFilters)
|
||||
adapts(ITrackingStorage)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
def list(self, person, activeOnly=True, sortKey=None):
|
||||
for item in self.listTracks(person, sortKey):
|
||||
yield item.taskId
|
||||
|
||||
def listTracks(self, person, sortKey=None):
|
||||
if person is None:
|
||||
return
|
||||
personUid = util.getUidForObject(person)
|
||||
if sortKey is None:
|
||||
sortKey = lambda x: -x.timeStamp
|
||||
for item in sorted(self.context.query(userName=personUid), key=sortKey):
|
||||
yield item
|
||||
|
||||
def add(self, obj, person, data=None):
|
||||
if None in (obj, person):
|
||||
return False
|
||||
uid = util.getUidForObject(obj)
|
||||
personUid = util.getUidForObject(person)
|
||||
if self.context.query(userName=personUid, taskId=uid):
|
||||
return False
|
||||
if data is None:
|
||||
data = {}
|
||||
return self.context.saveUserTrack(uid, 0, personUid, data)
|
||||
|
||||
def remove(self, id):
|
||||
changed = False
|
||||
for t in self.context.query(userName=personUid, taskId=uid):
|
||||
changed = True
|
||||
self.context.removeTrack(t)
|
||||
return changed
|
||||
|
||||
|
||||
class Filter(Track):
|
||||
|
||||
implements(IFilter)
|
||||
|
||||
typeName = 'Filter'
|
||||
|
|
@ -51,3 +51,39 @@ class IFavorite(ITrack):
|
|||
the user/person for which the favorite is to be stored.
|
||||
The tracking storage's run management is not used.
|
||||
"""
|
||||
|
||||
|
||||
class IFilters(Interface):
|
||||
""" A collection of filters.
|
||||
"""
|
||||
|
||||
def add(title, filter, person):
|
||||
""" Add a filter specification (a mapping) to the person's
|
||||
filters collection using the title given.
|
||||
"""
|
||||
|
||||
def activate(id):
|
||||
""" Activate the filter specified by its ID.
|
||||
"""
|
||||
|
||||
def deactivate(id):
|
||||
""" Deactivate the filter specified by its ID.
|
||||
"""
|
||||
|
||||
def remove(id):
|
||||
""" Remove the filter specified by its ID from the person's
|
||||
favorites collection.
|
||||
"""
|
||||
|
||||
def list(person, activeOnly=True, sortKey=None):
|
||||
""" Return a list of filters for the person given.
|
||||
"""
|
||||
|
||||
|
||||
class IFilter(ITrack):
|
||||
""" A filter is a stored query that will be used for restricting the result
|
||||
set of child and resource listings as well as explicit searches.
|
||||
It usually references a parent concept via the task id attribute.
|
||||
The user/person for which the filter is to be stored.
|
||||
The tracking storage's run management is not used.
|
||||
"""
|
||||
|
|
|
@ -27,6 +27,7 @@ from zope.interface import implements, Interface
|
|||
|
||||
from cybertools.tracking.btree import TrackingStorage
|
||||
from loops.organize.personal.favorite import Favorite
|
||||
from loops.organize.personal.filter import Filter
|
||||
from loops.setup import SetupManager as BaseSetupManager
|
||||
|
||||
|
||||
|
@ -36,3 +37,5 @@ class SetupManager(BaseSetupManager):
|
|||
records = self.context.getRecordManager()
|
||||
favorites = self.addObject(records, TrackingStorage, 'favorites',
|
||||
trackFactory=Favorite)
|
||||
filters = self.addObject(records, TrackingStorage, 'filters',
|
||||
trackFactory=Filter)
|
||||
|
|
Loading…
Add table
Reference in a new issue