Ejemplo n.º 1
0
    def append_record(self, history_type, timestamp=None, **kwargs):
        if timestamp and not isinstance(timestamp, datetime):
            raise TypeError("Invalid type for timestamp: {}".format(
                timestamp.__class__))
        if history_type not in self.record_classes:
            raise ValueError(
                'No record class registered for {}'.format(history_type))

        clazz = self.record_classes[history_type]

        history = self._get_history_for_writing()
        record = clazz(self.context, timestamp=timestamp, **kwargs)
        record.append_to(history)

        if record.needs_syncing:
            # currently we only sync from the submitted side
            # to the dossier
            path = self.context.load_model().physical_path
            request_data = {
                'data':
                advancedjson.dumps({
                    'timestamp': record.timestamp,
                    'data': record.data,
                })
            }
            dispatch_request(
                self.context.get_source_admin_unit_id(),
                '@@receive-proposal-history',
                path=path,
                data=request_data,
            )

        return record
Ejemplo n.º 2
0
    def append_record(self, history_type, timestamp=None, **kwargs):
        if timestamp and not isinstance(timestamp, datetime):
            raise TypeError("Invalid type for timestamp: {}".format(
                timestamp.__class__))
        if history_type not in self.record_classes:
            raise ValueError('No record class registered for {}'.format(
                history_type))

        clazz = self.record_classes[history_type]

        history = self._get_history_for_writing()
        record = clazz(self.context, timestamp=timestamp, **kwargs)
        record.append_to(history)

        if record.needs_syncing:
            # currently we only sync from the submitted side
            # to the dossier
            path = self.context.load_model().physical_path
            request_data = {'data': advancedjson.dumps({
                'timestamp': record.timestamp,
                'data': record.data,
            })}
            dispatch_request(
                self.context.get_source_admin_unit_id(),
                '@@receive-proposal-history',
                path=path,
                data=request_data,)

        return record
    def append_record(self, history_type, timestamp=None, **kwargs):
        if timestamp and not isinstance(timestamp, datetime):
            raise TypeError("Invalid type for timestamp: {}".format(
                timestamp.__class__))
        if history_type not in self.record_classes:
            raise ValueError(
                'No record class registered for {}'.format(history_type))

        clazz = self.record_classes[history_type]

        history = self._get_history_for_writing()
        record = clazz(self.context, timestamp=timestamp, **kwargs)
        record.append_to(history)

        if record.needs_syncing and self.context.is_submitted():
            path = self.context.get_sync_target_path()
            admin_unit_id = self.context.get_sync_admin_unit_id()

            request_data = {
                'data':
                advancedjson.dumps({
                    'timestamp': record.timestamp,
                    'data': record.data,
                })
            }
            dispatch_request(
                admin_unit_id,
                '@@receive-proposal-history',
                path=path,
                data=request_data,
            )
        return record
Ejemplo n.º 4
0
    def change_remote_tasks_workflow_state(self, transition, text, responsible="", responsible_client=""):

        tasks = self.get_tasks_to_sync(transition)
        if not tasks:
            return False

        for task in tasks:

            response = dispatch_request(
                task.admin_unit_id,
                "@@sync-task-workflow-state-receive",
                task.physical_path,
                data={
                    "transition": transition,
                    "text": text and text.encode("utf-8") or "",
                    "responsible": responsible,
                    "responsible_client": responsible_client,
                },
            )

            response_data = response.read().strip()
            if response_data != "OK":
                raise Exception(
                    "Could not change task on remote admin unit %s (%s)" % (task.admin_unit_id, task.physical_path)
                )

        return tasks
Ejemplo n.º 5
0
def accept_task_with_successor(dossier, predecessor_oguid, response_text):
    predecessor = Task.query.by_oguid(predecessor_oguid)

    # Transport the original task (predecessor) to this dossier. The new
    # response and task change is not yet done and will be done later. This
    # is necessary for beeing as transaction aware as possible.
    transporter = Transporter()
    successor = transporter.transport_from(dossier, predecessor.admin_unit_id,
                                           predecessor.physical_path)
    successor_tc = ISuccessorTaskController(successor)

    # Set the "X-CREATING-SUCCESSOR" flag for preventing the event handler
    # from creating additional responses per added document.
    successor.REQUEST.set('X-CREATING-SUCCESSOR', True)

    # copy documents and map the intids
    doc_transporter = getUtility(ITaskDocumentsTransporter)

    comment = _(u'version_message_accept_task',
                default=u'Document copied from task (task accepted)')
    intids_mapping = doc_transporter.copy_documents_from_remote_task(
        predecessor, successor, comment=comment)

    # copy the responses
    response_transporter = IResponseTransporter(successor)
    response_transporter.get_responses(predecessor.admin_unit_id,
                                       predecessor.physical_path,
                                       intids_mapping=intids_mapping)

    # Move current responsible from predecessor task to successor
    center = notification_center()
    center.add_task_responsible(successor, successor.responsible)

    # First "accept" the successor task..
    accept_task_with_response(successor, response_text)

    transaction.savepoint()
    response_text = response_text or ''
    request_data = {
        'text': response_text.encode('utf-8'),
        'successor_oguid': successor_tc.get_oguid()
    }

    response = dispatch_request(predecessor.admin_unit_id,
                                '@@accept_task_workflow_transition',
                                path=predecessor.physical_path,
                                data=request_data)

    response_body = response.read()
    if response_body.strip() != 'OK':
        raise TaskRemoteRequestError(
            'Adding the response and changing the workflow state on the '
            'predecessor task failed.')

    # Connect the predecessor and the successor task. This needs to be done
    # that late for preventing a deadlock because of the locked tasks table.
    successor_tc.set_predecessor(predecessor_oguid)

    return successor
Ejemplo n.º 6
0
def set_remote_import_stamp(context):
    """update the sync stap on every enabled client."""

    timestamp = update_sync_stamp(context)

    # fake the request, because dispatch_request expects it
    setRequest(context.REQUEST)

    for admin_unit in ogds_service().all_admin_units():
        try:
            dispatch_request(admin_unit.id(), '@@update_sync_stamp',
                             data={REQUEST_SYNC_KEY: timestamp})
            logger.info(
                "Issued remote request to update sync_stamp on %s to %s" % (
                    admin_unit.id(), timestamp))
        except URLError, e:
            logger.warn("ERROR while trying to remotely update sync_stamp"
                        "for %s: %s" % (admin_unit.id(), e))
Ejemplo n.º 7
0
def accept_task_with_successor(dossier, predecessor_oguid, response_text):
    predecessor = Task.query.by_oguid(predecessor_oguid)

    # Set the "X-CREATING-SUCCESSOR" flag for preventing the event handler
    # from creating additional responses per added document.
    getRequest().set('X-CREATING-SUCCESSOR', True)

    # Transport the original task (predecessor) to this dossier. The new
    # response and task change is not yet done and will be done later. This
    # is necessary for beeing as transaction aware as possible.
    transporter = Transporter()
    successor = transporter.transport_from(
        dossier, predecessor.admin_unit_id, predecessor.physical_path)
    successor_tc = ISuccessorTaskController(successor)

    # copy documents and map the intids
    doc_transporter = getUtility(ITaskDocumentsTransporter)

    comment = _(u'version_message_accept_task',
               default=u'Document copied from task (task accepted)')
    intids_mapping = doc_transporter.copy_documents_from_remote_task(
        predecessor, successor, comment=comment)

    # copy the responses
    response_transporter = IResponseTransporter(successor)
    response_transporter.get_responses(predecessor.admin_unit_id,
                                       predecessor.physical_path,
                                       intids_mapping=intids_mapping)

    # Move current responsible from predecessor task to successor
    center = notification_center()
    center.add_task_responsible(successor, successor.responsible)

    # First "accept" the successor task..
    accept_task_with_response(successor, response_text)

    transaction.savepoint()
    response_text = response_text or ''
    request_data = {'text': response_text.encode('utf-8'),
                    'successor_oguid': successor_tc.get_oguid()}

    response = dispatch_request(predecessor.admin_unit_id,
                                '@@accept_task_workflow_transition',
                                path=predecessor.physical_path,
                                data=request_data)

    response_body = response.read()
    if response_body.strip() != 'OK':
        raise TaskRemoteRequestError(
            'Adding the response and changing the workflow state on the '
            'predecessor task failed.')

    # Connect the predecessor and the successor task. This needs to be done
    # that late for preventing a deadlock because of the locked tasks table.
    successor_tc.set_predecessor(predecessor_oguid)

    return successor
Ejemplo n.º 8
0
def set_remote_import_stamp(context):
    """Update the sync stamp on every enabled admin unit.
    """
    timestamp = update_sync_stamp(context)

    # fake the request, because dispatch_request expects it
    setRequest(context.REQUEST)

    for admin_unit in ogds_service().all_admin_units():
        try:
            dispatch_request(admin_unit.id(),
                             '@@update_sync_stamp',
                             data={REQUEST_SYNC_KEY: timestamp})
            logger.info(
                "Issued remote request to update sync_stamp on %s to %s" %
                (admin_unit.id(), timestamp))
        except URLError, e:
            logger.warn("ERROR while trying to remotely update sync_stamp"
                        "for %s: %s" % (admin_unit.id(), e))
Ejemplo n.º 9
0
    def close_task(self, task, text):
        response = dispatch_request(
            task.admin_unit_id,
            u'@@close-task-wizard-remote_close',
            path=task.physical_path,
            data={'text': text.encode('utf-8') if text else u''})

        response_data = response.read().strip()
        if response_data != 'OK':
            raise Exception('Could not close task on remote site %s (%s)' %
                            (task.admin_unit_id, task.physical_path))
Ejemplo n.º 10
0
    def execute(self):
        model = self.submitted_proposal.load_model()
        response = dispatch_request(model.admin_unit_id,
                                    '@@reject-proposal',
                                    path=model.physical_path)

        response_body = response.read()
        if response_body != 'OK':
            raise ValueError(
                'Unexpected response {!r} when rejecting proposal.'.format(
                    response))
Ejemplo n.º 11
0
    def push_to_remote_client(self, key, admin_unit_id):
        data = self.get_data(key)

        req_data = {'data-set': json.dumps(data),
                    'key': key}
        response = dispatch_request(admin_unit_id,
                                    '@@receive-wizard-data-set',
                                    data=req_data)

        if response.read().strip() != 'OK':
            raise Exception('Could not push session data to admin_unit %s' % (
                            admin_unit_id))
Ejemplo n.º 12
0
    def execute(self):
        model = self.submitted_proposal.load_model()
        response = dispatch_request(
            model.admin_unit_id,
            '@@reject-proposal',
            path=model.physical_path)

        response_body = response.read()
        if response_body != 'OK':
            raise ValueError(
                'Unexpected response {!r} when rejecting proposal.'.format(
                    response_body))
Ejemplo n.º 13
0
    def push_to_remote_client(self, key, admin_unit_id):
        data = self.get_data(key)

        req_data = {'data-set': json.dumps(data),
                    'key': key}
        response = dispatch_request(admin_unit_id,
                                    '@@receive-wizard-data-set',
                                    data=req_data)

        response_body = response.read()
        if response_body.strip() != 'OK':
            raise Exception('Could not push session data to admin_unit %s' % (
                            admin_unit_id))
Ejemplo n.º 14
0
    def close_task(self, task, text):
        response = dispatch_request(
            task.admin_unit_id,
            u'@@close-task-wizard-remote_close',
            path=task.physical_path,
            data={'text': text.encode('utf-8') if text else u''})

        response_data = response.read().strip()
        if response_data != 'OK':
            raise Exception(
                'Could not close task on remote site %s (%s)' % (
                    task.admin_unit_id,
                    task.physical_path))
Ejemplo n.º 15
0
    def remove_scheduled(self, meeting):
        self.execute_transition('scheduled-submitted')
        IHistory(self.resolve_submitted_proposal()).append_record(
            u'remove_scheduled', meeting_id=meeting.meeting_id)

        request_data = {
            'data': advancedjson.dumps({
                'meeting_id': meeting.meeting_id,
            })
        }
        expect_ok_response(
            dispatch_request(self.admin_unit_id,
                             '@@receive-proposal-unscheduled',
                             path=self.physical_path,
                             data=request_data),
            'Unexpected response {!r} when unscheduling proposal.')
Ejemplo n.º 16
0
    def sync_deadline(self, new_deadline, text, transition):
        sct = ISuccessorTaskController(self.context)
        for successor in sct.get_successors():

            response = dispatch_request(
                successor.admin_unit_id,
                '@@remote_deadline_modifier',
                successor.physical_path,
                data={
                    'new_deadline': new_deadline.toordinal(),
                    'text': safe_utf8(text),
                    'transition': transition})

            if response.read().strip() != 'OK':
                raise Exception(
                    'Updating deadline on remote client %s. failed (%s)' % (
                        successor.admin_unit_id, response.read()))
Ejemplo n.º 17
0
    def send_responses(self, target_admin_unit_id, remote_task_url,
                       intids_mapping=None):
        """Sends all responses of task self.context to task on
        a remote admin unit.

        `target_admin_unit_id`: id of a target admin unit
        `remote_task_url`: url to a task on `target_cid` relative
        to its site root.
        `intids_mapping`: replace intids of RelationValues according
        to this mapping. This fixes the intids on remote admin unit.
        RelationValues not listed in this mapping will not be sent.

        """
        jsondata = self.extract_responses(intids_mapping)

        return dispatch_request(target_admin_unit_id,
                                '@@task-responses-receive',
                                path=remote_task_url,
                                data=dict(responses=jsondata))
Ejemplo n.º 18
0
    def send_responses(self, target_admin_unit_id, remote_task_url,
                       intids_mapping=None):
        """Sends all responses of task self.context to task on
        a remote admin unit.

        `target_admin_unit_id`: id of a target admin unit
        `remote_task_url`: url to a task on `target_cid` relative
        to its site root.
        `intids_mapping`: replace intids of RelationValues according
        to this mapping. This fixes the intids on remote admin unit.
        RelationValues not listed in this mapping will not be sent.

        """
        jsondata = self.extract_responses(intids_mapping)

        return dispatch_request(target_admin_unit_id,
                                '@@task-responses-receive',
                                path=remote_task_url,
                                data=dict(responses=jsondata))
Ejemplo n.º 19
0
    def get_responses(self, target_admin_unit_id, remote_task_path,
                      intids_mapping):
        """Retrieves all responses from the task with path `remote_task_path`
        on the admin_unit `target_admin_unit_id` and adds them to the current
        context (target task).

        Provide a an `intids_mapping` (dict), mapping the original intids of
        related objects to the new intids of the copies on this admin_unit.
        This is necessary for fixing the relations.

        """
        req_data = {'intids_mapping': json.dumps(intids_mapping)}
        response = dispatch_request(target_admin_unit_id,
                                    '@@task-responses-extract',
                                    path=remote_task_path,
                                    data=req_data)
        try:
            data = json.loads(response.read())
        except ValueError:
            # is a internal request
            data = response.read()

        self.create_responses(data)
Ejemplo n.º 20
0
    def reject(self, text):
        assert self.workflow.can_execute_transition(self, 'submitted-pending')

        self.submitted_physical_path = None
        self.submitted_admin_unit_id = None
        self.submitted_int_id = None
        self.date_of_submission = None

        # set workflow state directly for once, the transition is used to
        # redirect to a form.
        self.workflow_state = self.STATE_PENDING.name

        request_data = {
            'data': advancedjson.dumps({
                'text': text,
            })
        }
        expect_ok_response(
            dispatch_request(self.admin_unit_id,
                             '@@receive-proposal-rejected',
                             path=self.physical_path,
                             data=request_data),
            'Unexpected response {!r} when rejecting proposal.')
Ejemplo n.º 21
0
    def get_responses(self, target_admin_unit_id, remote_task_path,
                      intids_mapping):
        """Retrieves all responses from the task with path `remote_task_path`
        on the admin_unit `target_admin_unit_id` and adds them to the current
        context (target task).

        Provide a an `intids_mapping` (dict), mapping the original intids of
        related objects to the new intids of the copies on this admin_unit.
        This is necessary for fixing the relations.

        """
        req_data = {'intids_mapping': json.dumps(intids_mapping)}
        response = dispatch_request(target_admin_unit_id,
                                    '@@task-responses-extract',
                                    path=remote_task_path,
                                    data=req_data)
        try:
            data = json.loads(response.read())
        except ValueError:
            # is a internal request
            data = response.read()

        self.create_responses(data)
Ejemplo n.º 22
0
    def schedule(self, meeting):
        assert self.can_be_scheduled()

        self.execute_transition('submitted-scheduled')
        meeting.agenda_items.append(AgendaItem(proposal=self))
        meeting.reorder_agenda_items()

        submitted_proposal = self.resolve_submitted_proposal()
        ProposalScheduledActivity(submitted_proposal, getRequest(),
                                  meeting.meeting_id).record()
        IHistory(self.resolve_submitted_proposal()).append_record(
            u'scheduled', meeting_id=meeting.meeting_id)

        request_data = {
            'data': advancedjson.dumps({
                'meeting_id': meeting.meeting_id,
            })
        }
        expect_ok_response(
            dispatch_request(self.admin_unit_id,
                             '@@receive-proposal-scheduled',
                             path=self.physical_path,
                             data=request_data),
            'Unexpected response {!r} when scheduling proposal.')
Ejemplo n.º 23
0
def accept_forwarding_with_successor(
    context, predecessor_oguid, response_text, dossier=None):

    # the predessecor (the forwarding on the remote client)
    predecessor = Task.query.by_oguid(predecessor_oguid)

    # Set the "X-CREATING-SUCCESSOR" flag for preventing the event handler
    # from creating additional responses per added document.
    context.REQUEST.set('X-CREATING-SUCCESSOR', True)

    # transport the remote forwarding to the inbox or actual yearfolder
    transporter = Transporter()
    inbox = get_current_inbox(context)
    if dossier:
        yearfolder = get_current_yearfolder(inbox=inbox)
        successor_forwarding = transporter.transport_from(
            yearfolder, predecessor.admin_unit_id, predecessor.physical_path)
    else:
        successor_forwarding = transporter.transport_from(
            inbox, predecessor.admin_unit_id, predecessor.physical_path)

    # Replace the issuer with the current inbox
    successor_forwarding.issuer = get_current_org_unit().inbox().id()

    successor_tc = ISuccessorTaskController(successor_forwarding)

    # copy documents and map the intids
    doc_transporter = getUtility(ITaskDocumentsTransporter)

    comment = _(
        u'version_message_accept_forwarding',
        default=u'Document copied from forwarding (forwarding accepted)')
    intids_mapping = doc_transporter.copy_documents_from_remote_task(
        predecessor, successor_forwarding, comment=comment)

    # copy the responses
    response_transporter = IResponseTransporter(successor_forwarding)
    response_transporter.get_responses(predecessor.admin_unit_id,
                                       predecessor.physical_path,
                                       intids_mapping=intids_mapping)

    # Remove current responsible from predecessor and add issuer
    # and responsible to successor's watcher.
    center = notification_center()
    center.remove_task_responsible(Oguid.parse(predecessor_oguid),
                                   successor_forwarding.responsible)
    center.add_task_responsible(successor_forwarding,
                                successor_forwarding.responsible)
    center.add_task_issuer(successor_forwarding, successor_forwarding.issuer)

    # 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

        # 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)

        # 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_current_admin_unit().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 = dispatch_request(predecessor.admin_unit_id,
                                '@@store_forwarding_in_yearfolder',
                                path=predecessor.physical_path,
                                data=request_data)

    response_body = response.read()
    if response_body.strip() != 'OK':
        raise TaskRemoteRequestError(
            'Adding the response and changing the workflow state on the '
            'predecessor forwarding failed.')

    if dossier:
        # Update watchers for created successor forwarding and task
        center = notification_center()
        center.remove_task_responsible(successor_forwarding, task.responsible)
        center.add_task_responsible(task, task.responsible)

        # 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
Ejemplo n.º 24
0
    def deliver_documents_and_complete_task(self, formdata, response):
        """Delivers the selected documents to the predecesser task and
        complete the task:

        - Copy the documents to the predecessor task (no new responses)
        - Execute workflow transition (no new response)
        - Add a new response indicating the workflow transition, the added
        documents and containing the entered response text.
        """

        # add documents to the response
        response.added_object = PersistentList()

        predecessor = Task.query.by_oguid(self.context.predecessor)

        transporter = Transporter()
        intids = getUtility(IIntIds)

        data = {'documents': [],
                'text': formdata['text'],
                'transition': formdata['transition']}

        related_ids = []
        if getattr(self.context, 'relatedItems'):
            related_ids = [item.to_id for item in self.context.relatedItems]

        for doc_intid in formdata['documents']:
            doc = intids.getObject(int(doc_intid))
            data['documents'].append(transporter.extract(doc))

            # add a releation when a document from the dossier was selected
            if int(doc_intid) not in related_ids:
                # check if its a relation
                if aq_parent(aq_inner(doc)) != self.context:
                    # add relation to doc on task
                    if self.context.relatedItems:
                        self.context.relatedItems.append(
                            RelationValue(int(doc_intid)))
                    else:
                        self.context.relatedItems = [
                            RelationValue(int(doc_intid))]

                    # add response change entry for this relation
                    if not response.relatedItems:
                        response.relatedItems = [RelationValue(int(doc_intid))]
                    else:
                        response.relatedItems.append(
                            RelationValue(int(doc_intid)))

                    # set relation flag
                    doc._v__is_relation = True
                    response.add_change('relatedItems',
                        _(u'label_related_items', default=u"Related Items"),
                        '',
                        linked(doc, doc.Title()))

                else:
                    # add entry to the response for this document
                    response.added_object.append(RelationValue(int(doc_intid)))
            else:
                # append only the relation on the response
                doc._v__is_relation = True
                response.add_change('relatedItems',
                    _(u'label_related_items', default=u"Related Items"),
                    '',
                    linked(doc, doc.Title()))

        request_data = {'data': json.dumps(data)}
        response = dispatch_request(
            predecessor.admin_unit_id,
            '@@complete_successor_task-receive_delivery',
            predecessor.physical_path,
            data=request_data)

        if response.read().strip() != 'OK':
            raise Exception('Delivering documents and updating task failed '
                            'on remote client %s.' % predecessor.admin_unit_id)
Ejemplo n.º 25
0
def accept_forwarding_with_successor(context,
                                     predecessor_oguid,
                                     response_text,
                                     dossier=None):

    # the predessecor (the forwarding on the remote client)
    predecessor = Task.query.by_oguid(predecessor_oguid)

    # transport the remote forwarding to the inbox or actual yearfolder
    transporter = Transporter()
    inbox = get_current_inbox(context)
    if dossier:
        yearfolder = get_current_yearfolder(inbox=inbox)
        successor_forwarding = transporter.transport_from(
            yearfolder, predecessor.admin_unit_id, predecessor.physical_path)
    else:
        successor_forwarding = transporter.transport_from(
            inbox, predecessor.admin_unit_id, predecessor.physical_path)

    # Replace the issuer with the current inbox
    successor_forwarding.issuer = get_current_org_unit().inbox().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)

    comment = _(
        u'version_message_accept_forwarding',
        default=u'Document copied from forwarding (forwarding accepted)')
    intids_mapping = doc_transporter.copy_documents_from_remote_task(
        predecessor, successor_forwarding, comment=comment)

    # copy the responses
    response_transporter = IResponseTransporter(successor_forwarding)
    response_transporter.get_responses(predecessor.admin_unit_id,
                                       predecessor.physical_path,
                                       intids_mapping=intids_mapping)

    # Remove current responsible from predecessor and add issuer
    # and responsible to successor's watcher.
    center = notification_center()
    center.remove_task_responsible(Oguid.parse(predecessor_oguid),
                                   successor_forwarding.responsible)
    center.add_task_responsible(successor_forwarding,
                                successor_forwarding.responsible)
    center.add_task_issuer(successor_forwarding, successor_forwarding.issuer)

    # 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

        # 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)

        # 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_current_admin_unit().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 = dispatch_request(predecessor.admin_unit_id,
                                '@@store_forwarding_in_yearfolder',
                                path=predecessor.physical_path,
                                data=request_data)

    response_body = response.read()
    if response_body.strip() != 'OK':
        raise TaskRemoteRequestError(
            'Adding the response and changing the workflow state on the '
            'predecessor forwarding failed.')

    if dossier:
        # Update watchers for created successor forwarding and task
        center = notification_center()
        center.remove_task_responsible(successor_forwarding, task.responsible)
        center.add_task_responsible(task, task.responsible)

        # 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
Ejemplo n.º 26
0
    def deliver_documents_and_complete_task(self, formdata, response):
        """Delivers the selected documents to the predecesser task and
        complete the task:

        - Copy the documents to the predecessor task (no new responses)
        - Execute workflow transition (no new response)
        - Add a new response indicating the workflow transition, the added
        documents and containing the entered response text.
        """

        predecessor = Task.query.by_oguid(self.context.predecessor)

        transporter = Transporter()
        intids = getUtility(IIntIds)

        data = {
            'documents': [],
            'text': formdata['text'],
            'transition': formdata['transition']
        }

        related_ids = []
        if getattr(self.context, 'relatedItems'):
            related_ids = [item.to_id for item in self.context.relatedItems]

        for doc_intid in formdata['documents']:
            doc = intids.getObject(int(doc_intid))
            data['documents'].append(transporter.extract(doc))

            # add a releation when a document from the dossier was selected
            if int(doc_intid) not in related_ids:
                # check if its a relation
                if aq_parent(aq_inner(doc)) != self.context:
                    # add relation to doc on task
                    if self.context.relatedItems:
                        self.context.relatedItems.append(
                            RelationValue(int(doc_intid)))
                    else:
                        self.context.relatedItems = [
                            RelationValue(int(doc_intid))
                        ]

                    # add response change entry for this relation
                    response.add_related_item(RelationValue(int(doc_intid)))

                    # set relation flag
                    doc._v__is_relation = True
                    response.add_change(
                        'relatedItems', '', linked(doc, doc.Title()),
                        _(u'label_related_items', default=u"Related Items"))

                else:
                    # add entry to the response for this document
                    response.added_objects.append(RelationValue(
                        int(doc_intid)))
            else:
                # append only the relation on the response
                doc._v__is_relation = True
                response.add_change(
                    'relatedItems', '', linked(doc, doc.Title()),
                    _(u'label_related_items', default=u"Related Items"))

        request_data = {'data': json.dumps(data)}
        response = dispatch_request(
            predecessor.admin_unit_id,
            '@@complete_successor_task-receive_delivery',
            predecessor.physical_path,
            data=request_data)

        response_body = response.read()
        if response_body.strip() != 'OK':
            raise Exception('Delivering documents and updating task failed '
                            'on remote client %s.' % predecessor.admin_unit_id)
Ejemplo n.º 27
0
 def _dispatch_request(self, target_admin_unit_id, viewname, path, data):
     return dispatch_request(target_admin_unit_id, viewname, path, data)