appy.gen: removed fields Tool.showWorkflowCommentFieldForxx (workflow comment may not be entered into the confirm popup); appy.gen: security-related bugfixes.
This commit is contained in:
parent
cbb8d5cd12
commit
f6a828bc13
|
@ -564,11 +564,6 @@ class ToolClassDescriptor(ClassDescriptor):
|
||||||
fieldType = gen.Boolean(default=defaultValue, page='userInterface',
|
fieldType = gen.Boolean(default=defaultValue, page='userInterface',
|
||||||
group=groupName)
|
group=groupName)
|
||||||
self.addField(fieldName, fieldType)
|
self.addField(fieldName, fieldType)
|
||||||
# Adds the boolean field for showing or not the field "enter comments".
|
|
||||||
fieldName = 'showWorkflowCommentFieldFor%s' % className
|
|
||||||
fieldType = gen.Boolean(default=defaultValue, page='userInterface',
|
|
||||||
group=groupName)
|
|
||||||
self.addField(fieldName, fieldType)
|
|
||||||
# Adds the boolean field for showing all states in current state or not.
|
# Adds the boolean field for showing all states in current state or not.
|
||||||
# If this boolean is True but the current phase counts only one state,
|
# If this boolean is True but the current phase counts only one state,
|
||||||
# we will not show the state at all: the fact of knowing in what phase
|
# we will not show the state at all: the fact of knowing in what phase
|
||||||
|
|
|
@ -417,6 +417,8 @@ class ZopeInstaller:
|
||||||
self.configureSessions()
|
self.configureSessions()
|
||||||
self.installBaseObjects()
|
self.installBaseObjects()
|
||||||
self.installCatalog()
|
self.installCatalog()
|
||||||
|
# The following line cleans and rebuilds the catalog entirely.
|
||||||
|
#self.app.config.appy().refreshCatalog()
|
||||||
self.installTool()
|
self.installTool()
|
||||||
self.installUi()
|
self.installUi()
|
||||||
# Perform migrations if required
|
# Perform migrations if required
|
||||||
|
|
|
@ -896,7 +896,11 @@ class BaseMixin:
|
||||||
self.log('Wrong workflow info for a "%s"; is not in state "%s".' % \
|
self.log('Wrong workflow info for a "%s"; is not in state "%s".' % \
|
||||||
(self.meta_type, stateName))
|
(self.meta_type, stateName))
|
||||||
# Update permission attributes on the object if required
|
# Update permission attributes on the object if required
|
||||||
return state.updatePermissions(wf, self)
|
updated = state.updatePermissions(wf, self)
|
||||||
|
if updated:
|
||||||
|
# Reindex the object because security-related info is indexed.
|
||||||
|
self.reindex()
|
||||||
|
return updated
|
||||||
|
|
||||||
def hasHistory(self):
|
def hasHistory(self):
|
||||||
'''Has this object an history?'''
|
'''Has this object an history?'''
|
||||||
|
|
|
@ -188,7 +188,7 @@ class Translation(ModelClass):
|
||||||
toolFieldPrefixes = ('defaultValue', 'podTemplate', 'formats', 'resultColumns',
|
toolFieldPrefixes = ('defaultValue', 'podTemplate', 'formats', 'resultColumns',
|
||||||
'enableAdvancedSearch', 'numberOfSearchColumns',
|
'enableAdvancedSearch', 'numberOfSearchColumns',
|
||||||
'searchFields', 'optionalFields', 'showWorkflow',
|
'searchFields', 'optionalFields', 'showWorkflow',
|
||||||
'showWorkflowCommentField', 'showAllStatesInPhase')
|
'showAllStatesInPhase')
|
||||||
defaultToolFields = ('title', 'users', 'groups', 'translations',
|
defaultToolFields = ('title', 'users', 'groups', 'translations',
|
||||||
'enableNotifications', 'unoEnabledPython','openOfficePort',
|
'enableNotifications', 'unoEnabledPython','openOfficePort',
|
||||||
'numberOfResultsPerPage', 'listBoxesMaximumWidth',
|
'numberOfResultsPerPage', 'listBoxesMaximumWidth',
|
||||||
|
|
|
@ -38,9 +38,6 @@ class PoMessage:
|
||||||
MSG_searchFields = "Search fields"
|
MSG_searchFields = "Search fields"
|
||||||
MSG_optionalFields = 'Optional fields'
|
MSG_optionalFields = 'Optional fields'
|
||||||
MSG_showWorkflow = 'Show workflow-related information'
|
MSG_showWorkflow = 'Show workflow-related information'
|
||||||
MSG_showWorkflowCommentField = 'Show field allowing to enter a ' \
|
|
||||||
'comment every time a transition is ' \
|
|
||||||
'triggered'
|
|
||||||
MSG_showAllStatesInPhase = 'Show all states in phase'
|
MSG_showAllStatesInPhase = 'Show all states in phase'
|
||||||
POD_ASKACTION = 'Trigger related action'
|
POD_ASKACTION = 'Trigger related action'
|
||||||
REF_NO = 'No object.'
|
REF_NO = 'No object.'
|
||||||
|
|
|
@ -9,6 +9,7 @@ table { font-size: 100%; border-spacing: 0px; border-collapse:collapse;}
|
||||||
form { margin: 0; padding: 0;}
|
form { margin: 0; padding: 0;}
|
||||||
p { margin: 0;}
|
p { margin: 0;}
|
||||||
acronym {cursor: help;}
|
acronym {cursor: help;}
|
||||||
|
input { font: 92% Helvetica,Arial,sans-serif }
|
||||||
input[type=image] { border: 0; background: none; }
|
input[type=image] { border: 0; background: none; }
|
||||||
input[type=checkbox] { border: 0; background: none; cursor: pointer;}
|
input[type=checkbox] { border: 0; background: none; cursor: pointer;}
|
||||||
input[type=radio] { border: 0; background: none; cursor: pointer;}
|
input[type=radio] { border: 0; background: none; cursor: pointer;}
|
||||||
|
@ -44,6 +45,8 @@ img {border: 0}
|
||||||
border-top: 1px solid #5F7983; border-bottom: 1px solid #5F7983; }
|
border-top: 1px solid #5F7983; border-bottom: 1px solid #5F7983; }
|
||||||
.login { margin-top: 2px; margin-bottom: 2px; color: white;}
|
.login { margin-top: 2px; margin-bottom: 2px; color: white;}
|
||||||
.buttons { margin-left: 4px;}
|
.buttons { margin-left: 4px;}
|
||||||
|
.fakeButton { border: 1px solid #D7DEE4; background-color: #fde8e0;
|
||||||
|
padding: 0px 8px 2px; font: italic 92% Helvetica,Arial,sans-serif}
|
||||||
.message { color: #fd9c03; position: absolute; top: -55px; left: 100px;
|
.message { color: #fd9c03; position: absolute; top: -55px; left: 100px;
|
||||||
width: 700px; border: 1px black dashed; padding: 2px 6px;
|
width: 700px; border: 1px black dashed; padding: 2px 6px;
|
||||||
background-color: #f4f5f6}
|
background-color: #f4f5f6}
|
||||||
|
|
|
@ -307,7 +307,7 @@ function triggerTransition(transitionId, msg) {
|
||||||
theForm.submit();
|
theForm.submit();
|
||||||
}
|
}
|
||||||
else { // Ask the user to confirm.
|
else { // Ask the user to confirm.
|
||||||
askConfirm('form', 'triggerTransitionForm', msg);
|
askConfirm('form', 'triggerTransitionForm', msg, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,13 +409,17 @@ function closePopup(popupId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function triggered when an action needs to be confirmed by the user
|
// Function triggered when an action needs to be confirmed by the user
|
||||||
function askConfirm(actionType, action, msg) {
|
function askConfirm(actionType, action, msg, showComment) {
|
||||||
/* Store the actionType (send a form, call an URL or call a script) and the
|
/* Store the actionType (send a form, call an URL or call a script) and the
|
||||||
related action, and shows the confirm popup. If the user confirms, we
|
related action, and shows the confirm popup. If the user confirms, we
|
||||||
will perform the action. */
|
will perform the action. If p_showComment is true, an input field allowing
|
||||||
|
to enter a comment will be shown in the popup. */
|
||||||
var confirmForm = document.getElementById('confirmActionForm');
|
var confirmForm = document.getElementById('confirmActionForm');
|
||||||
confirmForm.actionType.value = actionType;
|
confirmForm.actionType.value = actionType;
|
||||||
confirmForm.action.value = action;
|
confirmForm.action.value = action;
|
||||||
|
var commentArea = document.getElementById('commentArea');
|
||||||
|
if (showComment) commentArea.style.display = "block";
|
||||||
|
else commentArea.style.display = "none";
|
||||||
openPopup("confirmActionPopup", msg);
|
openPopup("confirmActionPopup", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,8 +431,14 @@ function doConfirm() {
|
||||||
var actionType = confirmForm.actionType.value;
|
var actionType = confirmForm.actionType.value;
|
||||||
var action = confirmForm.action.value;
|
var action = confirmForm.action.value;
|
||||||
if (actionType == 'form') {
|
if (actionType == 'form') {
|
||||||
// We must submit the form whose id is in "action"
|
/* Submit the form whose id is in "action", and transmmit him the comment
|
||||||
document.getElementById(action).submit();
|
from the popup when relevant */
|
||||||
|
var theForm = document.getElementById(action);
|
||||||
|
if ((confirmForm.comment.style.display != 'none') &&
|
||||||
|
(confirmForm.comment.value)) {
|
||||||
|
theForm.comment.value = confirmForm.comment.value;
|
||||||
|
}
|
||||||
|
theForm.submit();
|
||||||
}
|
}
|
||||||
else if (actionType == 'url') {
|
else if (actionType == 'url') {
|
||||||
// We must go to the URL defined in "action"
|
// We must go to the URL defined in "action"
|
||||||
|
|
|
@ -88,8 +88,9 @@
|
||||||
<td tal:define="actorid python:event.get('actor');" tal:content="actorid"/>
|
<td tal:define="actorid python:event.get('actor');" tal:content="actorid"/>
|
||||||
<td tal:content="event/time"/>
|
<td tal:content="event/time"/>
|
||||||
<td tal:condition="not: isDataChange">
|
<td tal:condition="not: isDataChange">
|
||||||
<tal:comment condition="rhComments" tal:content="structure rhComments"/>
|
<tal:c condition="rhComments"
|
||||||
<span tal:condition="not: rhComments">No comment.</span>
|
content="structure python: contextObj.formatText(rhComments)"/>
|
||||||
|
<span tal:condition="not: rhComments">-</span>
|
||||||
</td>
|
</td>
|
||||||
<td tal:condition="isDataChange">
|
<td tal:condition="isDataChange">
|
||||||
<tal:comment replace="nothing">
|
<tal:comment replace="nothing">
|
||||||
|
@ -152,21 +153,16 @@
|
||||||
<input type="hidden" name="workflow_action"/>
|
<input type="hidden" name="workflow_action"/>
|
||||||
<table>
|
<table>
|
||||||
<tr valign="middle">
|
<tr valign="middle">
|
||||||
<tal:comment replace="nothing">Input field allowing to enter a comment before triggering a transition</tal:comment>
|
<tal:comment replace="nothing">Input field for storing comment</tal:comment>
|
||||||
<td tal:define="showCommentsField python:tool.getAttr('showWorkflowCommentFieldFor'+contextObj.meta_type)"
|
<textarea id="comment" name="comment" cols="30" rows="3" style="display:none"></textarea>
|
||||||
align="right" tal:condition="showCommentsField">
|
|
||||||
<span tal:content="python: tool.translate('workflow_comment')" class="discreet"></span>
|
|
||||||
<input type="text" id="comment" name="comment" size="30"/>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<tal:comment replace="nothing">Buttons for triggering transitions</tal:comment>
|
<tal:comment replace="nothing">Buttons for triggering transitions</tal:comment>
|
||||||
<td align="right" tal:repeat="transition transitions">
|
<td align="right" tal:repeat="transition transitions">
|
||||||
<tal:comment replace="nothing">Real button</tal:comment>
|
<tal:comment replace="nothing">Real button</tal:comment>
|
||||||
<input type="button" class="appyButton" tal:condition="transition/may_trigger"
|
<input type="button" tal:condition="transition/may_trigger"
|
||||||
tal:attributes="value transition/title;
|
tal:attributes="value transition/title;
|
||||||
onClick python: 'triggerTransition(\'%s\',\'%s\')' % (transition['name'],transition['confirm']);"/>
|
onClick python: 'triggerTransition(\'%s\',\'%s\')' % (transition['name'],transition['confirm']);"/>
|
||||||
<tal:comment replace="nothing">Fake button, explaining why the transition can't be triggered</tal:comment>
|
<tal:comment replace="nothing">Fake button, explaining why the transition can't be triggered</tal:comment>
|
||||||
<div class="appyButton fakeButton" tal:condition="not: transition/may_trigger">
|
<div class="fakeButton" tal:condition="not: transition/may_trigger">
|
||||||
<acronym tal:content="transition/title"
|
<acronym tal:content="transition/title"
|
||||||
tal:attributes="title transition/reason"></acronym>
|
tal:attributes="title transition/reason"></acronym>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -74,6 +74,12 @@
|
||||||
<p id="appyConfirmText"></p>
|
<p id="appyConfirmText"></p>
|
||||||
<input type="hidden" name="actionType"/>
|
<input type="hidden" name="actionType"/>
|
||||||
<input type="hidden" name="action"/>
|
<input type="hidden" name="action"/>
|
||||||
|
<div id="commentArea" align="left"><br/>
|
||||||
|
<span tal:content="python: tool.translate('workflow_comment')" class="discreet"></span>
|
||||||
|
<textarea name="comment" cols="30" rows="3"></textarea>
|
||||||
|
<br/>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
<input type="button" onClick="doConfirm()"
|
<input type="button" onClick="doConfirm()"
|
||||||
tal:attributes="value python:_('yes')"/>
|
tal:attributes="value python:_('yes')"/>
|
||||||
<input type="button" value="No" onClick="closePopup('confirmActionPopup')"
|
<input type="button" value="No" onClick="closePopup('confirmActionPopup')"
|
||||||
|
|
|
@ -95,10 +95,6 @@ class ToolWrapper(AbstractWrapper):
|
||||||
Stores the boolean field indicating if we must show workflow-
|
Stores the boolean field indicating if we must show workflow-
|
||||||
related information for p_klass or not.
|
related information for p_klass or not.
|
||||||
|
|
||||||
"showWorkflowCommentField"
|
|
||||||
Stores the boolean field indicating if we must show the field
|
|
||||||
allowing to enter a comment every time a transition is triggered.
|
|
||||||
|
|
||||||
"showAllStatesInPhase"
|
"showAllStatesInPhase"
|
||||||
Stores the boolean field indicating if we must show all states
|
Stores the boolean field indicating if we must show all states
|
||||||
linked to the current phase or not. If this field is False, we
|
linked to the current phase or not. If this field is False, we
|
||||||
|
@ -133,4 +129,29 @@ class ToolWrapper(AbstractWrapper):
|
||||||
expression="ctx['nb'] += int(obj.o.refreshSecurity())")
|
expression="ctx['nb'] += int(obj.o.refreshSecurity())")
|
||||||
msg = 'Security refresh: %d object(s) updated.' % context['nb']
|
msg = 'Security refresh: %d object(s) updated.' % context['nb']
|
||||||
self.log(msg)
|
self.log(msg)
|
||||||
|
|
||||||
|
def refreshCatalog(self, startObject=None):
|
||||||
|
'''Reindex all Appy objects. For some unknown reason, method
|
||||||
|
catalog.refreshCatalog is not able to recatalog Appy objects.'''
|
||||||
|
if not startObject:
|
||||||
|
# This is a global refresh. Clear the catallog completely, and then
|
||||||
|
# reindex all Appy-managed objects, ie those in folders "config"
|
||||||
|
# and "data".
|
||||||
|
# First, clear the catalog.
|
||||||
|
app = self.o.getParentNode()
|
||||||
|
app.catalog._catalog.clear()
|
||||||
|
app.config.reindex()
|
||||||
|
nb = 1
|
||||||
|
for obj in app.config.objectValues():
|
||||||
|
nb += self.refreshCatalog(startObject=obj)
|
||||||
|
# Then, refresh objects in the "data" folder.
|
||||||
|
for obj in app.data.objectValues():
|
||||||
|
nb += self.refreshCatalog(startObject=obj)
|
||||||
|
print '%d object(s) were reindexed.' % nb
|
||||||
|
else:
|
||||||
|
startObject.reindex()
|
||||||
|
nb = 1
|
||||||
|
for obj in startObject.objectValues():
|
||||||
|
nb += self.refreshCatalog(startObject=obj)
|
||||||
|
return nb
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -129,6 +129,7 @@ class ZopeUserPatches:
|
||||||
'''Returns the global roles that this user (or any of its groups)
|
'''Returns the global roles that this user (or any of its groups)
|
||||||
possesses.'''
|
possesses.'''
|
||||||
res = list(self.roles)
|
res = list(self.roles)
|
||||||
|
if 'Anonymous' not in res: res.append('Authenticated')
|
||||||
# Add group global roles
|
# Add group global roles
|
||||||
if not hasattr(aq_base(self), 'groups'): return res
|
if not hasattr(aq_base(self), 'groups'): return res
|
||||||
for roles in self.groups.itervalues():
|
for roles in self.groups.itervalues():
|
||||||
|
|
|
@ -375,10 +375,10 @@ class Cortexer:
|
||||||
|
|
||||||
Once the "cortex.admin" folder and its content has been generated, in
|
Once the "cortex.admin" folder and its content has been generated, in
|
||||||
order to push the app definition into Cortex, go in the folder where
|
order to push the app definition into Cortex, go in the folder where
|
||||||
"cortex.admin" lies and type (command-line tool "cortex-client" must
|
"cortex.admin" lies and type (command-line tool "cortex" must
|
||||||
be installed):
|
be installed):
|
||||||
|
|
||||||
cortex-client sync push --api http://<cortex-host-ip>/api
|
cortex sync push --api http://<cortex-host-ip>/api
|
||||||
'''
|
'''
|
||||||
def __init__(self, app, pythonVersions=('2.6',)):
|
def __init__(self, app, pythonVersions=('2.6',)):
|
||||||
self.appName = os.path.basename(app)
|
self.appName = os.path.basename(app)
|
||||||
|
|
Loading…
Reference in a new issue