def __call__(self): dao = MemberServicesDataAccess(self.context) ms_ids = self.request.get('ids', []) for id in ms_ids: memberservice = dao.get_memberservice_by_primary_key(id) dao.delete_memberservice(memberservice) return super(ListMemberServices, self).__call__()
def onMemberJoined(obj, event): memberid = obj.getId() portal = obj.restrictedTraverse('@@plone_portal_state').portal() products_and_services = portal._getOb('products_and_services') dao = MemberServicesDataAccess(obj) intids = queryUtility(IIntIds, context=obj) # 30 days free trial with 2 questions today = datetime.date.today() trialend = today + datetime.timedelta(days=30) intelligent_practice_services = ( 'maths-grade10-monthly-practice', 'maths-grade11-monthly-practice', 'maths-grade12-monthly-practice', 'science-grade10-monthly-practice', 'science-grade11-monthly-practice', 'science-grade12-monthly-practice', ) for sid in intelligent_practice_services: related_service = products_and_services[sid] mstitle = '%s for %s' % (related_service.title, memberid) props = {'memberid': memberid, 'title': mstitle, 'related_service_id': intids.getId(related_service), 'expiry_date': trialend, 'service_type': related_service.service_type} ms = dao.add_memberservice(**props) getUtility(IUserCatalog).index(obj)
def update(self): self.memberservices = [] self.dao = MemberServicesDataAccess(self.context) self.userid = self.request.get('userid', '') if self.userid: ids = practice_service_intids(self.context) dao = MemberServicesDataAccess(self.context) self.memberservices = dao.get_active_memberservices(self.userid)
def update(self): intids = practice_service_intids(self.context) pps = self.context.restrictedTraverse('@@plone_portal_state') memberid = pps.member().getId() dao = MemberServicesDataAccess(self.context) self.memberservices = dao.get_memberservices(intids, memberid) # grab any errors from the request, just in case we want to display # them later. self.errors = self.request.get('errors', [])
def get_display_items_from_order(order): memberid = order.userid orderitems = dict( (item.related_item.to_object, item.quantity) for item in order.order_items() ) dao = MemberServicesDataAccess(order) ids = [dao.intids.getId(service) for service in orderitems.keys()] display_items = dao.get_memberservices(ids, memberid) return display_items
def add_memberservice(self, related_service, memberid): now = datetime.now().date() dao = MemberServicesDataAccess(self.portal) mstitle = '%s for %s' % (related_service.title, memberid) props = {'memberid': memberid, 'title': mstitle, 'related_service_id': dao.intids.getId(related_service), 'expiry_date': now, 'service_type': related_service.service_type} ms = dao.add_memberservice(**props) return ms
def memberServiceAdded(obj, event): service = obj.related_service.to_object intids = queryUtility(IIntIds, context=service) related_service_id = intids.getId(service) memberid = obj.memberid dao = MemberServicesDataAccess(obj) memberservices = dao.get_memberservices([related_service_id], memberid) if memberservices is not None and len(memberservices) > 0: raise RuntimeError( 'Only one memberservice is allowed per purchasable service.' 'This member (%s) already has a memberservice for ' '%s.' %(obj.userid, service.Title()) )
class EditMemberService(form.SchemaForm): grok.name('edit-memberservice') grok.require('zope2.View') grok.context(Interface) schema = IMemberServiceForm ignoreContext = True label = _(u'Edit Member Service') description = _('Edit member service.') name = _('edit-memberservice') def __init__(self, context, request): super(EditMemberService, self).__init__(context, request) self.errors = [] self.memberservice = None self.dao = MemberServicesDataAccess(context) ms_pk = self.request.get('id', None) if not ms_pk: self.errors.append('Missing memberservice primary key.') return self.memberservice = self.dao.get_memberservice_by_primary_key(ms_pk) def update(self): if self.memberservice: for name in self.schema.names(): value = getattr(self.memberservice, name) if name == 'expiry_date': value = value.strftime('%m/%d/%y') self.request['form.widgets.%s' % name] = value super(EditMemberService, self).update() def updateWidgets(self): super(EditMemberService, self).updateWidgets() @button.buttonAndHandler(_(u'Save')) def handleApply(self, action): self.data, self.errors = self.extractData() ms_id = self.data.get('id') memberservice = self.dao.get_memberservice_by_primary_key(ms_id) if not memberservice: raise NotFound('Could not find memberservice with id:%s') % ms_id for attr_name in self.data.keys(): setattr(memberservice, attr_name, self.data[attr_name]) self.request.response.redirect('@@list-memberservices')
def setUp(self): self.portal = self.layer['portal'] self.services = self.portal._getOb('products_and_services') self.intids = queryUtility(IIntIds, context=self.portal) self.dao = MemberServicesDataAccess(self.portal) setRoles(self.portal, TEST_USER_ID, ['Member']) self.session = SESSION()
def update(self): self.service_intids = practice_service_intids(self.context) pps = self.context.restrictedTraverse('@@plone_portal_state') memberid = pps.member().getId() self.dao = MemberServicesDataAccess(self.context) self.memberservices = [] self.memberservices = \ self.dao.get_active_memberservices(memberid)
def setUp(self): super(TestPracticeBrowserView, self).setUp() self.portal = self.layer['portal'] settings = queryUtility(IRegistry).forInterface(IEmasSettings) settings.practiceurl = u'http://localhost:27183' self.dao = MemberServicesDataAccess(self.portal) self.intids = queryUtility(IIntIds, context=self.portal) self.services = self.portal._getOb('products_and_services')
def __init__(self, context, request): super(EditMemberService, self).__init__(context, request) self.errors = [] self.memberservice = None self.dao = MemberServicesDataAccess(context) ms_pk = self.request.get('id', None) if not ms_pk: self.errors.append('Missing memberservice primary key.') return self.memberservice = self.dao.get_memberservice_by_primary_key(ms_pk)
def __init__(self, context, request): super(List_Services, self).__init__(context, request) self.pps = self.context.restrictedTraverse('@@plone_portal_state') self.portal = self.pps.portal() self.portal_url = self.pps.portal_url() self.member = self.pps.member() self.memberservices = [] self.isMxit = self.context.restrictedTraverse('@@mobile_tool').isMXit() self.navroot = self.pps.navigation_root() self.subject = self.getSubject(self.navroot) self.services = self._getServices(self.portal, self.subject) self.dao = MemberServicesDataAccess(self.context) memberid = self.member.getId() if memberid: ids = practice_service_intids(self.context) self.memberservices = \ self.dao.get_memberservices_by_subject(memberid, self.subject)
class MemberServices(grok.View): """ Returns all the authenticated member's services """ grok.context(Interface) grok.require('zope2.View') grok.name('member-services') def update(self): self.service_intids = practice_service_intids(self.context) pps = self.context.restrictedTraverse('@@plone_portal_state') memberid = pps.member().getId() self.dao = MemberServicesDataAccess(self.context) self.memberservices = [] self.memberservices = \ self.dao.get_active_memberservices(memberid) def service_url(self, service): return ''
class List_Services(grok.View): """ Custom view for mobile practice service """ grok.context(Interface) grok.require('zope2.View') grok.name('list-services') def __init__(self, context, request): super(List_Services, self).__init__(context, request) self.pps = self.context.restrictedTraverse('@@plone_portal_state') self.portal = self.pps.portal() self.portal_url = self.pps.portal_url() self.member = self.pps.member() self.memberservices = [] self.isMxit = self.context.restrictedTraverse('@@mobile_tool').isMXit() self.navroot = self.pps.navigation_root() self.subject = self.getSubject(self.navroot) self.services = self._getServices(self.portal, self.subject) self.dao = MemberServicesDataAccess(self.context) memberid = self.member.getId() if memberid: ids = practice_service_intids(self.context) self.memberservices = \ self.dao.get_memberservices_by_subject(memberid, self.subject) def getSubject(self, navroot): return navroot.getId() def craftPaidLink(self, navroot, service): access_path = service.access_path link = ['%s' % service.Title(), '%s/%s' % (navroot.absolute_url(), access_path)] return link def craftNotPaidLink(self, navroot, service): if self.isMxit: link = ['%s' % service.Title(), '%s/@@mxitpaymentrequest?productId=%s' % ( navroot.absolute_url(), service.getId())] else: link = ['%s' % service.Title(), '%s/@@purchase?productId=%s' % ( navroot.absolute_url(), service.getId())] return link def getURLs(self): urls = { 'paid': [], 'notpaid': [] } if self.isMxit: paid, notpaid = self.getMXitServices( self.services, self.memberservices) else: paid, notpaid = self.getWebAndMobileServices( self.services, self.memberservices) urls['paid'] = \ [self.craftPaidLink(self.navroot, s) for s in paid] urls['notpaid'] = \ [self.craftNotPaidLink(self.navroot, s) for s in notpaid] return urls def _getServices(self, portal, subject): products_and_services = portal.products_and_services services = products_and_services.getFolderContents( full_objects=True, contentFilter={'portal_type': 'emas.app.service', 'subject': subject}) return services def getMXitServices(self, services, memberservices): """ Probably good idea to @memoize this. """ paid = [] notpaid = [] related_services = \ [s.related_service(self.context) for s in memberservices] for service in services: # we are only interested in the mxit services now if MXIT_SERVICE in service.channels: if service in related_services: paid.append(service) else: notpaid.append(service) return paid, notpaid def getWebAndMobileServices(self, services, memberservices): """ Probably good idea to @memoize this too. """ paid = [] notpaid = [] related_services = \ [s.related_service(self.context) for s in memberservices] for service in services: if MXIT_SERVICE not in service.channels: if service in related_services: paid.append(service) else: notpaid.append(service) return paid, notpaid def isPracticeService(self): """ """ path = self.context.getPhysicalPath() return PRACTICE_URL.split('/')[-1] in path
def update(self): pps = self.context.restrictedTraverse('@@plone_portal_state') self.products_and_services = pps.portal()._getOb('products_and_services') self.navroot = pps.navigation_root() self.base_url = 'http://billing.internal.mxit.com/Transaction/PaymentRequest' self.action = self.context.absolute_url() + '/@@mxitpaymentrequest' pmt = getToolByName(self.context, 'portal_membership') memberid = member_id( self.request.get(USER_ID_TOKEN.lower(), self.request.get(USER_ID_TOKEN) ) ) if not memberid: raise ValueError('No member id supplied.') member = pmt.getMemberById(memberid) if not member: password = password_hash(self.context, memberid) pmt.addMember(memberid, password, 'Member', '') member = pmt.getMemberById(memberid) # login as new member newSecurityManager(self.request, member) registry = queryUtility(IRegistry) self.emas_settings = registry.forInterface(IEmasSettings) self.transaction_reference = self.emas_settings.order_sequence_number +1 self.emas_settings.order_sequence_number = self.transaction_reference self.transaction_reference = '%04d' % self.transaction_reference self.product_id = self.request.get('productId') try: self.product = self.products_and_services._getOb(self.product_id) except AttributeError: raise AttributeError( 'Product with id %s not found' % self.product_id ) self.product_name = self.product.title self.product_description = self.product.description # create an order for this member : product combination if self.product: portal = pps.portal() member_orders = portal['orders'] props = {'id' : self.transaction_reference, 'title' : self.transaction_reference, 'userid' : memberid, 'payment_method': MOOLA, } self.order= createContentInContainer( member_orders, 'emas.app.order', False, **props ) self.order = member_orders._getOb(self.transaction_reference) self.order.verification_code = generate_verification_code(self.order) self.order.manage_setLocalRoles(self.order.userid, ('Owner',)) relation = create_relation(self.product.getPhysicalPath()) item_id = self.order.generateUniqueId(type_name='orderitem') props = {'id' : item_id, 'title' : item_id, 'related_item' : relation, 'quantity' : 1} order_item = createContentInContainer( self.order, 'emas.app.orderitem', False, **props ) order_item.manage_setLocalRoles(self.order.userid, ('Owner',)) self.callback_url = \ '%s/mxitpaymentresponse?productId=%s&order_number=%s&verification_code=%s' %( self.context.absolute_url(), self.product_id, self.order.getId(), self.order.verification_code ) self.cost_settings = registry.forInterface(IEmasServiceCost) self.vendor_id = self.cost_settings.MXitVendorId self.moola_amount = self.product.amount_of_moola self.currency_amount = self.product.price url = '%s/%s' %(self.navroot.absolute_url(), self.product.access_path) # get all active services for this user service_intids = practice_service_intids(self.context) dao = MemberServicesDataAccess(self.context) memberservices = dao.get_memberservices(service_intids, memberid) active_services = [m.related_service(self.context) for m in memberservices] # check if the currently requested one is in the list if self.product in active_services: return self.request.response.redirect(url) else: return self.render()
class TestPracticeBrowserView(unittest.TestCase): layer = INTEGRATION_TESTING def setUp(self): super(TestPracticeBrowserView, self).setUp() self.portal = self.layer['portal'] settings = queryUtility(IRegistry).forInterface(IEmasSettings) settings.practiceurl = u'http://*****:*****@@practice') self.assertRaises(Unauthorized, view, 'The system should force a login.') def test_logged_in_memberservices_expired(self): self.deactivate_services() view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) result = view() self.assertGreater(len(result), 0, 'No result found.') self.assertEqual(view.services_active(), False, 'The service should not be active.') doc = lxml.html.fromstring(result) elements = doc.xpath('//a[contains(.,"orders")]') self.assertGreater(len(elements), 0, 'No order links found.') def test_logged_in_memberservices_active(self): view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) result = view() self.assertEqual(view.services_active(), True, 'The service should be active.') doc = lxml.html.fromstring(result) elements = doc.xpath('//a[contains(.,"orders")]') self.assertEqual(len(elements), 0, 'There should be no order links.') def test_logged_in_grade10_maths(self): view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) result = view() assert 'maths-grade-10' in view.accessto, \ 'Grade 10 Maths service not in memberservices.' def test_practice_service_info_on_first_login(self): portal_state = self.portal.restrictedTraverse('@@plone_portal_state') member = portal_state.member() default = DateTime('2000/01/01') member.setProperties(login_time=default, last_login_time=default) view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) # The call to loginUser is the one that fires the required event. # The testcase's login method simly creates a new security manager, it # does not lead to the IUserLoggedInEvent. self.portal.portal_membership.loginUser(view.request) result = view() doc = lxml.html.fromstring(result) elements = doc.xpath('//a[contains(.,"@@practice")]') self.assertEqual(len(elements), 0, 'No link to @@practice found.') def test_expiry_warning(self): """ Memberservice are only valid for 30 days and the expiry warning for monthly services is 7 days before expiry. So they should not show now. """ view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) result = view() self.assertEqual(view.show_expirywarning(), False, 'Trial service should all expire withing NUM_DAYS days.') def test_expiry_warning_for_manager(self): self.setRoles(('Manager',)) view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) result = view() self.assertEqual(view.show_expirywarning(), False, "We don't show expiry warnings to manager users.") def test_get_services(self): view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) result = view() self.assertEqual(len(view.memberservices), NUM_SERVICES, 'There should be %s practice memberservices.') for ms in view.memberservices: assert (IMemberService.providedBy(ms), 'The memberservice does not provide the correct interface.') for service in view.practice_services: assert (IService.providedBy(service), 'The practice_service does not provide the correct interface.') def test_get_services_with_empty_access_path(self): view = self.portal.restrictedTraverse('maths/@@practice') memberservices, services = view.get_services(self.portal) self.assertEqual(len(memberservices), NUM_SERVICES, 'There should be %s memberservices.' % NUM_SERVICES) self.assertEqual(len(services), NUM_SERVICES, 'There should be %s practice services.' % NUM_SERVICES) self.clear_access_path() memberservices, services = view.get_services(self.portal) self.assertEqual(len(memberservices), 0, 'There should be 0 memberservices.') self.assertEqual(len(services), 0, 'There should be 0 practice services.') def test_filtered_services_for_maths_grade10(self): view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) view() memberservices, services = view.get_services(self.portal) filteredservices = view.filtered(memberservices, 'maths', 'grade-10') self.assertEqual(len(filteredservices), 1, 'There can be onle one!') def test_filtered_services_for_maths(self): view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) view() memberservices, services = view.get_services(self.portal) filteredservices = view.filtered(memberservices, 'maths', None) self.assertEqual(len(filteredservices), 3, 'We should find 3 member services for maths.') def test_filtered_services_for_None_subject_None_grade(self): view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) view() memberservices, services = view.get_services(self.portal) filteredservices = view.filtered(memberservices, None, None) self.assertEqual(len(filteredservices), 6, 'We should find 6 member services.') def test_manager_user_access(self): self.setRoles(('Manager',)) self.deactivate_services() view = self.portal.maths.restrictedTraverse('maths/@@practice') self.update_request(view) view() self.assertEqual(len(view.memberservices), 0, 'All member services should be expired.') self.assertEqual(len(view.accessto.split(',')), NUM_SERVICES, '"accesto" should be %s long.' % NUM_SERVICES) self.assertEqual(view.services_active(), True, 'Manager always has access.') def test_days_to_expiry_date_calculation(self): view = self.portal.restrictedTraverse('maths/@@practice') self.update_request(view) view() numdays = Practice.NUM_DAYS for offset in [0, 10, 10]: numdays = numdays - offset print 'Testing %s days.' % numdays self.change_service_expiry_date(view, offset) self.assertEqual(view.get_days_to_expiry_date(), numdays, 'Expiry date should be %s days away.' % numdays) def test_subject_and_grade_computing_no_subject_no_grade(self): view = self.portal.restrictedTraverse('maths/@@practice') view() self.assertEqual(view.get_days_to_expiry_date(), Practice.NUM_DAYS, 'Expiry date should be %s days away.' % Practice.NUM_DAYS) def clear_access_path(self): memberservices = self.portal._getOb('memberservices') for ms in memberservices.objectValues(): ms.related_service.to_object.access_path = u'' def change_service_expiry_date(self, view, days): for service in view.memberservices: newdate = service.expiry_date - timedelta(days) service.expiry_date = newdate service.reindexObject(idxs=['expiry_date']) def deactivate_services(self): service_uids = [self.intids.getId(service) \ for service in self.services.objectValues()] memberservices = self.dao.get_memberservices(service_uids, TEST_USER_ID) expired = date(1970, 01, 01) for service in memberservices: service.expiry_date = expired self.dao.update_memberservice(service) def update_request(self, view): cookie = '' path = 'maths/@@practice/grade-10' host = 'localhost:8080' serverurl = 'http://%s' % host referer = '%s%s' % (serverurl, path) props = {'REQUEST_METHOD': 'GET', 'PATH_INFO': path, 'HTTP_HOST': host, 'HTTP_COOKIE': cookie, 'HTTP_REFERER': referer, 'SERVER_URL': serverurl, 'CONTENT_LENGTH': '0', 'GATEWAY_INTERFACE': 'TestFooInterface/1.0',} view.request.environ.update(props) return view.request
data.update(kw) req = Request('http://localhost:6543/profile/update/{0}'.format(uuid), 'PUT') req.add_header('Content-Type', 'application/json') try: response = urllib2.urlopen(req, json.dumps(data)) return response.code == 200 except urllib2.HTTPError: pass return False uf = getToolByName(portal, 'acl_users') pwmap = uf.source_users._user_passwords msdao = MemberServicesDataAccess(portal) # Traverse the password map in source_users, as this is much less expensive # than using acl_users.getUsers or portal_membership.listMembers. Fetch each # member separately. total = len(pwmap) count = 0 for uid, pw in pwmap.items(): member = uf.getUser(uid) pw = pwmap.get(uid, None) # A quick inspection on live indicates all users have SSHA passwords. if pw is not None and pw.startswith('{SSHA}'): password = pw[6:] # Other details we need
class TestMemberServicesIntegration(unittest.TestCase): """Unit test for the MemberService type """ layer = INTEGRATION_TESTING def setUp(self): self.portal = self.layer['portal'] self.services = self.portal._getOb('products_and_services') self.intids = queryUtility(IIntIds, context=self.portal) self.dao = MemberServicesDataAccess(self.portal) setRoles(self.portal, TEST_USER_ID, ['Member']) self.session = SESSION() def tearDown(self): count = self.session.query(MemberService).filter( MemberService.memberid == TEST_USER_ID ).delete() print 'Deleted %s' % count transaction.commit() def test_get_all_memberservices(self): db_ms = self.session.query(MemberService).all() all_ms = self.dao.get_all_memberservices() self.assertEquals(len(db_ms), len(all_ms)) self.assertEquals(all_ms, db_ms) def test_get_memberservices(self): service = self.services.objectValues()[0] ms_args = self.get_ms_args(service, TEST_USER_ID) ms1 = self.dao.add_memberservice(**ms_args) self.session.flush() ms1_db = self.get_memberservice(ms1.id) service_uids = [self.intids.getId(service),] memberid = TEST_USER_ID memberservices = \ self.dao.get_memberservices(service_uids, memberid) self.assertEquals(memberservices, [ms1_db]) def test_get_memberservices_by_subject(self): maths_services = \ [s for s in self.services.objectValues() if 'maths' in s.subject] for count in range(0,3): service = maths_services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) self.dao.add_memberservice(**ms_args) self.session.flush() science_services = \ [s for s in self.services.objectValues() if 'science' in s.subject] for count in range(0,3): service = science_services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_memberservices_by_subject(TEST_USER_ID, 'maths') self.assertEqual(len(memberservices), 3) memberservices = \ self.dao.get_memberservices_by_subject(TEST_USER_ID, 'science') self.assertEqual(len(memberservices), 3) def test_get_memberservices_by_grade(self): grade_10_services = \ [s for s in self.services.objectValues() if s.grade == 'grade-10'] for count in range(0,3): service = grade_10_services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_memberservices_by_grade(TEST_USER_ID, 'grade-10') self.assertEqual(len(memberservices), 3) def test_get_memberservices_by_subject_and_grade(self): grade_10_maths_services = \ [s for s in self.services.objectValues() if s.grade == 'grade-10'] grade_10_maths_services = \ [s for s in grade_10_maths_services if 'maths' in s.subject] for count in range(0,3): service = grade_10_maths_services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_memberservices_by_subject_and_grade(TEST_USER_ID, 'maths', 'grade-10') self.assertEqual(len(memberservices), 3) memberservices = \ self.dao.get_memberservices_by_subject_and_grade(TEST_USER_ID, 'science', 'grade-10') self.assertEqual(len(memberservices), 0) def test_get_active_memberservices(self): for count in range(0,3): service = self.services.objectValues()[count] ms_args = self.get_ms_args(service, TEST_USER_ID) self.dao.add_memberservice(**ms_args) self.session.flush() now = datetime.now().date() td = timedelta(1) yesterday = now - td for count in range(3,6): service = self.services.objectValues()[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = yesterday self.dao.add_memberservice(**ms_args) self.session.flush() active_memberservices = self.dao.get_active_memberservices(TEST_USER_ID) self.assertEquals(len(active_memberservices), 3) for ms in active_memberservices: self.assertEquals(ms.expiry_date, now) def test_get_active_memberservices_by_subject(self): now = datetime.now().date() td = timedelta(1) yesterday = now - td services = \ [s for s in self.services.objectValues() if 'maths' in s.subject] for count in range(0,3): service = services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = now self.dao.add_memberservice(**ms_args) self.session.flush() services = \ [s for s in self.services.objectValues() if 'science' in s.subject] for count in range(0,3): service = services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = yesterday self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_active_memberservices_by_subject(TEST_USER_ID, 'maths') self.assertEqual(len(memberservices), 3) for ms in memberservices: self.assertEquals(ms.expiry_date, now) def test_get_active_memberservices_by_grade(self): now = datetime.now().date() td = timedelta(1) yesterday = now - td services = \ [s for s in self.services.objectValues() if s.grade == 'grade-10'] for count in range(0,3): service = services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = now self.dao.add_memberservice(**ms_args) self.session.flush() services = \ [s for s in self.services.objectValues() if s.grade == 'grade-11'] for count in range(0,3): service = services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = yesterday self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_active_memberservices_by_grade(TEST_USER_ID, 'grade-10') self.assertEqual(len(memberservices), 3) for ms in memberservices: self.assertEquals(ms.expiry_date, now) def test_get_active_memberservices_by_subject_and_grade(self): now = datetime.now().date() td = timedelta(1) yesterday = now - td grade_10_maths_services = \ [s for s in self.services.objectValues() if \ s.grade == 'grade-10' and 'maths' in s.subject] for count in range(0,3): service = grade_10_maths_services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = now self.dao.add_memberservice(**ms_args) self.session.flush() grade_10_science_services = \ [s for s in self.services.objectValues() if \ s.grade == 'grade-10' and 'science' in s.subject] for count in range(0,3): service = grade_10_science_services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = yesterday self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_memberservices_by_subject_and_grade(TEST_USER_ID, 'maths', 'grade-10') self.assertEqual(len(memberservices), 3) for ms in memberservices: self.assertEquals(ms.expiry_date, now) def test_get_expired_memberservices(self): now = datetime.now().date() for count in range(0,3): service = self.services.objectValues()[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = now self.dao.add_memberservice(**ms_args) self.session.flush() td = timedelta(1) yesterday = now - td for count in range(3,6): service = self.services.objectValues()[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = yesterday self.dao.add_memberservice(**ms_args) self.session.flush() expired_memberservices = self.dao.get_expired_memberservices(TEST_USER_ID) self.assertEquals(len(expired_memberservices), 3) for ms in expired_memberservices: self.assertEquals(ms.expiry_date, yesterday) def test_get_expired_memberservices_by_subject(self): now = datetime.now().date() td = timedelta(1) yesterday = now - td services = \ [s for s in self.services.objectValues() if 'maths' in s.subject] for count in range(0,3): service = services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = now self.dao.add_memberservice(**ms_args) self.session.flush() services = \ [s for s in self.services.objectValues() if 'science' in s.subject] for count in range(0,3): service = services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = yesterday self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_expired_memberservices_by_subject(TEST_USER_ID, 'science') self.assertEqual(len(memberservices), 3) for ms in memberservices: self.assertEquals(ms.expiry_date, yesterday) def test_get_expired_memberservices_by_grade(self): now = datetime.now().date() td = timedelta(1) yesterday = now - td services = \ [s for s in self.services.objectValues() if s.grade == 'grade-10'] for count in range(0,3): service = services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = now self.dao.add_memberservice(**ms_args) self.session.flush() services = \ [s for s in self.services.objectValues() if s.grade == 'grade-11'] for count in range(0,3): service = services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = yesterday self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_expired_memberservices_by_grade(TEST_USER_ID, 'grade-11') self.assertEqual(len(memberservices), 3) for ms in memberservices: self.assertEquals(ms.expiry_date, yesterday) def test_get_expired_memberservices_by_subject_and_grade(self): now = datetime.now().date() td = timedelta(1) yesterday = now - td grade_10_maths_services = \ [s for s in self.services.objectValues() if \ s.grade == 'grade-10' and 'maths' in s.subject] for count in range(0,3): service = grade_10_maths_services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = now self.dao.add_memberservice(**ms_args) self.session.flush() grade_10_science_services = \ [s for s in self.services.objectValues() if \ s.grade == 'grade-10' and 'science' in s.subject] for count in range(0,3): service = grade_10_science_services[count] ms_args = self.get_ms_args(service, TEST_USER_ID) ms_args['expiry_date'] = yesterday self.dao.add_memberservice(**ms_args) self.session.flush() memberservices = \ self.dao.get_expired_memberservices_by_subject_and_grade( TEST_USER_ID, 'science', 'grade-10') self.assertEqual(len(memberservices), 3) for ms in memberservices: self.assertEquals(ms.expiry_date, yesterday) def test_get_memberservice_by_primary_key(self): service = self.services.objectValues()[0] ms_args = self.get_ms_args(service, TEST_USER_ID) ms1 = self.dao.add_memberservice(**ms_args) self.session.flush() ms1_db = self.dao.get_memberservice_by_primary_key(ms1.id) self.assertEquals(ms1_db, self.get_memberservice(ms1.id)) def test_add_memberservice(self): service = self.services.objectValues()[0] ms_args = self.get_ms_args(service, TEST_USER_ID) ms1 = self.dao.add_memberservice(**ms_args) self.session.flush() ms1_db = self.get_memberservice(ms1.id) self.failUnless(IMemberService.providedBy(ms1_db)) def test_adding_duplicate_memberservices(self): service = self.services.objectValues()[0] ms_args = self.get_ms_args(service, TEST_USER_ID) ms1 = self.dao.add_memberservice(**ms_args) ms2 = self.dao.add_memberservice(**ms_args) self.session.flush() ms1_db = self.get_memberservice(ms1.id) ms2_db = self.get_memberservice(ms2.id) self.failUnless(IMemberService.providedBy(ms1_db)) def test_update_memberservice(self): service = self.services.objectValues()[0] ms_args = self.get_ms_args(service, TEST_USER_ID) ms1 = self.dao.add_memberservice(**ms_args) self.session.flush() ms1_db = self.get_memberservice(ms1.id) ms1_db.title = 'new title' self.dao.update_memberservice(ms1_db) self.session.flush() ms1_db = self.get_memberservice(ms1.id) self.assertEquals(ms1_db.title, 'new title') def test_delete_memberservice(self): service = self.services.objectValues()[0] ms_args = self.get_ms_args(service, TEST_USER_ID) ms1 = self.dao.add_memberservice(**ms_args) self.session.flush() ms1_db = self.get_memberservice(ms1.id) self.dao.delete_memberservice(ms1_db) ms1_db = self.get_memberservice(ms1.id) self.assertEquals(ms1_db, None) def test_related_service(self): service = self.services.objectValues()[0] ms_args = self.get_ms_args(service, TEST_USER_ID) ms1 = self.dao.add_memberservice(**ms_args) self.session.flush() ms1_db = self.get_memberservice(ms1.id) self.failUnless(self.dao.related_service(ms1_db), service) def test_fti(self): fti = queryUtility(IDexterityFTI, name='emas.app.memberservice') self.assertEquals(None, fti) def test_schema(self): fti = queryUtility(IDexterityFTI, name='emas.app.memberservice') schema = fti.lookupSchema() self.assertEquals(None, schema) def test_factory(self): fti = queryUtility(IDexterityFTI, name='emas.app.memberservice') factory = fti.factory self.assertEquals(factory, None) def get_memberservice(self, memberservice_id): memberservices = self.session.query(MemberService).filter_by( id = memberservice_id).all() return memberservices and memberservices[0] or None def create_services(self): subjects = ['maths', 'science'] grades = ['10', '11', '12'] for subject in subjects: for count, grade in grades: props = {'service_type' : 'subscription', 'grade' : grade, 'subject' : subject, 'price' : '111'} s_id = self.services.invokeFactory('emas.app.service', '%s-%s' % (subject, grade), **props) service = self.services._getOb(s_id) service.subject = props['subject'] def get_ms_args(self, service, memberid): ms_args = { 'memberid': memberid, 'title': '%s for %s' % (service.title, memberid), 'related_service_id': self.intids.getId(service), 'expiry_date': datetime.now(), } return ms_args
def __call__(self, *args, **kw): alsoProvides(self.request, IPracticeLayer) self.subject = \ get_subject_from_path('/'.join(self.context.getPhysicalPath())) self.memberservices = [] self.dao = MemberServicesDataAccess(self.context) self.practice_services = [] self.accessto = '' portal_state = self.context.restrictedTraverse('@@plone_portal_state') path = self.request.get_header('PATH_INFO') member = portal_state.member() sm = getSecurityManager() self.ismanager = sm.checkPermission( permissions.ManagePortal, self.context) or False # give managers access to everything if self.ismanager: self.accessto = ('maths-grade-10,maths-grade-11,maths-grade-12,' 'science-grade-10,science-grade-11,science-grade-12') elif member.getId(): self.memberservices, self.practice_services = \ self.get_services(self.context, member.getId(), self.subject) self.accessto = self.get_accessto(self.practice_services) else: self.accessto = '' self.show_no_access_message = False if portal_state.anonymous(): memberid = 'Anonymous' else: memberid = member.getId() log.info('X-Access-To for %s: %s' % (memberid, self.accessto)) urlparts = urlparse(self.settings.practiceurl) practiceserver = urlparts.netloc path = self.request.get_header('PATH_INFO', '') if path and len(path) > 0: startpos = path.find(self.__name__) # strip the view name from the path path = path[startpos+len(self.__name__):] headers = { "Accept-Encoding": "identity", "Host": self.request.HTTP_HOST, "Connection": "close", "Cookie": self.request.HTTP_COOKIE, "Referer": self.request.HTTP_REFERER, "User-Agent": self.request.HTTP_USER_AGENT, } if not portal_state.anonymous(): headers["Authorization"] = 'Basic ' + base64.b64encode(memberid) headers["X-Access-To"] = self.accessto # Forward GET and POST requests; complain for all other request types if self.request.method == 'GET': conn = httplib.HTTPConnection(practiceserver) conn.request("GET", path, headers=headers) elif self.request.method == 'POST': headers['Content-Type'] = 'application/x-www-form-urlencoded' conn = httplib.HTTPConnection(practiceserver, timeout=30) conn.request("POST", path, body=urlencode(self.request.form.items()), headers=headers) else: return self.request.RESPONSE.unauthorized() self.html = '' # Handle response from Monassis server response = conn.getresponse() # Force no caching of response, unless /static or /image if tuple(path.split('/')[:2]) not in [('','static'), ('','image')]: self.request.RESPONSE.appendHeader('Cache-Control', 'no-store, no-cache') else: for key in ['Cache-Control', 'Expires']: value = response.getheader(key) if value is not None: self.request.RESPONSE.appendHeader(key, value) if response.status == 200: # Ok body = response.read() if response.msg.type == 'text/html': html = lxml.html.fromstring(body) html.make_links_absolute(base_url=self.settings.practiceurl, resolve_base_href=True) content = html.find('.//*[@id="content"]') if content is not None: self.html = lxml.html.tostring(content) else: self.html = body return self.index() else: resp = self.request.RESPONSE for key in ['Content-Length', 'Content-Type', 'Content-Disposition']: value = response.msg.get(key) if value is not None: resp.setHeader(key, value) resp.write(body) elif response.status == 302: # Found urlparts = urlparse(response.msg.get('location')) redirto = '%s%s' % (self.context.absolute_url(), urlparts.path) if urlparts.fragment: redirto += '#%s' % urlparts.fragment return self.request.RESPONSE.redirect(redirto) elif response.status == 400: # Bad request raise BadRequest('The URL:%s is a bad request.' %path) elif response.status == 403: # Forbidden if portal_state.anonymous(): return self.request.RESPONSE.unauthorized() else: log.info('User:%s not allowed to access URL:%s.' % (memberid, path)) self.show_no_access_message = True self.add_noaccess_message() return self.index() elif response.status == 404: # NotFound raise NotFound('The URL:%s could not be found.' %path) else: log.warn('Upstream returned:%s for URL:%s. Status is not handled.' % (response.status, path))
def onOrderPaid(order, event): """ Once the order is paid we create the memberservices. """ if event.action == 'pay': portal = getToolByName(order, 'portal_url').getPortalObject() intids = queryUtility(IIntIds, context=portal) dao = MemberServicesDataAccess(portal) # we cannot use the authenticated user since an admin user might # trigger the workflow. memberid = order.userid now = datetime.datetime.now().date() # grab the services from the orderitems for item in order.order_items(): # try to find the memberservices based on the orderitem # related services. order_related_service = item.related_item.to_object related_service_ids = [intids.getId(order_related_service)] # filter out services that don't have subject or grade set, # eg. discounts service_purchased = item.related_item.to_object if not (service_purchased.grade and service_purchased.subject): continue # add the service siyavula.memberservices uses for trial access related_service_ids.append( service_subject_ids[order_related_service.subject][0] ) memberservices = dao.get_memberservices( related_service_ids, memberid ) tmpservices = [] for ms in memberservices: related_service = ms.related_service(order) if (related_service.subject == service_purchased.subject and related_service.access_path == \ service_purchased.access_path): tmpservices.append(ms) # create a new memberservice if it doesn't exist if len(memberservices) == 0: mstitle = '%s for %s' % (order_related_service.title, memberid) props = {'memberid': memberid, 'title': mstitle, 'related_service_id': intids.getId(order_related_service), 'expiry_date': now, 'service_type': order_related_service.service_type} ms = dao.add_memberservice(**props) tmpservices.append(ms) # update the memberservices with info from the orderitem for ms in tmpservices: # NOTE: remove this when we remove siyavula.what if order_related_service.service_type == 'credit': credits = ms.credits credits += order_related_service.amount_of_credits ms.credits = credits elif order_related_service.service_type == 'subscription': # Always use the current expiry date if it is greater than # 'now', since that gives the user everything he paid for. # Only use 'now' if the related_service has already expired, so we # don't give the user more than he paid for. if now > ms.expiry_date: ms.expiry_date = now expiry_date = ms.expiry_date + datetime.timedelta( order_related_service.subscription_period ) ms.expiry_date = expiry_date dao.update_memberservice(ms) # if we have specific access groups add the user to those here. access_group = order_related_service.access_group if access_group: gt = getToolByName(order, 'portal_groups') # now add the member to the correct group gt.addPrincipalToGroup(memberid, access_group)
def update_profile(uuid, **kw): data = {} data.update(kw) req = Request('http://localhost:6543/profile/update/{0}'.format(uuid), 'PUT') req.add_header('Content-Type', 'application/json') try: response = urllib2.urlopen(req, json.dumps(data)) return response.code == 200 except urllib2.HTTPError: pass return False uf = getToolByName(portal, 'acl_users') pwmap = uf.source_users._user_passwords msdao = MemberServicesDataAccess(portal) # Traverse the password map in source_users, as this is much less expensive # than using acl_users.getUsers or portal_membership.listMembers. Fetch each # member separately. total = len(pwmap) count = 0 for uid, pw in pwmap.items(): member = uf.getUser(uid) pw = pwmap.get(uid, None) # A quick inspection on live indicates all users have SSHA passwords. if pw is not None and pw.startswith('{SSHA}'): password = pw[6:] # Other details we need
class Practice(BrowserView): """ Proxy for practice in Monassis """ NUM_DAYS = 30 implements(IPractice, IPublishTraverse) index = ViewPageTemplateFile('templates/practice.pt') def __init__(self, context, request): super(Practice, self).__init__(context, request) self.settings = queryUtility(IRegistry).forInterface(IEmasSettings) def __call__(self, *args, **kw): alsoProvides(self.request, IPracticeLayer) self.subject = \ get_subject_from_path('/'.join(self.context.getPhysicalPath())) self.memberservices = [] self.dao = MemberServicesDataAccess(self.context) self.practice_services = [] self.accessto = '' portal_state = self.context.restrictedTraverse('@@plone_portal_state') path = self.request.get_header('PATH_INFO') member = portal_state.member() sm = getSecurityManager() self.ismanager = sm.checkPermission( permissions.ManagePortal, self.context) or False # give managers access to everything if self.ismanager: self.accessto = ('maths-grade-10,maths-grade-11,maths-grade-12,' 'science-grade-10,science-grade-11,science-grade-12') elif member.getId(): self.memberservices, self.practice_services = \ self.get_services(self.context, member.getId(), self.subject) self.accessto = self.get_accessto(self.practice_services) else: self.accessto = '' self.show_no_access_message = False if portal_state.anonymous(): memberid = 'Anonymous' else: memberid = member.getId() log.info('X-Access-To for %s: %s' % (memberid, self.accessto)) urlparts = urlparse(self.settings.practiceurl) practiceserver = urlparts.netloc path = self.request.get_header('PATH_INFO', '') if path and len(path) > 0: startpos = path.find(self.__name__) # strip the view name from the path path = path[startpos+len(self.__name__):] headers = { "Accept-Encoding": "identity", "Host": self.request.HTTP_HOST, "Connection": "close", "Cookie": self.request.HTTP_COOKIE, "Referer": self.request.HTTP_REFERER, "User-Agent": self.request.HTTP_USER_AGENT, } if not portal_state.anonymous(): headers["Authorization"] = 'Basic ' + base64.b64encode(memberid) headers["X-Access-To"] = self.accessto # Forward GET and POST requests; complain for all other request types if self.request.method == 'GET': conn = httplib.HTTPConnection(practiceserver) conn.request("GET", path, headers=headers) elif self.request.method == 'POST': headers['Content-Type'] = 'application/x-www-form-urlencoded' conn = httplib.HTTPConnection(practiceserver, timeout=30) conn.request("POST", path, body=urlencode(self.request.form.items()), headers=headers) else: return self.request.RESPONSE.unauthorized() self.html = '' # Handle response from Monassis server response = conn.getresponse() # Force no caching of response, unless /static or /image if tuple(path.split('/')[:2]) not in [('','static'), ('','image')]: self.request.RESPONSE.appendHeader('Cache-Control', 'no-store, no-cache') else: for key in ['Cache-Control', 'Expires']: value = response.getheader(key) if value is not None: self.request.RESPONSE.appendHeader(key, value) if response.status == 200: # Ok body = response.read() if response.msg.type == 'text/html': html = lxml.html.fromstring(body) html.make_links_absolute(base_url=self.settings.practiceurl, resolve_base_href=True) content = html.find('.//*[@id="content"]') if content is not None: self.html = lxml.html.tostring(content) else: self.html = body return self.index() else: resp = self.request.RESPONSE for key in ['Content-Length', 'Content-Type', 'Content-Disposition']: value = response.msg.get(key) if value is not None: resp.setHeader(key, value) resp.write(body) elif response.status == 302: # Found urlparts = urlparse(response.msg.get('location')) redirto = '%s%s' % (self.context.absolute_url(), urlparts.path) if urlparts.fragment: redirto += '#%s' % urlparts.fragment return self.request.RESPONSE.redirect(redirto) elif response.status == 400: # Bad request raise BadRequest('The URL:%s is a bad request.' %path) elif response.status == 403: # Forbidden if portal_state.anonymous(): return self.request.RESPONSE.unauthorized() else: log.info('User:%s not allowed to access URL:%s.' % (memberid, path)) self.show_no_access_message = True self.add_noaccess_message() return self.index() elif response.status == 404: # NotFound raise NotFound('The URL:%s could not be found.' %path) else: log.warn('Upstream returned:%s for URL:%s. Status is not handled.' % (response.status, path)) def add_first_login_message(self, member): last_login_time = member.getProperty('last_login_time') login_time = member.getProperty('login_time') # if it last login and current login are within 2 seconds of eachother, # we consider this the 'first login' if login_time.micros() - last_login_time.micros() < 2000000: plone_utils = getToolByName(self.context, 'plone_utils') message = _(u'Have a look at the practice services.') plone_utils.addPortalMessage(message, 'info') def services_active(self): """ If the user has the ManagePortal permission. OR If the user has any active services. We want to display the practice service content. """ return self.ismanager or len(self.memberservices) > 0 def practice_service_messages(self): grades = [10, 11, 12] messages = [] expiring_services = self.expiring_services() # Format messages about expiring services. if expiring_services.values(): msg = '' num_days = self.number_of_days_until(expiring_services) if num_days < 1: days = 'today.' else: days = num_days > 1 and 'in %s days.' or 'in %s day.' days = days % num_days template = 'Your access to %s practice will expire '+days service_grades = expiring_services.keys() service_grades.sort() if service_grades == grades: msg = template % self.subject.capitalize() else: services = ' and '.join(['Grade %s' %s for s in service_grades]) msg = template % services messages.append(msg) else: # no services expiring? Then don't show any messages. return [] # Now, we do the formatting of the active services. active_services = self.active_services() # Remove all the services that we already reported on above. for grade in expiring_services.keys(): active_services.pop(grade, None) if active_services.values(): # flatten the list of memberservice lists memberservices = ListType(chain.from_iterable(active_services.values())) # sort according to expiry_date memberservices.sort(key=lambda service: service.expiry_date) # use the first expiry date formatted_expiry_date = \ self.format_date(memberservices[0].expiry_date) msg = '' template = 'You will still have access to %s practice until %s.' service_grades = active_services.keys() service_grades.sort() services = ' and '.join(['Grade %s' %s for s in service_grades]) msg = template % (services, formatted_expiry_date) messages.append(msg) # Lastly, add a link to the order form. if expiring_services: messages.append( '<a href="/order">To extend your subscription, click here.</a>') return messages def format_date(self, expiry_date): if expiry_date.year == datetime.now().year: return expiry_date.strftime("%e %B") return expiry_date.strftime("%e %B %Y") def number_of_days_until(self, expiring_services): # flatten the list of memberservice lists memberservices = ListType(chain.from_iterable(expiring_services.values())) # sort according to expiry_date memberservices.sort(key=lambda service: service.expiry_date) # use the last expiry date expiry_date = memberservices[0].expiry_date now = datetime.now().date() delta = expiry_date - now return delta.days def expiring_services(self): now = datetime.now() expiring_services = {} for ms in self.memberservices: if self.is_expiring(now, ms): grade = int(self.dao.related_service(ms).grade.split('-')[-1]) tmpservices = expiring_services.get(grade, []) tmpservices.append(ms) expiring_services[grade] = tmpservices return expiring_services def active_services(self): now = datetime.now() active_services = {} for ms in self.memberservices: if not self.is_expiring(now, ms): grade = int(self.dao.related_service(ms).grade.split('-')[-1]) tmpservices = active_services.get(grade, []) tmpservices.append(ms) active_services[grade] = tmpservices return active_services def is_expiring(self, cutoff_date, memberservice): days = self.memberservice_expiry_threshold(memberservice) expiry_threshold = (cutoff_date + timedelta(days)).date() if memberservice.expiry_date <= expiry_threshold: return True return False def memberservice_expiry_threshold(self, memberservice): """ This method helps us decide when to show expiry warnings. For all services that have subscription_period of a YEAR or less, but not less than a MONTH, we want to show the message within the, 'annual_expiry_warning_threshold'. For all services that have subscription_period of a MONTH or less, we want to show the message within the, 'monthly_expiry_warning_threshold'. """ subperiod = self.dao.related_service(memberservice).subscription_period if subperiod <= MONTH: return self.settings.monthly_expiry_warning_threshold elif subperiod <= YEAR: return self.settings.annual_expiry_warning_threshold def get_services(self, context, userid, subject): memberservices = [] services = [] pps = self.context.restrictedTraverse('@@plone_portal_state') memberid = pps.member().getId() tmpservices = self.dao.get_active_memberservices_by_subject(memberid, subject) for ms in tmpservices: service = self.dao.related_service(ms) if service.access_path and '@@practice' in service.access_path: memberservices.append(ms) services.append(service) return memberservices, services def get_accessto(self, practice_services): accessto = ','.join( ['%s-%s' %(s.subject, s.grade) for s in practice_services] ) return accessto def add_noaccess_message(self): # set a portal message plone_utils = getToolByName(self.context, 'plone_utils') message = _(u'You do not currently have access to this service.') plone_utils.addPortalMessage(message, 'info') return message def publishTraverse(self, request, name): """ consume the subpath """ path = request['TraversalRequestNameStack'] subpath = path[:] path[:] = [] subpath.reverse() request.set('traverse_subpath', subpath) return self