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
					
				
					 12 changed files with 67 additions and 32 deletions
				
			
		|  | @ -564,11 +564,6 @@ class ToolClassDescriptor(ClassDescriptor): | |||
|         fieldType = gen.Boolean(default=defaultValue, page='userInterface', | ||||
|                                 group=groupName) | ||||
|         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. | ||||
|         # 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 | ||||
|  |  | |||
|  | @ -417,6 +417,8 @@ class ZopeInstaller: | |||
|         self.configureSessions() | ||||
|         self.installBaseObjects() | ||||
|         self.installCatalog() | ||||
|         # The following line cleans and rebuilds the catalog entirely. | ||||
|         #self.app.config.appy().refreshCatalog() | ||||
|         self.installTool() | ||||
|         self.installUi() | ||||
|         # Perform migrations if required | ||||
|  |  | |||
|  | @ -896,7 +896,11 @@ class BaseMixin: | |||
|             self.log('Wrong workflow info for a "%s"; is not in state "%s".' % \ | ||||
|                      (self.meta_type, stateName)) | ||||
|         # 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): | ||||
|         '''Has this object an history?''' | ||||
|  |  | |||
|  | @ -188,7 +188,7 @@ class Translation(ModelClass): | |||
| toolFieldPrefixes = ('defaultValue', 'podTemplate', 'formats', 'resultColumns', | ||||
|                      'enableAdvancedSearch', 'numberOfSearchColumns', | ||||
|                      'searchFields', 'optionalFields', 'showWorkflow', | ||||
|                      'showWorkflowCommentField', 'showAllStatesInPhase') | ||||
|                      'showAllStatesInPhase') | ||||
| defaultToolFields = ('title', 'users', 'groups', 'translations', | ||||
|                      'enableNotifications', 'unoEnabledPython','openOfficePort', | ||||
|                      'numberOfResultsPerPage', 'listBoxesMaximumWidth', | ||||
|  |  | |||
|  | @ -38,9 +38,6 @@ class PoMessage: | |||
|     MSG_searchFields = "Search fields" | ||||
|     MSG_optionalFields = 'Optional fields' | ||||
|     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' | ||||
|     POD_ASKACTION = 'Trigger related action' | ||||
|     REF_NO = 'No object.' | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ table { font-size: 100%; border-spacing: 0px; border-collapse:collapse;} | |||
| form { margin: 0; padding: 0;} | ||||
| p { margin: 0;} | ||||
| acronym {cursor: help;} | ||||
| input { font: 92% Helvetica,Arial,sans-serif } | ||||
| input[type=image] { border: 0; background: none; } | ||||
| input[type=checkbox] { 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; } | ||||
| .login { margin-top: 2px; margin-bottom: 2px; color: white;} | ||||
| .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; | ||||
|            width: 700px; border: 1px black dashed; padding: 2px 6px; | ||||
|            background-color: #f4f5f6} | ||||
|  |  | |||
|  | @ -307,7 +307,7 @@ function triggerTransition(transitionId, msg) { | |||
|     theForm.submit(); | ||||
|   } | ||||
|   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 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 | ||||
|      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'); | ||||
|   confirmForm.actionType.value = actionType; | ||||
|   confirmForm.action.value = action; | ||||
|   var commentArea = document.getElementById('commentArea'); | ||||
|   if (showComment) commentArea.style.display = "block"; | ||||
|   else commentArea.style.display = "none"; | ||||
|   openPopup("confirmActionPopup", msg); | ||||
| } | ||||
| 
 | ||||
|  | @ -427,8 +431,14 @@ function doConfirm() { | |||
|   var actionType = confirmForm.actionType.value; | ||||
|   var action = confirmForm.action.value; | ||||
|   if (actionType == 'form') { | ||||
|     // We must submit the form whose id is in "action"
 | ||||
|     document.getElementById(action).submit(); | ||||
|     /* Submit the form whose id is in "action", and transmmit him the comment | ||||
|        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') { | ||||
|     // 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:content="event/time"/> | ||||
|       <td tal:condition="not: isDataChange"> | ||||
|         <tal:comment condition="rhComments" tal:content="structure rhComments"/> | ||||
|         <span tal:condition="not: rhComments">No comment.</span> | ||||
|         <tal:c condition="rhComments" | ||||
|                content="structure python: contextObj.formatText(rhComments)"/> | ||||
|         <span tal:condition="not: rhComments">-</span> | ||||
|       </td> | ||||
|       <td tal:condition="isDataChange"> | ||||
|         <tal:comment replace="nothing"> | ||||
|  | @ -152,21 +153,16 @@ | |||
|     <input type="hidden" name="workflow_action"/> | ||||
|     <table> | ||||
|       <tr valign="middle"> | ||||
|         <tal:comment replace="nothing">Input field allowing to enter a comment before triggering a transition</tal:comment> | ||||
|         <td tal:define="showCommentsField python:tool.getAttr('showWorkflowCommentFieldFor'+contextObj.meta_type)" | ||||
|             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">Input field for storing comment</tal:comment> | ||||
|         <textarea id="comment" name="comment" cols="30" rows="3" style="display:none"></textarea> | ||||
|         <tal:comment replace="nothing">Buttons for triggering transitions</tal:comment> | ||||
|         <td align="right" tal:repeat="transition transitions"> | ||||
|           <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; | ||||
|                                  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> | ||||
|           <div class="appyButton fakeButton" tal:condition="not: transition/may_trigger"> | ||||
|           <div class="fakeButton" tal:condition="not: transition/may_trigger"> | ||||
|             <acronym tal:content="transition/title" | ||||
|                      tal:attributes="title transition/reason"></acronym> | ||||
|           </div> | ||||
|  |  | |||
|  | @ -74,6 +74,12 @@ | |||
|       <p id="appyConfirmText"></p> | ||||
|       <input type="hidden" name="actionType"/> | ||||
|       <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()" | ||||
|              tal:attributes="value python:_('yes')"/> | ||||
|       <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- | ||||
|                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" | ||||
|                Stores the boolean field indicating if we must show all states | ||||
|                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())") | ||||
|         msg = 'Security refresh: %d object(s) updated.' % context['nb'] | ||||
|         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) | ||||
|            possesses.''' | ||||
|         res = list(self.roles) | ||||
|         if 'Anonymous' not in res: res.append('Authenticated') | ||||
|         # Add group global roles | ||||
|         if not hasattr(aq_base(self), 'groups'): return res | ||||
|         for roles in self.groups.itervalues(): | ||||
|  |  | |||
|  | @ -375,10 +375,10 @@ class Cortexer: | |||
| 
 | ||||
|        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 | ||||
|        "cortex.admin" lies and type (command-line tool "cortex-client" must | ||||
|        "cortex.admin" lies and type (command-line tool "cortex" must | ||||
|        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',)): | ||||
|         self.appName = os.path.basename(app) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gaetan Delannay
						Gaetan Delannay