Exemple #1
0
 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__()
Exemple #2
0
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)
Exemple #3
0
 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)
Exemple #4
0
 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', [])
Exemple #5
0
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
Exemple #7
0
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())
        )
Exemple #8
0
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()
Exemple #10
0
 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)
Exemple #11
0
 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')
Exemple #12
0
    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)
Exemple #14
0
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
Exemple #16
0
    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()
Exemple #17
0
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
Exemple #18
0
    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
Exemple #20
0
    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))
Exemple #21
0
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
Exemple #23
0
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