def test_multi_admin_unit_team_task_edit_in_issuer_dossier(self, browser): self.login(self.regular_user, browser=browser) ra_admin_unit = create(Builder('admin_unit') .having(title=u'Ratskanzlei', unit_id=u'rk', public_url='http://nohost/plone')) create(Builder('org_unit') .id('rk') .having(title=u'Ratskanzlei', admin_unit=ra_admin_unit) .with_default_groups()) ITask(self.task).responsible = u'team:1' ITask(self.task).responsible_client = u'rk' self.task.get_sql_object().responsible = u'team:1' self.task.get_sql_object().assigned_org_unit = u'rk' self.set_workflow_state('task-state-open', self.task) browser.open(self.task) browser.click_on('task-transition-open-in-progress') browser.fill({'Accept the task and ...': 'participate'}) browser.click_on('Continue') self.assertEquals(self.regular_user.getId(), self.task.responsible) self.assertEquals(self.regular_user.getId(), self.task.get_sql_object().responsible)
def create_subtask_response(context, event): """When adding a new task object within a task(subtask), it adds a response to the maintask. """ # the event is fired multiple times when the task was transported, so we # need to verify that the request was not called by another client. request = context.REQUEST if request.get_header('X-OGDS-AC', None) or \ request.get_header('X-OGDS-AUID', None) or \ request.get('X-CREATING-SUCCESSOR', None): return parent = aq_parent(aq_inner(context)) if ITask.providedBy(parent): if ITask.providedBy(context): transition = 'transition-add-subtask' # If the the added object is a subtask we have to make sure # that the subtask is already synced to the globalindex if not context.get_sql_object(): TaskSqlSyncer(context, event).sync() elif IBaseDocument.providedBy(context): transition = 'transition-add-document' # add a response with a link to the object add_simple_response(parent, added_object=context, transition=transition)
def _update(self, transition, text): response = super(WorkflowResponseSyncerReceiver, self)._update(transition, text) transition = self.request.get('transition') responsible = self.request.get('responsible') responsible_client = self.request.get('responsible_client') wftool = getToolByName(self.context, 'portal_workflow') # change workflow state before = wftool.getInfoFor(self.context, 'review_state') before = wftool.getTitleForStateOnType(before, self.context.Type()) with elevated_privileges(): wftool.doActionFor(self.context, transition) after = wftool.getInfoFor(self.context, 'review_state') after = wftool.getTitleForStateOnType(after, self.context.Type()) if responsible and responsible is not 'None': # special handling for reassign response.add_change( 'responsible', _(u"label_responsible", default=u"Responsible"), ITask(self.context).responsible, responsible) ITask(self.context).responsible_client = responsible_client ITask(self.context).responsible = responsible notify(ObjectModifiedEvent(self.context)) response.add_change('review_state', _(u'Issue state'), before, after)
def create_successor_task(self, dossier): # we need all task field values from the forwarding fielddata = {} for fieldname in ITask.names(): value = ITask.get(fieldname).get(self.context) fielddata[fieldname] = value # Reset issuer to the current inbox fielddata['issuer'] = get_current_org_unit().inbox().id() # Predefine the task_type to avoid tasks with an invalid task_type fielddata['task_type'] = FORWARDING_SUCCESSOR_TYPE # lets create a new task - the successor task task = createContentInContainer( dossier, 'opengever.task.task', **fielddata) # Add issuer and responsible to the watchers of the newly created task center = notification_center() center.add_task_responsible(task, task.responsible) center.add_task_issuer(task, task.issuer) # copy documents and map the intids intids_mapping = _copy_documents_from_forwarding(self.context, task) # copy the responses response_transporter = IResponseTransporter(task) response_transporter.get_responses( get_current_admin_unit().id(), '/'.join(self.context.getPhysicalPath()), intids_mapping=intids_mapping) return task
def reassign_team_task(self, response): old_responsible = ITask(self.context).responsible ITask(self.context).responsible = api.user.get_current().getId() response.add_change( 'responsible', old_responsible, ITask(self.context).responsible, _(u"label_responsible", default=u"Responsible")) self.context.sync()
def reassign_team_tasks(task, event): if event.action != 'task-transition-open-in-progress': return if task.is_team_task: old_responsible = ITask(task).responsible ITask(task).responsible = api.user.get_current().getId() IResponseContainer(task)[-1].add_change( 'responsible', _(u"label_responsible", default=u"Responsible"), old_responsible, ITask(task).responsible)
def assign_forwarding_to_dossier( context, forwarding_oguid, dossier, response_text): forwarding = Task.query.by_oguid(forwarding_oguid) forwarding_obj = context.unrestrictedTraverse( forwarding.physical_path.encode('utf-8')) # we need all task field values from the forwarding fielddata = {} for fieldname in ITask.names(): value = ITask.get(fieldname).get(forwarding_obj) fielddata[fieldname] = value # Reset issuer to the current inbox fielddata['issuer'] = get_current_org_unit().inbox().id() # Predefine the task_type to avoid tasks with an invalid task_type fielddata['task_type'] = FORWARDING_SUCCESSOR_TYPE # lets create a new task - the successor task task = createContentInContainer( dossier, 'opengever.task.task', **fielddata) successor_tc_task = ISuccessorTaskController(task) # Add issuer and responsible to the watchers of the newly created task center = notification_center() center.add_task_responsible(task, task.responsible) center.add_task_issuer(task, task.issuer) # copy documents and map the intids intids_mapping = _copy_documents_from_forwarding(forwarding_obj, task) # copy the responses response_transporter = IResponseTransporter(task) response_transporter.get_responses( get_current_admin_unit().id(), '/'.join(forwarding_obj.getPhysicalPath()), intids_mapping=intids_mapping) # close and store the forwarding in yearfolder change_task_workflow_state( forwarding_obj, 'forwarding-transition-assign-to-dossier', text=response_text, successor_oguid=successor_tc_task.get_oguid()) IYearfolderStorer(forwarding_obj).store_in_yearfolder() # successor successor_tc_task.set_predecessor(forwarding_oguid) return task
def assign_forwarding_to_dossier(context, forwarding_oguid, dossier, response_text): forwarding = Task.query.by_oguid(forwarding_oguid) forwarding_obj = context.unrestrictedTraverse( forwarding.physical_path.encode('utf-8')) # we need all task field values from the forwarding fielddata = {} for fieldname in ITask.names(): value = ITask.get(fieldname).get(forwarding_obj) fielddata[fieldname] = value # Reset issuer to the current inbox fielddata['issuer'] = get_current_org_unit().inbox().id() # Predefine the task_type to avoid tasks with an invalid task_type fielddata['task_type'] = FORWARDING_SUCCESSOR_TYPE # lets create a new task - the successor task task = createContentInContainer(dossier, 'opengever.task.task', **fielddata) successor_tc_task = ISuccessorTaskController(task) # Add issuer and responsible to the watchers of the newly created task center = notification_center() center.add_task_responsible(task, task.responsible) center.add_task_issuer(task, task.issuer) # copy documents and map the intids intids_mapping = _copy_documents_from_forwarding(forwarding_obj, task) # copy the responses response_transporter = IResponseTransporter(task) response_transporter.get_responses(get_current_admin_unit().id(), '/'.join( forwarding_obj.getPhysicalPath()), intids_mapping=intids_mapping) # close and store the forwarding in yearfolder change_task_workflow_state(forwarding_obj, 'forwarding-transition-assign-to-dossier', text=response_text, successor_oguid=successor_tc_task.get_oguid()) IYearfolderStorer(forwarding_obj).store_in_yearfolder() # successor successor_tc_task.set_predecessor(forwarding_oguid) return task
def render(self): if not IInternalOpengeverRequestLayer.providedBy(self.request): raise Forbidden() transition = self.request.get('transition') text = self.request.get('text') responsible = self.request.get('responsible') responsible_client = self.request.get('responsible_client') if self.is_already_done(transition, text): # Set correct content type for text response self.request.response.setHeader("Content-type", "text/plain") return 'OK' wftool = getToolByName(self.context, 'portal_workflow') # change workflow state before = wftool.getInfoFor(self.context, 'review_state') before = wftool.getTitleForStateOnType(before, self.context.Type()) wftool.doActionFor(self.context, transition) after = wftool.getInfoFor(self.context, 'review_state') after = wftool.getTitleForStateOnType(after, self.context.Type()) # create response response = add_simple_response( self.context, transition=transition, text=text) if responsible and responsible is not 'None': # special handling for reassign response.add_change( 'reponsible', _(u"label_responsible", default=u"Responsible"), ITask(self.context).responsible, responsible) ITask(self.context).responsible_client = responsible_client ITask(self.context).responsible = responsible notify(ObjectModifiedEvent(self.context)) response.add_change('review_state', _(u'Issue state'), before, after) # Set correct content type for text response self.request.response.setHeader("Content-type", "text/plain") return 'OK'
def after_transition_hook(self, transition, disable_sync, transition_params): self.update_watchers() response = add_simple_response( self.context, transition=transition, text=transition_params.get('text')) response.add_change( 'responsible', ITask(self.context).responsible, ITask(self.context).issuer, _(u"label_responsible", default=u"Responsible")) self.save_related_items(response, transition_params.get('relatedItems')) self.switch_responsible()
def save_related_items(self, response, related_items): if not related_items: return intids = getUtility(IIntIds) current_ids = [item.to_id for item in ITask(self.context).relatedItems] for item in related_items: to_id = intids.getId(item) item._v__is_relation = True if to_id not in current_ids: ITask(self.context).relatedItems.append(RelationValue(to_id)) response.add_change( 'relatedItems', '', item.title, _(u'label_related_items', default=u"Related Items"))
def get_containing_task(self): """ Get the parent-tasks if we have one """ parent = aq_parent(aq_inner(self.context)) if ITask.providedBy(parent): return parent.get_sql_object() return None
def test_only_team_members_count_as_responsible(self, browser): self.login(self.regular_user, browser) ITask(self.task).responsible = u'team:2' self.task.get_sql_object().responsible = u'team:2' self.set_workflow_state('task-state-open', self.task) browser.open(self.task, view='tabbedview_view-overview') self.assertEquals( ['task-transition-reassign', 'label_add_comment'], browser.css('.actionButtons li').text, 'Expect none responsible actions, because the regular_user is not ' 'a team member and therefore not a responsible.') self.login(self.meeting_user, browser) browser.open(self.task, view='tabbedview_view-overview') self.assertEquals( [ 'task-transition-open-in-progress', 'task-transition-open-rejected', 'task-transition-open-resolved', 'task-transition-reassign', 'label_add_comment' ], browser.css('.actionButtons li').text, 'Expect responsible actions, because the meeting_user is a team ' 'member and therefore not a responsible.')
def _set_immediate_view(self, created): """The default behavior implemented by the dexterity add form is circumvented by this form. If there's only one task the immediate_view of the task fti is respected. If there is more than one task, a differen TaskRedirector implementation is used.""" if len(created) == 1: task = created[0] fti = getUtility(IDexterityFTI, name=self.portal_type) if fti.immediate_view: self.immediate_view = "{0}/{1}/{2}".format( self.context.absolute_url(), task.id, fti.immediate_view, ) else: self.immediate_view = "{0}/{1}".format( self.context.absolute_url(), task.id) else: if ITask.providedBy(self.context): redirect_to = '{0}#overview'.format( self.context.absolute_url()) else: redirect_to = '{0}#tasks'.format(self.context.absolute_url()) self.immediate_view = redirect_to
def get_added_objects(self): """ Returns two lists of docs, subtasks """ try: self.added_object except AttributeError: return [], [] # .. and sometimes it may be empty. if not self.added_object: return [], [] # Support for multiple added objects if hasattr(self.added_object, '__iter__'): relations = self.added_object else: relations = [self.added_object] docs = [] subtasks = [] for rel in relations: obj = rel.to_object if ITask.providedBy(obj): subtasks.append(obj) else: docs.append(obj) return docs, subtasks
def get_redirect_url(context): """return the url where the editing_document view was called from It should be a document listing.""" referer = context.REQUEST.environ.get('HTTP_REFERER') portal_url = '/'.join(context.portal_url().split('/')[:-1]) if referer: obj_path = referer[len(portal_url):] try: obj = context.restrictedTraverse(obj_path) except KeyError: return '%s#overview' % context.absolute_url() # redirect to right tabbedview-tab if ITask.providedBy(obj): return '%s#relateddocuments' % (obj.absolute_url()) elif IPloneSiteRoot.providedBy(obj): return '%s#mydocuments' % (obj.absolute_url()) elif IDossierMarker.providedBy(obj): return '%s#documents' % (obj.absolute_url()) else: return obj.absolute_url() else: return '%s#overview' % context.absolute_url()
def createAndAdd(self, data): created = [] # make sure we don't create private tasks when the feature is # not enabled. the field is hidden, but users could still submit. if not is_private_task_feature_enabled(): data['is_private'] = False if isinstance(data['responsible'], basestring): data['responsible'] = [data['responsible']] all_responsible_users = data['responsible'] for responsible in all_responsible_users: data['responsible'] = responsible update_reponsible_field_data(data) created.append(self._create_task(data)) # Restore responsible in data data['responsible'] = all_responsible_users # Set tasktemplate order and move to planned state if it's part # of a sequential process if ITask.providedBy( self.context) and self.context.is_sequential_main_task(): position = data['tasktemplate_position'] if not position: position = len(self.context.get_tasktemplate_order()) for task in created: self.context.add_task_to_tasktemplate_order(position, task) self._set_immediate_view(created) return created
def test_responsible_change_is_visible_in_the_response(self, browser): self.login(self.regular_user, browser) ITask(self.task).responsible = u'team:1' self.task.get_sql_object().responsible = u'team:1' self.set_workflow_state('task-state-open', self.task) browser.open(self.task, view='tabbedview_view-overview') browser.click_on('task-transition-open-in-progress') browser.fill({'Response': u'Das \xfcbernehme ich!'}) browser.click_on('Save') response = IResponseContainer(self.task).list()[-1] expected = [{ 'before': u'team:1', 'after': 'kathi.barfuss', 'field_id': 'responsible', 'field_title': u'label_responsible' }] self.assertEqual(expected, [dict(change) for change in response.changes]) browser.open(self.task, view='tabbedview_view-overview') self.assertEqual( u'Accepted by B\xe4rfuss K\xe4thi (kathi.barfuss), responsible ' u'changed from Projekt \xdcberbaung Dorfmatte (Finanz\xe4mt) to ' u'B\xe4rfuss K\xe4thi (kathi.barfuss).', browser.css('.answer h3').text[0])
def get_containing_task(self): """ Get the parent-tasks if we have one """ parent = aq_parent(aq_inner(self.context)) if ITask.providedBy(parent): return [parent] return []
def test_revokes_permissions_on_proposal(self): self.login(self.dossier_responsible) intids = getUtility(IIntIds) relation = RelationValue(intids.getId(self.proposaldocument)) ITask(self.subtask).relatedItems.append(relation) notify(ObjectModifiedEvent(self.subtask)) self.set_workflow_state('task-state-tested-and-closed', self.subtask) expected_assignments = [{ 'cause': ASSIGNMENT_VIA_TASK, 'roles': ['Reader', 'Editor'], 'reference': Oguid.for_object(self.subtask), 'principal': self.regular_user.id }, { 'cause': ASSIGNMENT_VIA_TASK_AGENCY, 'roles': ['Reader', 'Editor'], 'reference': Oguid.for_object(self.subtask), 'principal': u'fa_inbox_users' }] document_storage = RoleAssignmentManager(self.proposaldocument).storage self.assertEqual(expected_assignments, document_storage._storage()) proposal_storage = RoleAssignmentManager(self.proposal).storage self.assertEqual(expected_assignments, proposal_storage._storage()) RevokePermissions(self.subtask, self.request)() self.assertEqual([], proposal_storage._storage()) self.assertEqual([], document_storage._storage())
def assign_forwarding_to_dossier( context, forwarding_oguid, dossier, response_text): forwarding = getUtility(ITaskQuery).get_task_by_oguid(forwarding_oguid) forwarding_obj = context.unrestrictedTraverse( forwarding.physical_path.encode('utf-8')) # we need all task field values from the forwarding fielddata = {} for fieldname in ITask.names(): value = ITask.get(fieldname).get(forwarding_obj) fielddata[fieldname] = value # lets create a new task - the successor task task = createContentInContainer( dossier, 'opengever.task.task', **fielddata) successor_tc_task = ISuccessorTaskController(task) # copy documents and map the intids intids_mapping = _copy_documents_from_forwarding(forwarding_obj, task) # copy the responses response_transporter = IResponseTransporter(task) response_transporter.get_responses( get_client_id(), '/'.join(forwarding_obj.getPhysicalPath()), intids_mapping=intids_mapping) # close and store the forwarding in yearfolder change_task_workflow_state( forwarding_obj, 'forwarding-transition-assign-to-dossier', text=response_text, successor_oguid=successor_tc_task.get_oguid()) inbox = aq_parent(aq_inner(forwarding_obj)) yearfolder = _get_yearfolder(inbox) clipboard = inbox.manage_cutObjects((forwarding_obj.getId(),)) yearfolder.manage_pasteObjects(clipboard) # successor successor_tc_task.set_predecessor(forwarding_oguid) return task
def render(self): parent = aq_inner(aq_parent(self.context)) if ITask.providedBy(parent): redirect_to = '%s#overview' % parent.absolute_url() else: redirect_to = '%s#tasks' % parent.absolute_url() return self.request.RESPONSE.redirect(redirect_to)
def test_set_current_user_as_responsible_when_accepting_a_team_task(self, browser): self.login(self.regular_user, browser) ITask(self.task).responsible = u'team:1' self.task.get_sql_object().responsible = u'team:1' self.set_workflow_state('task-state-open', self.task) browser.open(self.task, view='tabbedview_view-overview') browser.click_on('task-transition-open-in-progress') browser.fill({'Response': u'Das \xfcbernehme ich!'}) browser.click_on('Save') self.assertEquals(self.regular_user.getId(), ITask(self.task).responsible) self.assertEquals(self.regular_user.getId(), self.task.get_sql_object().responsible)
def reindex_dossier_and_children(self, dossier): children = self.catalog(path='/'.join(dossier.getPhysicalPath())) for child in children: obj = child.getObject() obj.reindexObject(idxs=['reference']) if ITask.providedBy(obj): obj.get_sql_object().sync_with(obj)
def assign_forwarding_to_dossier(context, forwarding_oguid, dossier, response_text): forwarding = getUtility(ITaskQuery).get_task_by_oguid(forwarding_oguid) forwarding_obj = context.unrestrictedTraverse( forwarding.physical_path.encode('utf-8')) # we need all task field values from the forwarding fielddata = {} for fieldname in ITask.names(): value = ITask.get(fieldname).get(forwarding_obj) fielddata[fieldname] = value # lets create a new task - the successor task task = createContentInContainer(dossier, 'opengever.task.task', **fielddata) successor_tc_task = ISuccessorTaskController(task) # copy documents and map the intids intids_mapping = _copy_documents_from_forwarding(forwarding_obj, task) # copy the responses response_transporter = IResponseTransporter(task) response_transporter.get_responses(get_client_id(), '/'.join( forwarding_obj.getPhysicalPath()), intids_mapping=intids_mapping) # close and store the forwarding in yearfolder change_task_workflow_state(forwarding_obj, 'forwarding-transition-assign-to-dossier', text=response_text, successor_oguid=successor_tc_task.get_oguid()) inbox = aq_parent(aq_inner(forwarding_obj)) yearfolder = _get_yearfolder(inbox) clipboard = inbox.manage_cutObjects((forwarding_obj.getId(), )) yearfolder.manage_pasteObjects(clipboard) # successor successor_tc_task.set_predecessor(forwarding_oguid) return task
def reindex_containing_dossier_for_contained_objects(dossier, event): """Reindex the containging_dossier index for all the contained obects. """ for brain in dossier.portal_catalog(path='/'.join(dossier.getPhysicalPath())): obj = brain.getObject() obj.reindexObject(idxs=['containing_dossier']) if ITask.providedBy(obj): sync_task(brain.getObject(), event)
def object_moved_or_added(context, event): if isinstance(event, ObjectAddedEvent): # Don't consider moving or removing an object a "touch". Mass-moves # would immediately fill up the touched log, and removals should not # be tracked anyway. if should_track_touches(context): notify(ObjectTouchedEvent(context)) # If an object has been copy & pasted, we need to reindex some fields. # The IObjectCopiedEvent is too early to do that though, because at # that point the object doesn't have a full AQ chain yet. We therefore # just mark it during IObjectCopiedEvent, and do the reindexing here. if getattr(context, '_v_object_has_been_copied', False): context.reindexObject(idxs=reindex_after_copy) if IObjectRemovedEvent.providedBy(event): return # Update object security after moving or copying. # Specifically, this is needed for the case where an object is moved out # of a location where a Placeful Workflow Policy applies to a location # where it doesn't. # # Plone then no longer provides the placeful workflow for that object, # but doesn't automatically update the object's security. # # We use ftw.upgrade's update_security_for() here to correctly # recalculate security, but do the reindexing ourselves because otherwise # Plone will do it recursively (unnecessarily so). changed = update_security_for(context, reindex_security=False) if changed: reindex_object_security_without_children(context) # There are several indices that need updating when a dossier is moved. # first make sure obj was actually moved and not created if not event.oldParent or not event.newParent: return # When an object is moved, its containing_dossier needs reindexing. to_reindex = ['containing_dossier'] # containing_subdossier is really only used for documents, # while is_subdossier is only meaningful for dossiers. if IDossierMarker.providedBy(context): was_subdossier = IDossierMarker.providedBy(event.oldParent) is_subdossier = IDossierMarker.providedBy(event.newParent) if was_subdossier != is_subdossier: to_reindex.append('is_subdossier') if context.portal_type in TYPES_WITH_CONTAINING_SUBDOSSIER_INDEX: to_reindex.append('containing_subdossier') context.reindexObject(idxs=to_reindex) # synchronize with model if necessary if ITask.providedBy(context): sync_task(context, event)
def reindex_containing_dossier_for_contained_objects(dossier, event): """Reindex the containging_dossier index for all the contained obects. """ for brain in dossier.portal_catalog( path='/'.join(dossier.getPhysicalPath())): obj = brain.getObject() obj.reindexObject(idxs=['containing_dossier']) if ITask.providedBy(obj): sync_task(brain.getObject(), event)
def get_type(self, item): """differ the object typ and return the type as string """ if not item: return None elif isinstance(item, dict): return 'dict' elif isinstance(item, Task) or ITask.providedBy(item): return 'task' else: return 'obj'
def test_multi_admin_unit_team_task_edit_in_issuer_dossier(self, browser): self.login(self.regular_user, browser=browser) self.add_additional_admin_and_org_unit() ITask(self.task).responsible = u'team:1' ITask(self.task).responsible_client = u'gdgs' self.task.get_sql_object().responsible = u'team:1' self.task.get_sql_object().assigned_org_unit = u'gdgs' self.set_workflow_state('task-state-open', self.task) browser.open(self.task) browser.click_on('task-transition-open-in-progress') browser.fill({'Accept the task and ...': 'participate'}) browser.click_on('Continue') self.assertEquals(self.regular_user.getId(), self.task.responsible) self.assertEquals(self.regular_user.getId(), self.task.get_sql_object().responsible)
def get_type(self, item): """differ the object typ and return the type as string """ if not item: return None elif isinstance(item, dict): return "dict" elif isinstance(item, Task) or ITask.providedBy(item): return "task" else: return "obj"
def update_deadline(task, event): """Update the parents deadline, when a subtask deadline has changed.""" for descr in event.descriptions: for attr in descr.attributes: if attr == 'deadline': parent = aq_parent(aq_inner(task)) if ITask.providedBy(parent): temp = task.deadline + timedelta(MAIN_TASK_DEADLINE_DELTA) if parent.deadline < temp: parent.deadline = temp parent.reindexObject()
def _get_task_css_class(task): """A task helper function for `get_css_class`, providing some metadata of a task. The task may be a brain, a dexterity object or a sql alchemy globalindex object. """ if ICatalogBrain.providedBy(task) or ISolrDocument.providedBy(task): task = Task.query.by_brain(task) if ITask.providedBy(task): task = task.get_sql_object() return task.get_css_class()
def set_initial_state(task, event): """When adding a subtask to a sequential task process, the new task should be in the planned state. """ if IDuringTaskTemplateFolderTriggering.providedBy(getRequest()): return parent = aq_parent(aq_inner(task)) if ITask.providedBy(parent) \ and IFromSequentialTasktemplate.providedBy(parent): task.set_to_planned_state()
def _task_state_wrapper(self, item, text): """ Wrap a span-tag around the text with the status-css class """ if isinstance(item, Task): # Its a sql-task-object state = item.review_state elif ITask.providedBy(item): # Its a task-object state = getToolByName(self.context, "portal_workflow").getInfoFor(item, "review_state") else: return "" return '<span class="wf-%s">%s</span>' % (state, text)
def set_initial_state(task, event): """When adding a subtask to a sequential task process, the new task should be in the planned state. """ if IDuringTaskTemplateFolderTriggering.providedBy(getRequest()): return parent = aq_parent(aq_inner(task)) if ITask.providedBy(parent) \ and parent.is_sequential_main_task(): task.set_to_planned_state()
def update_deadline(task, event): """Update the parents deadline, when a subtask deadline has changed.""" for descr in event.descriptions: for attr in descr.attributes: if attr == 'deadline': parent = aq_parent(aq_inner(task)) if ITask.providedBy(parent): offset = api.portal.get_registry_record( 'deadline_timedelta', interface=ITaskSettings) temp = task.deadline + timedelta(offset) if parent.deadline < temp: parent.deadline = temp parent.reindexObject()
def render_task(self, item): """ Render the taskobject """ if isinstance(item, Task): # Its a task stored in sql return self._sqlalchemy_task_link(item) elif ITask.providedBy(item): # Its a normal task object return self._object_task_link(item) else: return None
def is_available(self): """The action should only be available on closed tasks for administrators and task issuer and only if the feature is enabled. """ if not is_optional_task_permissions_revoking_enabled(): return False if not ITask.providedBy(self.context): return False if not self.context.get_review_state() in FINAL_TASK_STATES: return False if api.user.has_permission('cmf.ManagePortal'): return True issuer = self.context.get_issuer_actor() return issuer.identifier == api.user.get_current().id
def object_moved_or_added(context, event): if isinstance(event, ObjectAddedEvent): # Don't consider moving or removing an object a "touch". Mass-moves # would immediately fill up the touched log, and removals should not # be tracked anyway. if should_track_touches(context): notify(ObjectTouchedEvent(context)) if IObjectRemovedEvent.providedBy(event): return # Update object security after moving or copying. # Specifically, this is needed for the case where an object is moved out # of a location where a Placeful Workflow Policy applies to a location # where it doesn't. # # Plone then no longer provides the placeful workflow for that object, # but doesn't automatically update the object's security. # # We use ftw.upgrade's update_security_for() here to correctly # recalculate security, but do the reindexing ourselves because otherwise # Plone will do it recursively (unnecessarily so). changed = update_security_for(context, reindex_security=False) if changed: reindex_object_security_without_children(context) # There are several indices that need updating when a dossier is moved. # first make sure obj was actually moved and not created if not event.oldParent or not event.newParent: return # When an object is moved, its containing_dossier needs reindexing. to_reindex = ['containing_dossier'] # containing_subdossier is really only used for documents, # while is_subdossier is only meaningful for dossiers. if IDossierMarker.providedBy(context): was_subdossier = IDossierMarker.providedBy(event.oldParent) is_subdossier = IDossierMarker.providedBy(event.newParent) if was_subdossier != is_subdossier: to_reindex.append('is_subdossier') if context.portal_type in TYPES_WITH_CONTAINING_SUBDOSSIER_INDEX: to_reindex.append('containing_subdossier') context.reindexObject(idxs=to_reindex) # synchronize with model if necessary if ITask.providedBy(context): sync_task(context, event)
def fix_child_mappings(self): dossier_brains = self.catalog(object_provides=IDossierMarker.__identifier__) for brain in dossier_brains: obj = brain.getObject() if ITemplateDossier.providedBy(obj): continue if obj.id in self.ignored_ids: continue self._fix_wrong_mappings(obj) for obj in self.objs_to_reindex: obj.reindexObject(idxs=['reference']) if ITask.providedBy(obj): obj.get_sql_object().sync_with(obj)
def get_parent_dossier(self): """Return the document's parent dossier. A parent dossier is available for documents in a dossier/subdossier or for documents in a task. No parent dossier is available for documents in an inbox, in a forwarding or inside a proposal. In that case this method returns None. """ parent = aq_parent(aq_inner(self)) if IDossierMarker.providedBy(parent) or IDossierTemplateMarker.providedBy(parent): return parent if ITask.providedBy(parent): return parent.get_containing_dossier() return None
def create_subtask_response(context, event): """When adding a new task object within a task(subtask), it adds a response to the maintask. """ # the event is fired multiple times when the task was transported, so we # need to verify that the request was not called by another client. request = context.REQUEST if request.get_header('X-OGDS-AC', None) or \ request.get_header('X-OGDS-CID', None) or \ request.get('X-CREATING-SUCCESSOR', None): return parent = aq_parent(aq_inner(context)) if ITask.providedBy(parent): # add a response with a link to the object add_simple_response(parent, added_object=context)
def test_create_a_task_for_every_selected_person_with_multiple_orgunits(self, browser): client2 = create(Builder('org_unit') .with_default_groups() .id('client2') .having(title='Client2', admin_unit=self.admin_unit)) user = create(Builder('ogds_user') .assign_to_org_units([client2]) .having(userid='some.user')) dossier = create(Builder('dossier')) doc = create(Builder("document").titled("test-doc") .within(dossier)) responsible_users = [ self.get_org_unit().id() + ':' + TEST_USER_ID, client2.id() + ':' + user.userid ] browser.login().visit(dossier) factoriesmenu.add('Task') browser.fill({'Title': 'Task title', 'Task Type': 'To comment', 'Related Items': doc}) form = browser.find_form_by_field('Responsible') form.find_widget('Responsible').fill(responsible_users) browser.find('Save').click() tasks = filter(lambda item: ITask.providedBy(item), dossier.objectValues()) self.assertEquals(2, len(tasks), 'Expect 2 tasks') self.assertEquals(TEST_USER_ID, tasks[0].responsible) self.assertEquals('client1', tasks[0].responsible_client) self.assertEquals(user.userid, tasks[1].responsible) self.assertEquals('client2', tasks[1].responsible_client) activities = Activity.query.all() self.assertEquals(2, len(activities)) self.assertEquals(u'task-added', activities[0].kind) self.assertEquals(TEST_USER_ID, activities[0].actor_id) self.assertEquals(u'task-added', activities[1].kind) self.assertEquals(TEST_USER_ID, activities[1].actor_id)
def get_task_info(self, item): """ return some task attributes for objects: Responsible client ID / responsible """ if not ITask.providedBy(item): return "" info = getUtility(IContactInformation) if not item.responsible_client or len(info.get_clients()) <= 1: # No responsible client is set yet or we have a single client # setup. return info.describe(item.responsible) # Client client = client_title_helper(item, item.responsible_client) taskinfo = "%s / %s" % (client, info.render_link(item.responsible)) return taskinfo.encode("utf-8")
def set_workflow_state(self, new_workflow_state_id, *objects): """Set the workflow state of one or many objects. When the state is changed for multiple nested objects at once, the method can optimize reindexing security so that it is not executed multiple times for the same object. """ wftool = api.portal.get_tool('portal_workflow') for obj in objects: chain = wftool.getChainFor(obj) self.assertEquals( 1, len(chain), 'set_workflow_state does only support objects with' ' exactly one workflow, but {!r} has {!r}.'.format(obj, chain)) workflow = wftool[chain[0]] self.assertIn(new_workflow_state_id, workflow.states) wftool.setStatusOf(chain[0], obj, { 'review_state': new_workflow_state_id, 'action': '', 'actor': ''}) workflow.updateRoleMappingsFor(obj) obj.reindexObject(idxs=['review_state']) if ITask.providedBy(obj): obj.get_sql_object().review_state = new_workflow_state_id # reindexObjectSecurity is recursive. We should avoid updating the same # object twice when the parent is changed too. security_reindexed = [] for obj in sorted(objects, key=methodcaller('getPhysicalPath')): current_path = '/'.join(obj.getPhysicalPath()) if any(filter(lambda path: current_path.startswith(path), security_reindexed)): # We just have updated the security of a parent recursively, # thus the security of ``obj`` must be up to date at this point. break obj.reindexObjectSecurity() security_reindexed.append(current_path)
def _set_immediate_view(self, created): """The default behavior implemented by the dexterity add form is circumvented by this form. If there's only one task the immediate_view of the task fti is respected. If there is more than one task, a differen TaskRedirector implementation is used.""" if len(created) == 1: task = created[0] fti = getUtility(IDexterityFTI, name=self.portal_type) if fti.immediate_view: self.immediate_view = "{0}/{1}/{2}".format( self.context.absolute_url(), task.id, fti.immediate_view,) else: self.immediate_view = "{0}/{1}".format( self.context.absolute_url(), task.id) else: if ITask.providedBy(self.context): redirect_to = '{0}#overview'.format(self.context.absolute_url()) else: redirect_to = '{0}#tasks'.format(self.context.absolute_url()) self.immediate_view = redirect_to
def is_subtask(obj): """ is_subtask indexer """ parent = aq_parent(aq_inner(obj)) return ITask.providedBy(parent)
def is_inside_a_task(self): parent = aq_parent(aq_inner(self)) return ITask.providedBy(parent)
def progress_to_cancelled_guard(self, c, include_agency): """Checks if: The task is generated from tasktemplate and its the main task. """ return self.context.is_from_tasktemplate and not \ ITask.providedBy(aq_parent(self.context))
def accept_forwarding_with_successor( context, predecessor_oguid, response_text, dossier=None): # the predessecor (the forwarding on the remote client) predecessor = getUtility(ITaskQuery).get_task_by_oguid(predecessor_oguid) # get the inbox cat = getToolByName(context, 'portal_catalog') inboxes = cat(portal_type="opengever.inbox.inbox") if len(inboxes) == 0: raise Unauthorized() else: inbox = inboxes[0].getObject() # transport the remote forwarding to the inbox or actual yearfolder transporter = getUtility(ITransporter) if dossier: yearfolder = _get_yearfolder(inbox, ) successor_forwarding = transporter.transport_from( yearfolder, predecessor.client_id, predecessor.physical_path) else: successor_forwarding = transporter.transport_from( inbox, predecessor.client_id, predecessor.physical_path) # Replace the issuer with the current inbox successor_forwarding.issuer = u'inbox:%s' % get_client_id() # Set the "X-CREATING-SUCCESSOR" flag for preventing the event handler # from creating additional responses per added document. successor_forwarding.REQUEST.set('X-CREATING-SUCCESSOR', True) successor_tc = ISuccessorTaskController(successor_forwarding) # copy documents and map the intids doc_transporter = getUtility(ITaskDocumentsTransporter) with CustomInitialVersionMessage( _(u'version_message_accept_forwarding', default=u'Document copied from forwarding (forwarding accepted)'), context.REQUEST): intids_mapping = doc_transporter.copy_documents_from_remote_task( predecessor, successor_forwarding) # copy the responses response_transporter = IResponseTransporter(successor_forwarding) response_transporter.get_responses(predecessor.client_id, predecessor.physical_path, intids_mapping=intids_mapping) # if a dossier is given means that a successor task must # be created in a new or a existing dossier if dossier: # we need all task field values from the forwarding fielddata = {} for fieldname in ITask.names(): value = ITask.get(fieldname).get(successor_forwarding) fielddata[fieldname] = value # lets create a new task - the successor task task = createContentInContainer( dossier, 'opengever.task.task', **fielddata) # copy documents and map the intids intids_mapping = _copy_documents_from_forwarding( successor_forwarding, task) # copy the responses response_transporter = IResponseTransporter(task) response_transporter.get_responses( get_client_id(), '/'.join(successor_forwarding.getPhysicalPath()), intids_mapping=intids_mapping) # successor successor_tc_task = ISuccessorTaskController(task) transaction.savepoint() # Close the predessecor forwarding response_text = response_text or '' request_data = {'response_text': response_text.encode('utf-8'), 'successor_oguid': successor_tc.get_oguid(), 'transition': 'forwarding-transition-accept'} response = remote_request(predecessor.client_id, '@@store_forwarding_in_yearfolder', path=predecessor.physical_path, data=request_data) if response.read().strip() != 'OK': raise Exception('Adding the response and changing the ' 'workflow state on the predecessor forwarding ' 'failed.') if dossier: # when a successor task exists, we close also the successor forwarding change_task_workflow_state( successor_forwarding, 'forwarding-transition-accept', text=response_text, successor_oguid=successor_tc_task.get_oguid()) # create the succssor relations successor_tc.set_predecessor(predecessor_oguid) if dossier: successor_tc_task.set_predecessor(successor_tc.get_oguid()) return task return successor_forwarding