Worflow state can not be used in ref fields; mayNavigate is not static anymore, but an instance method.

This commit is contained in:
Gaetan Delannay 2010-12-06 11:11:40 +01:00
parent e62e00d367
commit 2124cffa5e
14 changed files with 187 additions and 161 deletions

View file

@ -164,16 +164,25 @@ class ToolMixin(BaseMixin):
res.append((appyType.name, self.translate(appyType.labelId)))
return res
def getSearchableFields(self, contentType):
'''Returns, among the list of all searchable fields (see method above),
the list of fields that the user has configured as being effectively
used in the search screen.'''
res = []
fieldNames = getattr(self.appy(), 'searchFieldsFor%s' % contentType, ())
def getSearchInfo(self, contentType, refInfo=None):
'''Returns a tuple:
1) The list of searchable fields (ie fields among all indexed fields)
2) The number of columns for layouting those fields.'''
fields = []
if refInfo:
# The search is triggered from a Ref field.
refField = self.getRefInfo(refInfo)[1]
fieldNames = refField.queryFields or ()
nbOfColumns = refField.queryNbCols
else:
# The search is triggered from an app-wide search.
at = self.appy()
fieldNames = getattr(at, 'searchFieldsFor%s' % contentType,())
nbOfColumns = getattr(at, 'numberOfSearchColumnsFor%s' %contentType)
for name in fieldNames:
appyType = self.getAppyType(name, asDict=True,className=contentType)
res.append(appyType)
return res
fields.append(appyType)
return fields, nbOfColumns
def getImportElements(self, contentType):
'''Returns the list of elements that can be imported from p_path for
@ -220,7 +229,8 @@ class ToolMixin(BaseMixin):
def executeQuery(self, contentType, searchName=None, startNumber=0,
search=None, remember=False, brainsOnly=False,
maxResults=None, noSecurity=False, sortBy=None,
sortOrder='asc', filterKey=None, filterValue=None):
sortOrder='asc', filterKey=None, filterValue=None,
refField=None):
'''Executes a query on a given p_contentType (or several, separated
with commas) in Plone's portal_catalog. If p_searchName is specified,
it corresponds to:
@ -256,7 +266,10 @@ class ToolMixin(BaseMixin):
If p_filterKey is given, it represents an additional search parameter
to take into account: the corresponding search value is in
p_filterValue.'''
p_filterValue.
If p_refField is given, the query is limited to the objects that are
referenced through it.'''
# Is there one or several content types ?
if contentType.find(',') != -1:
portalTypes = contentType.split(',')
@ -276,6 +289,9 @@ class ToolMixin(BaseMixin):
if search:
# Add additional search criteria
for fieldName, fieldValue in search.fields.iteritems():
# Management of searches restricted to objects linked through a
# Ref field: not implemented yet.
if fieldName == '_ref': continue
# Make the correspondance between the name of the field and the
# name of the corresponding index.
attrName = Search.getIndexName(fieldName)
@ -306,7 +322,9 @@ class ToolMixin(BaseMixin):
# Return brains only.
if not maxResults: return brains
else: return brains[:maxResults]
if not maxResults: maxResults = self.appy().numberOfResultsPerPage
if not maxResults:
if refField: maxResults = refField.maxPerPage
else: maxResults = self.appy().numberOfResultsPerPage
elif maxResults == 'NO_LIMIT': maxResults = None
res = SomeObjects(brains, maxResults, startNumber,noSecurity=noSecurity)
res.brainsToObjects()
@ -327,14 +345,17 @@ class ToolMixin(BaseMixin):
s['search_%s' % searchName] = uids
return res.__dict__
def getResultColumnsNames(self, contentType):
def getResultColumnsNames(self, contentType, refField):
contentTypes = contentType.strip(',').split(',')
resSet = None # Temporary set for computing intersections.
res = [] # Final, sorted result.
fieldNames = None
appyTool = self.appy()
for cType in contentTypes:
fieldNames = getattr(appyTool, 'resultColumnsFor%s' % cType)
if refField:
fieldNames = refField.shownInfo
else:
fieldNames = getattr(appyTool, 'resultColumnsFor%s' % cType)
if not resSet:
resSet = set(fieldNames)
else:
@ -346,27 +367,6 @@ class ToolMixin(BaseMixin):
res.append(fieldName)
return res
def getResultColumns(self, anObject, contentType):
'''What columns must I show when displaying a list of root class
instances? Result is a list of tuples containing the name of the
column (=name of the field) and the corresponding appyType (dict
version).'''
res = []
for fieldName in self.getResultColumnsNames(contentType):
if fieldName == 'workflowState':
# We do not return a appyType if the attribute is not a *real*
# attribute, but the workfow state.
res.append(fieldName)
else:
appyType = anObject.getAppyType(fieldName, asDict=True)
if not appyType:
res.append({'name': fieldName, '_wrong': True})
# The field name is wrong.
# We return it so we can show it in an error message.
else:
res.append(appyType)
return res
def truncateValue(self, value, appyType):
'''Truncates the p_value according to p_appyType width.'''
maxWidth = appyType['width']
@ -452,14 +452,13 @@ class ToolMixin(BaseMixin):
return pythonClass.maySearch(self.appy())
return True
def userMayNavigate(self, someClass):
def userMayNavigate(self, obj):
'''This method checks if the currently logged user can display the
navigation panel within the portlet. This is done by calling method
"mayNavigate" on the class whose currently shown object is an
instance of. If no such method exists, we return True.'''
pythonClass = self.getAppyClass(someClass)
if 'mayNavigate' in pythonClass.__dict__:
return pythonClass.mayNavigate(self.appy())
"mayNavigate" on the currently shown object. If no such method
exists, we return True.'''
appyObj = obj.appy()
if hasattr(appyObj, 'mayNavigate'): return appyObj.mayNavigate()
return True
def onImportObjects(self):
@ -485,8 +484,9 @@ class ToolMixin(BaseMixin):
return False
def isSortable(self, name, className, usage):
'''Is field p_name defined on p_metaType sortable for p_usage purposes
'''Is field p_name defined on p_className sortable for p_usage purposes
(p_usage can be "ref" or "search")?'''
if (',' in className) or (name == 'workflowState'): return False
appyType = self.getAppyType(name, className=className)
return appyType.isSortable(usage=usage)
@ -591,10 +591,14 @@ class ToolMixin(BaseMixin):
oper = ' %s ' % rq.form.get(operKey, 'or').upper()
attrValue = oper.join(attrValue)
criteria[attrName[2:]] = attrValue
# Complete criteria with Ref info if the search is restricted to
# referenced objects of a Ref field.
refInfo = rq.get('ref', None)
if refInfo: criteria['_ref'] = refInfo
rq.SESSION['searchCriteria'] = criteria
# Go to the screen that displays search results
backUrl = '%s/query?type_name=%s&&search=_advanced' % \
(os.path.dirname(rq['URL']), rq['type_name'])
(os.path.dirname(rq['URL']),rq['type_name'])
return self.goto(backUrl)
def getJavascriptMessages(self):
@ -605,6 +609,18 @@ class ToolMixin(BaseMixin):
res += 'var %s = "%s";\n' % (msg, self.translate(msg))
return res
def getRefInfo(self, refInfo=None):
'''When a search is restricted to objects referenced through a Ref
field, this method returns information about this reference: the
source content type and the Ref field (Appy type). If p_refInfo is
not given, we search it among search criteria in the session.'''
if not refInfo:
criteria = self.REQUEST.SESSION.get('searchCriteria', None)
if criteria and criteria.has_key('_ref'): refInfo = criteria['_ref']
if not refInfo: return ('', None)
sourceContentType, refField = refInfo.split(':')
return refInfo, self.getAppyType(refField, className=sourceContentType)
def getSearches(self, contentType):
'''Returns the list of searches that are defined for p_contentType.
Every list item is a dict that contains info about a search or about
@ -650,8 +666,9 @@ class ToolMixin(BaseMixin):
on p_contentType.'''
baseUrl = self.getAppFolder().absolute_url() + '/skyn'
baseParams = 'type_name=%s' % contentType
# Manage start number
rq = self.REQUEST
if rq.get('ref'): baseParams += '&ref=%s' % rq.get('ref')
# Manage start number
if startNumber != None:
baseParams += '&startNumber=%s' % startNumber
elif rq.has_key('startNumber'):

View file

@ -490,9 +490,25 @@ class BaseMixin:
if tjs not in js: js.append(tjs)
return css, js
def getAppyTypesFromNames(self, fieldNames, asDict=True):
'''Gets the Appy types names p_fieldNames.'''
return [self.getAppyType(name, asDict) for name in fieldNames]
def getAppyTypesFromNames(self, fieldNames, asDict=True, addTitle=True):
'''Gets the Appy types named p_fieldNames. If 'title' is not among
p_fieldNames and p_addTitle is True, field 'title' is prepended to
the result.'''
res = []
for name in fieldNames:
appyType = self.getAppyType(name, asDict)
if appyType: res.append(appyType)
elif name == 'workflowState':
# We do not return a appyType if the attribute is not a *real*
# attribute, but the workfow state.
res.append({'name': name, 'labelId': 'workflow_state',
'filterable': False})
else:
self.appy().log('Field "%s", used as shownInfo in a Ref, ' \
'was not found.' % name, type='warning')
if addTitle and ('title' not in fieldNames):
res.insert(0, self.getAppyType('title', asDict))
return res
def getAppyStates(self, phase, currentOnly=False):
'''Returns information about the states that are related to p_phase.