merge branch master
This commit is contained in:
commit
07bb68ae9d
15 changed files with 152 additions and 57 deletions
|
@ -1010,7 +1010,7 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
def registerDojoComboBox(self):
|
def registerDojoComboBox(self):
|
||||||
self.registerDojo()
|
self.registerDojo()
|
||||||
jsCall = ('dojo.require("dijit.form.ComboBox");')
|
jsCall = ('dojo.require("dijit.form.ComboBox");')
|
||||||
self.controller.macros.register('js-execute',
|
self.controller.macros.register('js-execute',
|
||||||
'dojo.require.ComboBox', jsCall=jsCall)
|
'dojo.require.ComboBox', jsCall=jsCall)
|
||||||
|
|
||||||
def registerDojoFormAll(self):
|
def registerDojoFormAll(self):
|
||||||
|
@ -1066,6 +1066,7 @@ class LoggedIn(object):
|
||||||
params = parse_qsl(qs)
|
params = parse_qsl(qs)
|
||||||
params = [(k, v) for k, v in params if k != 'loops.messages.top:record']
|
params = [(k, v) for k, v in params if k != 'loops.messages.top:record']
|
||||||
params.append(('loops.messages.top:record', message.encode('UTF-8')))
|
params.append(('loops.messages.top:record', message.encode('UTF-8')))
|
||||||
|
url = url.encode('utf-8')
|
||||||
return '%s?%s' % (url, urlencode(params))
|
return '%s?%s' % (url, urlencode(params))
|
||||||
|
|
||||||
# vocabulary stuff
|
# vocabulary stuff
|
||||||
|
|
|
@ -954,7 +954,8 @@ class NodeTraverser(ItemTraverser):
|
||||||
if context.nodeType == 'menu':
|
if context.nodeType == 'menu':
|
||||||
setViewConfiguration(context, request)
|
setViewConfiguration(context, request)
|
||||||
if name == '.loops':
|
if name == '.loops':
|
||||||
return self.context.getLoopsRoot()
|
name = self.getTargetUid(request)
|
||||||
|
#return self.context.getLoopsRoot()
|
||||||
if name.startswith('.'):
|
if name.startswith('.'):
|
||||||
name = self.cleanUpTraversalStack(request, name)[1:]
|
name = self.cleanUpTraversalStack(request, name)[1:]
|
||||||
target = self.getTarget(name)
|
target = self.getTarget(name)
|
||||||
|
@ -981,17 +982,34 @@ class NodeTraverser(ItemTraverser):
|
||||||
obj = super(NodeTraverser, self).publishTraverse(request, name)
|
obj = super(NodeTraverser, self).publishTraverse(request, name)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
def getTargetUid(self, request):
|
||||||
|
parent = self.context.getLoopsRoot()
|
||||||
|
stack = request._traversal_stack
|
||||||
|
for i in range(2):
|
||||||
|
name = stack.pop()
|
||||||
|
obj = parent.get(name)
|
||||||
|
if not obj:
|
||||||
|
return name
|
||||||
|
parent = obj
|
||||||
|
return '.' + util.getUidForObject(obj)
|
||||||
|
|
||||||
def cleanUpTraversalStack(self, request, name):
|
def cleanUpTraversalStack(self, request, name):
|
||||||
traversalStack = request._traversal_stack
|
#traversalStack = request._traversal_stack
|
||||||
while traversalStack and traversalStack[0].startswith('.'):
|
#while traversalStack and traversalStack[0].startswith('.'):
|
||||||
# skip obsolete target references in the url
|
# skip obsolete target references in the url
|
||||||
name = traversalStack.pop(0)
|
# name = traversalStack.pop(0)
|
||||||
traversedNames = request._traversed_names
|
traversedNames = request._traversed_names
|
||||||
if traversedNames:
|
for n in list(traversedNames):
|
||||||
lastTraversed = traversedNames[-1]
|
if n.startswith('.'):
|
||||||
if lastTraversed.startswith('.') and lastTraversed != name:
|
# remove obsolete target refs
|
||||||
|
traversedNames.remove(n)
|
||||||
|
#if traversedNames:
|
||||||
|
# lastTraversed = traversedNames[-1]
|
||||||
|
# if lastTraversed.startswith('.') and lastTraversed != name:
|
||||||
# let <base .../> tag show the current object
|
# let <base .../> tag show the current object
|
||||||
traversedNames[-1] = name
|
# traversedNames[-1] = name
|
||||||
|
# let <base .../> tag show the current object
|
||||||
|
traversedNames.append(name)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def getTarget(self, name):
|
def getTarget(self, name):
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# types
|
# types
|
||||||
type(u'query', u'Abfrage', options=u'',
|
type(u'query', u'Abfrage', options=u'',
|
||||||
typeInterface='loops.expert.concept.IQueryConcept', viewName=u'')
|
typeInterface='loops.expert.concept.IQueryConcept', viewName=u'')
|
||||||
|
type(u'datatable', u'Datentabelle', options=u'action.portlet:edit_concept',
|
||||||
|
typeInterface='loops.table.IDataTable', viewName=u'')
|
||||||
type(u'task', u'Aufgabe', options=u'',
|
type(u'task', u'Aufgabe', options=u'',
|
||||||
typeInterface='loops.knowledge.interfaces.ITask', viewName=u'')
|
typeInterface='loops.knowledge.interfaces.ITask', viewName=u'')
|
||||||
type(u'domain', u'Bereich', options=u'', typeInterface=u'', viewName=u'')
|
type(u'domain', u'Bereich', options=u'', typeInterface=u'', viewName=u'')
|
||||||
|
|
9
data/loops_std_update_de.dmp
Normal file
9
data/loops_std_update_de.dmp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# update for old loops sites
|
||||||
|
|
||||||
|
type(u'datatable', u'Datentabelle', options=u'action.portlet:edit_concept',
|
||||||
|
typeInterface='loops.table.IDataTable', viewName=u'')
|
||||||
|
|
||||||
|
concept(u'issubtype', u'is Subtype', u'predicate')
|
||||||
|
|
||||||
|
child(u'general', u'issubtype', u'datatable')
|
||||||
|
child(u'system', u'issubtype', u'standard')
|
6
external/pyfunc.py
vendored
6
external/pyfunc.py
vendored
|
@ -44,11 +44,15 @@ class PyReader(object):
|
||||||
|
|
||||||
class InputProcessor(dict):
|
class InputProcessor(dict):
|
||||||
|
|
||||||
|
_constants = dict(True=True, False=False)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.elements = []
|
self.elements = []
|
||||||
self['__builtins__'] = {} # security!
|
self['__builtins__'] = dict() # security!
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
|
if key in self._constants:
|
||||||
|
return self._constants[key]
|
||||||
def factory(*args, **kw):
|
def factory(*args, **kw):
|
||||||
element = elementTypes[key](*args, **kw)
|
element = elementTypes[key](*args, **kw)
|
||||||
if key in toplevelElements:
|
if key in toplevelElements:
|
||||||
|
|
|
@ -44,5 +44,7 @@ class ExternalCollectionView(ConceptView):
|
||||||
cta.update()
|
cta.update()
|
||||||
if cta.updateMessage is not None:
|
if cta.updateMessage is not None:
|
||||||
self.request.form['message'] = cta.updateMessage
|
self.request.form['message'] = cta.updateMessage
|
||||||
|
if 'no_show_page' in self.request.form:
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,10 @@ file system.
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
import os, re, stat
|
import os, re, stat
|
||||||
|
import transaction
|
||||||
|
|
||||||
from zope.app.container.interfaces import INameChooser
|
from zope.app.container.interfaces import INameChooser
|
||||||
|
from zope.app.container.contained import ObjectRemovedEvent
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
|
@ -51,6 +53,8 @@ from loops.versioning.interfaces import IVersionable
|
||||||
|
|
||||||
TypeInterfaceSourceList.typeInterfaces += (IExternalCollection,)
|
TypeInterfaceSourceList.typeInterfaces += (IExternalCollection,)
|
||||||
|
|
||||||
|
logger = getLogger('loops.integrator.collection')
|
||||||
|
|
||||||
|
|
||||||
class ExternalCollectionAdapter(AdapterBase):
|
class ExternalCollectionAdapter(AdapterBase):
|
||||||
""" A concept adapter for accessing an external collection.
|
""" A concept adapter for accessing an external collection.
|
||||||
|
@ -66,7 +70,7 @@ class ExternalCollectionAdapter(AdapterBase):
|
||||||
|
|
||||||
newResources = None
|
newResources = None
|
||||||
updateMessage = None
|
updateMessage = None
|
||||||
|
|
||||||
def getExclude(self):
|
def getExclude(self):
|
||||||
return getattr(self.context, '_exclude', None) or []
|
return getattr(self.context, '_exclude', None) or []
|
||||||
def setExclude(self, value):
|
def setExclude(self, value):
|
||||||
|
@ -83,10 +87,11 @@ class ExternalCollectionAdapter(AdapterBase):
|
||||||
print '###', vaddr, vobj, vid
|
print '###', vaddr, vobj, vid
|
||||||
versions.add(vaddr)
|
versions.add(vaddr)
|
||||||
new = []
|
new = []
|
||||||
oldFound = []
|
oldFound = set([])
|
||||||
provider = component.getUtility(IExternalCollectionProvider,
|
provider = component.getUtility(IExternalCollectionProvider,
|
||||||
name=self.providerName or '')
|
name=self.providerName or '')
|
||||||
#print '*** old', old, versions, self.lastUpdated
|
#print '*** old', old, versions, self.lastUpdated
|
||||||
|
changeCount = 0
|
||||||
for addr, mdate in provider.collect(self):
|
for addr, mdate in provider.collect(self):
|
||||||
#print '***', addr, mdate
|
#print '***', addr, mdate
|
||||||
if addr in versions:
|
if addr in versions:
|
||||||
|
@ -94,8 +99,9 @@ class ExternalCollectionAdapter(AdapterBase):
|
||||||
if addr in old:
|
if addr in old:
|
||||||
# may be it would be better to return a file's hash
|
# may be it would be better to return a file's hash
|
||||||
# for checking for changes...
|
# for checking for changes...
|
||||||
oldFound.append(addr)
|
oldFound.add(addr)
|
||||||
if self.lastUpdated is None or (mdate and mdate > self.lastUpdated):
|
if self.lastUpdated is None or (mdate and mdate > self.lastUpdated):
|
||||||
|
changeCount +=1
|
||||||
obj = old[addr]
|
obj = old[addr]
|
||||||
# update settings and regenerate scale variant for media asset
|
# update settings and regenerate scale variant for media asset
|
||||||
adobj = adapted(obj)
|
adobj = adapted(obj)
|
||||||
|
@ -110,29 +116,41 @@ class ExternalCollectionAdapter(AdapterBase):
|
||||||
self.updateMessage = message
|
self.updateMessage = message
|
||||||
# force reindexing
|
# force reindexing
|
||||||
notify(ObjectModifiedEvent(obj))
|
notify(ObjectModifiedEvent(obj))
|
||||||
|
if changeCount % 10 == 0:
|
||||||
|
logger.info('Updated: %i.' % changeCount)
|
||||||
|
transaction.commit()
|
||||||
else:
|
else:
|
||||||
new.append(addr)
|
new.append(addr)
|
||||||
|
logger.info('%i objects updated.' % changeCount)
|
||||||
|
transaction.commit()
|
||||||
if new:
|
if new:
|
||||||
self.newResources = provider.createExtFileObjects(self, new)
|
self.newResources = provider.createExtFileObjects(self, new)
|
||||||
for r in self.newResources:
|
for r in self.newResources:
|
||||||
self.context.assignResource(r)
|
self.context.assignResource(r)
|
||||||
|
logger.info('%i objects created.' % len(new))
|
||||||
|
transaction.commit()
|
||||||
for addr in old:
|
for addr in old:
|
||||||
if str(addr) not in oldFound:
|
if str(addr) not in oldFound:
|
||||||
# not part of the collection any more
|
# not part of the collection any more
|
||||||
# TODO: only remove from collection but keep object?
|
# TODO: only remove from collection but keep object?
|
||||||
self.remove(old[addr])
|
self.remove(old[addr])
|
||||||
|
transaction.commit()
|
||||||
for r in self.context.getResources():
|
for r in self.context.getResources():
|
||||||
adobj = adapted(r)
|
adobj = adapted(r)
|
||||||
if self.metaInfo != adobj.metaInfo and (
|
if self.metaInfo != adobj.metaInfo and (
|
||||||
not adobj.metaInfo or self.overwriteMetaInfo):
|
not adobj.metaInfo or self.overwriteMetaInfo):
|
||||||
adobj.metaInfo = self.metaInfo
|
adobj.metaInfo = self.metaInfo
|
||||||
self.lastUpdated = datetime.today()
|
self.lastUpdated = datetime.today()
|
||||||
|
logger.info('External collection updated.')
|
||||||
|
transaction.commit()
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
for obj in self.context.getResources():
|
for obj in self.context.getResources():
|
||||||
self.remove(obj)
|
self.remove(obj)
|
||||||
|
|
||||||
def remove(self, obj):
|
def remove(self, obj):
|
||||||
|
logger.info('Removing object: %s.' % getName(obj))
|
||||||
|
notify(ObjectRemovedEvent(obj))
|
||||||
del self.resourceManager[getName(obj)]
|
del self.resourceManager[getName(obj)]
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -187,7 +205,7 @@ class DirectoryCollectionProvider(object):
|
||||||
for k, v in self.extFileTypeMapping.items())
|
for k, v in self.extFileTypeMapping.items())
|
||||||
container = client.context.getLoopsRoot().getResourceManager()
|
container = client.context.getLoopsRoot().getResourceManager()
|
||||||
directory = self.getDirectory(client)
|
directory = self.getDirectory(client)
|
||||||
for addr in addresses:
|
for idx, addr in enumerate(addresses):
|
||||||
name = self.generateName(container, addr)
|
name = self.generateName(container, addr)
|
||||||
title = self.generateTitle(addr)
|
title = self.generateTitle(addr)
|
||||||
contentType = guess_content_type(addr,
|
contentType = guess_content_type(addr,
|
||||||
|
@ -200,9 +218,8 @@ class DirectoryCollectionProvider(object):
|
||||||
if extFileType is None:
|
if extFileType is None:
|
||||||
extFileType = extFileTypes['image/*']
|
extFileType = extFileTypes['image/*']
|
||||||
if extFileType is None:
|
if extFileType is None:
|
||||||
getLogger('loops.integrator.collection.DirectoryCollectionProvider'
|
logger.warn('No external file type found for %r, '
|
||||||
).warn('No external file type found for %r, '
|
'content type: %r' % (name, contentType))
|
||||||
'content type: %r' % (name, contentType))
|
|
||||||
obj = addAndConfigureObject(
|
obj = addAndConfigureObject(
|
||||||
container, Resource, name,
|
container, Resource, name,
|
||||||
title=title,
|
title=title,
|
||||||
|
@ -219,6 +236,9 @@ class DirectoryCollectionProvider(object):
|
||||||
message = client.updateMessage or u''
|
message = client.updateMessage or u''
|
||||||
message += u'<br />'.join(adobj.processingErrors)
|
message += u'<br />'.join(adobj.processingErrors)
|
||||||
client.updateMessage = message
|
client.updateMessage = message
|
||||||
|
if idx and idx % 10 == 0:
|
||||||
|
logger.info('Created: %i.' % idx)
|
||||||
|
transaction.commit()
|
||||||
yield obj
|
yield obj
|
||||||
|
|
||||||
def getDirectory(self, client):
|
def getDirectory(self, client):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
|
|
||||||
<metal:block define-macro="render_collection"
|
<metal:block define-macro="render_collection"
|
||||||
tal:define="dummy item/update">
|
tal:condition="item/update">
|
||||||
|
|
||||||
<metal:block use-macro="view/concept_macros/conceptdata">
|
<metal:block use-macro="view/concept_macros/conceptdata">
|
||||||
<metal:fill tal:condition="item/editable"
|
<metal:fill tal:condition="item/editable"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2015 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
|
||||||
|
@ -46,11 +46,17 @@ class Questionnaire(AdapterBase, Questionnaire):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def questionGroups(self):
|
def questionGroups(self):
|
||||||
|
return self.getQuestionGroups()
|
||||||
|
|
||||||
|
def getQuestionGroups(self, personId=None):
|
||||||
return [adapted(c) for c in self.context.getChildren()]
|
return [adapted(c) for c in self.context.getChildren()]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def questions(self):
|
def questions(self):
|
||||||
for qug in self.questionGroups:
|
return self.getQuestions()
|
||||||
|
|
||||||
|
def getQuestions(self, personId=None):
|
||||||
|
for qug in self.getQuestionGroups(personId):
|
||||||
for qu in qug.questions:
|
for qu in qug.questions:
|
||||||
#qu.questionnaire = self
|
#qu.questionnaire = self
|
||||||
yield qu
|
yield qu
|
||||||
|
@ -65,12 +71,18 @@ class QuestionGroup(AdapterBase, QuestionGroup):
|
||||||
'questionnaire', 'questions', 'feedbackItems')
|
'questionnaire', 'questions', 'feedbackItems')
|
||||||
_noexportAttributes = _adapterAttributes
|
_noexportAttributes = _adapterAttributes
|
||||||
|
|
||||||
@property
|
def getQuestionnaires(self):
|
||||||
def questionnaire(self):
|
result = []
|
||||||
for p in self.context.getParents():
|
for p in self.context.getParents():
|
||||||
ap = adapted(p)
|
ap = adapted(p)
|
||||||
if IQuestionnaire.providedBy(ap):
|
if IQuestionnaire.providedBy(ap):
|
||||||
return ap
|
result.append(ap)
|
||||||
|
return result
|
||||||
|
|
||||||
|
@property
|
||||||
|
def questionnaire(self):
|
||||||
|
for qu in self.getQuestionnaires():
|
||||||
|
return qu
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def subobjects(self):
|
def subobjects(self):
|
||||||
|
|
|
@ -52,7 +52,7 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
|
|
||||||
template = template
|
template = template
|
||||||
|
|
||||||
adminMaySelectAllInstitutions = False
|
#adminMaySelectAllInstitutions = False
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def macro(self):
|
def macro(self):
|
||||||
|
@ -62,9 +62,8 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
@Lazy
|
@Lazy
|
||||||
def title(self):
|
def title(self):
|
||||||
title = self.context.title
|
title = self.context.title
|
||||||
personId = self.request.form.get('person')
|
if self.personId:
|
||||||
if personId:
|
person = adapted(getObjectForUid(self.personId))
|
||||||
person = adapted(getObjectForUid(personId))
|
|
||||||
if person is not None:
|
if person is not None:
|
||||||
return '%s: %s' % (title, person.title)
|
return '%s: %s' % (title, person.title)
|
||||||
return title
|
return title
|
||||||
|
@ -80,6 +79,10 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
return ''
|
return ''
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def personId(self):
|
||||||
|
return self.request.form.get('person')
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def report(self):
|
def report(self):
|
||||||
return self.request.form.get('report')
|
return self.request.form.get('report')
|
||||||
|
@ -104,7 +107,8 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
def groups(self):
|
def groups(self):
|
||||||
result = []
|
result = []
|
||||||
if self.questionnaireType == 'pref_selection':
|
if self.questionnaireType == 'pref_selection':
|
||||||
groups = [g.questions for g in self.adapted.questionGroups]
|
groups = [g.questions for g in
|
||||||
|
self.adapted.getQuestionGroups(self.personId)]
|
||||||
questions = []
|
questions = []
|
||||||
for idxg, g in enumerate(groups):
|
for idxg, g in enumerate(groups):
|
||||||
qus = []
|
qus = []
|
||||||
|
@ -118,7 +122,7 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
questions=questions[idx:idx+3]))
|
questions=questions[idx:idx+3]))
|
||||||
return [g for g in result if len(g['questions']) == 3]
|
return [g for g in result if len(g['questions']) == 3]
|
||||||
if self.adapted.noGrouping:
|
if self.adapted.noGrouping:
|
||||||
questions = list(self.adapted.questions)
|
questions = list(self.adapted.getQuestions(self.personId))
|
||||||
questions.sort(key=lambda x: x.title)
|
questions.sort(key=lambda x: x.title)
|
||||||
size = len(questions)
|
size = len(questions)
|
||||||
bs = self.batchSize
|
bs = self.batchSize
|
||||||
|
@ -126,7 +130,7 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
result.append(dict(title=u'Question', infoText=None,
|
result.append(dict(title=u'Question', infoText=None,
|
||||||
questions=questions[idx:idx+bs]))
|
questions=questions[idx:idx+bs]))
|
||||||
else:
|
else:
|
||||||
for group in self.adapted.questionGroups:
|
for group in self.adapted.getQuestionGroups(self.personId):
|
||||||
result.append(dict(title=group.title,
|
result.append(dict(title=group.title,
|
||||||
infoText=self.getInfoText(group),
|
infoText=self.getInfoText(group),
|
||||||
questions=group.questions))
|
questions=group.questions))
|
||||||
|
@ -185,8 +189,8 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
uid = self.getUidForObject(c)
|
uid = self.getUidForObject(c)
|
||||||
data = respManager.load(uid, instUid)
|
data = respManager.load(uid, instUid)
|
||||||
if data:
|
if data:
|
||||||
resp = Response(self.adapted, None)
|
resp = Response(self.adapted, self.personId)
|
||||||
for qu in self.adapted.questions:
|
for qu in self.adapted.getQuestions(self.personId):
|
||||||
if qu.questionType in (None, 'value_selection'):
|
if qu.questionType in (None, 'value_selection'):
|
||||||
if qu.uid in data:
|
if qu.uid in data:
|
||||||
value = data[qu.uid]
|
value = data[qu.uid]
|
||||||
|
@ -195,7 +199,7 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
else:
|
else:
|
||||||
resp.texts[qu] = data.get(qu.uid) or u''
|
resp.texts[qu] = data.get(qu.uid) or u''
|
||||||
qgAvailable = True
|
qgAvailable = True
|
||||||
for qg in self.adapted.questionGroups:
|
for qg in self.adapted.getQuestionGroups(self.personId):
|
||||||
if qg.uid in data:
|
if qg.uid in data:
|
||||||
resp.values[qg] = data[qg.uid]
|
resp.values[qg] = data[qg.uid]
|
||||||
else:
|
else:
|
||||||
|
@ -227,7 +231,7 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
if self.adapted.questionnaireType == 'pref_selection':
|
if self.adapted.questionnaireType == 'pref_selection':
|
||||||
return self.prefsResults(respManager, form, action)
|
return self.prefsResults(respManager, form, action)
|
||||||
data = {}
|
data = {}
|
||||||
response = Response(self.adapted, None)
|
response = Response(self.adapted, self.personId)
|
||||||
for key, value in form.items():
|
for key, value in form.items():
|
||||||
if key.startswith('question_'):
|
if key.startswith('question_'):
|
||||||
if value != 'none':
|
if value != 'none':
|
||||||
|
@ -265,7 +269,7 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
respManager = Responses(self.context)
|
respManager = Responses(self.context)
|
||||||
self.teamData = self.getTeamData(respManager)
|
self.teamData = self.getTeamData(respManager)
|
||||||
response = Response(self.adapted, None)
|
response = Response(self.adapted, None)
|
||||||
groups = self.adapted.questionGroups
|
groups = self.adapted.getQuestionGroups(self.personId)
|
||||||
teamValues = response.getTeamResult(groups, self.teamData)
|
teamValues = response.getTeamResult(groups, self.teamData)
|
||||||
for idx, r in enumerate(teamValues):
|
for idx, r in enumerate(teamValues):
|
||||||
group = r['group']
|
group = r['group']
|
||||||
|
@ -314,7 +318,7 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
#self.errors = self.check(response)
|
#self.errors = self.check(response)
|
||||||
if self.errors:
|
if self.errors:
|
||||||
return []
|
return []
|
||||||
for group in self.adapted.questionGroups:
|
for group in self.adapted.getQuestionGroups(self.personId):
|
||||||
score = 0
|
score = 0
|
||||||
for qu in group.questions:
|
for qu in group.questions:
|
||||||
value = data.get(qu.uid) or 0
|
value = data.get(qu.uid) or 0
|
||||||
|
@ -327,13 +331,13 @@ class SurveyView(InstitutionMixin, ConceptView):
|
||||||
def check(self, response):
|
def check(self, response):
|
||||||
errors = []
|
errors = []
|
||||||
values = response.values
|
values = response.values
|
||||||
for qu in self.adapted.questions:
|
for qu in self.adapted.getQuestions(self.personId):
|
||||||
if qu.required and qu not in values:
|
if qu.required and qu not in values:
|
||||||
errors.append(dict(uid=qu.uid,
|
errors.append(dict(uid=qu.uid,
|
||||||
text='Please answer the obligatory questions.'))
|
text='Please answer the obligatory questions.'))
|
||||||
break
|
break
|
||||||
qugroups = {}
|
qugroups = {}
|
||||||
for qugroup in self.adapted.questionGroups:
|
for qugroup in self.adapted.getQuestionGroups(self.personId):
|
||||||
qugroups[qugroup] = 0
|
qugroups[qugroup] = 0
|
||||||
for qu in values:
|
for qu in values:
|
||||||
qugroups[qu.questionGroup] += 1
|
qugroups[qu.questionGroup] += 1
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2015 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
|
||||||
|
@ -133,6 +133,10 @@ class SendEmailForm(NodeView):
|
||||||
|
|
||||||
__call__ = innerHtml
|
__call__ = innerHtml
|
||||||
|
|
||||||
|
def checkPermissions(self):
|
||||||
|
return (not self.isAnonymous and
|
||||||
|
super(SendEmailForm, self).checkPermissions())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def macro(self):
|
def macro(self):
|
||||||
return organize_macros.macros['send_email']
|
return organize_macros.macros['send_email']
|
||||||
|
@ -181,12 +185,16 @@ class SendEmailForm(NodeView):
|
||||||
|
|
||||||
class SendEmail(FormController):
|
class SendEmail(FormController):
|
||||||
|
|
||||||
|
def checkPermissions(self):
|
||||||
|
return (not self.isAnonymous and
|
||||||
|
super(SendEmail, self).checkPermissions())
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
form = self.request.form
|
form = self.request.form
|
||||||
subject = form.get('subject') or u''
|
subject = form.get('subject') or u''
|
||||||
message = form.get('mailbody') or u''
|
message = form.get('mailbody') or u''
|
||||||
recipients = form.get('recipients') or []
|
recipients = form.get('recipients') or []
|
||||||
recipients += (form.get('addrRecipients') or u'').split('\n')
|
recipients += (form.get('addrecipients') or u'').split('\n')
|
||||||
# TODO: remove duplicates
|
# TODO: remove duplicates
|
||||||
person = getPersonForUser(self.context, self.request)
|
person = getPersonForUser(self.context, self.request)
|
||||||
sender = person and adapted(person).email or 'loops@unknown.com'
|
sender = person and adapted(person).email or 'loops@unknown.com'
|
||||||
|
|
|
@ -123,20 +123,23 @@
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
<span i18n:translate="">Send Link by Email</span> -
|
<span i18n:translate="">Send Link by Email</span> -
|
||||||
<span tal:content="view/target/title"></span></div>
|
<span tal:content="view/target/title"></span></div>
|
||||||
<div>
|
<metal:content define-macro="mail_content">
|
||||||
<label i18n:translate="" for="subject">Subject</label>
|
|
||||||
<div>
|
<div>
|
||||||
<input name="subject" id="subject" style="width: 60em"
|
<label i18n:translate="" for="subject">Subject</label>
|
||||||
dojoType="dijit.form.ValidationTextBox" required
|
<div>
|
||||||
tal:attributes="value view/subject" /></div>
|
<input name="subject" id="subject" style="width: 60em"
|
||||||
</div>
|
dojoType="dijit.form.ValidationTextBox" required
|
||||||
<div>
|
tal:attributes="value view/subject" /></div>
|
||||||
<label i18n:translate="" for="mailbody">Mail Body</label>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<textarea name="mailbody" cols="80" rows="4" id="mailbody"
|
<label i18n:translate="" for="mailbody">Mail Body</label>
|
||||||
dojoType="dijit.form.SimpleTextarea" style="width: 60em"
|
<div>
|
||||||
tal:content="view/mailBody"></textarea></div>
|
<textarea name="mailbody" cols="80" rows="4" id="mailbody"
|
||||||
</div>
|
dojoType="dijit.form.SimpleTextarea" style="width: 60em"
|
||||||
|
tal:attributes="rows view/contentHeight|string:4"
|
||||||
|
tal:content="view/mailBody"></textarea></div>
|
||||||
|
</div>
|
||||||
|
</metal:content>
|
||||||
<div>
|
<div>
|
||||||
<label i18n:translate="">Recipients</label>
|
<label i18n:translate="">Recipients</label>
|
||||||
<div tal:repeat="member view/members">
|
<div tal:repeat="member view/members">
|
||||||
|
|
|
@ -24,6 +24,7 @@ from persistent.mapping import PersistentMapping
|
||||||
from zope import interface, component
|
from zope import interface, component
|
||||||
from zope.app.principalannotation import annotations
|
from zope.app.principalannotation import annotations
|
||||||
from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
|
from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
|
||||||
|
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
@ -60,10 +61,10 @@ def getPersonForUser(context, request=None, principal=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
return None
|
return None
|
||||||
if principal is None:
|
if principal is None:
|
||||||
if request is None:
|
if request is not None:
|
||||||
principal = getCurrentPrincipal()
|
|
||||||
else:
|
|
||||||
principal = getattr(request, 'principal', None)
|
principal = getattr(request, 'principal', None)
|
||||||
|
else:
|
||||||
|
principal = getPrincipal(context)
|
||||||
if principal is None:
|
if principal is None:
|
||||||
return None
|
return None
|
||||||
loops = context.getLoopsRoot()
|
loops = context.getLoopsRoot()
|
||||||
|
@ -78,6 +79,15 @@ def getPersonForUser(context, request=None, principal=None):
|
||||||
return pa.get(util.getUidForObject(loops))
|
return pa.get(util.getUidForObject(loops))
|
||||||
|
|
||||||
|
|
||||||
|
def getPrincipal(context):
|
||||||
|
principal = getCurrentPrincipal()
|
||||||
|
if principal is not None:
|
||||||
|
if IUnauthenticatedPrincipal.providedBy(principal):
|
||||||
|
return None
|
||||||
|
return principal
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Person(AdapterBase, BasePerson):
|
class Person(AdapterBase, BasePerson):
|
||||||
""" typeInterface adapter for concepts of type 'person'.
|
""" typeInterface adapter for concepts of type 'person'.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
<tal:version tal:condition="view/useVersioning">
|
<tal:version tal:condition="view/useVersioning">
|
||||||
<td class="center"
|
<td class="center"
|
||||||
tal:define="version object/version">
|
tal:define="version object/version">
|
||||||
<a tal:omit-tag="python: version == '1.1'"
|
<a tal:omit-tag="python: version in ('1.1', '1', '')"
|
||||||
tal:attributes="href string:$url?loops.viewName=listversions"
|
tal:attributes="href string:$url?loops.viewName=listversions"
|
||||||
tal:content="version">1.1</a>
|
tal:content="version">1.1</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -275,7 +275,9 @@ class TrackDetails(BaseView):
|
||||||
else:
|
else:
|
||||||
title = view.listingTitle
|
title = view.listingTitle
|
||||||
versionable = IVersionable(self.object, None)
|
versionable = IVersionable(self.object, None)
|
||||||
version = versionable is not None and versionable.versionId or ''
|
version = ((versionable is not None and
|
||||||
|
not (versionable.notVersioned) and
|
||||||
|
versionable.versionId) or '')
|
||||||
return dict(object=obj, title=title,
|
return dict(object=obj, title=title,
|
||||||
type=self.longTypeTitle, url=url, version=version,
|
type=self.longTypeTitle, url=url, version=version,
|
||||||
canAccess=canAccessObject(obj))
|
canAccess=canAccessObject(obj))
|
||||||
|
|
Loading…
Add table
Reference in a new issue