merge branch master

This commit is contained in:
Helmut Merz 2013-07-16 18:13:05 +02:00
commit 7e70140f52
18 changed files with 177 additions and 35 deletions

View file

@ -0,0 +1,4 @@
"""
package loops.browser.compound
"""

View file

@ -0,0 +1,14 @@
<configure
xmlns:zope="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="loops">
<zope:adapter
name="compound.html"
for="loops.interfaces.IConcept
zope.publisher.interfaces.browser.IBrowserRequest"
provides="zope.interface.Interface"
factory="loops.browser.compound.standard.CompoundView"
permission="zope.View" />
</configure>

View file

@ -0,0 +1,54 @@
#
# Copyright (c) 2013 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
#
"""
Definition of compound views.
"""
from zope import interface, component
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
from loops.browser.concept import ConceptView
from loops.util import _
compound_macros = ViewPageTemplateFile('view_macros.pt')
class CompoundView(ConceptView):
@Lazy
def macro(self):
return compound_macros.macros['standard']
def getParts(self):
parts = (self.options('view_parts') or self.typeOptions('view_parts') or [])
return self.getPartViews(parts)
def getPartViews(self, parts):
result = []
for p in parts:
view = component.queryMultiAdapter((self.adapted, self.request), name=p)
if view is None:
view = component.queryMultiAdapter((self.context, self.request), name=p)
if view is not None:
view.parent = self
result.append(view)
return result

View file

@ -0,0 +1,13 @@
<html i18n:domain="loops">
<metal:data define-macro="standard">
<tal:part repeat="item item/getParts">
<tal:check condition="item/checkPermissions">
<metal:part use-macro="item/macro" />
</tal:check>
</tal:part>
</metal:data>
</html>

View file

@ -235,6 +235,7 @@ class ConceptView(BaseView):
subMacro=concept_macros.macros['parents'],
priority=20, info=self)
# the part-based layout is now implemented in loops.browser.compound
def getParts(self):
parts = (self.params.get('parts') or []) # deprecated!
if not parts:

View file

@ -772,6 +772,7 @@
attribute="cleanup"
permission="zope.ManageSite" />
<include package=".compound" />
<include package=".skin" />
<include package=".lobo" />
<include package=".mobile" />

View file

@ -132,6 +132,9 @@ class ResourceView(BaseView):
def macro(self):
if 'image/' in self.context.contentType:
return self.template.macros['image']
#elif 'audio/' in self.context.contentType:
# self.registerDojoAudio()
# return self.template.macros['audio']
else:
return self.template.macros['download']

View file

@ -26,6 +26,7 @@ from zope.component import adapts
from zope.interface import implementer, implements
from loops.common import AdapterBase
from loops.interfaces import IConcept
from loops.knowledge.qualification.interfaces import ICompetence
from loops.type import TypeInterfaceSourceList

View file

@ -4,7 +4,14 @@
i18n_domain="loops">
<zope:adapter
factory="loops.knowledge.qualification.base.Competence" />
factory="loops.knowledge.qualification.base.Competence"
trusted="True" />
<zope:class class="loops.knowledge.qualification.base.Competence">
<require permission="zope.View"
interface="loops.knowledge.qualification.interfaces.ICompetence" />
<require permission="zope.ManageContent"
set_schema="loops.knowledge.qualification.interfaces.ICompetence" />
</zope:class>
<!-- views -->

View file

@ -23,11 +23,11 @@ Interfaces for knowledge management and elearning with loops.
from zope.interface import Interface, Attribute
from zope import interface, component, schema
from loops.interfaces import IConceptSchema
from loops.interfaces import IConceptSchema, ILoopsAdapter
from loops.util import _
class ICompetence(IConceptSchema):
class ICompetence(ILoopsAdapter):
""" The competence of a person.
Maybe assigned to the person via a 'knows' relation or

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: 0.13.0\n"
"POT-Creation-Date: 2007-05-22 12:00 CET\n"
"PO-Revision-Date: 2013-06-20 12:00 CET\n"
"PO-Revision-Date: 2013-07-15 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"
@ -965,6 +965,9 @@ msgstr "Kalender"
msgid "Work Items"
msgstr "Aktivitäten"
msgid "Work Items for $title"
msgstr "Aktivitäten für $title"
msgid "Day"
msgstr "Tag"

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
# Copyright (c) 2013 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
@ -18,8 +18,6 @@
"""
Basic implementations for stateful objects and adapters.
$Id$
"""
from zope.app.catalog.interfaces import ICatalog
@ -27,6 +25,7 @@ from zope.cachedescriptors.property import Lazy
from zope import component
from zope.component import adapts, adapter
from cybertools.composer.schema.field import Field
from cybertools.meta.interfaces import IOptions
from cybertools.stateful.base import Stateful as BaseStateful
from cybertools.stateful.base import StatefulAdapter, IndexInfo
@ -34,6 +33,7 @@ from cybertools.stateful.interfaces import IStatesDefinition, ITransitionEvent
from loops.common import adapted
from loops.interfaces import ILoopsObject, IConcept, IResource
from loops import util
from loops.util import _
class Stateful(BaseStateful):
@ -93,3 +93,10 @@ def handleTransition(obj, event):
if next != previous:
cat = component.getUtility(ICatalog)
cat.index_doc(int(util.getUidForObject(obj)), obj)
# predefined fields for transition forms
commentsField = Field('comments', _(u'label_transition_comments'), 'textarea',
description=_(u'desc_transition_comments'),
nostore=True)

View file

@ -28,8 +28,6 @@ from zope.i18n import translate
from zope.lifecycleevent import ObjectModifiedEvent, Attributes
from cybertools.browser.action import Action, actions
from cybertools.composer.schema.field import Field
from cybertools.composer.schema.interfaces import ISchemaFactory
from cybertools.composer.schema.schema import Schema
from cybertools.stateful.interfaces import IStateful, IStatesDefinition
from loops.browser.common import BaseView
@ -124,8 +122,18 @@ class ChangeStateBase(object):
def stateObject(self):
return self.stateful.getStateObject()
@Lazy
def schema(self):
schema = self.transition.schema
if schema is None:
return Schema()
else:
schema.manager = self
schema.request = self.request
return schema
class ChangeStateForm(ObjectForm, ChangeStateBase):
class ChangeStateForm(ChangeStateBase, ObjectForm):
form_action = 'change_state_action'
data = {}
@ -138,24 +146,26 @@ class ChangeStateForm(ObjectForm, ChangeStateBase):
def title(self):
return self.virtualTargetObject.title
@Lazy
def schema(self):
# TODO: use field information specified in transition
commentsField = Field('comments', _(u'label_transition_comments'),
'textarea',
description=_(u'desc_transition_comments'))
fields = [commentsField]
return Schema(name='change_state', request=self.request,
manager=self, *fields)
class ChangeState(EditObject, ChangeStateBase):
class ChangeState(ChangeStateBase, EditObject):
def update(self):
comments = self.request.form.get('comments') or u''
formData = self.request.form
# store data in context (unless field.nostore)
self.object = self.context
formState = self.instance.applyTemplate(data=formData)
# TODO: check formState
# track all fields
trackData = dict(transition=self.action)
for f in self.fields:
if f.readonly:
continue
name = f.name
fi = formState.fieldInstances[name]
rawValue = fi.getRawValue(formData, name, u'')
trackData[name] = fi.unmarshall(rawValue)
self.stateful.doTransition(self.action)
notify(ObjectModifiedEvent(self.view.virtualTargetObject,
dict(transition=self.action, comments=comments)))
notify(ObjectModifiedEvent(self.view.virtualTargetObject, trackData))
return True

View file

@ -26,12 +26,15 @@ from zope.component import adapter
from zope.interface import implementer
from zope.traversing.api import getName
from cybertools.composer.schema.schema import Schema
from cybertools.stateful.definition import StatesDefinition
from cybertools.stateful.definition import State, Transition
from cybertools.stateful.interfaces import IStatesDefinition, IStateful
from loops.common import adapted
from loops.organize.stateful.base import commentsField
from loops.organize.stateful.base import StatefulLoopsObject
from loops.security.interfaces import ISecuritySetter
from loops.util import _
def setPermissionsForRoles(settings):
@ -42,6 +45,10 @@ def setPermissionsForRoles(settings):
return setSecurity
defaultSchema = Schema(commentsField,
name='change_state')
@implementer(IStatesDefinition)
def taskStates():
return StatesDefinition('task_states',
@ -55,11 +62,11 @@ def taskStates():
color='x'),
State('archived', 'archived', ('reopen',),
color='grey'),
Transition('release', 'release', 'active'),
Transition('finish', 'finish', 'finished'),
Transition('cancel', 'cancel', 'cancelled'),
Transition('reopen', 're-open', 'draft'),
Transition('archive', 'archive', 'archived'),
Transition('release', 'release', 'active', schema=defaultSchema),
Transition('finish', 'finish', 'finished', schema=defaultSchema),
Transition('cancel', 'cancel', 'cancelled', schema=defaultSchema),
Transition('reopen', 're-open', 'draft', schema=defaultSchema),
Transition('archive', 'archive', 'archived', schema=defaultSchema),
initialState='draft')

View file

@ -43,13 +43,14 @@ from loops.browser.concept import ConceptView
from loops.browser.form import ObjectForm, EditObject
from loops.browser.node import NodeView
from loops.common import adapted
from loops.organize.interfaces import IPerson
from loops.organize.party import getPersonForUser
from loops.organize.stateful.browser import StateAction
from loops.organize.tracking.browser import BaseTrackView
from loops.organize.tracking.report import TrackDetails
from loops.organize.work.base import WorkItem
from loops.security.common import canAccessObject, canListObject, canWriteObject
from loops.security.common import checkPermission
from loops.security.common import canAccessRestricted, checkPermission
from loops import util
from loops.util import _
@ -228,6 +229,10 @@ class BaseWorkItemsView(object):
def macro(self):
return self.work_macros['workitems_query']
@Lazy
def title(self):
return _(u'Work Items for $title', mapping=dict(title=self.context.title))
@Lazy
def workItems(self):
rm = self.loopsRoot.getRecordManager()
@ -312,19 +317,25 @@ class RelatedTaskWorkItems(AllWorkItems):
class PersonWorkItems(BaseWorkItemsView, ConceptView):
""" A query view showing work items for a person, the query's parent.
""" A view showing work items for a person or the context object's parents.
"""
columns = set(['Task', 'Title', 'Day', 'Start', 'End', 'Duration', 'Info'])
def checkPermissions(self):
return canAccessRestricted(self.context)
def getCriteria(self):
return self.baseCriteria
def listWorkItems(self):
criteria = self.getCriteria()
for target in self.context.getParents([self.defaultPredicate]):
un = criteria.setdefault('userName', [])
un.append(util.getUidForObject(target))
un = criteria.setdefault('userName', [])
if IPerson.providedBy(self.adapted):
un.append(util.getUidForObject(self.context))
else:
for target in self.context.getParents([self.defaultPredicate]):
un.append(util.getUidForObject(target))
return sorted(self.query(**criteria), key=lambda x: x.track.timeStamp)

View file

@ -74,6 +74,9 @@ def canListObject(obj, noCheck=False):
return True
return canAccess(obj, 'title')
def canAccessRestricted(obj):
return checkPermission('loops.ViewRestricted', obj)
def canWriteObject(obj):
return canWrite(obj, 'title') or canAssignAsParent(obj)

View file

@ -145,4 +145,7 @@ def saveRequest(request):
local_data.request = request
def getRequest():
return local_data.request
try:
return local_data.request
except AttributeError:
return None