def test_untrashing_available_for_trashed_document(self, browser): self.login(self.regular_user, browser) trasher = ITrashable(self.document) trasher.trash() expected_file_actions = [ { u'id': u'download_copy', u'title': u'Download copy', u'icon': u'' }, { u'id': u'attach_to_email', u'title': u'Attach to email', u'icon': u'' }, { u'id': u'open_as_pdf', u'title': u'Open as PDF', u'icon': u'' }, { u'id': u'untrash_document', u'title': u'Untrash document', u'icon': u'' }, ] self.assertEqual(expected_file_actions, self.get_file_actions(browser, self.document))
def __call__(self): paths = self.request.get('paths') if paths: for item in paths: obj = self.context.restrictedTraverse(item) if not api.user.has_permission( 'opengever.trash: Untrash content', obj=obj): msg = _(u'Untrashing ${title} is forbidden', mapping={'title': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='error') continue trasher = ITrashable(obj) trasher.untrash() return self.request.RESPONSE.redirect( '%s#documents' % (self.context.absolute_url())) else: msg = _(u'You have not selected any items.') IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.RESPONSE.redirect('%s#trash' % self.context.absolute_url())
def after_create(self, obj): if self._trashed: trasher = ITrashable(obj) trasher.trash() obj.update_filename() super(MailBuilder, self).after_create(obj)
def reply(self): # Disable CSRF protection alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection) trasher = ITrashable(self.context) try: trasher.trash() except TrashError as exc: if exc.message == 'Already trashed': self.request.response.setStatus(400) return {'error': { 'type': 'Bad Request', 'message': 'Already trashed', }} elif exc.message == 'Document checked out': self.request.response.setStatus(400) return {'error': { 'type': 'Bad Request', 'message': 'Can not trash a checked-out document', }} self.request.response.setStatus(204) return super(Trash, self).reply()
def reply(self): # Disable CSRF protection alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection) trasher = ITrashable(self.context) try: trasher.trash() except TrashError as exc: if exc.message == 'Already trashed': self.request.response.setStatus(400) return { 'error': { 'type': 'Bad Request', 'message': 'Already trashed', } } elif exc.message == 'Document checked out': self.request.response.setStatus(400) return { 'error': { 'type': 'Bad Request', 'message': 'Can not trash a checked-out document', } } self.request.response.setStatus(204) return super(Trash, self).reply()
def test_untrash_document(self, browser): self.login(self.regular_user, browser) trasher = ITrashable(self.document) trasher.trash() browser.open(self.document.absolute_url() + '/@untrash', method='POST', headers={'Accept': 'application/json'}) self.assertEqual(204, browser.status_code) self.assertFalse(ITrashed.providedBy(self.document))
def after_create(self, obj): if self.checked_out: IAnnotations(obj)[CHECKIN_CHECKOUT_ANNOTATIONS_KEY] = self.checked_out if self._trashed: trasher = ITrashable(obj) trasher.trash() super(DocumentBuilder, self).after_create(obj)
def after_create(self, obj): if self.checked_out: IAnnotations( obj)[CHECKIN_CHECKOUT_ANNOTATIONS_KEY] = self.checked_out if self._trashed: trasher = ITrashable(obj) trasher.trash() super(DocumentBuilder, self).after_create(obj)
def reply(self): # Disable CSRF protection alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection) trasher = ITrashable(self.context) trasher.untrash() self.request.response.setStatus(204) return super(Untrash, self).reply()
def test_remove_action_not_available_in_private_folder(self, browser): self.login(self.manager, browser=browser) ITrashable(self.document).trash() browser.open(self.dossier, view="tabbed_view/listing?view_name=trash") self.assertItemsEqual([u'More actions \u25bc', 'untrashed', 'remove'], browser.css('#tabbedview-menu a').text) ITrashable(self.private_document).trash() browser.open(self.private_dossier, view="tabbed_view/listing?view_name=trash") self.assertItemsEqual([u'More actions \u25bc', 'untrashed'], browser.css('#tabbedview-menu a').text)
def after_create(self, obj): if self._checked_out: IAnnotations( obj)[CHECKIN_CHECKOUT_ANNOTATIONS_KEY] = self._checked_out obj.reindexObject(idxs=['checked_out']) if self._trashed: trasher = ITrashable(obj) trasher.trash() if self._is_shadow: obj.as_shadow_document() super(DocumentBuilder, self).after_create(obj)
def remove(self): assert self.meeting.is_editable() # the agenda_item is ad hoc if it has a document but no proposal if self.has_document and not self.has_proposal: document = self.resolve_document() trasher = ITrashable(document) trasher.trash() session = create_session() if self.proposal: self.proposal.remove_scheduled(self.meeting) session.delete(self) self.meeting.reorder_agenda_items()
def after_create(self, obj): if self._checked_out: IAnnotations(obj)[CHECKIN_CHECKOUT_ANNOTATIONS_KEY] = self._checked_out obj.reindexObject(idxs=['checked_out']) if self._trashed: trasher = ITrashable(obj) trasher.trash() if self._is_shadow: obj.as_shadow_document() obj.reindexObject(idxs=["review_state"]) super(DocumentBuilder, self).after_create(obj)
def test_trash_excerpt_is_forbidden_when_it_has_been_returned_to_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') ITrashable(excerpt1).trash() ITrashable(excerpt1).untrash() agenda_item.return_excerpt(excerpt1) with self.assertRaises(TrashError): ITrashable(excerpt1).trash()
def test_get_size_on_mails(self): self.grant('Manager') mail = create(Builder('mail').with_message('Not really an email')) self.assertEquals(19, IObjectSize(mail).get_size()) ITrashable(mail).trash() self.assertEquals(0, IObjectSize(mail).get_size())
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 __call__(self): paths = self.request.get('paths') catalog = getToolByName(self.context, 'portal_catalog') if paths: for item in paths: obj = self.context.restrictedTraverse(item) brains = catalog(path=item) # check that the object isn't already trashed if not brains: msg = _( u'could not trash the object ${obj}, ' 'it is already trashed', mapping={'obj': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='error') continue # check that the document isn't checked_out if brains[0].checked_out: msg = _( u'could not trash the object ${obj}, it is checked out.', mapping={'obj': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='error') continue if not api.user.has_permission( 'opengever.trash: Trash content', obj=obj): msg = _(u'Trashing ${title} is forbidden', mapping={'title': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='error') continue trasher = ITrashable(obj) trasher.trash() msg = _(u'the object ${obj} trashed', mapping={'obj': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='info') else: msg = _(u'You have not selected any items.') IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.RESPONSE.redirect('{}#documents'.format( self.context.absolute_url()))
def __call__(self): paths = self.request.get('paths') if paths: for item in paths: obj = self.context.restrictedTraverse(item) trasher = ITrashable(obj) try: trasher.trash() except TrashError as exc: if exc.message == 'Already trashed': msg = _( u'could not trash the object ${obj}, ' 'it is already trashed', mapping={'obj': obj.Title().decode('utf-8')}) elif exc.message == 'Document checked out': msg = _( u'could not trash the object ${obj}, it is checked' ' out.', mapping={'obj': obj.Title().decode('utf-8')}) elif exc.message == 'The document has been returned as excerpt': msg = _( u'could not trash the object ${obj}, it is an excerpt' ' that has been returned to the proposal.', mapping={'obj': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage( msg, type='error') except Unauthorized: msg = _(u'Trashing ${title} is forbidden', mapping={'title': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage( msg, type='error') else: msg = _(u'the object ${obj} trashed', mapping={'obj': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage( msg, type='info') else: msg = _(u'You have not selected any items.') IStatusMessage(self.request).addStatusMessage( msg, type='error') return self.request.RESPONSE.redirect( '{}#documents'.format(self.context.absolute_url()))
def test_get_size_on_document(self): self.grant('Manager') document = create( Builder('document').attach_file_containing('Hello World')) self.assertEquals(11, IObjectSize(document).get_size()) ITrashable(document).trash() self.assertEquals(0, IObjectSize(document).get_size())
def __call__(self): paths = self.request.get('paths') if paths: for item in paths: obj = self.context.restrictedTraverse(item) trasher = ITrashable(obj) try: trasher.trash() except TrashError as exc: if exc.message == 'Already trashed': msg = _( u'could not trash the object ${obj}, ' 'it is already trashed', mapping={'obj': obj.Title().decode('utf-8')}) elif exc.message == 'Document checked out': msg = _( u'could not trash the object ${obj}, it is checked' ' out.', mapping={'obj': obj.Title().decode('utf-8')}) elif exc.message == 'The document has been returned as excerpt': msg = _( u'could not trash the object ${obj}, it is an excerpt' ' that has been returned to the proposal.', mapping={'obj': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='error') except Unauthorized: msg = _(u'Trashing ${title} is forbidden', mapping={'title': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='error') else: msg = _(u'the object ${obj} trashed', mapping={'obj': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='info') else: msg = _(u'You have not selected any items.') IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.RESPONSE.redirect('{}#documents'.format( self.context.absolute_url()))
def delete(self): """Unschedule the current agenda_item. If the agenda_item has no proposal, the agenda_item gets deleted. If there is a proposal related, the proposal is unscheduled. """ if not self.context.model.is_editable(): raise Unauthorized("Editing is not allowed") # the agenda_item is ad hoc if it has a document but no proposal if self.agenda_item.has_document and not self.agenda_item.has_proposal: document = self.agenda_item.resolve_document() trasher = ITrashable(document) trasher.trash() self.agenda_item.remove() return JSONResponse(self.request).info( _(u'agenda_item_deleted', default=u'Agenda Item Successfully deleted')).dump()
def __call__(self): paths = self.request.get('paths') if paths: for item in paths: obj = self.context.restrictedTraverse(item) trasher = ITrashable(obj) try: trasher.untrash() except Unauthorized: msg = _(u'Untrashing ${title} is forbidden', mapping={'title': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.RESPONSE.redirect( '%s#documents' % (self.context.absolute_url())) else: msg = _(u'You have not selected any items.') IStatusMessage(self.request).addStatusMessage(msg, type='error') return self.request.RESPONSE.redirect('%s#trash' % self.context.absolute_url())
def __call__(self): paths = self.request.get('paths') if paths: for item in paths: obj = self.context.restrictedTraverse(item) trasher = ITrashable(obj) try: trasher.untrash() except Unauthorized: msg = _(u'Untrashing ${title} is forbidden', mapping={'title': obj.Title().decode('utf-8')}) IStatusMessage(self.request).addStatusMessage( msg, type='error') return self.request.RESPONSE.redirect('%s#documents' % ( self.context.absolute_url())) else: msg = _(u'You have not selected any items.') IStatusMessage(self.request).addStatusMessage( msg, type='error') return self.request.RESPONSE.redirect( '%s#trash' % self.context.absolute_url())
def test_trashed_exceprts_are_not_listed_for_ad_hoc_agendaitem( self, browser): self.login(self.committee_responsible, browser) agenda_item = self.schedule_ad_hoc(self.meeting, 'Foo') agenda_item.decide() excerpt1 = agenda_item.generate_excerpt('excerpt 1') agenda_item.generate_excerpt('excerpt 2') excerpts = browser.open(self.agenda_item_url( agenda_item, 'list')).json.get('items')[0].get('excerpts') self.assertEqual(len(excerpts), 2) ITrashable(excerpt1).trash() excerpts = browser.open(self.agenda_item_url( agenda_item, 'list')).json.get('items')[0].get('excerpts') self.assertEqual(len(excerpts), 1) excerpt_links = ' '.join([excerpt.get('link') for excerpt in excerpts]) excerpt_titles = browser.open_html(excerpt_links).css('a').text self.assertEqual(['excerpt 2'], excerpt_titles)
def test_remove_excerpt_for_adhoc_agendaitem_removes_entry_from_sql_database( self, browser): self.login(self.committee_responsible, browser) agenda_item = self.schedule_ad_hoc(self.meeting, 'Foo') agenda_item.decide() excerpt1 = agenda_item.generate_excerpt('excerpt 1') agenda_item.generate_excerpt('excerpt 2') self.assertEqual( 2, len(agenda_item.get_excerpt_documents(include_trashed=True))) excerpts = Excerpt.query.filter( Excerpt.agenda_item_id == agenda_item.agenda_item_id).all() self.assertEqual(2, len(excerpts)) ITrashable(excerpt1).trash() with elevated_privileges(): Remover([excerpt1]).remove() self.assertEqual( 1, len(agenda_item.get_excerpt_documents(include_trashed=True))) excerpts = Excerpt.query.filter( Excerpt.agenda_item_id == agenda_item.agenda_item_id).all() self.assertEqual(1, len(excerpts))
def test_content_modifications_update_usage(self): """Test that adding, updating, removing and moving update the usage. This test is implemented as story so that we do not create that many objects in order to speed up tests. As soon as we can use fixtures these tests can be refactored. """ self.grant('Manager') user_root = create(Builder('private_root')) user_folder = create_members_folder(user_root) user_dossier = create(Builder('dossier').within(user_folder)) shared_dossier = create(Builder('dossier')) self.assertEqual(0, ISizeQuota(user_folder).get_usage(), 'Expected usage to be 0 for an empty root.') with self.assert_usage_change(user_folder, +1, 'add first document'): doc1 = create(Builder('document') .attach_file_containing('X') .within(user_dossier)) with self.assert_usage_change(user_folder, -1 + 2, 'update document'): doc1.file = NamedBlobFile('XX', filename=u'test.txt') notify(ObjectModifiedEvent(doc1)) with self.assert_usage_change(user_folder, +3, 'add second document'): doc2 = create(Builder('document') .attach_file_containing('XXX') .within(user_dossier)) with self.assert_usage_change(user_folder, -3, 'move away from quota container'): shared_dossier.manage_pasteObjects( user_dossier.manage_cutObjects([doc2.getId()])) with self.assert_usage_change(user_folder, +3, 'move back into quota container'): user_dossier.manage_pasteObjects( shared_dossier.manage_cutObjects([doc2.getId()])) with self.assert_usage_change(user_folder, -3, 'trash document'): ITrashable(doc2).trash() with self.assert_usage_change(user_folder, +3, 'restore document'): ITrashable(doc2).untrash() with self.assert_usage_change(user_folder, -3, 'delete'): user_dossier.manage_delObjects([doc2.getId()]) # clear and recalculate self.assertEqual(2, ISizeQuota(user_folder).get_usage()) ISizeQuota(user_folder).get_usage_map(for_writing=True).clear() self.assertEqual(0, ISizeQuota(user_folder).get_usage()) ISizeQuota(user_folder).recalculate() self.assertEqual(2, ISizeQuota(user_folder).get_usage()) # changes to foreign user folders should never affect our user folder with self.assert_usage_change(user_folder, 0, 'create and fill foreign user folder'): john_doe = create(Builder('user').named('John', 'Deo') .with_roles('Contributor', 'Editor', 'Reader')) login(self.portal, john_doe.getId()) other_user_folder = create_members_folder(user_root) other_user_dossier = create(Builder('dossier').within( other_user_folder)) create(Builder('document') .attach_file_containing('XXX') .within(other_user_dossier)) login(self.portal, TEST_USER_NAME) with self.assert_usage_change(user_folder, 0, 'recalculate without change'): ISizeQuota(user_folder).get_usage_map( for_writing=True)['purge-me'] = 999 ISizeQuota(user_folder).recalculate()
def is_untrash_document_available(self): trasher = ITrashable(self.context) return trasher.verify_may_untrash(raise_on_violations=False)