def cancel(self): """Cancel the current checkout.""" # is the user allowed to cancel? if not self.is_cancel_allowed(): raise Unauthorized # revert to prior version (baseline) if a version exists. versioner = Versioner(self.context) if versioner.has_initial_version(): self.revert_to_version(versioner.get_current_version_id(), create_version=False, force=True) # remember that we canceled in self.annotations[CHECKIN_CHECKOUT_ANNOTATIONS_KEY] = None # finally, reindex the object catalog = api.portal.get_tool('portal_catalog') catalog.reindexObject( self.context, idxs=( 'checked_out', ), update_metadata=True, ) # Clear any WebDAV locks left over by ExternalEditor if necessary self.clear_locks() # fire the event notify(ObjectCheckoutCanceledEvent(self.context))
def test_closing_meeting_does_not_regenerate_edited_protocol(self, browser): self.login(self.committee_responsible, browser) model = self.meeting.model # Make sure there is already a protocol generated: model.update_protocol_document() self.assertEquals(0, model.protocol_document.generated_version) # Fake editing the protocol document = model.protocol_document.resolve_document() versioner = Versioner(document) versioner.create_initial_version() versioner.create_version("bumb version") # When closing the meeting, we should end up with a new version browser.open(self.meeting) self.assertEquals( ['Closing the meeting will not update the protocol automatically.' '\nMake sure to transfer your changes or recreate the protocol.', 'Are you sure you want to close this meeting?'], browser.css('#confirm_close_meeting p').text) model.close() self.assertEquals(0, model.protocol_document.generated_version) self.assertEquals(u'closed', model.workflow_state)
def close(self): self.stream.seek(0) versioner = Versioner(self.context) if not versioner.has_initial_version(): versioner.create_initial_version() self.filefield.data = self.stream.read()
def test_download_copy_without_overlay_creates_journal_entry(self, browser): self.login(self.regular_user, browser) versioner = Versioner(self.document) versioner.create_version('Initial version.') DownloadConfirmationHelper(self.document).deactivate() browser.open(self.document, view='tabbed_view/listing', data={'view_name': 'overview'}) browser.find('Download copy').click() self.assert_journal_entry(self.document, 'File copy downloaded', 'Download copy current version (0)')
def test_initial_version_is_created_when_updating_the_file(self): self.login(self.regular_user) versioner = Versioner(self.document) self.assertFalse(versioner.has_initial_version()) self.document.file = NamedBlobFile(data='New', filename=u'test.txt') self.assertTrue(versioner.has_initial_version()) self.assertEquals( 1, versioner.get_history_metadata().getLength(countPurged=False))
def comment(self): """Comment for this version. """ versioner = Versioner(self.obj) if versioner.get_custom_initial_version_comment(): return versioner.get_custom_initial_version_comment() return translate(_(u'initial_document_version_change_note', default=u'Initial version'), context=getRequest())
def comment(self): """Comment for this version. """ versioner = Versioner(self.obj) if versioner.get_custom_initial_version_comment(): return versioner.get_custom_initial_version_comment() return translate( _(u'initial_document_version_change_note', default=u'Initial version'), context=getRequest())
def test_fetching_version_metadata(self): self.login(self.regular_user) versioner = Versioner(self.document) versioner.set_custom_initial_version_comment(u'custom initial version') self.document.file = NamedBlobFile(data='New', filename=u'test.txt') sys_metadata = versioner.get_version_metadata(0).get('sys_metadata') self.assertEqual(u'custom initial version', sys_metadata.get('comment')) self.assertEqual('robert.ziegler', sys_metadata.get('principal')) self.assertEqual('document-state-draft', sys_metadata.get('review_state'))
def test_ftw_journal_still_present_on_working_copy(self): self.login(self.regular_user) self.create_version(self.document) versioner = Versioner(self.document) shadow_history = versioner.get_history_metadata() self.assertEquals(2, len(shadow_history)) ann = IAnnotations(self.document) self.assertIn(self.JOURNAL_KEY, ann) self.assertEqual(3, len(ann[self.JOURNAL_KEY]))
def test_protocol_generate_action_only_available_for_unedited_protocols(self, browser): self.login(self.committee_responsible, browser) self.schedule_paragraph(self.meeting, u'A-Gesch\xe4fte') self.schedule_proposal(self.meeting, self.submitted_proposal) meeting = self.meeting.model self.assertIsNone(meeting.protocol_document) browser.open(meeting.get_url()) # generate first protocol generate_button = browser.css('.meeting-document.protocol-doc .action.generate').first # Make sure we have the action without overwrite self.assertIn("overwrite=False", generate_button.get("href")) generate_button.click() statusmessages.assert_message( u'Protocol for meeting 9. Sitzung der ' u'Rechnungspr\xfcfungskommission has been generated ' u'successfully.') self.assertIsNotNone(meeting.protocol_document) self.assertEqual(0, meeting.protocol_document.generated_version) # Fake editing the protocol document = meeting.protocol_document.resolve_document() versioner = Versioner(document) versioner.create_initial_version() versioner.create_version("bumb version") # Without reloading the page, we still have the link to update the protocol # without confirmation generate_button = browser.css('.meeting-document.protocol-doc .action.generate').first # Make sure we have the action without overwrite self.assertIn("overwrite=False", generate_button.get("href")) generate_button.click() # Protocol was not updated, as update needs confirmation self.assertEqual(0, meeting.protocol_document.generated_version) statusmessages.assert_message( u'Protocol for meeting 9. Sitzung der Rechnungspr\xfcfungskommission ' 'has not been updated. The protocol has been modified manually and ' 'these modifications will be lost if you regenerate the protocol.') # Reload browser page and make sure we now have the link with confirmation browser.open(meeting.get_url()) generate_button = browser.css('.meeting-document.protocol-doc .action.generate').first self.assertIn("overwrite=True", generate_button.get("href")) self.assertEqual('generate_protocol_with_confirm', generate_button.get("id")) generate_button.click() statusmessages.assert_message( u'Protocol for meeting 9. Sitzung der ' u'Rechnungspr\xfcfungskommission has been updated successfully.') self.assertIsNotNone(meeting.protocol_document) self.assertEqual(2, meeting.protocol_document.generated_version)
def test_doc_property_writer_creates_initial_version(self): self.activate_feature('doc-properties') self.login(self.dossier_responsible) versioner = Versioner(self.document) self.assertFalse(versioner.has_initial_version()) DocPropertyWriter(self.document).update_doc_properties(only_existing=False) self.assertTrue(versioner.has_initial_version()) self.assertEquals( 1, versioner.get_history_metadata().getLength(countPurged=False))
def test_ftw_journal_is_not_versioned(self): self.login(self.regular_user) self.create_version(self.document) versioner = Versioner(self.document) shadow_history = versioner.get_history_metadata() self.assertEquals(2, len(shadow_history)) for version_number in range(len(shadow_history)): historic_obj = versioner.retrieve(version_number) historic_annotations = IAnnotations(historic_obj) self.assertNotIn(self.JOURNAL_KEY, historic_annotations)
def test_custom_comment_is_used_when_creating_initial_version(self, browser): self.login(self.regular_user) versioner = Versioner(self.document) versioner.set_custom_initial_version_comment(u'custom initial version') self.document.file = NamedBlobFile(data='New', filename=u'test.txt') version = versioner.retrieve_version(0) self.assertEquals( u'custom initial version', version.sys_metadata['comment']) self.assertIsNone(versioner.get_custom_initial_version_comment())
def test_updating_a_document_via_webdav_creates_initial_version_too(self, browser): self.login(self.regular_user) versioner = Versioner(self.document) self.assertFalse(versioner.has_initial_version()) writer = IRawWriteFile(self.document, None) writer.write('New Data') writer.close() self.assertTrue(versioner.has_initial_version()) self.assertEquals( 1, versioner.get_history_metadata().getLength(countPurged=False))
def test_download_confirmation_view_for_version_download(self, browser): self.login(self.regular_user, browser) versioner = Versioner(self.document) versioner.create_version('Initial version') versioner.create_version('Some updates.') browser.open(self.document, view='file_download_confirmation', data={'version_id': 1}) self.assertEqual( "You're downloading a copy of the document Vertraegsentwurf.docx", browser.css(".details > p").first.text, ) browser.find('label_download').click() expected_url = "{}/download_file_version?version_id=1".format(self.document.absolute_url()) self.assertEqual(expected_url, browser.url) self.assertEqual(self.document.file.data, browser.contents)
def copy_documents_from_remote_task(self, task, target, documents=None, comment=None): transporter = Transporter() data = dispatch_json_request(task.admin_unit_id, '@@task-documents-extract', path=task.physical_path, data={'documents': json.dumps(documents)}) intids_mapping = {} intids = getUtility(IIntIds) for item in data: obj = transporter.create(item, target) # Set custom initial version comment if comment: Versioner(obj).set_custom_initial_version_comment(comment) oldintid = IAnnotations(obj)[ORIGINAL_INTID_ANNOTATION_KEY] newintid = intids.getId(obj) intids_mapping[oldintid] = newintid return intids_mapping
def versioner(self): try: self._versioner except AttributeError: self._versioner = Versioner(self.context) return self._versioner
def _create_doc(self): doc = create( Builder('document').within(self.dossier).attach_file_containing( u"INITIAL VERSION DATA", u"somefile.txt")) Versioner(doc).create_initial_version() return doc
def create_document_version(doc, version_id, data=None, comment=None): vdata = data or 'VERSION {} DATA'.format(version_id) doc.file.data = vdata if comment is None: comment = u'This is Version %s' % version_id Versioner(doc).create_version(comment)
def test_persisted_interfaces_in_zc_relation_catalog(self): root = create(Builder('repository_root').titled(u'Repository')) repo = create(Builder('repository') .within(root) .titled(u'Testposition')) dossier_a = create(Builder('dossier') .within(repo)) create(Builder('dossier') .within(repo) .having(relatedDossier=[dossier_a])) create(Builder('meeting_dossier') .within(repo) .having(relatedDossier=[dossier_a])) create(Builder('private_dossier') .within(repo) .having(relatedDossier=[dossier_a])) dossiertemplate = create(Builder('dossier') .having(relatedDossier=[dossier_a])) create(Builder('repository') .having(addable_dossier_templates=[dossiertemplate])) document_a = create(Builder('document').within(dossier_a)) Versioner(document_a).create_initial_version() create(Builder('document').within(dossier_a).relate_to(document_a)) create(Builder('proposaltemplate').relate_to(document_a)) create(Builder('task').within(dossier_a).relate_to([document_a])) create(Builder('forwarding').within(dossier_a).relate_to([document_a])) sablontemplate_a = create(Builder('sablontemplate')) sablontemplate_b = create(Builder('sablontemplate') .relate_to(sablontemplate_a)) create(Builder('committee_container') .having(protocol_template=sablontemplate_b)) committee = create(Builder('committee') .having(protocol_template=sablontemplate_b)) proposal, submittedproposal = create( Builder('proposal') .having(committee=committee.load_model()) .within(dossier_a) .relate_to(document_a) .with_submitted()) dossier_expired = create(Builder('dossier').as_expired()) self.grant('Records Manager') create(Builder('disposition').having(dossiers=[dossier_expired])) self.maxDiff = None self.assertItemsEqual( EXPECTED_INTERFACES, self.get_all_persisted_interfaces(), 'Seems that a type does newly or no longer provides an interface.' ' Make sure if a interface has been removed, that the relation' ' catalog is cleaned up and adjust the EXPECTED_INTERFACES list.')
def get_checkin_comment(self): version_id = self.version_id if version_id is None: version_id = getattr(self.context, 'version_id', None) if version_id is not None: version_metadata = Versioner( self.context).get_version_metadata(version_id) return version_metadata['sys_metadata']['comment'] return u''
def _retrieve_version(self, context, version_id): try: # CMFEditions causes writes to the parent when retrieving versions unprotected_write(aq_parent(context)) return Versioner(context).retrieve(version_id) except ArchivistRetrieveError: # Version does not exists. raise NotFound
def test_shows_custom_initial_comment_when_set(self, browser): Versioner(self.document).set_custom_initial_version_comment( u'Document copied from task (task closed)') transaction.commit() browser.login().open(self.document, view='tabbedview_view-versions') listing = browser.css('.listing').first self.assertEquals(u'Document copied from task (task closed)', listing.dicts()[0].get('Comment'))
def check_version_is_convertable(self, version_id): """ The object action is only available for documents that are convertable, but in the version tab, there is a link for each version and convertability is not checked. We therefore only check if it is convertable for requests with a version_id parameter. """ if not version_id: return True document = Versioner(self.context).retrieve(version_id) return IBumblebeeServiceV3(self.request).is_convertable(document)
def test_documents_with_custom_sort(self): task = self._create_task(self.portal, with_docs=True) target = self._create_task(self.portal) doc_transporter = getUtility(ITaskDocumentsTransporter) doc_transporter.copy_documents_from_remote_task( task.get_sql_object(), target, comment=u'Custom initial version') doc = target.getFolderContents()[0].getObject() self.assertEquals(u'Custom initial version', Versioner(doc).get_custom_initial_version_comment())
def test_initial_version_date_is_documents_creation_date(self, browser): self.login(self.manager) self.document.file = NamedBlobFile(data='New', filename=u'test.txt') versioner = Versioner(self.document) version = versioner.repository.retrieve(self.document, 0) creation_date = self.document.creation_date creation_date = creation_date.asdatetime().replace(tzinfo=None) self.assertEquals( creation_date, datetime.fromtimestamp(version.sys_metadata.get('timestamp')))
def test_download_versioned_copy_creates_journal_entries_with_versions_in_title(self, browser): self.login(self.regular_user, browser) versioner = Versioner(self.document) versioner.create_version('Initial version') versioner.create_version('Some updates.') browser.open(self.document, view='tabbedview_view-versions') browser.css('a.function-download-copy').first.click() browser.find('label_download').click() self.assert_journal_entry(self.document, 'File copy downloaded', 'Download copy version 1') versioner.create_version('Oops.') browser.open(self.document, view='tabbedview_view-versions') browser.css('a.function-download-copy').first.click() browser.find('label_download').click() self.assert_journal_entry(self.document, 'File copy downloaded', 'Download copy version 2')
def test_closing_meeting_does_not_regenerate_edited_protocol( self, browser): self.login(self.committee_responsible, browser) model = self.meeting.model # Make sure there is already a protocol generated: model.update_protocol_document() self.assertEquals(0, model.protocol_document.generated_version) # Fake editing the protocol document = model.protocol_document.resolve_document() versioner = Versioner(document) versioner.create_initial_version() versioner.create_version("bumb version") # When closing the meeting, we should end up with a new version browser.open(self.meeting) self.assertEquals([ 'Closing the meeting will not update the protocol automatically.' '\nMake sure to transfer your changes or recreate the protocol.', 'Are you sure you want to close this meeting?' ], browser.css('#confirm_close_meeting p').text) model.close() self.assertEquals(0, model.protocol_document.generated_version) self.assertEquals(u'closed', model.workflow_state)
def __call__(self): data = self.request.get('data', None) assert data is not None, 'Bad request: no delivery data found' data = json.loads(data) if self.is_already_delivered(data): return ok_response() mtool = getToolByName(self.context, 'portal_membership') member = mtool.getAuthenticatedMember() if not member.checkPermission('Add portal content', self.context): raise Unauthorized() # Set the "X-CREATING-SUCCESSOR" flag for preventing the event # handler from creating additional responses per added document. self.request.set('X-CREATING-SUCCESSOR', True) # Create the delivered documents: transporter = Transporter() documents = [] message = _( u'version_message_resolved_task', default=u'Document copied from task (task resolved)') if data.get( 'transition') == 'task-transition-in-progress-tested-and-closed': message = _( u'version_message_closed_task', default=u'Document copied from task (task closed)') for item in data['documents']: doc = transporter.create(item, self.context) Versioner(doc).set_custom_initial_version_comment(message) # append `RE:` prefix to the document title doc.title = '%s: %s' % ( translate( _(u'answer_prefix', default=u'RE'), context=self.context.REQUEST), doc.title) documents.append(doc) notify(ObjectAddedEvent(doc)) # Change workflow state of predecessor task: util.change_task_workflow_state( self.context, data['transition'], text=data['text'], added_object=documents) return ok_response()
def test_save_pdf_under_form_asserts_version_is_convertable(self, browser): self.login(self.regular_user, browser) self.document.file.filename = u"test.wav" self.document.file.contentType = "audio/wav" Versioner(self.document).create_version("") self.document.file.filename = u"test.txt" self.document.file.contentType = "text/plain" Versioner(self.document).create_version("") # when the version is convertable, we get to the form browser.open(self.document, view='save_pdf_under', data={"version_id": "1"}) self.assertEqual("/".join([self.document.absolute_url(), 'save_pdf_under']), browser.url) # when the version cannot be converted, we get redirected back to the # the source document and an error message is displayed. browser.open(self.document, view='save_pdf_under', data={"version_id": "0"}) errors = statusmessages.error_messages() self.assertEqual(1, len(errors)) self.assertEqual('This document cannot be converted to PDF.', errors[0]) self.assertEqual(self.document.absolute_url(), browser.url)
def test_checksum_is_updated_before_storing_version(self, browser): content = bumblebee_asset('example.docx').bytes() document = create(Builder('document') .within(self.dossier) .attach_file_containing( content, u'example.docx') .checked_out()) document.update_file('foo', content_type='text/plain', filename=u'foo.txt') notify(ObjectModifiedEvent(document)) transaction.commit() # checksum has not been updated self.assertEqual( DOCX_CHECKSUM, IBumblebeeDocument(document).get_checksum()) manager = getMultiAdapter((document, self.portal.REQUEST), ICheckinCheckoutManager) manager.checkin() # checksum has been updated self.assertEqual(TXT_CHECKSUM, IBumblebeeDocument(document).get_checksum()) versioner = Versioner(document) history = versioner.get_history_metadata() self.assertEqual(2, history.getLength(countPurged=False)) version_0 = versioner.retrieve(0) self.assertEqual(DOCX_CHECKSUM, IBumblebeeDocument(version_0).get_checksum()) # document checksum should be updated before storing the version version_1 = versioner.retrieve(1) self.assertEqual(TXT_CHECKSUM, IBumblebeeDocument(version_1).get_checksum())
def test_protocol_generate_action_only_available_for_unedited_protocols( self, browser): self.login(self.committee_responsible, browser) self.schedule_paragraph(self.meeting, u'A-Gesch\xe4fte') self.schedule_proposal(self.meeting, self.submitted_proposal) meeting = self.meeting.model self.assertIsNone(meeting.protocol_document) browser.open(meeting.get_url()) # generate first protocol generate_button = browser.css( '.meeting-document.protocol-doc .action.generate').first # Make sure we have the action without overwrite self.assertIn("overwrite=False", generate_button.get("href")) generate_button.click() statusmessages.assert_message( u'Protocol for meeting 9. Sitzung der ' u'Rechnungspr\xfcfungskommission has been generated ' u'successfully.') self.assertIsNotNone(meeting.protocol_document) self.assertEqual(0, meeting.protocol_document.generated_version) # Fake editing the protocol document = meeting.protocol_document.resolve_document() versioner = Versioner(document) versioner.create_initial_version() versioner.create_version("bumb version") # Without reloading the page, we still have the link to update the protocol # without confirmation generate_button = browser.css( '.meeting-document.protocol-doc .action.generate').first # Make sure we have the action without overwrite self.assertIn("overwrite=False", generate_button.get("href")) generate_button.click() # Protocol was not updated, as update needs confirmation self.assertEqual(0, meeting.protocol_document.generated_version) statusmessages.assert_message( u'Protocol for meeting 9. Sitzung der Rechnungspr\xfcfungskommission ' 'has not been updated. The protocol has been modified manually and ' 'these modifications will be lost if you regenerate the protocol.') # Reload browser page and make sure we now have the link with confirmation browser.open(meeting.get_url()) generate_button = browser.css( '.meeting-document.protocol-doc .action.generate').first self.assertIn("overwrite=True", generate_button.get("href")) self.assertEqual('generate_protocol_with_confirm', generate_button.get("id")) generate_button.click() statusmessages.assert_message( u'Protocol for meeting 9. Sitzung der ' u'Rechnungspr\xfcfungskommission has been updated successfully.') self.assertIsNotNone(meeting.protocol_document) self.assertEqual(2, meeting.protocol_document.generated_version)
def test_download_copy_with_overlay_creates_journal_entry(self, browser): self.login(self.regular_user, browser) versioner = Versioner(self.document) versioner.create_version('Initial version') versioner.create_version('Some updates.') browser.open(self.document, view='tabbed_view/listing', data={'view_name': 'overview'}) browser.find('Download copy').click() browser.find('label_download').click() self.assert_journal_entry(self.document, 'File copy downloaded', 'Download copy current version (1)')
def test_checksum_is_updated_before_storing_version(self, browser): content = bumblebee_asset('example.docx').bytes() document = create( Builder('document').within(self.dossier).attach_file_containing( content, u'example.docx').checked_out()) document.update_file('foo', content_type='text/plain', filename=u'foo.txt') notify(ObjectModifiedEvent(document)) transaction.commit() # checksum has not been updated self.assertEqual(DOCX_CHECKSUM, IBumblebeeDocument(document).get_checksum()) manager = getMultiAdapter((document, self.portal.REQUEST), ICheckinCheckoutManager) manager.checkin() # checksum has been updated self.assertEqual(TXT_CHECKSUM, IBumblebeeDocument(document).get_checksum()) versioner = Versioner(document) history = versioner.get_history_metadata() self.assertEqual(2, history.getLength(countPurged=False)) version_0 = versioner.retrieve(0) self.assertEqual(DOCX_CHECKSUM, IBumblebeeDocument(version_0).get_checksum()) # document checksum should be updated before storing the version version_1 = versioner.retrieve(1) self.assertEqual(TXT_CHECKSUM, IBumblebeeDocument(version_1).get_checksum())
def update_file(self, data, content_type=None, filename=None, create_version=False, comment=''): content_type = content_type or self.file.contentType filename = filename or self.file.filename self.file = NamedBlobFile(data=data, filename=filename, contentType=content_type) if create_version: Versioner(self).create_version(comment) self.setModificationDate() self.reindexObject()
def file(self, value): if self.__dict__.get('file'): # Self is not aquisition wrapped, but we need an aquisition # wrapped object for checking/creating an initial version. document = api.content.get(UID=self.UID()) # When retrieving a version, for example in the # opengever.bumblebee.download view, the document file attribute # is set by the CopyModifyMergeRepositoryTool._recursiveRetrieve. # Therefore we only create the initial version, if the document can # be aquisition wrapped if document: # Create an initial version before updating the document. Versioner(document).create_initial_version() self.__dict__['file'] = value
def test_initial_version_is_not_created_when_adding_a_document(self): self.login(self.regular_user) versioner = Versioner(self.document) self.assertFalse(versioner.has_initial_version())