def _enableField(self, field_names, cfg=None, related_to='MeetingItem', enable=True, reload=False): """ """ if not hasattr(field_names, "__iter__"): field_names = [field_names] cfg = cfg or self.meetingConfig for field_name in field_names: if related_to == 'MeetingItem': usedItemAttrs = list(cfg.getUsedItemAttributes()) if enable and field_name not in usedItemAttrs: usedItemAttrs.append(field_name) elif not enable and field_name in usedItemAttrs: usedItemAttrs.remove(field_name) cfg.setUsedItemAttributes(usedItemAttrs) elif related_to == 'Meeting': usedMeetingAttrs = list(cfg.getUsedMeetingAttributes()) if enable and field_name not in usedMeetingAttrs: usedMeetingAttrs.append(field_name) elif not enable and field_name in usedMeetingAttrs: usedMeetingAttrs.remove(field_name) cfg.setUsedMeetingAttributes(tuple(usedMeetingAttrs)) if reload: currentUser = self.member.getId() self.changeUser('siteadmin') cfg.at_post_edit_script() self.changeUser(currentUser) else: cleanRamCacheFor('Products.PloneMeeting.MeetingItem.attribute_is_used') cleanRamCacheFor('Products.PloneMeeting.content.meeting.attribute_is_used')
def test_getMeetingsAcceptingItems(self): """ For 'meeting-config-council', meetings in state 'in_committee', 'in_council' are also accepting items. """ cfg2 = self.meetingConfig2 self.changeUser("pmManager") self.setMeetingConfig(cfg2.getId()) meeting = self.create("Meeting", date=DateTime("2016/10/04")) # created, available for everyone self.assertEqual(meeting.queryState(), "created") self.assertEqual( [brain.UID for brain in cfg2.getMeetingsAcceptingItems()], [meeting.UID()]) self.changeUser("pmCreator1") self.assertEqual( [brain.UID for brain in cfg2.getMeetingsAcceptingItems()], [meeting.UID()]) # in_committee self.changeUser("pmManager") self.do(meeting, "setInCommittee") self.assertEqual(meeting.queryState(), "in_committee") self.assertEqual( [brain.UID for brain in cfg2.getMeetingsAcceptingItems()], [meeting.UID()]) cleanRamCacheFor( "Products.PloneMeeting.MeetingConfig.getMeetingsAcceptingItems") self.changeUser("pmCreator1") self.assertEqual( [brain.UID for brain in cfg2.getMeetingsAcceptingItems()], []) # in_council self.changeUser("pmManager") self.do(meeting, "setInCouncil") self.assertEqual(meeting.queryState(), "in_council") cleanRamCacheFor( "Products.PloneMeeting.MeetingConfig.getMeetingsAcceptingItems") self.assertEqual( [brain.UID for brain in cfg2.getMeetingsAcceptingItems()], [meeting.UID()]) cleanRamCacheFor( "Products.PloneMeeting.MeetingConfig.getMeetingsAcceptingItems") self.changeUser("pmCreator1") self.assertEqual( [brain.UID for brain in cfg2.getMeetingsAcceptingItems()], []) cleanRamCacheFor( "Products.PloneMeeting.MeetingConfig.getMeetingsAcceptingItems") # closed self.changeUser("pmManager") self.do(meeting, "close") self.assertEqual(meeting.queryState(), "closed") self.assertEqual( [brain.UID for brain in cfg2.getMeetingsAcceptingItems()], []) cleanRamCacheFor( "Products.PloneMeeting.MeetingConfig.getMeetingsAcceptingItems") self.changeUser("pmCreator1") self.assertEqual( [brain.UID for brain in cfg2.getMeetingsAcceptingItems()], [])
def test_ws_getItemInfosInTheNameOf(self): """ Test that getting an item inTheNameOf antother user works Create an item by 'pmCreator1', member of the 'developers' group Item will be viewable : - by 'pmManager' - while getting informations in the name of 'pmCreator1' Item will NOT be viewable : - while getting informations in the name of 'pmCreator2' that is not in the 'developers' group """ # create an item by 'pmCreator1' self.changeUser('pmCreator1') item = self.create('MeetingItem') # check first a working example the degrades it... req = getItemInfosRequest() req._inTheNameOf = None req._UID = item.UID() responseHolder = getItemInfosResponse() # 'pmCreator1' can get infos about the item result = SOAPView(self.portal, req).getItemInfosRequest(req, responseHolder) self.assertTrue(result._itemInfo[0].UID == item.UID()) # now begin, we need to be a 'MeetingManager' or 'Manager' to # getItemInfos(inTheNameOf) req._inTheNameOf = 'pmCreator1' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getItemInfosRequest(req, responseHolder) self.assertEqual( cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to get item informations 'inTheNameOf'!" ) # now has a 'MeetingManager' self.changeUser('pmManager') # a MeetingManager can get informations inTheNameOf 'pmCreator1' # and it will return relevant result as 'pmCreator1' can see the item cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') result = SOAPView(self.portal, req).getItemInfosRequest(req, responseHolder) self.assertTrue(result._itemInfo[0].UID == item.UID()) # as we switch user while using inTheNameOf, make sure we have # falled back to original user self.assertTrue(self.portal.portal_membership.getAuthenticatedMember(). getId() == 'pmManager') # as 'pmCreator2', we can not get item informations req._inTheNameOf = 'pmCreator2' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') result = SOAPView(self.portal, req).getItemInfosRequest(req, responseHolder) self.assertTrue(result._itemInfo == []) # now for an unexisting inTheNameOf userid req._inTheNameOf = 'unexistingUserId' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getItemInfosRequest(req, responseHolder) self.assertEqual( cm.exception.string, "Trying to get item informations 'inTheNameOf' an unexisting user 'unexistingUserId'!" )
def onModifyProjectSpace(obj, event): """ Handler when a projectspace is modified Update : - projects - budget globalization when projects budget states modified """ if not event.descriptions: return for desc in event.descriptions: for attr in desc.attributes: if attr == 'use_ref_number': pc = api.portal.get_tool('portal_catalog') for brain in pc(object_provides=IProject.__identifier__): brain.getObject().reindexObject( ['Title', 'sortable_title']) cleanRamCacheFor('imio.prettylink.adapters.getLink') if attr.endswith('budget_states'): if attr == 'pstaction_budget_states': obj.pstsubaction_budget_states = obj.pstaction_budget_states # we redo budget globalization if states change pc = api.portal.get_tool('portal_catalog') # first remove all brains = pc.searchResults( object_provides=IProject.__identifier__, sort_on='path', sort_order='reverse') for brain in brains: ob = brain.getObject() changed = False obj_annotations = IAnnotations(ob) for fld, AK in SUMMARIZED_FIELDS.items(): if AK in obj_annotations: changed = True del obj_annotations[AK] if changed: ob.reindexObject() # globalize again brains = pc.searchResults( object_provides=IProject.__identifier__, sort_on='path', sort_order='reverse') pw = api.portal.get_tool('portal_workflow') for brain in brains: ob = brain.getObject() if pw.getInfoFor(ob, 'review_state') in getattr( obj, '{}_budget_states'.format(ob.portal_type)): _updateSummarizedFields(ob)
def test_pm_UpdatePersonalLabels(self): """ """ # remove extra users from their groups to not break test for extra_user_id in ['pmN1', 'pmN2', 'pmSecretaire']: user = api.user.get(extra_user_id) # remove from every groups, bypass Plone groups (including virtual) for group_id in [ user_group_id for user_group_id in user.getGroups() if '_' in user_group_id ]: api.group.remove_user(groupname=group_id, username=extra_user_id) cleanRamCacheFor( 'Products.PloneMeeting.ToolPloneMeeting._users_groups_value') super(testMeetingConfig, self).test_pm_UpdatePersonalLabels()
def test_cleanRamCacheFor(self): """ This helper method invalidates ram.cache for given method. """ self.portal.REQUEST.set('ramcached', 'a') self.assertEquals(ramCachedMethod(self.portal, param='1'), 'a') # change value in REQUEST, as it is ram cached, it will still return 'a' self.portal.REQUEST.set('ramcached', 'b') self.assertEquals(ramCachedMethod(self.portal, param='1'), 'a') # ram.cache works as expected if param changes self.assertEquals(ramCachedMethod(self.portal, param='2'), 'b') # try again self.assertEquals(ramCachedMethod(self.portal, param='1'), 'a') # now clean cache, it will returns 'b' cleanRamCacheFor('imio.helpers.tests.test_cache.ramCachedMethod') self.assertEquals(ramCachedMethod(self.portal, param='1'), 'b')
def test_cleanRamCacheFor(self): """ This helper method invalidates ram.cache for given method. """ self.portal.REQUEST.set('ramcached', 'a') self.assertEquals(ramCachedMethod(self.portal, param='1'), 'a') # change value in REQUEST, as it is ram cached, it will still return 'a' self.portal.REQUEST.set('ramcached', 'b') self.assertEquals(ramCachedMethod(self.portal, param='1'), 'a') # ram.cache works as expected if param changes self.assertEquals(ramCachedMethod(self.portal, param='2'), 'b') # try again self.assertEquals(ramCachedMethod(self.portal, param='1'), 'a') # now clean cache, it will returns 'b' cleanRamCacheFor('imio.helpers.tests.test_cache.ramCachedMethod') self.assertEquals(ramCachedMethod(self.portal, param='1'), 'b')
def test_pm_FromPortletTodo(self): """While getting searches in portlet_todo, the TAL condition for searches have a 'fromPortletTodo=True', it is not the case in the portlet_plonemeeting, this way we may know that we are in portlet_todo or portlet_plonemeeting and display searches using a different condition.""" cfg = self.meetingConfig self._setup_portlets() # by default, no condition, viewable in both portlets searches = cfg.searches searchAllItems = searches.searches_items.searchallitems searchAllItems.tal_condition = '' searchAllItemsUID = searchAllItems.UID() # select 'searchallitems' in the MeetingConfig.toDoListSearches cfg.setToDoListSearches([searchAllItemsUID]) # viewable in portlet_plonemeeting self.changeUser('pmCreator1') item = self.create('MeetingItem') item_url = item.absolute_url() cleanRamCacheFor('Products.PloneMeeting.adapters.compute_criteria') self.assertTrue(searchAllItemsUID in self.portlet_pm_renderer.render()) # and viewable in portlet_todo self.request.set('load_portlet_todo', True) self.assertTrue( searchAllItemsUID in self.portlet_todo_renderer.render()) self.assertTrue(item_url in self.portlet_todo_renderer.render()) # set 'python: fromPortletTodo' as condition for a search, it will be displayed # in the portlet_todo but not in the portlet_plonemeeting searchAllItems.tal_condition = 'python: fromPortletTodo' notify(ObjectModifiedEvent(searchAllItems)) self._setup_portlets() # not viewable in portlet_plonemeeting self.assertFalse( searchAllItemsUID in self.portlet_pm_renderer.render()) # but viewable in portlet_todo self.assertTrue( searchAllItemsUID in self.portlet_todo_renderer.render()) self.assertTrue(item_url in self.portlet_todo_renderer.render())
def test_ws_canNotGetUserInfosForAnotherUser(self): """ Test that getting informations about another user is not possible except if the connected user is MeetingManager or Manager """ # any PM user can have his own informations self.changeUser('pmCreator1') req = getUserInfosRequest() req._userId = 'pmCreator2' responseHolder = getUserInfosResponse() with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getUserInfosRequest(req, responseHolder) self.assertEquals( cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to get " "user informations for another user than 'pmCreator1'!") self.changeUser('pmManager') # pmManager can get informations for another user as it is a MeetingManager cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') response = SOAPView(self.portal, req).getUserInfosRequest(req, responseHolder) self.assertTrue(response._fullname == 'M. PMCreator Two')
def test_ws_getItemTemplateRequest(self): """ Test that getting an item with a given UID and specifying that we want showTemplates returns informations about generatable POD templates """ self.changeUser('pmCreator1') self.failUnless( len(self.portal.portal_catalog(portal_type='MeetingItemPma')) == 0) # prepare data for a default item req = self._prepareCreationData() # remove unuseable catagory req._creationData._category = '' # create the item newItem, reponse = self._createItem(req) # if the user can not access the item, a ZSI Fault is raised req = getItemTemplateRequest() newItemUID = newItem.UID() req._itemUID = newItemUID responseHolder = getItemTemplateResponse() self.changeUser('pmCreator2') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getItemTemplateRequest(req, responseHolder) self.assertEquals(cm.exception.string, 'You can not access this item!') # if we try to use another template, than one available for this item, a ZSI Fault is raised self.changeUser('pmCreator1') cfg = self.tool.get(self.usedMeetingConfigId) wrongTemplate = cfg.podtemplates.agendaTemplate req._templateId = '%s__format__%s' % (wrongTemplate.getId(), 'odt') cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getItemTemplateRequest(req, responseHolder) self.assertEquals(cm.exception.string, 'You can not access this template!') # if everything is correct, we receive the rendered template req._templateId = '{0}__format__{1}'.format( cfg.podtemplates.itemTemplate.getId(), 'odt') cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') renderedTemplate = SOAPView(self.portal, req).getItemTemplateRequest( req, responseHolder) # check that the rendered file correspond to the newItem's data self._isCorrectlyRenderedTemplate(renderedTemplate, newItem) # test if PloneMeeting raise a PloneMeetingError # for example, trying to generate a PDF when Ooo is not in server mode cfg.podtemplates.itemTemplate.pod_formats = ['pdf'] cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getItemTemplateRequest(req, responseHolder) self.assertEquals( cm.exception.string, "Exception : Asked output format 'odt' is not available for template 'itemTemplate'!" )
def test_ws_checkIsLinkedRequest(self): """ Test that we can ckech that an item is linked to a given externalIdentifier even if the MeetingManager doing the can can not actually see the item... (we use unrestricted search) """ # try as a non MeetingManager self.changeUser('pmCreator1') checkIsLinkedReq = checkIsLinkedRequest() checkIsLinkedResponseHolder = checkIsLinkedResponse() with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, checkIsLinkedReq).checkIsLinkedRequest( checkIsLinkedReq, checkIsLinkedResponseHolder) self.assertEquals( cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to check if an element is linked to an item!" ) # now create an item as 'pmCreator2', aka a user in a group 'pmManager' can not access self.changeUser('pmCreator2') req = self._prepareCreationData() req._proposingGroupId = 'vendors' req._creationData._externalIdentifier = 'my-external-identifier' newItem, response = self._createItem(req) # check that using getItemInfos, MeetingManager can not get informations about created item self.changeUser('pmManager') self.failIf( self._getItemInfos(newItem.UID(), toBeDeserialized=False)._itemInfo) # but while checking if an item is linked, it works... # first check for anotherexternalIdentifier checkIsLinkedReq._meetingConfigId = None checkIsLinkedReq._externalIdentifier = 'my-unexisting-external-identifier' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') res = SOAPView(self.portal, checkIsLinkedReq).checkIsLinkedRequest( checkIsLinkedReq, checkIsLinkedResponseHolder) self.assertFalse(res._isLinked) # passing a wrong meetingConfigId will raise a ZSI.Fault # first check for anotherexternalIdentifier checkIsLinkedReq._meetingConfigId = 'wrong-meeting-config-id' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, checkIsLinkedReq).checkIsLinkedRequest( checkIsLinkedReq, checkIsLinkedResponseHolder) self.assertEquals( cm.exception.string, "Unknown meetingConfigId : 'wrong-meeting-config-id'!") # now with the values corresponding to the created item checkIsLinkedReq._meetingConfigId = 'plonegov-assembly' checkIsLinkedReq._externalIdentifier = 'my-external-identifier' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') res = SOAPView(self.portal, checkIsLinkedReq).checkIsLinkedRequest( checkIsLinkedReq, checkIsLinkedResponseHolder) self.assertTrue(res._isLinked)
def test_ws_showCategoriesForUser(self): """ Test while getting configInfos with categories and using userToShowCategoriesFor. """ # first of all, we need to be a Manager/MeetingManager to use userToShowCategoriesFor self.changeUser('pmCreator1') req = getConfigInfosRequest() req._showCategories = True req._userToShowCategoriesFor = 'pmCreator1' responseHolder = getConfigInfosResponse() with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getConfigInfosRequest(req, responseHolder) self.assertEquals( cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to get available categories for a user!" ) # now try with a 'pmManager' self.changeUser('pmManager') req._userToShowCategoriesFor = 'unexistingUserId' # the userToShowCategoriesFor must exists! cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getConfigInfosRequest(req, responseHolder) self.assertEquals( cm.exception.string, "Trying to get avaialble categories for an unexisting user 'unexistingUserId'!" ) # now get it. The 'subproducts' category is only available to vendors (pmCreator2) req._userToShowCategoriesFor = 'pmCreator1' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') response = SOAPView(self.portal, req).getConfigInfosRequest(req, responseHolder) resp = deserialize(response) # for 'pmCreator1', subproducts is not available self.assertFalse('<id>subproducts</id>' in resp) req._userToShowCategoriesFor = 'pmCreator2' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') response = SOAPView(self.portal, req).getConfigInfosRequest(req, responseHolder) resp = deserialize(response) # but for 'pmCreator2', subproducts is available self.assertTrue('<id>subproducts</id>' in resp)
def test_pm_SearchItemsToValidateOfHighestHierarchicLevel(self): """Test the searchItemsToValidateOfHighestHierarchicLevel method. This should return a list of items a user ***really*** has to validate. Items to validate are items for which user is a reviewer and only regarding his higher hierarchic level. So a reviewer level 1 and level 2 will only see items in level 2, a reviewer in level 1 (only) will only see items in level 1.""" self.changeUser("admin") cfg = self.meetingConfig itemTypeName = cfg.getItemTypeName() # first test the generated query adapter = getAdapter( cfg, ICompoundCriterionFilter, name="items-to-validate-of-highest-hierarchic-level", ) # if user si not a reviewer, we want the search to return # nothing so the query uses an unknown review_state self.assertEquals(adapter.query, _find_nothing_query(itemTypeName)) # for a reviewer, query is correct self.changeUser("pmReviewer1") cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.assertDictEqual( adapter.query, { "portal_type": { "query": itemTypeName }, 'reviewProcessInfo': { 'query': [ '{}__reviewprocess__proposed_to_director'.format( self.developers_uid) ] }, }, ) # activate 'prevalidation' if necessary if ("prereviewers" in MEETINGREVIEWERS and not "pre_validation" in cfg.getWorkflowAdaptations()): cfg.setWorkflowAdaptations("pre_validation") performWorkflowAdaptations(cfg, logger=pm_logger) # now do the query # this adapter is used by the "searchitemstovalidate" collection = cfg.searches.searches_items.searchitemstovalidate # create an item self.changeUser("pmCreator1") item = self.create("MeetingItem") # jump to first level of validation self.do(item, self.TRANSITIONS_FOR_PROPOSING_ITEM_1[0]) cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.failIf(collection.results()) self.changeUser("pmReviewerLevel1") cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.failUnless(collection.getQuery()) # now as 'pmReviewerLevel2', the item should not be returned # as he only see items of his highest hierarchic level self.changeUser("pmReviewerLevel2") cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.failIf(collection.results()) # pass the item to second last level of hierarchy, where 'pmReviewerLevel2' is reviewer for self.changeUser("pmReviewerLevel1") # jump to last level of validation self.proposeItem(item) cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.failIf(collection.results()) # alderman don't see the item validated to director self.changeUser("pmReviewerLevel2") cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.maxDiff = None query = adapter.query query['reviewProcessInfo']['query'].sort() self.assertDictEqual( adapter.query, { "portal_type": { "query": itemTypeName }, 'reviewProcessInfo': { 'query': sorted([ '{}__reviewprocess__proposed_to_director'.format( self.developers_uid), '{}__reviewprocess__proposed_to_director'.format( self.vendors_uid) ]) }, }, ) self.changeUser("pmDirector1") cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.assertDictEqual( adapter.query, { "portal_type": { "query": itemTypeName }, 'reviewProcessInfo': { 'query': [ '{}__reviewprocess__proposed_to_director'.format( self.developers_uid) ] }, }, ) # now give a view on the item by 'pmReviewer2' and check if, as a reviewer, # the search does returns him the item, it should not as he is just a reviewer # but not able to really validate the new item cfg.setUseCopies(True) cfg.setItemCopyGroupsStates("proposed_to_director") item.setCopyGroups(("{}_reviewers".format(self.vendors_uid), )) item.at_post_edit_script() self.changeUser("pmReviewer2") # the user can see the item self.failUnless(self.hasPermission("View", item)) # but the search will not return it cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.failIf(collection.results()) # if the item is validated, it will not appear for pmReviewer1 anymore self.changeUser("pmReviewer1") cleanRamCacheFor( "Products.PloneMeeting.adapters.query_itemstovalidateofhighesthierarchiclevel" ) self.failUnless(collection.getQuery()) self.validateItem(item) self.failIf(collection.results())
def test_pm_SearchItemsOfMyCommissions(self): self.add_commission_plone_groups() """Test the 'items-of-my-commissions' adapter that returns items using category if it matches the right commissions for the user.""" cfg = self.meetingConfig2 itemTypeName = cfg.getItemTypeName() # siteadmin is not member of any commissions. adapter = getAdapter( cfg, ICompoundCriterionFilter, name="items-of-my-commissions" ) self.changeUser("siteadmin") self.assertEqual( adapter.query, {"portal_type": {"query": itemTypeName}, "getRawClassifier": {"query": []}}, ) # commissioneditor is member of 'commission-ag' self.changeUser("commissioneditor") cleanRamCacheFor( "Products.MeetingLalouviere.adapters.query_itemsofmycommissions" ) self.assertEqual( adapter.query, { "portal_type": {"query": "MeetingItemCouncil"}, "getRawClassifier": { "query": ["commission-ag", "commission-ag-1er-supplement"] }, }, ) self.changeUser("commissioneditor2") cleanRamCacheFor( "Products.MeetingLalouviere.adapters.query_itemsofmycommissions" ) self.assertDictEqual( adapter.query, { "portal_type": {"query": "MeetingItemCouncil"}, "getRawClassifier": { "query": [ "commission-patrimoine", "commission-patrimoine-1er-supplement" ] }, }, ) self.changeUser("pmManager") cleanRamCacheFor( "Products.MeetingLalouviere.adapters.query_itemsofmycommissions" ) self.assertDictEqual( adapter.query, { "portal_type": {"query": "MeetingItemCouncil"}, "getRawClassifier": { "query": [] }, }, )
def test_ws_getItemTemplateInTheNameOf(self): """ Test that getting an item template inTheNameOf antother user works Create an item by 'pmCreator1', member of the 'developers' group Template will be generatable : - by 'pmManager' - while generating the template inTheNameOf 'pmCreator1' Template will NOT be generatable : - while generating the template inTheNameOf 'pmCreator2' that is not in the 'developers' group """ # create an item by 'pmCreator1' self.changeUser('pmCreator1') # prepare data for a default item req = self._prepareCreationData() # remove unuseable catagory req._creationData._category = '' # create the item newItem, reponse = self._createItem(req) # prepare data to query the template req = getItemTemplateRequest() newItemUID = newItem.UID() req._itemUID = newItemUID cfg = self.meetingConfig req._templateId = '%s__format__%s' % ( cfg.podtemplates.itemTemplate.getId(), 'odt') req._inTheNameOf = 'pmCreator1' # the current user can get item template inTheNameOf himself responseHolder = getItemTemplateResponse() # need to be a 'Manager' or 'MeetingManager' with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getItemTemplateRequest(req, responseHolder) self.assertEquals( cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to get " "a template for an item 'inTheNameOf'!") # now as MeetingManager, it works self.changeUser('pmManager') cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') renderedTemplate = SOAPView(self.portal, req).getItemTemplateRequest( req, responseHolder) # check that the rendered file correspond to the newItem's data self._isCorrectlyRenderedTemplate(renderedTemplate, newItem) # as we switch user while using inTheNameOf, make sure we have # falled back to original user self.assertTrue(self.portal.portal_membership.getAuthenticatedMember(). getId() == 'pmManager') # now inTheNameOf a user that can not access newItem req._inTheNameOf = 'pmCreator2' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getItemTemplateRequest(req, responseHolder) self.assertEquals(cm.exception.string, "You can not access this item!") req._inTheNameOf = 'unexistingUserId' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).getItemTemplateRequest(req, responseHolder) self.assertEquals( cm.exception.string, "Trying to create an item 'inTheNameOf' an unexisting user 'unexistingUserId'!" ) self._check_after_inTheNameOf()
def create(self, objectType, folder=None, autoAddCategory=True, is_classifier=False, **attrs): '''Creates an instance of a meeting (if p_objectType is 'Meeting') or meeting item (if p_objectType is 'MeetingItem') and returns the created object. p_attrs is a dict of attributes that will be given to invokeFactory.''' cfg = self.meetingConfig shortName = cfg.getShortName() # Some special behaviour occurs if the item to create is # a recurring item or an item template contentType = objectType if objectType == 'MeetingItemRecurring': contentType = '%s%s' % (objectType, shortName) folder = cfg.recurringitems elif objectType == 'MeetingItemTemplate': contentType = '%s%s' % (objectType, shortName) folder = folder or cfg.itemtemplates elif objectType == 'MeetingConfig': folder = self.tool elif objectType == 'organization': folder = folder or self.own_org elif objectType == 'person': folder = self.portal.contacts elif objectType == 'held_position': if folder is None: raise Exception( 'The "folder" parameter must be a person when creating a held_position!') elif objectType == 'meetingcategory': if is_classifier: folder = cfg.classifiers else: folder = cfg.categories elif objectType == 'ConfigurablePODTemplate': folder = cfg.podtemplates else: contentType = '%s%s' % (objectType, shortName) folder = self.getMeetingFolder(cfg) # Add some computed attributes idInAttrs = 'id' in attrs if not idInAttrs: attrs.update({'id': self._generateId(folder)}) if objectType == 'Meeting' and attrs.get('date', None) is None: attrs.update({'date': datetime.now()}) if objectType == 'MeetingItem': if 'proposingGroup' not in attrs.keys(): cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting._get_org_uids_for_user') proposingGroupUids = self.tool.get_orgs_for_user(suffixes=['creators']) if len(proposingGroupUids): attrs.update({'proposingGroup': proposingGroupUids[0]}) obj = getattr(folder, folder.invokeFactory(contentType, **attrs)) if objectType == 'Meeting': self.setCurrentMeeting(obj) elif objectType == 'MeetingItem': # optionalAdvisers are not set (???) by invokeFactory... if 'optionalAdvisers' in attrs: obj.setOptionalAdvisers(attrs['optionalAdvisers']) # decision is not set (???) by invokeFactory... if 'decision' in attrs: obj.setDecision(attrs['decision']) # define a category for the item if necessary if autoAddCategory and not \ cfg.getUseGroupsAsCategories() and not \ obj.getCategory(): aCategory = cfg.getCategories()[0].getId() obj.setCategory(aCategory) if hasattr(obj.aq_inner, 'processForm'): # at_post_create_script is called by processForm # but processForm manage the _at_creation_flag # keep id if it was given if idInAttrs: obj._at_rename_after_creation = False obj.processForm() if idInAttrs: obj._at_rename_after_creation = True if objectType == 'Meeting': # manage attendees if using it usedMeetingAttrs = cfg.getUsedMeetingAttributes() if 'attendees' in usedMeetingAttrs: default_attendees = _get_default_attendees(obj) default_attendees = OrderedDict(( (attendee, 'attendee') for attendee in default_attendees)) signatories = [] if 'signatories' in usedMeetingAttrs: signatories = _get_default_signatories(obj) voters = [] if cfg.getUseVotes(): voters = _get_default_voters(obj) obj._do_update_contacts(attendees=default_attendees, signatories=signatories, voters=voters) # manage default values add_form = folder.restrictedTraverse('++add++{0}'.format(obj.portal_type)) add_form.update() for field_name, widget in add_form.form_instance.w.items(): if widget.value and \ not getattr(obj, field_name) and \ isinstance(widget.value, (str, unicode)): setattr(obj, field_name, widget.field.fromUnicode(widget.value)) # make sure we do not have permission check cache problems... self.cleanMemoize() return obj
def test_pm_ItemPrettyLinkColumnWhenNotPrivacyViewable(self): """When item is not privacyViewable : - no link is rendred, only the title; - more infos are not displayed.""" cfg = self.meetingConfig cfg.setRestrictAccessToSecretItems(True) self._setPowerObserverStates( observer_type='restrictedpowerobservers', states=(self._stateMappingFor('itemcreated'), )) self.request.cookies['pmShowDescriptions'] = 'true' self.changeUser('pmCreator1') # create 2 exactly same items, second will be set 'secret' publicItem = self.create('MeetingItem', title='Public item title', description='Public item description') self.addAnnex(publicItem) self.addAnnex(publicItem, relatedTo='item_decision') publicItem.setPrivacy('public') publicItem._update_after_edit() publicBrain = self.catalog(UID=publicItem.UID())[0] secretItem = self.create('MeetingItem', title='Secret item title', description='Secret item description') self.addAnnex(secretItem) secretItem.setPrivacy('secret') secretItem._update_after_edit() secretBrain = self.catalog(UID=secretItem.UID())[0] meetingFolder = self.getMeetingFolder() faceted_table = meetingFolder.restrictedTraverse('faceted-table-view') column = PMPrettyLinkColumn(meetingFolder, self.portal.REQUEST, faceted_table) # as a normal user, everything is viewable # link to title, more-infos and annexes self.assertTrue(publicItem.adapted().isPrivacyViewable()) self.assertTrue(secretItem.adapted().isPrivacyViewable()) publicBrainPrettyLinkColumn = column.renderCell(publicBrain) secretBrainPrettyLinkColumn = column.renderCell(secretBrain) # make sure cache is shared between cell and item view self.assertTrue( publicItem.getPrettyLink() in publicBrainPrettyLinkColumn) self.assertTrue( secretItem.getPrettyLink() in secretBrainPrettyLinkColumn) # link to title self.assertTrue("href='{0}'".format(publicBrain.getURL()) in publicBrainPrettyLinkColumn) self.assertTrue("href='{0}'".format(secretBrain.getURL()) in secretBrainPrettyLinkColumn) # more infos self.assertTrue(' class="pmMoreInfo">' in publicBrainPrettyLinkColumn) self.assertTrue(' class="pmMoreInfo">' in secretBrainPrettyLinkColumn) # annexes self.assertTrue(' class="pmMoreInfo">' in publicBrainPrettyLinkColumn) self.assertTrue(' class="pmMoreInfo">' in secretBrainPrettyLinkColumn) # now as a restricted power observer, secretItem title is only shown (without a link) self.changeUser('restrictedpowerobserver1') cleanRamCacheFor('Products.PloneMeeting.MeetingItem.isPrivacyViewable') self.assertTrue(publicItem.adapted().isPrivacyViewable()) self.assertFalse(secretItem.adapted().isPrivacyViewable()) publicBrainPrettyLinkColumn = column.renderCell(publicBrain) secretBrainPrettyLinkColumn = column.renderCell(secretBrain) # make sure cache is shared between cell and item view self.assertTrue( publicItem.getPrettyLink() in publicBrainPrettyLinkColumn) self.assertTrue( secretItem.getPrettyLink() in secretBrainPrettyLinkColumn) # link to title self.assertTrue("href='{0}'".format(publicBrain.getURL()) in publicBrainPrettyLinkColumn) # more infos self.assertTrue(' class="pmMoreInfo">' in publicBrainPrettyLinkColumn) # annexes self.assertTrue(' class="pmMoreInfo">' in publicBrainPrettyLinkColumn) # the secret item is not accessible item_portal_type_title = translate( self.portal.portal_types[secretItem.portal_type].Title()) self.assertEqual( secretBrainPrettyLinkColumn, u"<div class='pretty_link' title='Secret item title'>" u"<span class='pretty_link_icons'>" u"<img title='{0}' src='http://nohost/plone/MeetingItem.png' " u"style=\"width: 16px; height: 16px;\" /></span>" u"<span class='pretty_link_content state-itemcreated'>Secret item title " u"<span class='discreet no_access'>(You can not access this element)</span>" u"</span></div>".format(item_portal_type_title))
def test_ws_searchItemsInTheNameOf(self): """ Test that searching items inTheNameOf antother user works Create 2 items, one by 'pmCreator1', member of the 'developers' group and one by 'pmCreator2', member of the 'vendors' group Item 1 will be viewable : - by 'pmManager' and 'pmCreator1' Item 1 will NOT be viewable : - while getting informations in the name of 'pmCreator2' that is not in the 'developers' group Item 2 will be viewable : - by 'pmManager' and 'pmCreator2' Item 2 will NOT be viewable : - while getting informations in the name of 'pmCreator1' that is not in the 'vendors' group """ # put pmManager in the 'vendors_creators' so he can have # access to itemcreated items of 'pmCreator2' self.portal.portal_groups.addPrincipalToGroup('pmManager', self.vendors_creators) SAME_TITLE = 'sameTitleForBothItems' # create an item by 'pmCreator1' self.changeUser('pmCreator1') item1 = self.create('MeetingItem') item1.setTitle(SAME_TITLE) item1.reindexObject(idxs=[ 'Title', ]) # create an item by 'pmCreator2' self.changeUser('pmCreator2') item2 = self.create('MeetingItem') item2.setTitle(SAME_TITLE) item2.reindexObject(idxs=[ 'Title', ]) req = searchItemsRequest() req._inTheNameOf = None req._Title = SAME_TITLE responseHolder = searchItemsResponse() # 'pmCreator1' can get infos about item1 self.changeUser('pmCreator1') result = SOAPView(self.portal, req).searchItemsRequest(req, responseHolder) # only one result and about item1 self.assertEqual(result._itemInfo[0].UID, item1.UID()) self.assertEqual(len(result._itemInfo), 1) # 'pmCreator2' can get infos about item2 self.changeUser('pmCreator2') cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') result = SOAPView(self.portal, req).searchItemsRequest(req, responseHolder) # only one result and about item2 self.assertEqual(result._itemInfo[0].UID, item2.UID()) self.assertEqual(len(result._itemInfo), 1) # None of 'pmCreatorx' can searchItems inTheNameOf req._inTheNameOf = 'pmCreator1' self.changeUser('pmCreator1') cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).searchItemsRequest(req, responseHolder) self.assertEqual( cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to get item informations 'inTheNameOf'!" ) req._inTheNameOf = 'pmCreator2' self.changeUser('pmCreator2') cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).searchItemsRequest(req, responseHolder) self.assertEqual( cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to get item informations 'inTheNameOf'!" ) # now working examples with a 'Manager' self.changeUser('pmManager') req._inTheNameOf = None cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') result = SOAPView(self.portal, req).searchItemsRequest(req, responseHolder) # both items are returned self.assertEqual(len(result._itemInfo), 2) # returned items are item1 and item2 createdItemsUids = set((item1.UID(), item2.UID())) resultUids = set((result._itemInfo[0].UID, result._itemInfo[1].UID)) self.assertEqual(createdItemsUids, resultUids) # as we switch user while using inTheNameOf, make sure we have # falled back to original user self.assertEqual( self.portal.portal_membership.getAuthenticatedMember().getId(), 'pmManager') # now searchItems inTheNameOf 'pmCreator1' req._inTheNameOf = 'pmCreator1' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') result = SOAPView(self.portal, req).getItemInfosRequest(req, responseHolder) self.assertEqual(len(result._itemInfo), 1) self.assertEqual(result._itemInfo[0].UID, item1.UID()) # now searchItems inTheNameOf 'pmCreator2' req._inTheNameOf = 'pmCreator2' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') result = SOAPView(self.portal, req).getItemInfosRequest(req, responseHolder) self.assertEqual(len(result._itemInfo), 1) self.assertEqual(result._itemInfo[0].UID, item2.UID())
def test_ws_createItemInTheNameOf(self): """ It is possible for Managers and MeetingManagers to create an item inTheNameOf another user Every other checks are made except that for using the inTheNameOf functionnality : - the calling user must be 'Manager' or 'MeetingManager' - the created item is finally like if created by the inTheNameOf user """ self.meetingConfig.setUseGroupsAsCategories(False) # check first a working example the degrades it... # and every related informations (creator, ownership, ...) are corretly linked to inTheNameOf user self.changeUser('pmManager') req = self._prepareCreationData() req._inTheNameOf = 'pmCreator2' req._proposingGroupId = 'vendors' req._creationData._category = 'development' data = {'title': 'My annex 1', 'filename': 'smallTestFile.pdf', 'file': 'smallTestFile.pdf'} req._creationData._annexes = [self._prepareAnnexInfo(**data)] responseHolder = createItemResponse() response = SOAPView(self.portal, req).createItemRequest(req, responseHolder) # as we switch user while using inTheNameOf, make sure we have # falled back to original user self.assertTrue(self.portal.portal_membership.getAuthenticatedMember().getId() == 'pmManager') # make also sure that cached methods using user_id are correct as well newItem = self.portal.uid_catalog(UID=response._UID)[0].getObject() # as the item is really created by the inTheNameOf user, everything is correct self.assertEqual(newItem.Creator(), 'pmCreator2') self.assertEqual(newItem.owner_info()['id'], 'pmCreator2') # with those data but with a non 'Manager'/'MeetingManager', it fails self.changeUser('pmCreator1') cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).createItemRequest(req, responseHolder) self.assertEqual(cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to create an item 'inTheNameOf'!") # now use the MeetingManager but specify a proposingGroup the inTheNameOf user can not create for self.changeUser('pmManager') req._proposingGroupId = 'developers' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).createItemRequest(req, responseHolder) self.assertEqual(cm.exception.string, "'pmCreator2' can not create items for the 'developers' group!") # now for an unexisting inTheNameOf userid req._inTheNameOf = 'unexistingUserId' # set back correct proposingGroupId req._proposingGroupId = 'vendors' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).createItemRequest(req, responseHolder) self.assertEqual(cm.exception.string, "Trying to create an item 'inTheNameOf' an unexisting user 'unexistingUserId'!") # create an itemInTheNameOf a user having no personal area... # if the user trying to create an item has no member area, a ZSI.Fault is raised # remove the 'pmCreator2' personal area self.changeUser('admin') # remove the created item because we can not remove a folder containing items # it would raise a BeforeDeleteException in PloneMeeting newItem.aq_inner.aq_parent.manage_delObjects(ids=[newItem.getId(), ]) self.portal.Members.manage_delObjects(ids=['pmCreator2']) self.changeUser('pmManager') req._inTheNameOf = 'pmCreator2' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).createItemRequest(req, responseHolder) self.assertEqual(cm.exception.string, "No member area for 'pmCreator2'. Never connected to PloneMeeting?") # test that _listAllowedRolesAndUsers is not messed up # this happened before because ToolPloneMeeting.get_plone_groups_for_user # had a different value between request.AUTHENTICATED_USER and api.user.get_current self._check_after_inTheNameOf()
def test_ws_createItemInTheNameOf(self): """ It is possible for Managers and MeetingManagers to create an item inTheNameOf another user Every other checks are made except that for using the inTheNameOf functionnality : - the calling user must be 'Manager' or 'MeetingManager' - the created item is finally like if created by the inTheNameOf user """ # check first a working example the degrades it... # and every related informations (creator, ownership, ...) are corretly linked to inTheNameOf user self.changeUser('pmManager') req = self._prepareCreationData() req._inTheNameOf = 'pmCreator2' req._proposingGroupId = 'vendors' responseHolder = createItemResponse() response = SOAPView(self.portal, req).createItemRequest(req, responseHolder) # as we switch user while using inTheNameOf, make sure we have # falled back to original user self.assertTrue(self.portal.portal_membership.getAuthenticatedMember(). getId() == 'pmManager') newItem = self.portal.uid_catalog(UID=response._UID)[0].getObject() # as the item is really created by the inTheNameOf user, everything is correct self.assertEqual(newItem.Creator(), 'pmCreator2') self.assertEqual(newItem.owner_info()['id'], 'pmCreator2') # with those data but with a non 'Manager'/'MeetingManager', it fails self.changeUser('pmCreator1') cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).createItemRequest(req, responseHolder) self.assertEqual( cm.exception.string, "You need to be 'Manager' or 'MeetingManager' to create an item 'inTheNameOf'!" ) # now use the MeetingManager but specify a proposingGroup the inTheNameOf user can not create for self.changeUser('pmManager') req._proposingGroupId = 'developers' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).createItemRequest(req, responseHolder) self.assertEqual( cm.exception.string, "'pmCreator2' can not create items for the 'developers' group!") # now for an unexisting inTheNameOf userid req._inTheNameOf = 'unexistingUserId' # set back correct proposingGroupId req._proposingGroupId = 'vendors' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).createItemRequest(req, responseHolder) self.assertEqual( cm.exception.string, "Trying to create an item 'inTheNameOf' an unexisting user 'unexistingUserId'!" ) # create an itemInTheNameOf a user having no personal area... # if the user trying to create an item has no member area, a ZSI.Fault is raised # remove the 'pmCreator2' personal area self.changeUser('admin') # remove the created item because we can not remove a folder containing items # it would raise a BeforeDeleteException in PloneMeeting newItem.aq_inner.aq_parent.manage_delObjects(ids=[ newItem.getId(), ]) self.portal.Members.manage_delObjects(ids=['pmCreator2']) self.changeUser('pmManager') req._inTheNameOf = 'pmCreator2' cleanRamCacheFor('Products.PloneMeeting.ToolPloneMeeting.userIsAmong') with self.assertRaises(ZSI.Fault) as cm: SOAPView(self.portal, req).createItemRequest(req, responseHolder) self.assertEqual( cm.exception.string, "No member area for 'pmCreator2'. Never connected to PloneMeeting?" )