def handleCancelCheckout(event): lockable = ILockable(event.object) if lockable.locked(): # unlock working copy if it was auto-locked, or this will fail lockable.clear_locks() lock.unlockContext(event.baseline) event.baseline.reindexObject(idxs=['review_state'])
def delete_unwanted_objects_from_memberfolder(portal,memberfolder,logger): ct = getToolByName(portal,'portal_catalog') strURL = "/".join(memberfolder.getPhysicalPath()) query = {'path':{'query':strURL},'portal_type':('Space','RecycleBin')} objMemSpaces = [b.getObject() for b in ct(query)] for o in objMemSpaces: if callable(o.id): o_id = o.id() else: o_id = o.id try: from plone.locking.interfaces import ILockable lockable = ILockable(o) was_locked = False if lockable.locked(): was_locked = True lockable.unlock() parentItem = o.getParentNode() parentItem.manage_delObjects(ids=[o_id]) transaction.savepoint() except ComponentLookupError: pass logger.info("Deleted %s object from %s member folder." % (o_id, memberfolder.getId(),)) transaction.savepoint()
def test_lockinfo_tile(self): self.other_browser.open( self.pageURL + '/@@plone.app.standardtiles.lockinfo' ) self.assertIn('plone-lock-status', self.other_browser.contents) root = fromstring(self.other_browser.contents) nodes = root.xpath('//body//*[@id="plone-lock-status"]') self.assertEqual(len(nodes), 1) self.assertEqual(0, len(nodes[0].getchildren())) # Then lock the page: lockable = ILockable(self.page) lockable.lock() transaction.commit() # The tile will show them: self.other_browser.open( self.pageURL + '/@@plone.app.standardtiles.lockinfo' ) self.assertIn('plone-lock-status', self.other_browser.contents) root = fromstring(self.other_browser.contents) nodes = root.xpath('//body//*[@id="plone-lock-status"]') self.assertEqual(len(nodes), 1) self.assertGreaterEqual(len(nodes[0].getchildren()), 1)
def test_decide_agenda_item_creates_locked_excerpt_in_dossier(self, browser): self.setup_excerpt_template() proposal = self.setup_proposal() # schedule view = 'unscheduled_proposals/{}/schedule'.format( proposal.load_model().proposal_id) browser.login().open(self.meeting_wrapper, view=view) agenda_item = AgendaItem.query.first() browser.login().open( self.meeting_wrapper, view='agenda_items/{}/decide'.format(agenda_item.agenda_item_id), data={'_authenticator': createToken()}) agenda_item = AgendaItem.query.first() # refresh proposal = agenda_item.proposal excerpt_in_dossier = proposal.excerpt_document.resolve_document() lockable = ILockable(excerpt_in_dossier) self.assertTrue(lockable.locked()) self.assertTrue(lockable.can_safely_unlock(MEETING_EXCERPT_LOCK)) browser.open(excerpt_in_dossier) self.assertEqual(u'This document is a copy of the excerpt Fooo - ' u'C\xf6mmunity meeting from the meeting C\xf6mmunity ' u'meeting and cannot be edited directly.', info_messages()[0]) message_links = browser.css('.portalMessage.info a') self.assertEqual( 'http://nohost/plone/opengever-meeting-committeecontainer/committee-1/submitted-proposal-1/document-3', message_links[0].get('href')) self.assertEqual( 'http://nohost/plone/opengever-meeting-committeecontainer/committee-1/meeting-1/view', message_links[1].get('href'))
def test_submit_additional_document_creates_new_locked_document(self): committee = create(Builder('committee').titled('My committee')) document = create(Builder('document') .within(self.dossier) .titled(u'A Document') .with_dummy_content()) proposal = create(Builder('proposal') .within(self.dossier) .titled(u'My Proposal') .as_submitted() .having(committee=committee.load_model())) proposal.submit_additional_document(document) submitted_proposal = api.portal.get().restrictedTraverse( proposal.load_model().submitted_physical_path.encode('utf-8')) docs = submitted_proposal.listFolderContents() self.assertEqual(1, len(docs)) submitted_document = docs.pop() self.assertEqual(document.Title(), submitted_document.Title()) self.assertEqual(document.file.filename, submitted_document.file.filename) # submitted document should be locked by custom lock lockable = ILockable(submitted_document) self.assertTrue(lockable.locked()) self.assertTrue(lockable.can_safely_unlock(MEETING_SUBMITTED_LOCK)) self.assertSubmittedDocumentCreated(proposal, document, submitted_document)
def test_locked_is_false_if_lock_is_invalid(self): create(Builder('lock') .of_obj(self.wrapper) .having(time=utcnow_tz_aware() - timedelta(seconds=800))) lockable = ILockable(self.wrapper) self.assertFalse(lockable.locked())
def migrate(self, unittest=0): """Migrates the object """ beforeChange, afterChange = self.getMigrationMethods() lockable = ILockable(self.old, None) if lockable and lockable.locked(): lockable.unlock() for method in beforeChange: __traceback_info__ = (self, method, self.old, self.orig_id) # may raise an exception, catch it later method() # preserve position on rename self.need_order = IOrderedContainer.providedBy(self.parent) if self.need_order: self._position = self.parent.getObjectPosition(self.orig_id) self.renameOld() self.createNew() for method in afterChange: __traceback_info__ = (self, method, self.old, self.orig_id) # may raise an exception, catch it later method() self.reorder() self.remove()
def is_locked_by_another_user(self): """Return False if the document is locked by the current user or is not locked at all, True otherwise. """ lockable = ILockable(self.context) return not lockable.can_safely_unlock()
def safe_unlock(self, redirect=True): """Unlock the object if the current user has the lock """ lockable = ILockable(self.context) if lockable.can_safely_unlock(): lockable.unlock() if redirect: self.redirect()
def test_lockinfo_is_visible_for_lock_owner(self, browser): self.login(self.regular_user, browser=browser) browser.open(self.document) self.assertEquals([], info_messages()) lockable = ILockable(self.document) lockable.lock() browser.open(self.document) self.assertEquals([self.lock_message], info_messages())
def is_available_for_current_user(self): """Check whether the current meeting can be safely unlocked. This means the current meeting is not locked by another user. """ lockable = ILockable(self.context) return lockable.can_safely_unlock()
def testLockedItem(self): membership_tool = getToolByName(self.folder, 'portal_membership') membership_tool.addMember('anotherMember', 'secret', ['Member'], []) locking = ILockable(self.folder.doc1) locking.lock() self.login('anotherMember') actions = self.menu.getMenuItems(self.folder.doc1, self.request) self.assertEqual(len(actions), 0)
def is_locked_for_current_user(self): """True if this object is locked for the current user (i.e. the current user is not the lock owner) """ lockable = ILockable(aq_inner(self.context)) # Faster version - we rely on the fact that can_safely_unlock() is # True even if the object is not locked return not lockable.can_safely_unlock()
def test_unlock_button_is_visible_for_manager(self, browser): self.login(self.regular_user, browser=browser) browser.open(self.document) self.assertEquals([], info_messages()) lockable = ILockable(self.document) lockable.lock() self.login(self.manager, browser=browser) browser.open(self.document) self.assertEquals([self.lock_message + self.unlock_message], info_messages())
def test_refresh_locks_update_locks_to_current_time(self): lockable = ILockable(self.wrapper) lockable.lock() with freeze(pytz.UTC.localize(datetime(2015, 03, 10, 12, 05))): lockable.refresh_lock() lock = Lock.query.one() self.assertEqual( pytz.UTC.localize(datetime(2015, 03, 10, 12, 05)), lock.time)
def force_unlock(self, redirect=True): """Steal the lock. If redirect is True, redirect back to the context URL, i.e. reload the page. """ lockable = ILockable(self.context) lockable.unlock() if redirect: self.redirect()
def force_unlock(self, redirect=True): """Steal the lock. If redirect is True, redirect back to the context URL, i.e. reload the page. """ lockable = ILockable(self.context) lockable.unlock() if redirect: self.request.RESPONSE.redirect(self.context.absolute_url())
def step1andstep2(self): """Explore the site's content searching for misplaced content and move it to its nearest translated parent. """ portal = getSite() output = [] # Step 1 - Audit the content tree and make a list with the candidates # to be moved to the right RLF. Once we get a candidate, decide if it # should be moved to its nearest parent with the same language. Trying # to avoid the catalog in order to avoid problems with big sites and # bad or corrupted catalogs. self.content_tree = [] self.findContent(portal, 0) logger.info("Step 1: Eligible content: %s" % self.content_tree) # We now have a list of lists that maps each eligible content with its # depth in the content tree # Step 2 - Move the eligible content to its nearest translated parent # from the most deepest located content to the outer ones self.content_tree.reverse() for depth in self.content_tree: if depth != []: for content in depth: parent = aq_parent(content) target_folder = self.searchNearestTranslatedParent(content) # Test if the id already exist previously try: cutted = parent.manage_cutObjects(content.getId()) except ResourceLockedError: lockable = ILockable(content) lockable.unlock() cutted = parent.manage_cutObjects(content.getId()) try: target_folder.manage_pasteObjects(cutted) info_str = "Step 2: Moved object %s to folder %s" % ( '/'.join(content.getPhysicalPath()), '/'.join(target_folder.getPhysicalPath())) log = logger.info except Exception as err: info_str = "ERROR. Step 2: not possible to move " \ "object %s to folder %s. Error: %s" % ( '/'.join(content.getPhysicalPath()), '/'.join(target_folder.getPhysicalPath()), err) log = logger.error log(info_str) output.append(info_str) logger.info('Finished step 2') return output
def begin(self, formname, fieldname, structure='false'): """Begin inline editing - find the widget for the given field name in the given form (looked up as a view on the context), then hide the block with the id '${fieldname}-display' and display an edit form in its place. If 'structure' is 'true' (a string), then the inline editable field will eventually permit HTML input to be rendered unescaped. """ context = aq_inner(self.context) request = aq_inner(self.request) form = getMultiAdapter((context, request), name=formname) form = form.__of__(context) if fieldname.startswith(form.prefix): fieldname = fieldname[len(form.prefix)+1:] formlib_field = form.form_fields[fieldname] widgets = formlib.setUpEditWidgets((formlib_field,), form.prefix, context, request, ignore_request=True) widget = widgets[fieldname] display_id = '%s-display' % fieldname form_id = '%s-form' % fieldname ksscore = self.getCommandSet('core') zopecommands = self.getCommandSet('zope') plonecommands = self.getCommandSet('plone') # lock the context (or issue warning) locking = ILockable(context, None) if locking: if not locking.can_safely_unlock(): selector = ksscore.getHtmlIdSelector('plone-lock-status') zopecommands.refreshViewlet(selector, 'plone.abovecontent', 'plone.lockinfo') plonecommands.refreshContentMenu() return else: # we are locking the content locking.lock() plonecommands.issuePortalMessage('') # hide the existing display field display_selector = ksscore.getHtmlIdSelector(display_id) ksscore.addClass(display_selector, 'hiddenStructure') # show the form form_html = self.form_template(widget=widget, form_id=form_id, fieldname=fieldname, structure=structure) ksscore.insertHTMLAfter(display_selector, form_html)
def step1andstep2(self): """Explore the site's content searching for misplaced content and move it to its nearest translated parent. """ portal = getSite() output = [] # Step 1 - Audit the content tree and make a list with the candidates # to be moved to the right RLF. Once we get a candidate, decide if it # should be moved to its nearest parent with the same language. Trying # to avoid the catalog in order to avoid problems with big sites and # bad or corrupted catalogs. self.content_tree = [] self.findContent(portal, 0) logger.info("Step 1: Eligible content: %s" % self.content_tree) # We now have a list of lists that maps each eligible content with its # depth in the content tree # Step 2 - Move the eligible content to its nearest translated parent # from the most deepest located content to the outer ones self.content_tree.reverse() for depth in self.content_tree: if depth != []: for content in depth: parent = aq_parent(content) target_folder = self.searchNearestTranslatedParent(content) # Test if the id already exist previously try: cutted = parent.manage_cutObjects(content.getId()) except ResourceLockedError: lockable = ILockable(content) lockable.unlock() cutted = parent.manage_cutObjects(content.getId()) try: target_folder.manage_pasteObjects(cutted) info_str = "Step 2: Moved object %s to folder %s" % ( '/'.join(content.getPhysicalPath()), '/'.join( target_folder.getPhysicalPath())) log = logger.info except Exception as err: info_str = "ERROR. Step 2: not possible to move " \ "object %s to folder %s. Error: %s" % ( '/'.join(content.getPhysicalPath()), '/'.join(target_folder.getPhysicalPath()), err) log = logger.error log(info_str) output.append(info_str) logger.info('Finished step 2') return output
def step3(self): """Move the existing site content to its correspondent RLF. """ portal = getSite() pc = getToolByName(portal, "portal_catalog") pl = getToolByName(portal, "portal_languages") supported_langs = pl.getSupportedLanguages() output = [] # Step 3: Move all the remaining content to its correspondent RLFs for lang in supported_langs: RLF_id = "%s" % lang folder = getattr(portal, RLF_id, None) if not folder: raise AttributeError("One of the root language folder are \ missing. Check the site's language \ setup.") path = '/'.join(portal.getPhysicalPath()) objects = pc.searchResults(path={ 'query': path, 'depth': 1 }, sort_on='getObjPositionInParent', Language=lang) for brain in objects: if brain.id != lang: old_path = brain.getPath() try: cutted = self.context.manage_cutObjects(brain.id) except ResourceLockedError: content = brain.getObject() lockable = ILockable(content) lockable.unlock() cutted = self.context.manage_cutObjects(brain.id) try: folder.manage_pasteObjects(cutted) info_str = "Moved object %s to language root folder "\ "%s" % (old_path, lang) log = logger.info except Exception as err: info_str = "ERROR. Step 3: not possible to move "\ "object %s to root language folder %s. Error: %s"\ % (old_path, lang, err) log = logger.error log(info_str) output.append(info_str) logger.info('Finished step 3') return output
def unlockPerson(self): obj = self.context.aq_inner try: from plone.locking.interfaces import ILockable HAS_LOCKING = True except ImportError: HAS_LOCKING = False if HAS_LOCKING: lockable = ILockable(obj) if lockable.locked(): lockable.unlock() return self.render()
def testLockedItem(self): if self.is_dx: # dexterity has no locking ootb # see https://github.com/plone/plone.app.contenttypes/issues/140 return membership_tool = getToolByName(self.folder, 'portal_membership') membership_tool.addMember('anotherMember', 'secret', ['Member'], []) locking = ILockable(self.folder.doc1) locking.lock() login(self.portal, 'anotherMember') actions = self.menu.getMenuItems(self.folder.doc1, self.request) self.assertEqual(len(actions), 0)
def test_protocol_document_is_unlocked_when_meeting_is_closed(self, browser): self.setup_generated_protocol(browser) browser.find('Close meeting').click() browser.open(self.meeting.get_url()) browser.find('Protocol-My meeting').click() document = browser.context lockable = ILockable(document) self.assertFalse(lockable.locked())
def test_update_locked_object_with_token_succeeds(self): lockable = ILockable(self.doc) lockable.lock() transaction.commit() response = self.api_session.patch( "/", headers={"Lock-Token": lockable.lock_info()[0]["token"]}, json={"title": "New Title"}, ) transaction.commit() self.assertEqual(response.status_code, 204) self.assertEqual(self.doc.Title(), "New Title")
def test_protocol_document_is_unlocked_when_meeting_is_closed( self, browser): self.setup_generated_protocol(browser) browser.find('Close meeting').click() browser.open(self.meeting.get_url()) browser.find('Protocol-My meeting').click() document = browser.context lockable = ILockable(document) self.assertFalse(lockable.locked())
def action(self, obj): parent = obj.aq_inner.aq_parent lockable = ILockable(obj, None) if lockable and lockable.locked(): lockable.clear_locks() try: parent.manage_delObjects(obj.getId(), self.request) except Unauthorized: self.errors.append( _(u'You are not authorized to delete ${title}.', mapping={u'title': self.objectTitle(self.dest)}))
def test_protocol_document_is_locked_by_system_once_generated(self, browser): self.setup_generated_protocol(browser) browser.find('Protocol-My meeting').click() document = browser.context lockable = ILockable(document) self.assertTrue(lockable.locked()) self.assertTrue(lockable.can_safely_unlock(SYS_LOCK)) self.assertFalse(lockable.can_safely_unlock(STEALABLE_LOCK)) lock_info = lockable.lock_info()[0] self.assertEqual(u'sys.lock', lock_info['type'].__name__)
def test_atct_not_lockable(self): portal = self.layer['portal'] setRoles(portal, TEST_USER_ID, ['Contributor']) portal.invokeFactory('Document', 'adoc', title='A title', description='Some description', text='Some text') doc = portal['adoc'] lockable = ILockable(doc) self.assertEqual(False, lockable.locked()) lockable.lock() self.assertEqual(False, lockable.locked())
def test_force_unlock_clears_lock(self, browser): self.login(self.regular_user, browser) oc_url = self.fetch_document_checkout_oc_url(browser, self.document) tokens = self.validate_checkout_token(self.regular_user, oc_url, self.document) lockable = ILockable(self.document) self.lock_document(browser, tokens, self.document) self.assertTrue(lockable.locked()) self.login(self.manager, browser) browser.open(self.document) browser.click_on("Unlock") self.assertFalse(lockable.locked())
def step3(self): """Move the existing site content to its correspondent RLF. """ portal = getSite() pc = getToolByName(portal, "portal_catalog") pl = getToolByName(portal, "portal_languages") supported_langs = pl.getSupportedLanguages() output = [] # Step 3: Move all the remaining content to its correspondent RLFs for lang in supported_langs: RLF_id = "%s" % lang folder = getattr(portal, RLF_id, None) if not folder: raise AttributeError("One of the root language folder are \ missing. Check the site's language \ setup.") path = '/'.join(portal.getPhysicalPath()) objects = pc.searchResults(path={'query': path, 'depth': 1}, sort_on='getObjPositionInParent', Language=lang) for brain in objects: if brain.id != lang: old_path = brain.getPath() try: cutted = self.context.manage_cutObjects(brain.id) except ResourceLockedError: content = brain.getObject() lockable = ILockable(content) lockable.unlock() cutted = self.context.manage_cutObjects(brain.id) try: folder.manage_pasteObjects(cutted) info_str = "Moved object %s to language root folder "\ "%s" % (old_path, lang) log = logger.info except Exception as err: info_str = "ERROR. Step 3: not possible to move "\ "object %s to root language folder %s. Error: %s"\ % (old_path, lang, err) log = logger.error log(info_str) output.append(info_str) logger.info('Finished step 3') return output
def remove_spacesobject_fromsite(portal,logger): from plone.app.linkintegrity.interfaces import ILinkIntegrityNotificationException portal_properties=getToolByName(portal, 'portal_properties') is_link_integrity = portal_properties.site_properties.enable_link_integrity_checks if is_link_integrity: portal_properties.site_properties.manage_changeProperties(enable_link_integrity_checks=False) spaces = None try: spaces = getToolByName(portal,'spaces') if spaces.portal_type != 'SpacesFolder': spaces = None except AttributeError: pass spacesid = 'spaces' try: if spaces <> None: if callable(spaces.id): o_id = spaces.id() else: o_id = spaces.id spacesid = o_id from plone.locking.interfaces import ILockable lockable = ILockable(spaces) was_locked = False if lockable.locked(): was_locked = True lockable.unlock() portal.manage_delObjects(ids=[o_id]) logger.info("Deleted spaces object from site.") transaction.savepoint() except ILinkIntegrityNotificationException: pass recyclebin = getToolByName(portal,'recyclebin') if recyclebin <> None: try: objspaces = getattr(portal,spacesid) if objspaces.portal_type == 'SpacesFolder': from plone.locking.interfaces import ILockable lockable = ILockable(objspaces) was_locked = False if lockable.locked(): was_locked = True lockable.unlock() recyclebin.manage_delObjects(ids=[spacesid]) logger.info("Deleting spaces object from global recyclebin.") except AttributeError: pass if is_link_integrity: portal_properties.site_properties.manage_changeProperties(enable_link_integrity_checks=True)
def test_clear_locks_remove_all_locks_on_the_object(self): lockable = ILockable(self.wrapper) lockable.lock() self.assertTrue(lockable.locked()) lockable.clear_locks() self.assertFalse(lockable.locked())
def is_locked(obj, request): """Returns true if the object is locked and the request doesn't contain the lock token. """ lockable = ILockable(obj, None) if lockable is None: return False if lockable.locked(): token = request.getHeader("Lock-Token", "") lock_info = lockable.lock_info() if len(lock_info) > 0 and lock_info[0]["token"] == token: return False return True return False
def reply(self): lockable = ILockable(self.context) if lockable.can_safely_unlock(): lockable.unlock() if INonStealableLock.providedBy(self.context): noLongerProvides(self.context, INonStealableLock) # Disable CSRF protection if "IDisableCSRFProtection" in dir(plone.protect.interfaces): alsoProvides(self.request, plone.protect.interfaces.IDisableCSRFProtection) return lock_info(self.context)
def test_can_safely_unlock_is_true_if_a_lock_of_the_current_user_exists( self): lock = create( Builder('lock').of_obj( self.wrapper).having(lock_type=u'plone.locking.stealable')) self.assertTrue(ILockable(self.wrapper).can_safely_unlock())
def test_lock_info_returns_an_list_of_dicts_of_all_valid_locks(self): # valid lock1 = create(Builder('lock') .of_obj(self.wrapper) .having(time=utcnow_tz_aware() - timedelta(seconds=100))) self.assertEquals( [{'creator': TEST_USER_ID, 'time': lock1.time, 'token': 'Meeting:1', 'type': STEALABLE_LOCK}], ILockable(self.wrapper).lock_info()) # invalid lock1.time = utcnow_tz_aware() - timedelta(seconds=800) self.assertEquals([], ILockable(self.wrapper).lock_info())
def test_delete_confirmation_if_locked(self): folder = self.portal['f1'] lockable = ILockable.providedBy(folder) form = getMultiAdapter( (folder, self.request), name='delete_confirmation') form.update() self.assertFalse(form.is_locked) if lockable: lockable.lock() form = getMultiAdapter( (folder, self.request), name='delete_confirmation') form.update() self.assertFalse(form.is_locked) # After switching the user it should not be possible to delete the # object. Of course this is only possible if our context provides # ILockable interface. if lockable: logout() login(self.portal, 'editor') form = getMultiAdapter( (folder, self.request), name='delete_confirmation') form.update() self.assertTrue(form.is_locked) logout() login(self.portal, TEST_USER_NAME) ILockable(folder).unlock()
def do_action(self): if is_locked(self): # force unlock before delete... lockable = ILockable(self.context) lockable.clear_locks() try: self.parent.manage_cutObjects(self.context.getId(), self.request) except CopyError: return self.do_redirect( self.view_url, _(u'${title} is not moveable.', mapping={'title': self.title})) return self.do_redirect( self.view_url, _(u'${title} cut.', mapping={'title': self.title}), 'info')
def test_is_locked(self): self.assertEquals(self.dview.is_locked(), False) ILockable(self.folder.d1).lock() self.logout( ) # The object is not "locked" if it was locked by the current user del self.app.REQUEST.__annotations__ self.assertEquals(self.dview.is_locked(), True)
def test_logged_in_locked_icon_is_locked(self): viewlet = self._get_viewlet() ILockable(self.context).lock() lockIconUrl = '<img src="http://nohost/plone/lock_icon.png" alt="" \ title="Locked" height="16" width="16" />' self.assertEqual(viewlet.locked_icon(), lockIconUrl)
def kss_obj_delete(self, selector='.kssDeletionRegion'): obj = self.context.aq_inner if obj.getPortalTypeName() == 'Discussion Item': parent = obj.inReplyTo() if parent is not None: portal_discussion = getUtility(IDiscussionTool) talkback = portal_discussion.getDiscussionFor(parent) else: talkback = obj.aq_parent # remove the discussion item talkback.deleteReply(str(obj.getId())) else: # 被锁定时先解锁 if HAS_LOCKING: lockable = ILockable(obj) if lockable.locked(): lockable.unlock() parent = obj.aq_parent # archetypes的manage_delObjects会检查每个item的删除权限 originalSecurityManager = SecurityManagement.getSecurityManager() SecurityManagement.newSecurityManager( None, User.SimpleUser('admin', '', ('Manager', ), '')) parent.manage_delObjects(str(obj.getId())) SecurityManagement.setSecurityManager(originalSecurityManager) if selector.startswith('redirect2'): # 跳转到某个地址 # 需要定义 # class="kssattr-delSelector-redirect2http://test.everydo.com" redirect2url = selector[len('redirect2'):] self.getCommandSet('zopen').redirect(url=redirect2url) else: core = self.getCommandSet('core') effects = self.getCommandSet('effects') selector = core.getParentNodeSelector(selector) # effects.effect(selector, 'fade') core.deleteNode(selector) self.getCommandSet('plone').issuePortalMessage( translate(_(u'Deleted.'), default="Deleted.", context=self.request), translate(_(u'Info'), default="Info", context=self.request)) return self.render()
def xmChangeWorkflowState(self, uid, url): """Change the workflow state, currently only of a Task.""" context = aq_inner(self.context) ksscore = self.getCommandSet('core') zopecommands = self.getCommandSet('zope') plonecommands = self.getCommandSet('plone') locking = ILockable(context, None) if locking is not None and not locking.can_safely_unlock(): selector = ksscore.getHtmlIdSelector('plone-lock-status') zopecommands.refreshViewlet(selector, 'plone.abovecontent', 'plone.lockinfo') plonecommands.refreshContentMenu() return self.render() (proto, host, path, query, anchor) = urlsplit(url) if not path.endswith('content_status_modify'): raise KSSExplicitError('only content_status_modify is handled') action = query.split("workflow_action=")[-1].split('&')[0] uid_catalog = getToolByName(context, 'uid_catalog') brain = uid_catalog(UID=uid)[0] obj = brain.getObject() # This may give a UnicodeDecodeError if the title has # non-ascii characters: # obj.content_status_modify(action) # So we do it manually, which is better anyway: wftool = getToolByName(context, 'portal_workflow') wftool.doActionFor(obj, action=action) if IXMStory.providedBy(self.context): # Only refresh content if the context is a Story, # otherwise you get too much tasks listed. selector = ksscore.getCssSelector('.contentViews') zopecommands.refreshViewlet(selector, 'plone.contentviews', 'plone.contentviews') zopecommands.refreshProvider('.tasklist_table', 'xm.tasklist.simple') plonecommands.refreshContentMenu() else: # In all other cases, we can at least refresh the part # that shows the workflow info for this item. wf_change = obj.restrictedTraverse('xm_workflow_change') html = wf_change() selector = ksscore.getHtmlIdSelector('id-%s' % uid) ksscore.replaceHTML(selector, html) self.issueAllPortalMessages() self.cancelRedirect()
def lock_info(obj): """Returns lock information about the given object.""" lockable = ILockable(obj, None) if lockable is not None: info = {"locked": lockable.locked(), "stealable": lockable.stealable()} lock_info = lockable.lock_info() if len(lock_info) > 0: info["creator"] = lock_info[0]["creator"] info["time"] = lock_info[0]["time"] info["token"] = lock_info[0]["token"] lock_type = lock_info[0]["type"] if lock_type: info["name"] = lock_info[0]["type"].__name__ lock_item = webdav_lock(obj) if lock_item: info["timeout"] = lock_item.getTimeout() return info
def force_unlock(self, redirect=True): """Steal the lock. If redirect is True, redirect back to the context URL, i.e. reload the page. """ lockable = ILockable(self.context) lockable.unlock() if redirect: url = self.context.absolute_url() props_tool = getToolByName(self.context, 'portal_properties') if props_tool: types_use_view = props_tool.site_properties.typesUseViewActionInListings if self.context.portal_type in types_use_view: url += '/view' self.request.RESPONSE.redirect(url)
def force_unlock(self, redirect=True): """Steal the lock. If redirect is True, redirect back to the context URL, i.e. reload the page. """ lockable = ILockable(self.context) lockable.unlock() if redirect: url = self.context.absolute_url() registry = getUtility(IRegistry) types_use_view = registry.get( 'plone.types_use_view_action_in_listings', []) if self.context.portal_type in types_use_view: url += '/view' self.request.RESPONSE.redirect(url)
def addTranslation(self, language, *args, **kwargs): """Adds a translation.""" canonical = self.getCanonical() parent = aq_parent(aq_inner(self)) if ITranslatable.providedBy(parent): parent = parent.getTranslation(language) or parent if self.hasTranslation(language): translation = self.getTranslation(language) raise AlreadyTranslated, translation.absolute_url() id = canonical.getId() while not parent.checkIdAvailable(id): id = '%s-%s' % (id, language) kwargs[config.KWARGS_TRANSLATION_KEY] = canonical if kwargs.get('language', None) != language: kwargs['language'] = language o = _createObjectByType(self.portal_type, parent, id, *args, **kwargs) # If there is a custom factory method that doesn't add the # translation relationship, make sure it is done now. if o.getCanonical() != canonical: o.addTranslationReference(canonical) self.invalidateTranslationCache() # Copy over the language independent fields schema = canonical.Schema() independent_fields = schema.filterFields(languageIndependent=True) for field in independent_fields: accessor = field.getEditAccessor(canonical) if not accessor: accessor = field.getAccessor(canonical) data = accessor() translation_mutator = getattr(o, field.translation_mutator) translation_mutator(data) # If this is a folder, move translated subobjects aswell. if self.isPrincipiaFolderish: moveids = [] for obj in self.objectValues(): if ITranslatable.providedBy(obj) and \ obj.getLanguage() == language: lockable = ILockable(obj, None) if lockable is not None and lockable.can_safely_unlock(): lockable.unlock() moveids.append(obj.getId()) if moveids: o.manage_pasteObjects(self.manage_cutObjects(moveids)) o.reindexObject() if isDefaultPage(canonical, self.REQUEST): o._lp_default_page = True
def test_getLink_caching_showIcons(self): """Cache takes the 'showIcons' parameter into account.""" adapted = IPrettyLink(self.folder) self.assertTrue(adapted.showIcons) ILockable(self.folder).lock() self.assertTrue(u"lock_icon.png" in adapted.getLink()) adapted.showIcons = False self.assertFalse(u"lock_icon.png" in adapted.getLink())
def _set_id(self, value): """ """ context = aq_inner(self.context) parent = aq_parent(context) if not value: # plone.dexterity.fti.DexterityFTI factory_info = context.getTypeInfo() new_id = generate_content_id(factory_info.getId()) # else add prefix/suffix with user provided value? else: new_id = value if parent is None: # Object hasn't been added to graph yet; just set directly context.id = value return if getattr(aq_base(context), 'id', None): transaction.savepoint() locked = False lockable = ILockable(context, None) if lockable is not None and lockable.locked(): locked = True lockable.unlock() parent.manage_renameObject(context.getId(), new_id) if locked: lockable.lock() else: context.id = new_id
def delete(self): obj = self.get_by_uid(self.request.get('uid')) lockable = ILockable(obj, None) if lockable and lockable.locked(): lockable.clear_locks() try: api.content.delete(obj) api.portal.show_message( 'Successfully deleted "%s" located at: %s' % (unidecode(obj.Title()), self.get_path(obj)), self.request, type='warning') except LinkIntegrityNotificationException: api.portal.show_message( 'Can not delete "%s" located at: %s because it is still linked.' % (unidecode(obj.Title()), self.get_path(obj)), self.request, type='warning')
def test_submit_additional_document(self): self.login(self.administrator) ori_document = self.subdocument with self.observe_children(self.submitted_proposal) as children: with self.login(self.dossier_responsible): self.proposal.submit_additional_document(ori_document) self.assertEquals(1, len(children['added'])) submitted_document, = children['added'] self.assertEqual(ori_document.Title(), submitted_document.Title()) self.assertEqual(ori_document.file.filename, submitted_document.file.filename) self.assertSubmittedDocumentCreated(self.proposal, ori_document) # submitted document should be locked by custom lock lockable = ILockable(submitted_document) self.assertTrue(lockable.locked()) self.assertFalse(lockable.can_safely_unlock(MEETING_SUBMITTED_LOCK))
def update(self): if (getattr(self.context, "collective_immediatecreate", None) != "initial" # noqa: W503 ): url = self.context.absolute_url() + "/edit" url = addTokenToUrl(url) raise Redirect(url) self.portal_type = self.context.portal_type if ILocking.providedBy(self.context): lockable = ILockable(self.context) if lockable.locked(): lockable.unlock() super().update() # fire the edit begun only if no action was executed if len(self.actions.executedActions) == 0: notify(EditBegunEvent(self.context))
def lock_info(self): """Get information about the current lock, a dict containing: creator - the id of the user who created the lock fullname - the full name of the lock creator author_page - a link to the home page of the author time - the creation time of the lock time_difference - a string representing the time since the lock was acquired. """ portal_membership = getToolByName(self.context, 'portal_membership') portal_url = getToolByName(self.context, 'portal_url') lockable = ILockable(aq_inner(self.context)) url = portal_url() for info in lockable.lock_info(): creator = info['creator'] time = info['time'] token = info['token'] lock_type = info['type'] # Get the fullname, but remember that the creator may not # be a member, but only Authenticated or even anonymous. # Same for the author_page fullname = '' author_page = '' member = portal_membership.getMemberById(creator) if member: fullname = member.getProperty('fullname', '') author_page = "%s/author/%s" % (url, creator) if fullname == '': fullname = creator or _('label_an_anonymous_user', u'an anonymous user') time_difference = self._getNiceTimeDifference(time) return { 'creator': creator, 'fullname': fullname, 'author_page': author_page, 'time': time, 'time_difference': time_difference, 'token': token, 'type': lock_type, }
def test_lock_creation_removes_expired_locks_for_same_object(self): expired_lock = create( Builder('lock').of_obj(self.wrapper).having( time=utcnow_tz_aware() - timedelta(seconds=1000))) ILockable(self.wrapper).lock() locks = Lock.query.all() self.assertEquals(1, len(locks)) self.assertNotIn(expired_lock, locks)
def test_database_entry_is_deleted_when_removing_submitted_proposal(self): self.login(self.manager) submitted_document = self.submitted_proposal.get_documents()[0] self.assertIsNotNone( SubmittedDocument.query.get_by_target(submitted_document)) # Submitted proposals are locked with an unstealable lock ILockable(submitted_document).clear_locks() api.content.delete(submitted_document) self.assertIsNone( SubmittedDocument.query.get_by_target(submitted_document))
def empty(self): for item in [ i for i in self.catalog(trashed=True, object_provides=ITrashed.__identifier__) ]: obj = item.getObject() lockable = ILockable(obj, None) if lockable and lockable.locked(): lockable.clear_locks() try: api.content.delete(obj, check_linkintegrity=False) except LinkIntegrityNotificationException: # could be a folder that has been deleted api.portal.show_message( 'Some content could not be removed because it is still linked ' 'to other content on the site.', self.request, type='warning') api.portal.show_message('Trash emptied', self.request, type='warning')