Exemplo n.º 1
0
    def test_listing(self):
        self.login(self.records_manager)

        with freeze(datetime(2016, 11, 1, 11, 0)):
            storage = IHistoryStorage(self.disposition)
            storage.add('edited', api.user.get_current().getId(), [])

        with freeze(datetime(2016, 11, 6, 12, 33)), elevated_privileges():
            api.content.transition(self.disposition,
                                   'disposition-transition-appraise')
            api.content.transition(self.disposition,
                                   'disposition-transition-dispose')

        with freeze(datetime(2016, 11, 16, 8, 12)), elevated_privileges():
            api.content.transition(self.disposition,
                                   'disposition-transition-archive')

        rows = self.get_listing_rows(self.disposition,
                                     'disposition_history',
                                     self.disposition.get_history())

        expected_rows = [
            ['Nov 16, 2016 08:12 AM', 'Flucht Ramon (ramon.flucht)', 'disposition-transition-archive'],
            ['Nov 06, 2016 12:33 PM', 'Flucht Ramon (ramon.flucht)', 'disposition-transition-dispose'],
            ['Nov 06, 2016 12:33 PM', 'Flucht Ramon (ramon.flucht)', 'disposition-transition-appraise'],
            ['Nov 01, 2016 11:00 AM', 'Flucht Ramon (ramon.flucht)', 'Disposition edited'],
            ['Aug 31, 2016 07:07 PM', 'Flucht Ramon (ramon.flucht)', 'Disposition added']]

        for row, expected_row in zip(rows, expected_rows):
            self.assert_row_values(expected_row, row)
Exemplo n.º 2
0
    def test_listing(self):
        self.login(self.records_manager)

        with freeze(datetime(2016, 11, 1, 11, 0)):
            storage = IHistoryStorage(self.disposition)
            storage.add('edited', api.user.get_current().getId(), [])

        with freeze(datetime(2016, 11, 6, 12, 33)), elevated_privileges():
            api.content.transition(self.disposition,
                                   'disposition-transition-appraise')
            api.content.transition(self.disposition,
                                   'disposition-transition-dispose')

        with freeze(datetime(2016, 11, 16, 8, 12)), elevated_privileges():
            api.content.transition(self.disposition,
                                   'disposition-transition-archive')

        rows = self.get_listing_rows(self.disposition,
                                     'disposition_history',
                                     self.disposition.get_history())

        expected_rows = [
            ['Nov 16, 2016 08:12 AM', 'Flucht Ramon (ramon.flucht)', 'disposition-transition-archive'],
            ['Nov 06, 2016 12:33 PM', 'Flucht Ramon (ramon.flucht)', 'disposition-transition-dispose'],
            ['Nov 06, 2016 12:33 PM', 'Flucht Ramon (ramon.flucht)', 'disposition-transition-appraise'],
            ['Nov 01, 2016 11:00 AM', 'Flucht Ramon (ramon.flucht)', 'Disposition edited'],
            ['Aug 31, 2016 07:05 PM', 'Flucht Ramon (ramon.flucht)', 'Disposition added']]

        for row, expected_row in zip(rows, expected_rows):
            self.assert_row_values(expected_row, row)
Exemplo n.º 3
0
    def create_journal_pdf(self):
        """Creates a pdf representation of the dossier journal, and add it to
        the dossier as a normal document.

        If the dossiers has an end date use that date as the document date.
        This prevents the dossier from entering an invalid state with a
        document date outside the dossiers start-end range.
        """
        if not self.get_property('journal_pdf_enabled'):
            return

        view = self.context.unrestrictedTraverse('pdf-dossier-journal')
        today = api.portal.get_localized_time(
            datetime=datetime.today(), long_format=True)
        filename = u'Journal {}.pdf'.format(today)
        title = _(u'title_dossier_journal',
                  default=u'Journal of dossier ${title}, ${timestamp}',
                  mapping={'title': self.context.title,
                           'timestamp': today})
        kwargs = {
            'preserved_as_paper': False,
        }
        dossier = IDossier(self.context)
        if dossier and dossier.end:
            kwargs['document_date'] = dossier.end

        with elevated_privileges():
            CreateDocumentCommand(
                self.context, filename, view.get_data(),
                title=translate(title, context=self.context.REQUEST),
                content_type='application/pdf',
                **kwargs).execute()
    def __call__(self):
        jsondata = self.request.get(REQUEST_KEY)
        data = encode_after_json(json.loads(jsondata))
        committee = Oguid.parse(data['committee_oguid']).resolve_object()
        proposal_oguid = Oguid.parse(data['proposal_oguid'])
        proposal = meeting_service().fetch_proposal_by_oguid(proposal_oguid)

        with elevated_privileges():
            submitted_proposal = SubmittedProposal.create(proposal, committee)

            # XXX use Transporter API?
            collector = getMultiAdapter((submitted_proposal, ),
                                        IDataCollector,
                                        name='field-data')
            data['field-data']['ISubmittedProposal'] = data['field-data'].pop(
                'IProposal')
            collector.insert(data['field-data'])
            # XXX fix data types in transporter
            submitted_proposal.date_of_submission = date.today()

            # sync data to proposal after inserting field data
            submitted_proposal.sync_model(proposal_model=proposal)

            submitted_proposal.create_proposal_document(
                filename=data['file']['filename'],
                content_type=data['file']['contentType'].encode('utf-8'),
                data=base64.decodestring(data['file']['data']))

            history_data = advancedjson.loads(self.request.get('history_data'))
            IHistory(submitted_proposal).append_record(
                u'submitted', uuid=history_data['uuid'])

            self.request.response.setHeader("Content-type", "application/json")
            return json.dumps(
                {'path': '/'.join(submitted_proposal.getPhysicalPath())})
    def __call__(self):
        jsondata = self.request.get(REQUEST_KEY)
        data = encode_after_json(json.loads(jsondata))
        committee = Oguid.parse(data['committee_oguid']).resolve_object()
        proposal_oguid = Oguid.parse(data['proposal_oguid'])
        proposal = meeting_service().fetch_proposal_by_oguid(proposal_oguid)

        with elevated_privileges():
            submitted_proposal = SubmittedProposal.create(proposal, committee)

            # XXX use Transporter API?
            collector = getMultiAdapter((submitted_proposal,), IDataCollector,
                                        name='field-data')
            data['field-data']['ISubmittedProposal'] = data['field-data'].pop(
                'IProposal')
            collector.insert(data['field-data'])
            # XXX fix data types in transporter
            submitted_proposal.date_of_submission = date.today()

            # sync data to proposal after inserting field data
            submitted_proposal.sync_model(proposal_model=proposal)

            submitted_proposal.create_proposal_document(
                filename=data['file']['filename'],
                content_type=data['file']['contentType'].encode('utf-8'),
                data=base64.decodestring(data['file']['data']))

            history_data = advancedjson.loads(self.request.get('history_data'))
            IHistory(submitted_proposal).append_record(
                u'submitted', uuid=history_data['uuid'])

            self.request.response.setHeader("Content-type", "application/json")
            return json.dumps(
                {'path': '/'.join(submitted_proposal.getPhysicalPath())})
Exemplo n.º 6
0
 def setUp(self):
     super(TestClosedDispositionOverview, self).setUp()
     with elevated_privileges():
         api.content.transition(obj=self.disposition, transition='disposition-transition-appraise')
         api.content.transition(obj=self.disposition, transition='disposition-transition-dispose')
         api.content.transition(obj=self.disposition, transition='disposition-transition-archive')
         api.content.transition(obj=self.disposition, transition='disposition-transition-close')
Exemplo n.º 7
0
    def reply(self):

        userid = self.request.form.get('userid')
        if not userid:
            return self.error(message='Missing userid.')

        file_ = self.request.form.get('file')
        if not file_:
            return self.error(message='Missing file.')

        # Disable CSRF protection
        if 'IDisableCSRFProtection' in dir(plone.protect.interfaces):
            alsoProvides(self.request,
                         plone.protect.interfaces.IDisableCSRFProtection)

        try:
            adopt_user = api.env.adopt_user(username=userid)
        except api.exc.UserNotFoundError:
            return self.error(status=404, message='Unknown user.')

        with adopt_user:
            destination = self.destination()
            if destination:
                # XXX - Duck typing as error handling
                # We've encountered an error while discovering a destination
                if isinstance(destination, dict):
                    return destination
                filename = file_.filename.decode('utf8')
                command = CreateDocumentCommand(destination, filename, file_)
                with elevated_privileges():
                    command.execute()

        self.request.response.setStatus(201)
        return super(ScanIn, self).reply()
Exemplo n.º 8
0
    def render(self):
        if not self.context.is_submitted_document():
            raise NoSubmittedDocument()

        if self.context.is_checked_out():
            raise Unauthorized()

        with elevated_privileges():
            transporter = Transporter()
            transporter.update(self.context, self.request)

            portal_path = '/'.join(api.portal.get().getPhysicalPath())
            intids = getUtility(IIntIds)
            repository = api.portal.get_tool('portal_repository')
            comment = translate(_(
                u"Updated with a newer docment version from proposal's "
                "dossier."),
                                context=self.request)
            repository.save(obj=self.context, comment=comment)

            data = {
                'path':
                '/'.join(self.context.getPhysicalPath())[len(portal_path) +
                                                         1:],
                'intid':
                intids.queryId(self.context)
            }

        # Set correct content type for JSON response
        self.request.response.setHeader("Content-type", "application/json")
        return json.dumps(data)
Exemplo n.º 9
0
    def reject(self, text):
        RejectProposalCommand(self).execute()
        proposal = self.load_model()
        proposal.reject(text)

        with elevated_privileges():
            api.content.delete(self)
Exemplo n.º 10
0
    def reply(self):

        userid = self.request.form.get('userid')
        if not userid:
            return self.error(message='Missing userid.')

        file_ = self.request.form.get('file')
        if not file_:
            return self.error(message='Missing file.')

        # Disable CSRF protection
        if 'IDisableCSRFProtection' in dir(plone.protect.interfaces):
            alsoProvides(self.request,
                         plone.protect.interfaces.IDisableCSRFProtection)

        try:
            adopt_user = api.env.adopt_user(username=userid)
        except api.exc.UserNotFoundError:
            return self.error(status=404, message='Unknown user.')

        with adopt_user:
            destination = self.destination()
            if destination:
                # XXX - Duck typing as error handling
                # We've encountered an error while discovering a destination
                if isinstance(destination, dict):
                    return destination
                filename = file_.filename.decode('utf8')
                command = CreateDocumentCommand(destination, filename, file_)
                with elevated_privileges():
                    command.execute()

        self.request.response.setStatus(201)
        return super(ScanIn, self).reply()
Exemplo n.º 11
0
    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)
Exemplo n.º 12
0
    def test_oggbundle_transmogrifier(self):
        # this is a bit hackish, but since builders currently don't work in
        # layer setup/teardown and isolation of database content is ensured
        # on a per test level we abuse just one test to setup the pipeline and
        # test its data.

        # load pipeline
        # XXX move this to a layer
        self.grant("Manager")

        transmogrifier = Transmogrifier(api.portal.get())
        IAnnotations(transmogrifier)[BUNDLE_PATH_KEY] = resource_filename(
            'opengever.bundle.tests',
            'assets/business_rule_violations.oggbundle')

        # We need to add documents to dossiers that have already been created
        # in the 'closed' state, which isn't allowed for anyone except users
        # inheriting from `UnrestrictedUser` -> we need elevated privileges
        with freeze(FROZEN_NOW), elevated_privileges():
            transmogrifier(u'opengever.bundle.oggbundle')

        # test content creation
        # XXX use separate test-cases based on a layer
        root = self.assert_repo_root_created()
        self.assert_deeply_nested_repo_folder_created(root)

        folder = root.restrictedTraverse(
            'ordnungsposition-1/ordnungsposition-1.1')
        self.assert_deeply_nested_subdossier_created(folder)
        self.assert_resolved_dossier_with_violations_created(folder)
    def test_oggbundle_transmogrifier(self):
        # this is a bit hackish, but since builders currently don't work in
        # layer setup/teardown and isolation of database content is ensured
        # on a per test level we abuse just one test to setup the pipeline and
        # test its data.

        # Create the 'bundle_guid' index. In production, this will be done
        # by the "bin/instance import" command in opengever.bundle.console
        add_guid_index()

        # load pipeline
        # XXX move this to a layer
        self.grant("Manager")

        transmogrifier = Transmogrifier(api.portal.get())
        IAnnotations(transmogrifier)[BUNDLE_PATH_KEY] = resource_filename(
            'opengever.bundle.tests',
            'assets/business_rule_violations.oggbundle')

        # We need to add documents to dossiers that have already been created
        # in the 'closed' state, which isn't allowed for anyone except users
        # inheriting from `UnrestrictedUser` -> we need elevated privileges
        with freeze(FROZEN_NOW), elevated_privileges():
            transmogrifier(u'opengever.bundle.oggbundle')

        # test content creation
        # XXX use separate test-cases based on a layer
        root = self.assert_repo_root_created()
        self.assert_deeply_nested_repo_folder_created(root)

        folder = root.restrictedTraverse(
            'ordnungsposition-1/ordnungsposition-1.1')
        self.assert_deeply_nested_subdossier_created(folder)
        self.assert_resolved_dossier_with_violations_created(folder)
        self.assert_disallowed_subobject_type_not_created(root)
Exemplo n.º 14
0
    def create_journal_pdf(self):
        """Creates a pdf representation of the dossier journal, and add it to
        the dossier as a normal document.
        """
        if not self.get_property('journal_pdf_enabled'):
            return

        view = self.context.unrestrictedTraverse('pdf-dossier-journal')
        today = api.portal.get_localized_time(datetime=datetime.today(),
                                              long_format=True)
        filename = u'Journal {}.pdf'.format(today)
        title = _(u'title_dossier_journal',
                  default=u'Journal of dossier ${title}, ${timestamp}',
                  mapping={
                      'title': self.context.title,
                      'timestamp': today
                  })

        with elevated_privileges():
            CreateDocumentCommand(self.context,
                                  filename,
                                  view.get_data(),
                                  title=translate(
                                      title, context=self.context.REQUEST),
                                  content_type='application/pdf',
                                  preserved_as_paper=False).execute()
Exemplo n.º 15
0
    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)
Exemplo n.º 16
0
    def render(self):
        if not self.context.is_submitted_document():
            raise NoSubmittedDocument()

        if self.context.is_checked_out():
            raise Unauthorized()

        with elevated_privileges():
            transporter = Transporter()
            transporter.update(self.context, self.request)

            portal_path = '/'.join(api.portal.get().getPhysicalPath())
            intids = getUtility(IIntIds)
            repository = api.portal.get_tool('portal_repository')
            comment = translate(
                _(u"Updated with a newer docment version from proposal's "
                    "dossier."),
                context=self.request)
            repository.save(obj=self.context, comment=comment)

            data = {
                'path': '/'.join(self.context.getPhysicalPath())[
                    len(portal_path) + 1:],
                'intid': intids.queryId(self.context)
                }

        # Set correct content type for JSON response
        self.request.response.setHeader("Content-type", "application/json")
        return json.dumps(data)
Exemplo n.º 17
0
    def create_proposal_document(self, source_blob=None, **kwargs):
        """Creates a proposal document within this proposal or submitted
        proposal.
        Only one proposal document can be created.
        """
        if not is_word_meeting_implementation_enabled():
            raise WordMeetingImplementationDisabledError()

        if self.get_proposal_document():
            raise ValueError('There is already a proposal document.')

        if source_blob:
            kwargs.setdefault('filename', source_blob.filename)
            kwargs.setdefault('data', source_blob.open().read())
            kwargs.setdefault('content_type', source_blob.contentType)

        kwargs['context'] = self
        kwargs.setdefault('preserved_as_paper', False)

        title = _(u'proposal_document_title',
                  default=u'Proposal document ${title}',
                  mapping={'title': safe_unicode(self.Title())})
        title = translate(title, context=self.REQUEST).strip()
        kwargs.setdefault('title', title)

        with elevated_privileges():
            obj = CreateDocumentCommand(**kwargs).execute()

        self._proposal_document_uuid = IUUID(obj)
        return obj
Exemplo n.º 18
0
    def test_remove_excerpt_for_agendaitem_removes_relation_in_submitted_proposal(
            self, browser):
        self.login(self.committee_responsible, browser)
        agenda_item = self.schedule_proposal(self.meeting,
                                             self.submitted_proposal)
        agenda_item.decide()
        excerpt1 = agenda_item.generate_excerpt('excerpt 1')
        agenda_item.generate_excerpt('excerpt 2')

        self.assertEqual(2, len(self.submitted_proposal.excerpts))
        self.assertEqual(
            2, len(self.submitted_proposal.get_excerpts(include_trashed=True)))
        self.assertEqual(
            2, len(agenda_item.get_excerpt_documents(include_trashed=True)))
        self.assertEqual(2, len(list(_relations(self.submitted_proposal))))

        ITrashable(excerpt1).trash()
        with elevated_privileges():
            Remover([excerpt1]).remove()

        self.assertEqual(1, len(self.submitted_proposal.excerpts))
        self.assertEqual(
            1, len(self.submitted_proposal.get_excerpts(include_trashed=True)))
        self.assertEqual(
            1, len(agenda_item.get_excerpt_documents(include_trashed=True)))
        self.assertEqual(1, len(list(_relations(self.submitted_proposal))))
    def test_oggbundle_transmogrifier(self):
        # this is a bit hackish, but since builders currently don't work in
        # layer setup/teardown and isolation of database content is ensured
        # on a per test level we abuse just one test to setup the pipeline and
        # test its data.

        # load pipeline
        # XXX move this to a layer
        self.grant("Manager")

        transmogrifier = Transmogrifier(api.portal.get())
        annotations = IAnnotations(transmogrifier)
        annotations[BUNDLE_PATH_KEY] = resource_filename(
            'opengever.bundle.tests', 'assets/basic.oggbundle')

        unc_share_asset_directory = resource_filename(
            'opengever.bundle.tests', 'assets/files_outside_bundle')
        annotations[BUNDLE_INGESTION_SETTINGS_KEY] = {
            'unc_mounts': {u'\\\\host\\mount': unc_share_asset_directory},
        }
        # We need to add documents to dossiers that have already been created
        # in the 'closed' state, which isn't allowed for anyone except users
        # inheriting from `UnrestrictedUser` -> we need elevated privileges
        with freeze(FROZEN_NOW), elevated_privileges():
            transmogrifier(u'opengever.bundle.oggbundle')

        bundle = annotations[BUNDLE_KEY]

        # test content creation
        # XXX use separate test-cases based on a layer
        root = self.assert_repo_root_created()
        folder_staff = self.assert_repo_folders_created(root)
        dossier_peter = self.assert_dossiers_created(folder_staff)
        self.assert_documents_created(dossier_peter)
        self.assert_report_data_collected(bundle)
Exemplo n.º 20
0
    def check_preconditions(self):
        errors = []
        if not self.context.is_all_checked_in():
            errors.append(NOT_ALL_CHECKED_IN)

        if self.context.has_active_proposals():
            errors.append(CONTAINS_ACTIVE_PROPOSAL)

        # Check for subdossiers the user cannot deactivate
        for subdossier in self.context.get_subdossiers(unrestricted=True):
            with elevated_privileges():
                subdossier = subdossier.getObject()

            wftool = api.portal.get_tool('portal_workflow')
            user_can_deactivate = any(
                transition['name'] == 'dossier-transition-deactivate'
                for transition in wftool.getTransitionsFor(subdossier)
            )
            state = api.content.get_state(subdossier)

            # A subdossier already being inactive is not a blocker
            if not user_can_deactivate and state != 'dossier-state-inactive':
                if api.user.has_permission('View', obj=subdossier):
                    subdossier_title = subdossier.title_or_id()
                    # We cannot deactivate if some of the subdossiers are already resolved
                    if state == 'dossier-state-resolved':
                        msg = _(
                            u"The Dossier can't be deactivated, the subdossier ${dossier} is already resolved.",
                            mapping=dict(dossier=subdossier_title),
                        )
                    else:
                        # The deactvation of this subdossier is most likely not allowed by role
                        msg = _(
                            u"The Dossier ${dossier} can't be deactivated by the user.",
                            mapping=dict(dossier=subdossier_title),
                        )
                # Inform the user which of the parents contains the blocking subdossier they cannot see
                else:
                    # We are guaranteed to hit a dossier the user can view
                    # Grab the title of the first parent we do have access to
                    # Default to an empty string
                    parent_title = ''
                    parent = subdossier.get_parent_dossier()
                    while parent:
                        if api.user.has_permission('View', obj=parent):
                            parent_title = parent.title_or_id()
                            break
                        parent = subdossier.get_parent_dossier()

                    msg = _(
                        u"The Dossier ${dossier} contains a subdossier which can't be deactivated by the user.",
                        mapping=dict(dossier=parent_title),
                    )
                errors.append(msg)

        if self.context.has_active_tasks():
            errors.append(CONTAINS_ACTIVE_TASK)

        return errors
Exemplo n.º 21
0
def delete_copied_proposal(obj, event):
    """Prevent that proposals are copied.

    Turns out the easiest way to accomplish this is to delete the proposal
    after it has been copied.
    """
    with elevated_privileges():
        api.content.delete(obj)
Exemplo n.º 22
0
def delete_copied_proposal(obj, event):
    """Prevent that proposals are copied.

    Turns out the easiest way to accomplish this is to delete the proposal
    after it has been copied.
    """
    with elevated_privileges():
        api.content.delete(obj)
Exemplo n.º 23
0
    def check_preconditions(self):
        errors = []
        if not self.context.is_all_checked_in():
            errors.append(NOT_ALL_CHECKED_IN)

        if self.context.has_active_proposals():
            errors.append(CONTAINS_ACTIVE_PROPOSAL)

        # Check for subdossiers the user cannot deactivate
        for subdossier in self.context.get_subdossiers(unrestricted=True):
            with elevated_privileges():
                subdossier = subdossier.getObject()

            wftool = api.portal.get_tool('portal_workflow')
            user_can_deactivate = any(
                transition['name'] == 'dossier-transition-deactivate'
                for transition in wftool.getTransitionsFor(subdossier))
            state = api.content.get_state(subdossier)

            # A subdossier already being inactive is not a blocker
            if not user_can_deactivate and state != 'dossier-state-inactive':
                if api.user.has_permission('View', obj=subdossier):
                    subdossier_title = subdossier.title_or_id()
                    # We cannot deactivate if some of the subdossiers are already resolved
                    if state == 'dossier-state-resolved':
                        msg = _(
                            u"The Dossier can't be deactivated, the subdossier ${dossier} is already resolved.",
                            mapping=dict(dossier=subdossier_title),
                        )
                    else:
                        # The deactvation of this subdossier is most likely not allowed by role
                        msg = _(
                            u"The Dossier ${dossier} can't be deactivated by the user.",
                            mapping=dict(dossier=subdossier_title),
                        )
                # Inform the user which of the parents contains the blocking subdossier they cannot see
                else:
                    # We are guaranteed to hit a dossier the user can view
                    # Grab the title of the first parent we do have access to
                    # Default to an empty string
                    parent_title = ''
                    parent = subdossier.get_parent_dossier()
                    while parent:
                        if api.user.has_permission('View', obj=parent):
                            parent_title = parent.title_or_id()
                            break
                        parent = subdossier.get_parent_dossier()

                    msg = _(
                        u"The Dossier ${dossier} contains a subdossier which can't be deactivated by the user.",
                        mapping=dict(dossier=parent_title),
                    )
                errors.append(msg)

        if self.context.has_active_tasks():
            errors.append(CONTAINS_ACTIVE_TASK)

        return errors
Exemplo n.º 24
0
    def reject(self, text):
        """Reject the submitted proposal."""

        RejectProposalCommand(self).execute()
        proposal = self.load_model()
        proposal.reject(text)

        with elevated_privileges():
            api.content.delete(self)
Exemplo n.º 25
0
 def close_disposition(self):
     with elevated_privileges():
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-appraise')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-dispose')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-archive')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-close')
    def store_in_yearfolder(self):
        """Move the forwarding (adapted context) in the actual yearfolder."""

        inbox = aq_parent(aq_inner(self.context))
        yearfolder = get_current_yearfolder(inbox=inbox)

        self.context.REQUEST.set(DISABLE_DOCPROPERTY_UPDATE_FLAG, True)

        with elevated_privileges():
            clipboard = inbox.manage_cutObjects((self.context.getId(),))
            yearfolder.manage_pasteObjects(clipboard)
Exemplo n.º 27
0
    def test_elevated_privileges_sets_priviledged_user_and_restores_old(self):
        self.assertEqual(TEST_USER_ID, api.user.get_current().getId())
        self.assertNotIn('manage', api.user.get_current().getRoles())

        with elevated_privileges():
            current_user = api.user.get_current()
            self.assertEqual(TEST_USER_ID, current_user.getId())
            self.assertIn('manage', current_user.getRoles())

        self.assertNotIn('manage', api.user.get_current().getRoles())
        self.assertEqual(TEST_USER_ID, current_user.getId())
Exemplo n.º 28
0
    def destroy_dossiers(self):
        if not self.dossiers:
            return

        alsoProvides(getRequest(), IDuringDossierDestruction)

        dossiers = [relation.to_object for relation in self.dossiers]
        self.set_destroyed_dossiers(dossiers)
        self.check_destroy_permission(dossiers)
        with elevated_privileges():
            api.content.delete(objects=dossiers)
Exemplo n.º 29
0
    def destroy_dossiers(self):
        if not self.dossiers:
            return

        alsoProvides(getRequest(), IDuringDossierDestruction)

        dossiers = [relation.to_object for relation in self.dossiers]
        self.set_destroyed_dossiers(dossiers)
        self.check_destroy_permission(dossiers)
        with elevated_privileges():
            api.content.delete(objects=dossiers)
Exemplo n.º 30
0
 def close_disposition(self):
     with elevated_privileges():
         api.content.transition(
             obj=self.disposition,
             transition='disposition-transition-appraise')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-dispose')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-archive')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-close')
Exemplo n.º 31
0
    def test_dispositon_in_disposed_state_can_be_refused_by_an_archivist(self):

        with elevated_privileges():
            api.content.transition(self.disposition,
                                   to_state='disposition-state-disposed')

        self.login(self.archivist)
        api.content.transition(self.disposition,
                               'disposition-transition-refuse')
        self.assertEquals('disposition-state-in-progress',
                          api.content.get_state(self.disposition))
Exemplo n.º 32
0
    def test_elevated_privileges_sets_priviledged_user_and_restores_old(self):
        self.assertEqual(TEST_USER_ID, api.user.get_current().getId())
        self.assertNotIn('manage', api.user.get_current().getRoles())

        with elevated_privileges():
            current_user = api.user.get_current()
            self.assertEqual(TEST_USER_ID, current_user.getId())
            self.assertIn('manage', current_user.getRoles())

        self.assertNotIn('manage', api.user.get_current().getRoles())
        self.assertEqual(TEST_USER_ID, current_user.getId())
    def receive(self):
        with elevated_privileges():
            with as_internal_workflow_transition():
                api.content.transition(
                    obj=self.context, transition='proposal-transition-decide')
            IHistory(self.context).append_record(u'decided')
            ProposalDecideActivity(self.context, self.request).record()

        document = super(ReceiveProposalDecided, self).receive()
        ILockable(document).lock(MEETING_EXCERPT_LOCK)
        return document
Exemplo n.º 34
0
    def create_tasks_listing_pdf(self):
        """Creates a pdf representation of the dossier tasks, and add it to
        the dossier as a normal document.

        If the dossiers has an end date use that date as the document date.
        This prevents the dossier from entering an invalid state with a
        document date outside the dossiers start-end range.
        """
        if not self.get_property('tasks_pdf_enabled'):
            return

        view = self.context.unrestrictedTraverse('pdf-dossier-tasks')

        today = api.portal.get_localized_time(datetime=datetime.today(),
                                              long_format=True)
        filename = u'Tasks {}.pdf'.format(today)
        title = _(u'title_dossier_tasks',
                  default=u'Task list of dossier ${title}, ${timestamp}',
                  mapping={
                      'title': self.context.title,
                      'timestamp': today
                  })
        kwargs = {
            'preserved_as_paper': False,
        }
        dossier = IDossier(self.context)
        if dossier and dossier.end:
            kwargs['document_date'] = dossier.end

        results = api.content.find(object_provides=IDossierTasksPDFMarker,
                                   depth=1,
                                   context=self.context)

        with elevated_privileges():
            if len(results) > 0:
                document = results[0].getObject()
                document.title = translate(title, context=self.context.REQUEST)
                comment = _(
                    u'Updated with a newer generated version from dossier ${title}.',
                    mapping=dict(title=self.context.title))
                document.update_file(view.get_data(),
                                     create_version=True,
                                     comment=comment)
                return

            document = CreateDocumentCommand(
                self.context,
                filename,
                view.get_data(),
                title=translate(title, context=self.context.REQUEST),
                content_type='application/pdf',
                interfaces=[IDossierTasksPDFMarker],
                **kwargs).execute()
            document.reindexObject(idxs=['object_provides'])
Exemplo n.º 35
0
    def test_elevated_privileges_allows_custom_user_id(self):
        self.login(self.regular_user)

        self.assertEqual('kathi.barfuss', api.user.get_current().getId())
        self.assertNotIn('manage', api.user.get_current().getRoles())

        with elevated_privileges(user_id='peter'):
            self.assertEqual('peter', api.user.get_current().getId())
            self.assertIn('manage', api.user.get_current().getRoles())

        self.assertNotIn('manage', api.user.get_current().getRoles())
        self.assertEqual('kathi.barfuss', api.user.get_current().getId())
Exemplo n.º 36
0
    def create_initial_version(self):
        """Creates an initial version for the document.

        Copied from `Products.CMFEditions.CopyModifyMergeRepositoryTool.save`
        only the timestamp is changed to the creation timestamp.
        """
        if self.has_initial_version():
            return

        if self.get_custom_initial_version_comment():
            comment = self.get_custom_initial_version_comment()
        else:
            comment = _(u'initial_document_version_change_note',
                        default=u'Initial version')
            comment = translate(comment, context=getRequest())

        self.repository._assertAuthorized(self.document, SaveNewVersion,
                                          'save')
        sp = transaction.savepoint(optimistic=True)
        sys_metadata = self.repository._prepareSysMetadata(comment)

        # Set creation datetime as initial version timestamp,
        # cmfeditions stores unix timestamps without any timezone information
        # therefore we have to do the same.
        created = self.document.created().asdatetime().replace(tzinfo=None)
        sys_metadata['timestamp'] = time.mktime(created.timetuple())
        metadata = {}

        creator = self.document.Creator()

        try:
            # Create the initial version using a temporary security manager
            # that claims a user ID of the user that was the creator of the
            # document.
            #
            # This will execute the version creation with Manager privileges,
            # but the given user_id.
            #
            # We need to do this this way because setting
            # sys_metadata['principal'] to the current user ID is hardcoded
            # in Products.CMFEditions.ArchivistTool.PreparedObject.__init__
            with elevated_privileges(user_id=creator):
                self.repository._recursiveSave(
                    self.document,
                    metadata,
                    sys_metadata,
                    autoapply=self.repository.autoapply)
        except ModifierException:
            # modifiers can abort save operations under certain conditions
            sp.rollback()
            raise

        self.remove_custom_initial_version_comment()
Exemplo n.º 37
0
    def test_elevated_privileges_sets_priviledged_user_and_restores_old(self):
        self.login(self.regular_user)

        self.assertEqual('kathi.barfuss', api.user.get_current().getId())
        self.assertNotIn('manage', api.user.get_current().getRoles())

        with elevated_privileges():
            self.assertEqual('kathi.barfuss', api.user.get_current().getId())
            self.assertIn('manage', api.user.get_current().getRoles())

        self.assertNotIn('manage', api.user.get_current().getRoles())
        self.assertEqual('kathi.barfuss', api.user.get_current().getId())
Exemplo n.º 38
0
    def test_elevated_privileges_sets_priviledged_user_and_restores_old(self):
        self.login(self.regular_user)

        self.assertEqual('kathi.barfuss', api.user.get_current().getId())
        self.assertNotIn('manage', api.user.get_current().getRoles())

        with elevated_privileges():
            self.assertEqual('kathi.barfuss', api.user.get_current().getId())
            self.assertIn('manage', api.user.get_current().getRoles())

        self.assertNotIn('manage', api.user.get_current().getRoles())
        self.assertEqual('kathi.barfuss', api.user.get_current().getId())
Exemplo n.º 39
0
    def test_elevated_privileges_allows_custom_user_id(self):
        self.login(self.regular_user)

        self.assertEqual('kathi.barfuss', api.user.get_current().getId())
        self.assertNotIn('manage', api.user.get_current().getRoles())

        with elevated_privileges(user_id='peter'):
            self.assertEqual('peter', api.user.get_current().getId())
            self.assertIn('manage', api.user.get_current().getRoles())

        self.assertNotIn('manage', api.user.get_current().getRoles())
        self.assertEqual('kathi.barfuss', api.user.get_current().getId())
Exemplo n.º 40
0
 def setUp(self):
     super(TestClosedDispositionOverview, self).setUp()
     with elevated_privileges():
         api.content.transition(
             obj=self.disposition,
             transition='disposition-transition-appraise')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-dispose')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-archive')
         api.content.transition(obj=self.disposition,
                                transition='disposition-transition-close')
Exemplo n.º 41
0
    def receive(self):
        document = super(RecieveSubmittedDocumentView, self).receive()

        history_data = advancedjson.loads(self.request.get('history_data'))
        with elevated_privileges():
            IHistory(self.context).append_record(
                u'document_submitted',
                document_title=document.title,
                submitted_version=history_data['submitted_version'],
                uuid=history_data['uuid'])

        ILockable(document).lock(MEETING_SUBMITTED_LOCK)
        return document
Exemplo n.º 42
0
    def trash_shadowed_docs(self):
        """Trash all documents that are in shadow state (recursive).
        """
        portal_catalog = api.portal.get_tool('portal_catalog')
        query = {'path': {'query': self.context.absolute_url_path(), 'depth': -1},
                'object_provides': [IBaseDocument.__identifier__],
                'review_state': "document-state-shadow"}
        shadowed_docs = portal_catalog.unrestrictedSearchResults(query)

        if shadowed_docs:
            with elevated_privileges():
                api.content.delete(
                    objects=[brain.getObject() for brain in shadowed_docs])
Exemplo n.º 43
0
    def accept(self):
        """Accept a invitation by setting the role and redirect the user
        to the workspace.
        """
        invitation = self.get_invitation_and_validate_payload()
        with elevated_privileges():
            target = uuidToObject(invitation['target_uuid'])
            target.manage_setLocalRoles(invitation['recipient'],
                                        [invitation['role']])
            target.reindexObjectSecurity()
            self.storage().remove_invitation(invitation['iid'])

        return self.request.RESPONSE.redirect(target.absolute_url())
Exemplo n.º 44
0
    def accept(self):
        """Accept a invitation by setting the role and redirect the user
        to the workspace.
        """
        invitation = self.get_invitation_and_validate_payload()
        with elevated_privileges():
            target = uuidToObject(invitation['target_uuid'])
            target.manage_setLocalRoles(invitation['recipient'],
                                        [invitation['role']])
            target.reindexObjectSecurity()
            self.storage().remove_invitation(invitation['iid'])

        return self.request.RESPONSE.redirect(target.absolute_url())
Exemplo n.º 45
0
    def render(self):
        jsondata = self.request.get(REQUEST_KEY)
        data = json.loads(jsondata)
        committee = Oguid.parse(data['committee_oguid']).resolve_object()
        proposal_oguid = Oguid.parse(data['proposal_oguid'])
        proposal = meeting_service().fetch_proposal_by_oguid(proposal_oguid)

        with elevated_privileges():
            submitted_proposal = SubmittedProposal.create(proposal, committee)

            self.request.response.setHeader("Content-type", "application/json")
            return json.dumps(
                {'path': '/'.join(submitted_proposal.getPhysicalPath())})
Exemplo n.º 46
0
    def test_archivist_is_not_allowed_to_close_a_disposition(self):
        with elevated_privileges():
            api.content.transition(obj=self.disposition,
                                   to_state='disposition-state-archived')

        self.login(self.archivist)
        with self.assertRaises(InvalidParameterError):
            api.content.transition(obj=self.disposition,
                                   transition='disposition-transition-close')

        self.login(self.records_manager)
        api.content.transition(obj=self.disposition,
                               transition='disposition-transition-close')
Exemplo n.º 47
0
    def reject(self, text):
        """Reject the submitted proposal."""

        proposal = self.load_model()
        proposal.reject(text)

        ProposalRejectedActivity(self, self.REQUEST).record()

        remove_watchers_on_submitted_proposal_deleted(
            self, proposal.committee.group_id)

        with elevated_privileges():
            api.content.delete(self)
Exemplo n.º 48
0
    def receive(self):
        document = super(RecieveSubmittedDocumentView, self).receive()

        history_data = advancedjson.loads(self.request.get('history_data'))
        with elevated_privileges():
            IHistory(self.context).append_record(
                u'document_submitted',
                document_title=document.title,
                submitted_version=history_data['submitted_version'],
                uuid=history_data['uuid']
            )

        ILockable(document).lock(MEETING_SUBMITTED_LOCK)
        return document
Exemplo n.º 49
0
    def accept(self):
        """Accept a invitation by setting the role and redirect the user
        to the workspace.
        """
        invitation = self.get_invitation_and_validate_payload()
        with elevated_privileges():
            target = uuidToObject(invitation['target_uuid'])

            assignment = InvitationRoleAssignment(
                invitation['recipient'], [invitation['role']], target)
            RoleAssignmentManager(target).add_or_update_assignment(assignment)
            self.storage().remove_invitation(invitation['iid'])

        return self.request.RESPONSE.redirect(target.absolute_url())
    def test_check_does_not_fail_if_document_has_no_longer_existent_backrefs(
            self):
        document_a = create(Builder('document').trashed())
        document_b = create(
            Builder('document').titled('Doc b').relate_to([document_a]))

        checker = RemoveConditionsChecker(document_a)
        self.assertFalse(checker.removal_allowed())

        with elevated_privileges():
            api.content.delete(obj=document_b)

        checker = RemoveConditionsChecker(document_a)
        self.assertTrue(checker.removal_allowed())
Exemplo n.º 51
0
    def _accept(self, invitation):
        with elevated_privileges():
            target = uuidToObject(invitation['target_uuid'])

            assignment = InvitationRoleAssignment(invitation['recipient'],
                                                  [invitation['role']], target)
            RoleAssignmentManager(target).add_or_update_assignment(assignment)
            self.storage().remove_invitation(invitation['iid'])

            manager = WorkspaceWatcherManager(self.context)
            manager.new_participant_added(invitation['recipient'],
                                          invitation['role'])

        return target
Exemplo n.º 52
0
    def create_initial_version(self):
        """Creates an initial version for the document.

        Copied from `Products.CMFEditions.CopyModifyMergeRepositoryTool.save`
        only the timestamp is changed to the creation timestamp.
        """
        if self.has_initial_version():
            return

        if self.get_custom_initial_version_comment():
            comment = self.get_custom_initial_version_comment()
        else:
            comment = _(u'initial_document_version_change_note',
                        default=u'Initial version')
            comment = translate(comment, context=getRequest())

        self.repository._assertAuthorized(self.document, SaveNewVersion, 'save')
        sp = transaction.savepoint(optimistic=True)
        sys_metadata = self.repository._prepareSysMetadata(comment)

        # Set creation datetime as initial version timestamp,
        # cmfeditions stores unix timestamps without any timezone information
        # therefore we have to do the same.
        created = self.document.created().asdatetime().replace(tzinfo=None)
        sys_metadata['timestamp'] = time.mktime(created.timetuple())
        metadata = {}

        creator = self.document.Creator()

        try:
            # Create the initial version using a temporary security manager
            # that claims a user ID of the user that was the creator of the
            # document.
            #
            # This will execute the version creation with Manager privileges,
            # but the given user_id.
            #
            # We need to do this this way because setting
            # sys_metadata['principal'] to the current user ID is hardcoded
            # in Products.CMFEditions.ArchivistTool.PreparedObject.__init__
            with elevated_privileges(user_id=creator):
                self.repository._recursiveSave(
                    self.document, metadata, sys_metadata,
                    autoapply=self.repository.autoapply)
        except ModifierException:
            # modifiers can abort save operations under certain conditions
            sp.rollback()
            raise

        self.remove_custom_initial_version_comment()
Exemplo n.º 53
0
    def test_add_history_entry_when_dispose_a_disposition(self):
        self.login(self.records_manager)
        with elevated_privileges():
            api.content.transition(obj=self.disposition,
                                   transition='disposition-transition-appraise')
            api.content.transition(obj=self.disposition,
                                   transition='disposition-transition-dispose')

        entry = IHistoryStorage(self.disposition).get_history()[0]

        self.assertTrue(isinstance(entry, Disposed))
        self.assertEquals('dispose', entry.css_class)
        self.assertEquals(
            u'Disposition disposed for the archive by {}'.format(self.current_user_link),
            translate(entry.msg(), context=self.request))
    def test_check_does_not_fail_if_document_has_no_longer_existent_backrefs(self):
        document_a = create(Builder('document')
                            .trashed())
        document_b = create(Builder('document')
                            .titled('Doc b')
                            .relate_to([document_a]))

        checker = RemoveConditionsChecker(document_a)
        self.assertFalse(checker.removal_allowed())

        with elevated_privileges():
            api.content.delete(obj=document_b)

        checker = RemoveConditionsChecker(document_a)
        self.assertTrue(checker.removal_allowed())
Exemplo n.º 55
0
    def create_tasks_listing_pdf(self):
        """Creates a pdf representation of the dossier tasks, and add it to
        the dossier as a normal document.

        If the dossiers has an end date use that date as the document date.
        This prevents the dossier from entering an invalid state with a
        document date outside the dossiers start-end range.
        """
        if not self.get_property('tasks_pdf_enabled'):
            return

        view = self.context.unrestrictedTraverse('pdf-dossier-tasks')

        today = api.portal.get_localized_time(
            datetime=datetime.today(), long_format=True)
        filename = u'Tasks {}.pdf'.format(today)
        title = _(u'title_dossier_tasks',
                  default=u'Task list of dossier ${title}, ${timestamp}',
                  mapping={'title': self.context.title,
                           'timestamp': today})
        kwargs = {
            'preserved_as_paper': False,
        }
        dossier = IDossier(self.context)
        if dossier and dossier.end:
            kwargs['document_date'] = dossier.end

        results = api.content.find(object_provides=IDossierTasksPDFMarker,
                                   depth=1,
                                   context=self.context)

        with elevated_privileges():
            if len(results) > 0:
                document = results[0].getObject()
                document.title = translate(title, context=self.context.REQUEST)
                comment = _(u'Updated with a newer generated version from dossier ${title}.',
                            mapping=dict(title=self.context.title))
                document.update_file(view.get_data(), create_version=True,
                                     comment=comment)
                return

            document = CreateDocumentCommand(
                self.context, filename, view.get_data(),
                title=translate(title, context=self.context.REQUEST),
                content_type='application/pdf',
                interfaces=[IDossierTasksPDFMarker],
                **kwargs).execute()
            document.reindexObject(idxs=['object_provides'])
Exemplo n.º 56
0
def delete_copied_proposal(copied_proposal, event):
    """Prevent that proposals are copied.

    This deletes the proposal from the copied subtree (a ZEXP) before the
    subtree gets inserted into the destination location.

    Suppress deletion events in order to avoid attempts to uncatalog
    an object that
    1) hasn't even been cataloged yet
    2) doesn't have a proper AQ chain because it's parts of a subtree
       that only exists as a temporary ZEXP that hasn't been attached to
       a container yet
    """
    with elevated_privileges():
        container = aq_parent(copied_proposal)
        container._delObject(copied_proposal.id, suppress_events=True)
Exemplo n.º 57
0
    def purge_trash(self):
        """Delete all trashed documents inside the dossier (recursive).
        """
        if not self.get_property('purge_trash_enabled'):
            return

        trashed_docs = api.content.find(
            context=self.context,
            depth=-1,
            object_provides=[IBaseDocument],
            trashed=True)

        if trashed_docs:
            with elevated_privileges():
                api.content.delete(
                    objects=[brain.getObject() for brain in trashed_docs])
Exemplo n.º 58
0
    def test_listing(self):
        self.login(self.regular_user)
        with elevated_privileges():
            api.content.transition(obj=self.disposition, transition='disposition-transition-appraise')
            api.content.transition(obj=self.disposition, transition='disposition-transition-dispose')
            api.content.transition(obj=self.disposition, transition='disposition-transition-archive')
            api.content.transition(obj=self.disposition, transition='disposition-transition-close')

        rows = self.get_listing_rows(self.disposition,
                                     'destroyed_dossiers',
                                     self.disposition.get_dossier_representations())

        self.assert_row_values(
            ['Client1 1.1 / 12', 'Hannah Baufrau', 'Yes'], rows[0])
        self.assert_row_values(
            ['Client1 1.1 / 13', 'Hans Baumann', 'No'], rows[1])
    def test_oggbundle_transmogrifier(self):
        # this is a bit hackish, but since builders currently don't work in
        # layer setup/teardown and isolation of database content is ensured
        # on a per test level we abuse just one test to setup the pipeline and
        # test its data.

        self.login(self.manager)

        # Create the 'bundle_guid' index. In production, this will be done
        # by the "bin/instance import" command in opengever.bundle.console
        add_guid_index()

        # load pipeline
        transmogrifier = Transmogrifier(api.portal.get())
        annotations = IAnnotations(transmogrifier)
        annotations[BUNDLE_PATH_KEY] = resource_filename(
            'opengever.bundle.tests', 'assets/basic.oggbundle')

        unc_share_asset_directory = resource_filename(
            'opengever.bundle.tests', 'assets/files_outside_bundle')

        ingestion_settings = {
            'unc_mounts': {
                u'\\\\host\\mount': unc_share_asset_directory.decode('utf-8')
            },
        }

        # Shove ingestion settings through JSON deserialization to be as
        # close as possible to the real thing (unicode strings!).
        ingestion_settings = json.loads(json.dumps(ingestion_settings))
        annotations[BUNDLE_INGESTION_SETTINGS_KEY] = ingestion_settings

        # We need to add documents to dossiers that have already been created
        # in the 'closed' state, which isn't allowed for anyone except users
        # inheriting from `UnrestrictedUser` -> we need elevated privileges
        with freeze(FROZEN_NOW), elevated_privileges():
            transmogrifier(u'opengever.bundle.oggbundle')

        bundle = annotations[BUNDLE_KEY]

        # test content creation
        # XXX use separate test-cases based on a layer
        root = self.assert_repo_root_created()
        folder_staff = self.assert_repo_folders_created(root)
        dossier_peter = self.assert_dossiers_created(folder_staff)
        self.assert_documents_created(dossier_peter)
        self.assert_report_data_collected(bundle)